Replicating MeshLambertMaterial Using ShaderMaterial ignores textures

时光毁灭记忆、已成空白 提交于 2019-11-26 08:26:35

问题


I noticed that THREE.js uses shaders internally to create core material \"e.g. MeshLambertMaterial\", So I decided to copy the lambert shader from Three.js code into a new shader and build on it.

This is the code I got (Copied faithfully from 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\")

}

and this is the code that I use to setup my uniforms and create the material.

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
                });

The problem is that when I use these parameters to create a MeshLambertMaterial I get the correct lighting and texture repetitions, when I use it to create ShaderMaterial the lights and shadows seem to be working but the texture map isn\'t loaded, to fix this I dug through the code and managed to get the map to load by adding this ugly \"hack\" to my code, right after the material definition

material.map = true;

Now the texture is loaded and displayed but it looks like the texture coordinates are messed up, instead of repeating, the Shader seems to be ignoring the repeat values I supplied.

Why did I need that hack to get my texture processed and what can I do to get the correct texture repetitions?


回答1:


three.js was designed to be easy to use, not easy to modify. This may change in the future...

You need to set the material.defines like so:

var defines = {};

defines[ "USE_MAP" ] = "";. 

Then specify defines in the material constructor.

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

Regarding the texture repetitions, you need to add the repeat to your uniforms:

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

three.js r.66



来源:https://stackoverflow.com/questions/21928178/replicating-meshlambertmaterial-using-shadermaterial-ignores-textures

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!