1、几何体顶点与UV和法向量
几何体顶点
three.js的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry类构建的,BufferGeometry是一个没有任何形状的空几何体,我们可以通过BufferGeometry自定义任何几何形状,就是定义顶点数据
1、设置顶点坐标来绘制几何体。注意:面是由 2 个三角形组成的,所以要传入 2 个三角形顶点坐标
const geometry = new THREE.BufferGeometry()
利用js中的类型化数组Float32Array
创建xyz坐标数据来表示顶点坐标
const vertices = new Float32Array([
// z 轴正面两个三角形组成面
-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,
// x 轴正面
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,
// z 轴背面
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,
// x 轴背面
-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,
// y 轴正面
-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,
// y 轴背面(顺时针写,其他逆时针写)
-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,
])
创建属性缓冲区对象,每3个为一组,分别表示一个顶点的xyz坐标
const attribue = new THREE.BufferAttribute(vertices, 3)
设置几何体attributes属性的位置属性
geometry.attributes.position = attribue
自己设置用了 108 个点坐标组成了立方体,为何 three.js 用了 72 个顶点坐标就可以了?
console.log(cube)
console.log(cube.geometry.attributes.position.array) // 72 个数值
因为每个面是由 4 个顶点坐标组成,每个顶点坐标x,y,z坐标值是 3 个数字,所以一个面由 12 个数字组成,6 个面就是 72 个顶点坐标。
设置 index 属性可以复用两个三角形重复的顶点坐标
const geometry = new THREE.BufferGeometry()
// 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,
])
const attribue = new THREE.BufferAttribute(vertices, 3)
geometry.attributes.position = attribue
index 属性:允许顶点在多个三角面片间可以重用(注意要和上面顶点数组顺序对应),则0代表上面属性的第一组
const indexes = new Uint16Array([
2, 3, 1, 3, 0, 1
])
设置为 1 个数字代表上面一组坐标(3 个数字,xyz 坐标位置)
geometry.index = new THREE.BufferAttribute(indexes, 1)
顶点着色,每一个顶点都可以设置自己的颜色。
const colors = new Float32Array([
0, 1, 0, // 绿色
1, 0, 0, // 红色
0, 0, 1, // 蓝色
0, 1, 1, // 蓝绿色
])
设置几何体attributes属性的颜色color属性,三个为一组。
geometry.attributes.color = new THREE.BufferAttribute(colors, 3)
让材质开启顶点着色功能
const material = new THREE.MeshBasicMaterial({ vertexColors: true })
UV
UV属性是一组二维坐标,每个顶点都有一个对应的UV坐标。在三维模型上贴上二维的纹理贴图时,需要将所有顶点映射到纹理上的对应位置。UV属性的取值范围一般是[0,1],表示纹理上的相对位置。
console.log(cube.geometry.attributes.uv.array) // 48 个数值
UV 贴图实际类似把一个立方体展开铺开,只有 x,y 两个方向的坐标,原点在左下角,右向是 U 方向(x),值为 0 - 1, 纵向向上是 V 方向(y),值为 0 - 1; 所以每个点平面坐标,一个面只需要 8 个数值表示 4 个点坐标的 x,y 坐标数值
法向量
法向属性是每个顶点的法向量,用于确定顶点所在面的方向和光照效果。在three.js中,光照效果是基于每个顶点的法向量和光线方向计算的。因此,为了让模型的光照效果更真实,在创建几何体时需要设置每个顶点的法向量信息。通过修改法向属性,可以调整模型的光照效果和表面平滑度。
法向量(每个顶点朝向-如何折射光)
console.log(cube.geometry.attributes.normal.array) // 72 个数值
2、基础网格材质
材质就像物体的皮肤,决定了几何体的外表。例如,材质可以定义一个几何体看起来像金属还是木板,是否透明,什么颜色等,然后添加到Mesh中才可以添加到场景中进行渲染。
光照模型
Three.js会提供一些的光照模型来模拟物体表面的光照,光照模型就一种模拟光照的计算方法。MeshPhysicalMaterial
和MeshLambertMaterial
一样都是渲染网格模型的材质,但是他们用的光照模型不同,具体点说就是材质模拟Mesh反射光照的代码算法不同,算法不同,自然模拟光照的真实程度也不同。
-
MeshLambertMaterial: Lambert光照模型(漫反射)
-
MeshPhongMaterial:Phong光照模型(漫反射、高光反射)
-
MeshStandardMaterial和MeshPhysicalMaterial:基于物理的光照模型(微平面理论、能量守恒、菲涅尔反射...)
金属度metalness
金属度属性.metalness
表示材质像金属的程度, 非金属材料,如木材或石材,使用0.0,金属使用1.0。
new THREE.MeshStandardMaterial({
metalness: 1.0,//金属度属性
})
mesh.material.metalness = 1.0;//金属度
粗糙度roughness
粗糙度roughness
表示模型表面的光滑或者说粗糙程度,越光滑镜面反射能力越强,越粗糙,表面镜面反射能力越弱,更多地表现为漫反射。
粗糙度roughness
,0.0表示平滑的镜面反射,1.0表示完全漫反射,默认0.5。
new THREE.MeshStandardMaterial({
roughness: 0.5,//表面粗糙度
})
mesh.material.roughness = 0.5;//表面粗糙度
颜色贴图
通过纹理贴图加载器TextureLoader
的.load()
方法加载一张图片可以返回一个纹理对象Texture
。
立方体纹理加载器CubeTextureLoader
的.load()
方法是加载6张图片,返回一个立方体纹理对象CubeTexture
。
立方体纹理对象CubeTexture
的父类是纹理对象Texture
。
图片转成纹理对象,设置给材质作为贴图
const mapTexture = new THREE.TextureLoader().load('texture/basecolor.jpg')
颜色通道-设置SRGB才是原图样子
mapTexture.colorSpace = THREE.SRGBColorSpace
创建网格材质,装入纹理
const material = new THREE.MeshBasicMaterial({
map: mapTexture // 颜色贴图
})
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
纹理对象详细控制
纹理偏移,旋转等
纹理位移(二维向量,值范围是 0 - 1,默认值是 0)
mapTexture.offset.x = 0.5
纹理旋转(弧度)- 默认绕左下角为中心旋转
mapTexture.rotation = Math.PI / 3
物件中心点为旋转中心点
mapTexture.center.set(0.5, 0.5)
物件重复(但是只绘制一次)
mapTexture.repeat.set(2, 2)
纹理贴图在水平方向上将如何包裹,在UV映射中对应于U。
mapTexture.wrapS = THREE.RepeatWrapping // 重复
纹理贴图在垂直方向上将如何包裹,在UV映射中对应于V
mapTexture.wrapT = THREE.RepeatWrapping // 重复
透明度贴图 创建透明度贴图-纹理对象
const alphaTexture = new THREE.TextureLoader().load('texture/opacity.jpg')
alphaTexture.colorSpace = THREE.SRGBColorSpace
const material = new THREE.MeshBasicMaterial({
map: mapTexture, // 颜色贴图
alphaMap: alphaTexture, // 2. 传入透明纹理对象
transparent: true, // 3. 开启透明材质
opacity: 0.1 // 全透明
})
环境遮挡贴图
计算灯光的阴暗/明亮的对比效果,基础网格材质是模拟效果,受光照影响的材质设置环境遮挡贴图需要加环境光才有效果
const aoTexture = new THREE.TextureLoader().load('texture/ambientOcclusion.jpg')
aoTexture.colorSpace = THREE.SRGBColorSpace
const material = new THREE.MeshBasicMaterial({
map: mapTexture, // 颜色贴图
alphaMap: alphaTexture, // 透明度贴图
transparent: true,
// opacity: 0.1,
aoMap: aoTexture, // 2. 环境遮挡贴图(把透明度注释掉,为了看到效果)
// aoMapIntensity: 1 // 环境遮挡效果的强度。默认值为1。零是不遮挡效果。
})
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)