第一天
一、准备工作
1.准备工具
编辑工具vscode
2.下载three.js依赖
2.1 npm安装
npm i three
2.2github 下载
https://github.com/mrdoob/three.js/
3.引入three.js文件
3.1直接引入文件
// 下载的文件夹中找到three.js 创建新的文件夹放入
<script src="js/three.js"></script>
3.2 import导入文件
import * as THREE from './js/three.js';
二、实现一个三维动画
1.创建场景对象
const scene = new THREE.Scene();
2.放入摄像机
three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。
- 第一个属性是视野角度(FOV)。
- 第二个值是长宽比(aspect ratio)。
- 接下来的两个值是远剪切面和近剪切面。
- 也就是说当物体所在的位置比摄像机的远剪切面远或者所在位置比近剪切面近的时候,该物体超出的部分将不会被渲染到场景中。
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
3.渲染器
- 除了我们在这里用到的WebGLRenderer渲染器之外,Three.js同时提供了其他几种渲染器,当用户所使用的浏览器过于老旧,或者由于其他原因不支持WebGL时,可以使用这几种渲染器进行降级。
var renderer = new THREE.WebGLRenderer();
- 除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的大小尺寸.
renderer.setSize(window.innerWidth, window.innerHeight);
- 最后,我们将renderer(渲染器)这个元素添加到我们的HTML文档中,
document.body.appendChild(renderer.domElement);
4.画一个正方体
- 要创建一个立方体,我们需要一个BoxGeometry(立方体)对象.
var geometry = new THREE.BoxGeometry(1, 1, 1);
- 我们需要给它一个材质,来让它有颜色。Three.js自带了几种材质,在这里我们使用的是MeshBasicMaterial。color属性,值为0x00ff00,
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
- 第三步,我们需要一个Mesh(网格)。
- 网格是包含有一个几何体以及应用在在此几何体上的材质的对象,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。
var cube = new THREE.Mesh(geometry, material);
- 默认情况下,当我们调用scene.add()的时候,物体将会被添加到坐标为(0,0,0)的位置。
- 这可能会使得摄像机的位置和立方体相互重叠(也就是摄像机位于立方体中)
- 为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。
scene.add(cube);
5.实现正方体的旋转
// 照相机向z轴移动
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
三、创建坐标轴以及光源
1. 设置坐标轴
- AxesHelper
- 用于简单模拟3个坐标轴的对象.
- 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
var axes = new THREE.AxesHelper(50);
scene.add(axes)
2.设置光源
// SpotLightHelper
// 用于模拟聚光灯 SpotLight 的锥形辅助对象.
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( -60, 40, -65 );
spotLight.castShadow = true;
// 设置阴影效果
spotLight.shadow.mapSize = new THREE.Vector2(1024,1024);
spotLight.shadow.camera.far = 130
spotLight.shadow.camera.near = 40
scene.add( spotLight );
五、场景的方法和属性
1.获取到列表对象个数
```js
console.log(scene.children.length)
```
2.获取指定name的位置
//创建第二个正方体
//创建长宽高为4的几何体
var geometry2 = new THREE.BoxGeometry(4, 4, 4);
// 创建该几何体的外观材质
var material2 = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
// 将几何体和材质合并为能够添加到场景中的网格
var cube2 = new THREE.Mesh(geometry2, material2);
//设置阴影效果
cube2.castShadow = true
cube2.position.x += 5;
cube2.position.y += 10;
cube2.position.z += 0;
cube2.name = "cube2"
// 将合并的网格放入场景中
scene.add(cube2)
//查找指定name
var findObj = scene.getObjectByName("cube2",false)
console.log(findObj.position)
3.删除正方形
var ctrlObj2 = new function () {
// 为了误删查找到的光源和场景
this.removeFindeCube = function () {
if (findObj instanceof THREE.Mesh) {
scene.remove(findObj)
}
}
}
var ctrl2 = new dat.GUI()
ctrl2.add(ctrlObj2, "removeFindeCube")
4.动态生成正方形
var ctrlObj2 = new function () {
// 动态创建立方体
this.addNewCube = function () {
var geometryTemp = new THREE.BoxGeometry(4, 4, 4);
// 创建该几何体的外观材质
var materialTemp = new THREE.MeshLambertMaterial({ color: 0x0000ff });
// 将几何体和材质合并为能够添加到场景中的网格
var cubeTemp = new THREE.Mesh(geometryTemp, materialTemp);
//设置阴影效果
cubeTemp.castShadow = true
cubeTemp.position.x += Math.random() * 10 + 2;
cubeTemp.position.y += Math.random() * 10 + 2;
cubeTemp.position.z += Math.random() * 10 + 2;
// 将合并的网格放入场景中
scene.add(cubeTemp)
}
}
var ctrl2 = new dat.GUI()
ctrl2.add(ctrlObj2, "addNewCube")
5.动态为生成的正方体添加动态
//traverse 方法的参数是一个函数,被调用者和每个后代对象都会调用该函数
scene.traverse(function (obj) {
if (obj instanceof THREE.Mesh && obj != plane) {
obj.rotation.x += ctrlObj.rootationSpeed;
obj.rotation.y += ctrlObj.rootationSpeed;
obj.rotation.z += ctrlObj.rootationSpeed;
}
})
6.雾化效果
- 第一个参数是雾化的颜色,第二个值是雾化近处的值,第三个参数是雾化的远处值
scene.fog = new THREE.Fog(0xff0000,0.01,100)
- 第一个参数是雾化的颜色,第二个参数是雾化的浓度
scene.fog = new THREE.FogExp2(0xffffff,0.01)
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/dat.gui.js"></script>
<script>
// npm 安装three导入
// import * as THREE from 'three';
const scene = new THREE.Scene();
// 雾化效果
// 第一个参数是无华的颜色,第二个值是雾化近处的值,第三个参数是雾化的远处值
// scene.fog = new THREE.Fog(0xff0000,0.01,100)
// 第一个参数是雾化的颜色,第二个参数是雾化的浓度
// scene.fog = new THREE.FogExp2(0xffffff,0.01)
// Our Javascript will go here.
// 复制文件导入
// var scene = new THREE.Scene();
// three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。
// 第一个属性是视野角度(FOV)。
// 第二个值是长宽比(aspect ratio)。
// 接下来的两个值是远剪切面和近剪切面。
// 也就是说当物体所在的位置比摄像机的远剪切面远或者所在位置比近剪切面近的时候,该物体超出的部分将不会被渲染到场景中。
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 接下来是渲染器。这里是施展魔法的地方。
// 除了我们在这里用到的WebGLRenderer渲染器之外,Three.js同时提供了其他几种渲染器,当用户所使用的浏览器过于老旧,或者由于其他原因不支持WebGL时,可以使用这几种渲染器进行降级。
var renderer = new THREE.WebGLRenderer();
// 除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的大小尺寸。
// 。比如说,我们可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满我们的应用程序。
// 因此,我们可以将渲染器宽高设置为浏览器窗口宽高。
// 对于性能比较敏感的应用程序来说,你可以给setSize传入一个较小的值,例如window.innerWidth/2和window.innerHeight/2,这将使得应用程序在渲染时,以一半的长宽尺寸渲染场景。
renderer.setSize(window.innerWidth, window.innerHeight);
// 最后,我们将renderer(渲染器)这个元素添加到我们的HTML文档中,
renderer.shadowMap.enabled = true
document.body.appendChild(renderer.domElement);
// 要创建一个立方体,我们需要一个BoxGeometry(立方体)对象.
// 设置坐标轴
//AxesHelper
// 用于简单模拟3个坐标轴的对象.
// 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
var axes = new THREE.AxesHelper(50);
// axes.setColors(0x0)
scene.add(axes)
var geometry = new THREE.BoxGeometry(8, 8, 8);
// 我们需要给它一个材质,来让它有颜色。Three.js自带了几种材质,在这里我们使用的是MeshBasicMaterial。
//color属性,值为0x00ff00,
var material = new THREE.MeshLambertMaterial({ color: 0xff2288 });
// 第三步,我们需要一个Mesh(网格)。
// 网格是包含有一个几何体以及应用在在此几何体上的材质的对象,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。
var cube = new THREE.Mesh(geometry, material);
// 默认情况下,当我们调用scene.add()的时候,物体将会被添加到坐标为(0,0,0)的位置。
// 这可能会使得摄像机的位置和立方体相互重叠(也就是摄像机位于立方体中)
// 。为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。
scene.add(cube);
// 三、渲染场景
cube.castShadow = true
cube.position.x += 15;
cube.position.y += 10;
cube.position.z += 20;
// 创建第二个正方体
//创建长宽高为4的几何体
var geometry2 = new THREE.BoxGeometry(4, 4, 4);
// 创建该几何体的外观材质
var material2 = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
// 将几何体和材质合并为能够添加到场景中的网格
var cube2 = new THREE.Mesh(geometry2, material2);
//设置阴影效果
cube2.castShadow = true
cube2.position.x += 5;
cube2.position.y += 10;
cube2.position.z += 0;
cube2.name = "cube2"
// 将合并的网格放入场景中
scene.add(cube2)
var findObj = scene.getObjectByName("cube2", false)
console.log(findObj.position)
// 地面网格
var geometry = new THREE.PlaneGeometry(100, 100);
var material = new THREE.MeshLambertMaterial({ color: 0xcccccc, side: THREE.DoubleSide });
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -0.5 * Math.PI // 沿着x轴向内旋转90度
plane.position.set(15, 0, 0)
plane.receiveShadow = true //地面接受阴影
scene.add(plane);
camera.position.x = -30;
camera.position.y = 45;
camera.position.z = 35;
camera.lookAt(scene.position)
// SpotLightHelper
// 用于模拟聚光灯 SpotLight 的锥形辅助对象.
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-60, 40, -65);
spotLight.castShadow = true;
// 设置阴影效果
spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
spotLight.shadow.camera.far = 130
spotLight.shadow.camera.near = 40
scene.add(spotLight);
var spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);
// 光源对象
// 环境光会均匀的照亮场景中的所有物体。
// 环境光不能用来投射阴影,因为它没有方向。
var light = new THREE.AmbientLight(0xAAAAA); // soft white light
scene.add(light);
// 获取到列表对象个数
console.log(scene.children.length)
var ctrlObj = {
rootationSpeed: 0.01,
jumpSpeed: 0.01
}
var ctrl = new dat.GUI()
// 设置跳跃速度和旋转速度
ctrl.add(ctrlObj, "rootationSpeed", 0, 1)
ctrl.add(ctrlObj, "jumpSpeed", 0, 1)
var ctrlObj2 = new function () {
// 为了误删查找到的光源和场景
this.removeFindeCube = function () {
if (findObj instanceof THREE.Mesh) {
scene.remove(findObj)
}
}
// 动态创建立方体
this.addNewCube = function () {
var geometryTemp = new THREE.BoxGeometry(4, 4, 4);
// 创建该几何体的外观材质
var materialTemp = new THREE.MeshLambertMaterial({ color: 0x0000ff });
// 将几何体和材质合并为能够添加到场景中的网格
var cubeTemp = new THREE.Mesh(geometryTemp, materialTemp);
//设置阴影效果
cubeTemp.castShadow = true
cubeTemp.position.x += Math.random() * 10 + 2;
cubeTemp.position.y += Math.random() * 10 + 2;
cubeTemp.position.z += Math.random() * 10 + 2;
// 将合并的网格放入场景中
scene.add(cubeTemp)
}
}
var ctrl2 = new dat.GUI()
ctrl2.add(ctrlObj2, "removeFindeCube")
ctrl2.add(ctrlObj2, "addNewCube")
renderScene()
// 跳跃
var gap = 0
function renderScene() {
// cube2.rotation.x += 0.01;
// cube2.rotation.y += 0.01;
// cube2.rotation.z += 0.01;
// cube.rotation.x += ctrlObj.rootationSpeed;
// cube.rotation.y += ctrlObj.rootationSpeed;
// cube.rotation.z += ctrlObj.rootationSpeed;
//traverse 方法的参数是一个函数,被调用者和每个后代对象都会调用该函数
scene.traverse(function (obj) {
if (obj instanceof THREE.Mesh && obj != plane) {
obj.rotation.x += ctrlObj.rootationSpeed;
obj.rotation.y += ctrlObj.rootationSpeed;
obj.rotation.z += ctrlObj.rootationSpeed;
}
})
// gap += 0.01
gap += ctrlObj.jumpSpeed
// Math.sin()方法创建正方体在x轴方向上的运行轨迹
cube.position.x = 25 + (20 * (Math.sin(gap)));
cube.position.y = 6 + (20 * Math.abs(Math.cos(gap)))
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
// 实现自适应
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight)
}
</script>
</body>
</html>