目录
纹理是一种图像或图像数据,用于为物体的材质提供颜色、纹理、法线、位移等信息,从而实现更加逼真的渲染结果。
纹理可以应用于Three.js
中的材质类型,如MeshBasicMaterial
、MeshLambertMaterial
、MeshPhongMaterial
、MeshStandardMaterial
等。
UV映射
UV映射是2D图像投影到3D模型的表面以进行纹理映射的3D建模过程(也即把位图贴到3D几何形状的过程或者方法)。在这个过程中,3D模型上的每个顶点都会被赋予一个二维坐标(U, V)。
由于X,Y,Z已经表示模型空间中的3D图形的轴了。所以用U和V分别表示纹理坐标的水平和垂直方向。
顶点UV坐标可以在0~1.0之间任意取值,纹理贴图左下角对应的UV坐标是(0,0)
,右上角对应的坐标(1,1)
。
UV映射公式如下:
(u,v) -> (x,y,z)
(u,v)
代表纹理上的坐标,(x,y,z)
代表几何图形上的点(向量)。
以立方缓冲几何体的一个面为例:
贴图的左下角
(0,0)
映射到几何体的(-1,-1,1)
;贴图的左下角
(1,0)
映射到几何体的(1,-1,1)
;贴图的左下角
(0,1)
映射到几何体的(-1,1,1)
;贴图的左下角
(1,1)
映射到几何体的(1,1,1)
;
three.js的所有内置的几何体都内置了UV映射,所以开发者不需要担心这个问题。
纹理的使用方法
加载纹理
// 1.
const textureLoader = new THREE.TextureLoader();
// 2.
const texture = textureLoader.load(uv);
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
map: texture, // 2.重点位置
});
const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial);
scene.add(boxMesh);
- 使用
TextureLoader
进行加载纹理;- 加载图像并在纹理准备就绪后更新纹理,然后设置给MeshStandardMaterial的
map
。
纹理变换
repeat
我们可以使用 repeat
属性对纹理进行重复显示,repeat
是一个 Vector2
实例,所以可以指定 x
和 y
属性。
texture.repeat.x = 2;
texture.repeat.y = 2;
默认情况下纹理不会重复(
THREE.ClampToEdgeWrapping
),最后一个像素被拉伸了,我们需要设置 wrapS 和 wrapT可重复。
texture.wrapS = THREE.RepeatWrapping
texture.wrapT = THREE.RepeatWrapping
wrapS
和wrapT
上面重复的纹理方向是相同的,可以设置为镜像方向。
texture.wrapS = THREE.MirroredRepeatWrapping
texture.wrapT = THREE.MirroredRepeatWrapping`
offset
我们可以使用 offset
属性对纹理进行重复偏移,repeat
是一个 Vector2
实例,所以可以指定 x
和 y
属性。
texture.offset.x = 0.1;
texture.offset.y = 0.1;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
如果不设置
THREE.RepeatWrapping
重复,则会出现纹理空白区域。
-
rotation
texture.rotation = Math.PI / 4;
旋转是弧度,逆时针方向旋转。旋转的点默认是(0,0)这个点
center
如果要按照纹理的中心进行旋转,需要修改center
。
texture.center = new THREE.Vector2(0.5, 0.5);
minFilter
和magFilter
可以使用 minFilter
属性来设置纹理图的 minification
缩小过滤器,使用magFilter
属性来设置纹理图的 minification
放大过滤器。
当纹理的像素小于渲染像素时,我们需要将纹理放大;当纹理的像素大于渲染像素时,我们需要将纹理缩小
以放大过滤器为例:
Nearest
就是找最近的一个像素点的颜色;Linear
就是根据附近的四个像素点的平均颜色值️;
纹理类型
纹理有很多种类型,接下来我们就来介绍这些不同的纹理。
如果只是测试效果,可以在一些免费的纹理图片网站上去下载。譬如 www.3dtextures.me 等。
本文使用的纹理图片如下:
颜色纹理
颜色纹理只会将纹理的像素应用在几何体上。它等同于直接在 material
上设置 color
属性,但是 color
属性只能设置一种颜色,而颜色纹理可以为每一个位置设置颜色。
const textureLoader = new THREE.TextureLoader();
const colorTexture = textureLoader.load('path/to/color_texture.jpg');
const material = new THREE.MeshBasicMaterial({
map: colorTexture // 增加颜色纹理
});
法线纹理
法线纹理它不会移动顶点,但是它会让光线认为面的朝向不同。所以看起来会有凹凸立体感。
const normalTexture = textureLoader.load('./images/door/normal.jpg');
const planeMaterial = new THREE.MeshStandardMaterial({
map: texture,
normalMap: normalTexture, // 增加法线纹理
});
立体视觉效果还是比较明显的
位移纹理
位移纹理是灰度图像,它将移动顶点以创造一些高度。使用高度纹理,你要添加更多的细分网格才能看到效果。
const displacementTexture = textureLoader.load("./images/door/height.jpg");
const planeGeometry = new THREE.PlaneGeometry(3, 3, 16, 16); // 增加网格
const planeMaterial = new THREE.MeshStandardMaterial({
map: texture,
normalMap: normalTexture,
displacementMap: displacementTexture,// 增加高度纹理
});
可以通过
displacementScale
控制位移的距离。
金属纹理
金属纹理(metalness texture)是灰度图像,将指定哪个部分是金属(白色)和非金属(黑色)。此信息将有助于创造反射,给 material 增加金属质感。
const metalTexture = textureLoader.load("./images/door/metalness.jpg");
const planeMaterial = new THREE.MeshStandardMaterial({
map: texture,
normalMap: normalTexture,
metalnessMap: metalTexture, // 增加金属纹理
});
增加金属感,是否有感觉?我没看出来。
粗糙度纹理
粗糙度(rougness texture)经常和金属度纹理一起使用,它也是灰度图,它将指定哪个部分是粗糙的(白色),哪一部分是光滑的(黑色)。
const roughTexture = textureLoader.load("./images/door/roughness.jpg");
const planeMaterial = new THREE.MeshStandardMaterial({
map: texture,
normalMap: normalTexture,
metalnessMap: metalTexture,
roughnessMap: roughTexture, // 增加粗糙度纹理
});
这个例子看不出效果,就不截图了。
环境光遮蔽纹理
环境遮挡纹理(ambient occlusion texture)是灰度图像,它将在表面缝隙中添加假的阴影。虽然它在物理上不准确,但它有助于创建对比度。
const aoTexture = textureLoader.load("./images/door/ambientOcclusion.jpg");
const planeMaterial = new THREE.MeshStandardMaterial({
map: texture,
normalMap: normalTexture,
metalnessMap: metalTexture,
roughnessMap: roughTexture,
aoMap: aoTexture, // 增加环境光遮蔽纹理
});
环境纹理
环境纹理来模拟物体周围的环境光照和反射。环境纹理通常用于创建反射镜面效果或提供全局光照。
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(2, 50, 50),
new THREE.MeshPhysicalMaterial({
roughness: 0,
metalness: 0,
color: 0xffea00,
envMap: texture, // 设置环境纹理
transmission: 1,
ior: 2.3,
})
);
看看这个玻璃球上的效果
重要参考资料:
three.js - Textures & Texture Mapping
Three.js Texture Mapping Tutorial
Texture