「这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战」
在3D世界中,很多模型,包括OBJ、VTK、GLTF等等,它们有很多相似的地方。无论是什么模型,在三维世界中它们都是由点线面组成的,在加上纹理、材质和光线,就更接近自然世界中的物体。
这节我们来看下怎么给Obj模型赋予多个纹理。
准备纹理
- 我们需要准备两张纹理图来实现我们的功能
- 第一张图是我们之前使用过的带有纹理坐标的纹理图
- 第二张图是我们找的一张新的纹理图
创建多个纹理实例
- 一个纹理实例绑定一个纹理贴图,我们这里需要两个
// 创建纹理实例
var texture = new THREE.Texture();
var texture2 = new THREE.Texture();
加载多个纹理图片资源
- 加载多个纹理资源,赋值给不同的纹理实例进行缓存。
var loader = new THREE.ImageLoader(manager);
loader.setCrossOrigin("Anonymous"); // 解决跨域问题
loader.load(`${base_url}/textures/UV_Grid_Sm.jpg`, function (image) {
texture.image = image;
texture.needsUpdate = true;
})
loader.load(`${base_url}/textures/disturb.jpg`, function (image) {
texture2.image = image;
texture2.needsUpdate = true;
})
- 使用
THREE.ImageLoader
加载我们的图片资源 - 设置
setCrossOrigin
来解决我们线上图片跨域问题 - 加载的图片添加到纹理中
- 纹理需要设置
needsUpdate
来进行更新。
给obj模型添加多个的纹理
- 我们遍历模型中的子模型,通过判断取模给子模型赋值不同的纹理
var i = 0;
var objLoader = new THREE.OBJLoader(manager)
objLoader.setCrossOrigin("Anonymous"); // 解决跨域问题
objLoader.load(`${base_url}/models/obj/male02/male02.obj`, function (object) {
// 遍历子模型
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
// 当取模等于0的时候赋予纹理2
if (i % 2 == 0) {
child.material.map = texture2
} else {
child.material.map = texture
}
i++
}
})
object.position.y = -80
scene.add(object)
}, onProgress, onError)
- 通过
THREE.OBJLoader
加载我们的 obj 模型 - 加载完成获取到模型后,通过
object.traverse
遍历子模型 - 根据我们的判断条件给不同的子模型赋值不同的纹理
- 我们也可以通过
onProgress
监听加载进度,onError
监听加载错误。 - 完成效果展示,目前随机给的纹理贴图,两只手和两只脚的贴图不一样,有点不协调。
- 我们也可以只给身体赋予纹理2,其他部位赋予纹理1,这样手和脚的贴图就能对称了。
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
// 模型的名字是身体部位,赋予纹理2
if (child.name === 'mesh1.002_mesh1-geometry') {
child.material.map = texture2
} else {
child.material.map = texture
}
}
})
mesh1.002_mesh1-geometry
这个模型是模型的身体部位,其他的子模型就是手脚和头发了。- 完成效果展示,这样看起来协调多了,如果想把头部单独赋予贴图,需要把头部做成一个单独的模型,这个需要模型师进行处理。
codepen示例代码 以上就是我们对与如何给模型赋予多个纹理的实战了。
总结
这一节我们主要讲了以下内容:
- 准备多个纹理图片
- 通过判断给模型赋予多个纹理