携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
关键代码
let uniformsBuild = null
let clockBuild = new THREE.Clock()
uniformsBuild = {
time: { value: 1.0 }
}
let material = new THREE.ShaderMaterial({
uniforms: uniformsBuild,
vertexShader: document.getElementById('vertex_shader').textContent,
fragmentShader: document.getElementById('fragment_shader').textContent
})
<script id="vertex_shader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fragment_shader" type="x-shader/x-fragment">
uniform float time;
varying vec2 vUv;
void main( void ) {
vec2 position = vUv;
float color = 0.0;
color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
color *= sin( time / 10.0 ) * 0.5;
gl_FragColor = vec4( vec3( color * 0.2, color * 0.6, color ), 0.5 );
}
</script>
// 皮肤变动动画
if (uniformsBuild !== null) {
let delta = clockBuild.getDelta()
uniformsBuild.time.value += delta * 5
}
// 画一个立方体盒子,贴皮肤成功
let geometry = new THREE.BoxBufferGeometry(8, 10, 2)
let mesh = new THREE.Mesh(geometry, material)
// console.log(mesh.geometry.attributes)
scene.add(mesh)
// 导入一个模型立方体盒子,贴皮肤失败
let loader = new GLTFLoader()
loader.load('/static/3d/test.glb', function (obj) {
obj.scene.position.y = 1
let cube = obj.scene.getObjectByName('立方体')
cube.material = material
// console.log(cube.geometry.attributes)
scene.add(obj.scene)
}, function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
}, function (error) {
console.error(error, 'load error!')
})
问题如下
画一个方盒子,贴皮肤ShaderMaterialc成功;然而从外部导入一个方盒子,贴皮肤ShaderMaterials失败。
问题分析
console.log(cube.geometry.attributes)
打印导入的模型查看可知:
没有uv,而vertex_shader需要使用到模型的uv,再查看画的立方体盒子是有uv的!!!
于是强制把画的立方体盒子的uv赋值给导入的模型立方体,皮肤就显示正常了。
问题延伸
模型UV展开与未展开,贴图对比图如下:
blender导出可UV贴图的模型:
因为模型的复杂所以需要从外部导入,那么如何让blender画的模型,导出并导入代码后有uv的存在呢?
1、模型导出时勾选Export texture coordinates
文件-导出-glTF 2.0(.glb)-左下角的Export glTF 2.0 binary中一定要勾选属性Export texture coordinates!!!
注意:
这样导出的模型场景,并不是给其中的所有子mesh对象都能正常贴uv皮肤,还需要对指定对象进行下一步操作。
2、对需要UV贴皮肤的模型组件进行UV展开
对于需要使用three.js代码贴uv皮肤的部分模型组件,需要在blender中对其进行UV展开!!
- 2.1、切换视图到UV Editing
- 2.2、在右侧视图选中需要UV贴皮肤的部分,切换到编辑模式
- 2.3、切换到面选取,全选当前物体的所有面
- 2.4、全选后按键盘【U】,选择展开,此时左侧视图明显展开了选中对象,若左侧视图无反应,选择其他展开方式比如智能UV投射等
- 2.5、然后导出仍记得勾选Export texture coordinates!!!
3、总而言之二点
- 1、一定要UV展开
- 2、导出记得勾选Export texture coordinates
blender的UV贴皮肤操作:
具体参考文档如下:
步骤总结:
- 1、切换视图到UV Editing
- 2、在右侧视图选中需要UV贴皮肤的部分,切换到编辑模式
- 3、切换到面选取,全选当前物体的所有面
- 4、全选后按键盘【U】,选择展开,此时左侧视图明显展开了选中对象,若左侧视图无反应,选择其他展开方式比如智能UV投射等 ==若只是贴材质==
- 5、右侧视图切换编辑模式为纹理绘制
- 6、右侧视图的左边选择槽选项卡,Painting Mode选择材质,对材质进行选取编辑即可 ==若要贴图像==
- 5、左侧视图下方点击新建-确定(或者打开一张本地图片),鼠标中轴滚动缩小左侧视图区域
- 6、左侧视图的右边修改当前新建的UV皮肤的名字、颜色等,或用画笔在左侧视图中进行绘制
- 7、绘制完成后在右侧视图中,切换编辑模式为纹理绘制
- 8、右侧视图的左边选择槽选项卡,Painting Mode选择图像,Canvas Image点击小图标选择之前新建的UV皮肤即可
注意点:
- 1、要使用UV贴图,需要切换到UV Editing模式,进行UV展开。
- 2、在UV Editing模式下导入图片仅用于查看UV贴图的效果,处理好图片后需保存图片至电脑本机。
- 3、回到默认模式,创建材质,再创建纹理,导入保存在本地的贴图,选择uv模式即可同UV展开那边的纹理展示效果一致。
- 4、blender中切换展示方式,切换到纹理能看到纹理,切换到材质能看到导出后的效果,但明明有纹理材质时切换到渲染啥都看不见,因为没有灯光。添加一个灯光,四处拖动照射看看效果。
参考文档: