使用ShaderMaterial复制MeshLambertMaterial将忽略纹理

我注意到THREE.js在内部使用着色器来创build核心材质,例如MeshLambertMaterial,所以我决定将Three.js代码中的lambert着色器复制到一个新的着色器中并在其上构build。

这是我得到的代码(从Three.js r66忠实复制)

THREE.MyShader = { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], { "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } } ]), vertexShader: [ "#define LAMBERT", "varying vec3 vLightFront;", "#ifdef DOUBLE_SIDED", "varying vec3 vLightBack;", "#endif", THREE.ShaderChunk[ "map_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "map_vertex" ], THREE.ShaderChunk[ "lightmap_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_lambert_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join("\n"), fragmentShader: [ "uniform float opacity;", "varying vec3 vLightFront;", "#ifdef DOUBLE_SIDED", "varying vec3 vLightBack;", "#endif", 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[ "shadowmap_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" ], "#ifdef DOUBLE_SIDED", //"float isFront = float( gl_FrontFacing );", //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", "if ( gl_FrontFacing )", "gl_FragColor.xyz *= vLightFront;", "else", "gl_FragColor.xyz *= vLightBack;", "#else", "gl_FragColor.xyz *= vLightFront;", "#endif", 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") } 

这是我用来设置我的制服和创build材料的代码。

 var textureUsed = 'rock_1'; var texture = THREE.ImageUtils.loadTexture( texturePath + textureUsed + "/diffuse.png"); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.x = 128; texture.repeat.y = 128; var shaderUniforms = THREE.UniformsUtils.clone( THREE.MyShader.uniforms ); shaderUniforms[ "map" ].value = texture; var material = new THREE.ShaderMaterial({ name: "TerrainShader", uniforms : shaderUniforms, vertexShader: THREE.MyShader.vertexShader, fragmentShader: THREE.MyShader.fragmentShader, fog:false, lights:true }); 

问题是,当我使用这些参数来创build一个MeshLambertMaterial我得到正确的照明和纹理重复,当我用它来创buildShaderMaterial灯光和阴影似乎工作,但纹理贴图不加载,以解决这个我挖通过代码,并设法得到地图加载通过添加这个丑陋的“黑客”到我的代码,正好在材料定义

 material.map = true; 

现在纹理被加载并显示出来,但是看起来纹理坐标是混乱的,而不是重复,Shader似乎忽略了我提供的重复值。

为什么我需要这个黑客来处理我的纹理,我能做些什么来获得正确的纹理重复?

three.js被devise为易于使用,不容易修改。 这可能会在未来…

您需要像这样设置material.defines

 var defines = {}; defines[ "USE_MAP" ] = "";. 

然后在材质构造函数中指定defines

 var material = new THREE.ShaderMaterial({ name: "TerrainShader", defines : defines, uniforms : shaderUniforms, vertexShader: THREE.MyShader.vertexShader, fragmentShader: THREE.MyShader.fragmentShader, fog:false, lights:true }); 

关于纹理重复,你需要添加重复你的制服:

 shaderUniforms[ "offsetRepeat" ].value.set( 0, 0, 2, 2 ); 

three.js r.66