如何在Three.js自定义GLTF模型上应用Ocean海洋着色器
代码存在的核心问题
- 传入
Water构造器的第一个参数要求是BufferGeometry/Geometry类型,你现在传的是完整的Mesh对象waterGeo,会直接导致初始化失败 - 变量
waterGeo没有显式声明,存在作用域污染问题,且如果GLTF模型内有多个Mesh的话,只会保留最后遍历到的Mesh water.rotation.x = - Math.PI / 2是官方示例给平面海面设置的旋转角度,用在自定义3D模型上会导致模型姿态异常- 开头定义的
waterMat没有实际使用,可以删除 - 你贴出的代码片段缺少
loader.load回调、以及遍历函数的闭合括号,实际运行会触发语法错误
修正后代码
const loader = new GLTFLoader().setPath( 'models/gltf/DamagedHelmet/glTF/' ); loader.load( 'DamagedHelmet.gltf', function ( gltf ) { let targetGeo; let meshTransform; gltf.scene.traverse( function ( child ) { if ( child.isMesh ) { targetGeo = child.geometry; // 保存原模型的位置/旋转/缩放信息 meshTransform = child.matrix; } } ); // 加载水法线纹理 const waterNormals = new THREE.TextureLoader().load( 'textures/waternormals.jpg', function ( texture ) { texture.wrapS = texture.wrapT = THREE.RepeatWrapping; } ); const water = new Water( targetGeo, { textureWidth: 512, textureHeight: 512, waterNormals: waterNormals, sunDirection: new THREE.Vector3(0, 1, 0).normalize(), // 可根据光照调整阳光方向 sunColor: 0xffffff, waterColor: 0x001e0f, distortionScale: 3.7, fog: scene.fog !== undefined } ); // 继承原模型的变换属性,避免位置偏移 water.applyMatrix4(meshTransform); scene.add(water); });
额外注意事项
- 渲染循环中需要添加时间参数更新逻辑,否则波浪动画不会运行:
function animate() { requestAnimationFrame(animate); // 同步更新水材质的时间 uniforms water.material.uniforms.time.value += 1 / 60; renderer.render(scene, camera); } - 如果自定义模型包含多个Mesh,需要给每个Mesh单独创建Water实例,或者提前合并所有Mesh的几何体为单个BufferGeometry再使用
- 可通过调整
distortionScale参数、水法线纹理的重复次数,适配不同尺寸的模型,避免波浪效果失真
内容的提问来源于stack exchange,提问作者Onur Caba
相关产品推荐
相关产品推荐

