世界坐标辅助器 -- AxesHelper
************************const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
轨道控制器 -- OrbitControls
可以旋转角度查看模型,需要配合自动渲染动画使用,一直更新。// 需要单独引入
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼 (滑动带有渐停)
controls.enableDamping = true;
// 设置阻尼系数
controls.dampingFactor = 0.05;
// 设置自动旋转
controls.autoRotate = true;
// 添加动画
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
// 轨道控制器更新 必须在animate中调用
controls.update();
renderer.render(scene, camera);
}
animate();
场景属性 -- Scene
添加背景 **scene.background** = 图片 || 颜色添加雾(效果)Fog
// 添加背景颜色
scene.background = new THREE.Color(0x666666);
// 添加背景图片
scene.background = new THREE.CubeTextureLoader().setPath('/').load(['2.jpg', '2.jpg', '2.jpg', '2.jpg', '2.jpg', '2.jpg']);
// 添加雾
scene.fog = new THREE.Fog(0xcccccc, 10, 15);
透视相机 -- PerspectiveCamera
**fov**,****视锥体近端面,远端面;
lookAt(cube.position),相机的视野方向,眼球除了位置还有方向概念;
gui调试器
用于在网页上快速调试,需要单独下载dat.gui插件使用步骤:
1.先创建一个控制属性对象
// 创建一个控制对象
const controlData = {
rotationSpeed: 0.01, // 转速
color: 0x00ff00,
wireframe: false,
envMap: '无'
}
2.new一个gui对象实例
const gui = new dat.GUI()
3.添加配置
const f = gui.addFolder('配置') // 创建一个设置分组
f.add(controlData, 'rotationSpeed').min(0.01).max(0.1).step(0.01).name('旋转速度') // 最小值,最大值,步长
// 颜色选择器
f.addColor(controlData, 'color').name('颜色')
// 下拉列表
f.add(controlData, 'envMap', ['无', '环境贴图1', '环境贴图2']).name('环境贴图')
// checkbox
f.add(controlData, 'wireframe').name('线框')
f.open() // 默认展开
4.具体实现
原理就是在animate动画中设置网格cube的各种属性,属性值就等于配置对象中的值,这样只要属性值以改变,几何体也就一起改变。注意color接受的时 THREE.Color的包裹值,不能直接赋值16进制数值
function animate() {
requestAnimationFrame(animate);
// cube.rotation.x += 0.05;
// cube.rotation.y += 0.05;
// 绑定为gui调试器的值
cube.rotation.x += controlData.rotationSpeed;
cube.rotation.y += controlData.rotationSpeed;
cube.material.color = new THREE.Color(controlData.color);
material.wireframe = controlData.wireframe;
// 轨道控制器更新 必须在animate中调用
controls.update();
renderer.render(scene, camera);
}
材质贴图和环境贴图 -- TextureLoader -- CubeTextureLoader
:::info 几何体呈现的样式,涂鸦由材质决定,材质分为很多种,都有公用的一些属性和自己的单独属性,如下为基础网格材质的属性 --** 贴图**,贴图所需要的值为**纹理(Texture);**:::
TextureLoader,平面贴图,用于在几何体身上使用,使几何体更加真实
创建纹理 -- 平面贴图
const texture = new THREE.TextureLoader().load("/texture/1mp.jpg");
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
map: texture
});
CubeTextureLoader,立体纹理,多用于环境贴图,通过6个不同的环境面,模拟真实的空间,顺序为 左右上下前后。
创建立体纹理 -- 左右上下前后
const cubeTexture = new THREE.CubeTextureLoader().setPath("/texture/").load([
"04.jpg", "01.jpg",
"05.jpg", "02.jpg",
"06.jpg", "03.jpg",
])
scene.background = cubeTexture
基础网格材质除了map这种颜色贴图,也支持envMap环境贴图,将环境贴图的属性赋值给球状几何体,可以模拟出反射的状态; 效果图如上;
创建球体
const geometry = new THREE.SphereGeometry(1);
const material = new THREE.MeshBasicMaterial({
envMap: cubeTexture
});
自定义几何图形 -- BufferGeometry
在创建几何体时,可以通过官方提供的一些常见的几何体快捷的创建,但是除了这些我们也可以自定义去创建几何体,几何体的面都是由多个**三角形**拼接而成的,所以每**三个坐标**就代表**一个顶点**,**x,y,z**;创建方式一:直接描述所有顶点****
const geometry = new THREE.BufferGeometry();
// 创建一个简单的矩形. 在这里我们左上和右下顶点被复制了两次。
// 因为在两个三角面片里,这两个顶点都需要被用到。 x,y,z
const vertices = new Float32Array( [
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, -1.0, 1.0
] );
// itemSize = 3 因为每个顶点都是一个三元组。
geometry.setAttribute('position', new THREE.BufferAttribute( vertices, 3 ) );
创建方式一这样写虽然说也可以实现,但是会有几个点是重合的,我们可以省略他们。
创建方式二:使用顶点索引方式创建,在已有的Float32Array数组中,直接使用索引生成,最后设置给geometry的index属性
// 需要确认几何体的顶点
// 利用索引来确定几何体的绘制方式
const indices = new Uint16Array([
0, 1, 2, 2, 3, 0
])
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
自定义UV值 -- Float32Array
创建网格材质的map为纹理对象时texture时,默认的显示位置是通过uv值决定的,可以自定义灯光的变化 -- AmbientLight
在之前的例子中,使用的材质都是基础网格材质,是不受光源影响的;当使用高光反射材质时,物体就会受到灯光的影响,所以没有灯光的情况下,物体渲染出来就是漆黑的,看不到自身的颜色。当在场景中添加上环境光后(),物体就会可见
const ambientLight = new THREE.AmbientLight(0xffffff, 1); // 光颜色 光照强度
scene.add(ambientLight);
光有环境光还不是很真实,添加一个点灯光,模拟自然中的太阳,灯泡.。。。
在添加点灯光后,需要手动开启灯光投射阴影,pointLight.castShadow = true; // 灯光将投射阴影,然后给几何体也开启投射阴影,这样在光照处就可以有阴影的显示了
const pointLight = new THREE.PointLight(0xffffff, 100, 100);
pointLight.position.set( 2, 3, 5 );
pointLight.castShadow = true; // 灯光将投射阴影
scene.add( pointLight );
// 添加灯光辅助
const lightHelper = new THREE.PointLightHelper(pointLight, 0.1);
scene.add(lightHelper);
Object3d和分组 -- Vector3 -- Group
在**三维空间中**,所有物体都有**自己**的**三维向量**Vector3(**x, y, z**),对于物体坐标可以使用创建的三维向量来进行赋值,实际场景中物体的移动应该是靠改变该变量而实现的。const vector = new THREE.Vector3(1, 1, 1);
// 之前修改
// cube.position.set(1, 1, 1);
// cube.position.x = 1
// 通过三维向量修改
cube.position.add(vector)
Object3d:
cube.position.addScalar(1) // 在当前的坐标位置基础上+1
cube.position.clone() // 当前坐标位置
cube.translateX(1); // 局部平移
cube.visible = true; // 是否可见
cube.scale.set(2, 1, 1); // 局部缩放
分组:正常是直接创建一个网格添加到场景中,分组是先创建两个网格,都有各自的OBject3D属性,然后创建一个组,将两个网格添加到组中,最后将组添加到场景中,组也有自己的Object3D属性
// 物体1
const cubeA = new THREE.Mesh( geometry, material );
// 设置物体1的位置
cubeA.position.set( 1, 1, 1 );
// 物体2
const cubeB = new THREE.Mesh( geometry, material );
cubeB.position.set( -1, -1, -1 );
// 创建组
const group = new THREE.Group();
// 设置组的位置
group.position.set(2, 0, 0);
// 组add物体1
group.add( cubeA );
group.add( cubeB );
// 场景加组
scene.add( group );
欧拉角度 -- Euler
blender基本使用
+ 按住滚轮可以拖动视角 + shift+滚轮可以移动物体 + s+滚轮放大缩小 + ~操作相机 + 左上角箭头可以设置视图 + 导出模型格式 + .fbx: + .obj: 游戏用,可编辑 + .glb/gltf: web浏览器用GLTE模型加载器 -- GLTFLoader
在实际开发中,threejs提供的简单几何体无法满足需求,需要通过建模软件来制作成品,我们直接使用,GLTFLoader就是用来在three中引入这些3D模型的;**需要注意所有3D模型引入进来都是黑的,需要灯光才能显示**const loader = new GLTFLoader();
loader.load('/src/assets/01.glb', function (gltf) {
console.log(gltf, 'gltf');
gltf.scene.traverse((child) => {
// 遍历模型中的物体
if (child.name == '柱体') {
child.material = material;
child.castShadow = true; // 开启阴影
}
// 接收投影(立方体)
if( child.name == '立方体' ){
child.receiveShadow = true;
child.position.y = -1.5;
}
})
scene.add(gltf.scene);
})
总体逻辑就是在场景中引入外部3D模型,然后GLTFLoader实例对象中的load方法的第二个参数回调函数中的参数中有我们整个模型的信息,通过名字判断其中模型的具体内容,来进行操作设置,每一个模型都是一个普通的Mesh对象