我尝试使用 three.js 为汽车模型制作材料,其中汽车的基色可以动态更改。通过更改我正在使用的 MeshPhongMaterial 的颜色属性,这很容易。然后我需要在顶部应用纹理,并认为通过将图像添加到材质的贴图属性就很容易了。结果不是我所期望的,地图/纹理图像也被颜色属性设置的颜色着色。我希望它基本上覆盖基色。
谁能指出我正确的方向?
我尝试使用 three.js 为汽车模型制作材料,其中汽车的基色可以动态更改。通过更改我正在使用的 MeshPhongMaterial 的颜色属性,这很容易。然后我需要在顶部应用纹理,并认为通过将图像添加到材质的贴图属性就很容易了。结果不是我所期望的,地图/纹理图像也被颜色属性设置的颜色着色。我希望它基本上覆盖基色。
谁能指出我正确的方向?
这是一个完整的脚本块。读完三.js后立即插入
<script>
THREE.ShaderChunk.map_fragment = [
"#ifdef USE_MAP",
"vec4 texelColor = texture2D( map, vUv ); /* NEWWW */",
"#ifdef GAMMA_INPUT",
"texelColor.xyz *= texelColor.xyz;",
"#endif",
"gl_FragColor.rgb = mix(gl_FragColor.rgb,texelColor.rgb,texelColor.a);",
"vec3 surfDiffuse = mix(diffuse,vec3(1,1,1),texelColor.a);",
"#else",
"vec3 surfDiffuse = diffuse;",
"#endif"].join('\n');
// now replace references to 'diffuse' with 'surfDiffuse'
THREE.ShaderChunk.lights_phong_fragment =
THREE.ShaderChunk.lights_phong_fragment.replace(/\bdiffuse\b/gm,'surfDiffuse')
THREE.ShaderLib.phong.fragmentShader = [
"uniform vec3 diffuse;",
"uniform float opacity;",
"uniform vec3 ambient;",
"uniform vec3 emissive;",
"uniform vec3 specular;",
"uniform float shininess;",
THREE.ShaderChunk[ "color_pars_fragment" ],
THREE.ShaderChunk[ "map_pars_fragment" ],
THREE.ShaderChunk[ "lightmap_pars_fragment" ],
THREE.ShaderChunk[ "envmap_pars_fragment" ],
THREE.ShaderChunk[ "fog_pars_fragment" ],
THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
THREE.ShaderChunk[ "normalmap_pars_fragment" ],
THREE.ShaderChunk[ "specularmap_pars_fragment" ],
"void main() {",
"gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",
THREE.ShaderChunk[ "map_fragment" ],
THREE.ShaderChunk[ "alphatest_fragment" ],
THREE.ShaderChunk[ "specularmap_fragment" ],
THREE.ShaderChunk[ "lights_phong_fragment" ],
THREE.ShaderChunk[ "lightmap_fragment" ],
THREE.ShaderChunk[ "color_fragment" ],
THREE.ShaderChunk[ "envmap_fragment" ],
THREE.ShaderChunk[ "shadowmap_fragment" ],
THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
THREE.ShaderChunk[ "fog_fragment" ],
"}"
].join('\n');
</script>
了解了有关three.js phong 材料的一些知识——它不能以我想要的方式处理突出显示,但是......无论如何。如果您需要更多复杂性,我建议您改用 ShaderMaterial。
为此,您将需要一个自定义着色器——以及一个带有 alpha 通道的纹理(本质上是一种 DDS 格式)。如果您查看 three.js 源代码,您会看到一些名为“map_fragment”的片段着色器代码,如下所示:
"#ifdef USE_MAP",
"#ifdef GAMMA_INPUT",
"vec4 texelColor = texture2D( map, vUv );",
"texelColor.xyz *= texelColor.xyz;",
"gl_FragColor = gl_FragColor * texelColor;",
"#else",
"gl_FragColor = gl_FragColor * texture2D( map, vUv );",
"#endif",
"#endif"
如您所见,它将您的纹理贴图乘以颜色(此时位于“gl_FragColor”中)。相反,听起来您希望您的地图覆盖在基色之上,只是您已经绘制了它(例如,镀铬保险杠和前灯)。
一个简单的方法可能是在实例化任何 phong 材质之前更改“phong”的工作方式,方法是更改“map_fragment”字符串的值。
而不是“gl_FragColor * (something)”——尝试将此作为重新分配 THREE.ShaderChunk.map_fragment:
[
"#ifdef USE_MAP",
"vec4 texelColor = texture2D( map, vUv );",
"#ifdef GAMMA_INPUT",
"texelColor.xyz *= texelColor.xyz;",
"#endif",
"gl_FragColor = vec4(mix(gl_FragColor.rgb,texelColor.rgb,texelColor.a),(gl_FragColor.a*texelColor.a));",
"#endif"
].join('\n');
以这种方式覆盖 stock 方法的危险在于它将应用于场景中的所有模型——绘制的纹理将覆盖材质颜色。如果没问题,你就完成了。否则,您应该创建一个类似于“phong”的新 THREE.ShaderMaterial,除了此处引用的不同之处。