Search code examples
three.jsshaderfragment-shadervertex-shadershadow-mapping

ThreeJS [r85]: Custom Shader with Shadowmap


I've created a custom shader to be able to use a BlendMap with 4 different textures but I'm unable to get the shadows/lightning effects to work with it.

What am I missing here? Or is there some other way I can achieve same functionality?

Mesh creation method below which shows all textures blended properly.

// Creates the ground
function CreateGround() {
    var uniforms = THREE.UniformsUtils.merge([
        THREE.UniformsLib["lights"],
        THREE.UniformsLib["shadowmap"],
    {
        TextureBackground: { type: "t", value: null },
        TextureR: { type: "t", value: null },
        TextureG: { type: "t", value: null },
        TextureB: { type: "t", value: null },
        TextureBlendMap: { type: "t", value: null }
    }]);

    var shaderMaterial;
    try {
        shaderMaterial = new THREE.ShaderMaterial({
            lights: true,
            uniforms: uniforms,
            vertexShader: BlendMapVertexShader,
            fragmentShader: BlendMapFragmentShader
        });
    } catch (e) {
        alert("Error 'CreateGround' : GPU Shader couldn't compile");
    }


    shaderMaterial.uniforms.TextureBlendMap.value = _TextureBlendMap;
    shaderMaterial.uniforms.TextureBackground.value = _TextureSand;
    shaderMaterial.uniforms.TextureR.value = _TextureClay;
    shaderMaterial.uniforms.TextureG.value = _TextureClay;
    shaderMaterial.uniforms.TextureB.value = _TextureRock;

    var geometry = new THREE.BoxGeometry(GROUND_SIZE, GROUND_HEIGHT, GROUND_SIZE);
    var mesh = new THREE.Mesh(geometry, shaderMaterial);

    mesh.castShadow = false;
    mesh.receiveShadow = true;

    return mesh;
}

And this is my current shader:

BlendMapVertexShader = [
THREE.ShaderChunk["shadowmap_pars_vertex"],
"varying vec2 vUv;",
"varying vec3 vPosition;",

"void main( void ) {",
    "vUv = uv;",
    "vPosition = position;",
    "gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1);",

    THREE.ShaderChunk["begin_vertex"],
    THREE.ShaderChunk["worldpos_vertex"],
    THREE.ShaderChunk["shadowmap_vertex"],
"}",
].join("\n");

BlendMapFragmentShader = [
THREE.ShaderChunk["common"],
THREE.ShaderChunk["packing"],
THREE.ShaderChunk["shadowmap_pars_fragment"],

"varying vec2 vUv;",
"varying vec3 vPosition;",
"uniform sampler2D TextureBlendMap;",
"uniform sampler2D TextureBackground;",
"uniform sampler2D TextureR;",
"uniform sampler2D TextureG;",
"uniform sampler2D TextureB;",

"void main() {",

    "vec4 cBlend = texture2D(TextureBlendMap, vUv);",
    "float bText = 1.0 - (cBlend.r + cBlend.g + cBlend.b);",
    "vec2 tiledCoords = vUv * 40.0;",
    "vec4 cBack = texture2D(TextureBackground, tiledCoords) * bText;",
    "vec4 cR = texture2D(TextureR, tiledCoords) * cBlend.r;",
    "vec4 cG = texture2D(TextureG, tiledCoords) * cBlend.g;",
    "vec4 cB = texture2D(TextureB, tiledCoords) * cBlend.b;",
    "vec4 cTot = cBack + cR + cG + cB;",
    "gl_FragColor = cTot;",
    THREE.ShaderChunk["shadowmap_fragment"],
"}",
].join("\n");

I have no errors nor warnings in the browser.

three.js r85Dev


Solution

  • Alright. I ended up copying the PHONG shader and then override the diffuse color input. Solution below.

    This is the method to create the mesh with blendmapshader

    // Creates the ground
    function CreateGround(material) {
        var uniforms = THREE.UniformsUtils.merge([
            THREE.UniformsLib["common"],
            THREE.UniformsLib["aomap"],
            THREE.UniformsLib["lightmap"],
            THREE.UniformsLib["emissivemap"],
            THREE.UniformsLib["bumpmap"],
            THREE.UniformsLib["normalmap"],
            THREE.UniformsLib["displacementmap"],
            THREE.UniformsLib["gradientmap"],
            THREE.UniformsLib["fog"],
            THREE.UniformsLib["lights"],
        {
            emissive: { type: "c", value: new THREE.Color(0x000000) },
            specular: { type: "c", value: new THREE.Color(0x111111) },
            shininess: { type: "f", value: 30 },
    
            TextureBackground: { type: "t", value: null },
            TextureR: { type: "t", value: null },
            TextureG: { type: "t", value: null },
            TextureB: { type: "t", value: null },
            TextureBlendMap: { type: "t", value: null },
        }]);
    
        var shaderMaterial;
        try {
            shaderMaterial = new THREE.ShaderMaterial({
                lights: true,
                uniforms: uniforms,
                vertexShader: BlendMapVertexShader,
                fragmentShader: BlendMapFragmentShader
            });
        } catch (e) {
            alert("Error 'CreateGround' : GPU Shader couldn't compile");
        }
    
        shaderMaterial.uniforms.TextureBlendMap.value = _TextureBlendMap;
        shaderMaterial.uniforms.TextureBackground.value = _TextureSand;
        shaderMaterial.uniforms.TextureR.value = _TextureClay;
        shaderMaterial.uniforms.TextureG.value = _TextureGrass;
        shaderMaterial.uniforms.TextureB.value = _TextureSandRock;
    
        var geometry = new THREE.BoxGeometry(GROUND_SIZE, GROUND_HEIGHT, GROUND_SIZE);
        var mesh = new THREE.Mesh(geometry, shaderMaterial);
    
        mesh.castShadow = false;
        mesh.receiveShadow = true;
    
        return mesh;
    }
    

    And this is the modified PHONG shader:

    BlendMapVertexShader = [
    "#define PHONG",
    
    "varying vec3 vViewPosition;",
    "varying vec2 vUv;",
    
    "#ifndef FLAT_SHADED",
    
    "varying vec3 vNormal;",
    
    "#endif",
    
    
    THREE.ShaderChunk["common"],
    THREE.ShaderChunk["uv_pars_vertex"],
    THREE.ShaderChunk["uv2_pars_vertex"],
    THREE.ShaderChunk["displacementmap_pars_vertex"],
    THREE.ShaderChunk["envmap_pars_vertex"],
    THREE.ShaderChunk["color_pars_vertex"],
    THREE.ShaderChunk["morphtarget_pars_vertex"],
    THREE.ShaderChunk["skinning_pars_vertex"],
    THREE.ShaderChunk["shadowmap_pars_vertex"],
    THREE.ShaderChunk["logdepthbuf_pars_vertex"],
    THREE.ShaderChunk["clipping_planes_pars_vertex"],
    
    "void main() {",
        THREE.ShaderChunk["uv_vertex"],
        THREE.ShaderChunk["uv2_vertex"],
        THREE.ShaderChunk["color_vertex"],
    
        THREE.ShaderChunk["beginnormal_vertex"],
        THREE.ShaderChunk["morphnormal_vertex"],
        THREE.ShaderChunk["skinbase_vertex"],
        THREE.ShaderChunk["skinnormal_vertex"],
        THREE.ShaderChunk["defaultnormal_vertex"],
    
        "#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED",
    
            "vNormal = normalize( transformedNormal );",
    
        "#endif",
        THREE.ShaderChunk["begin_vertex"],
        THREE.ShaderChunk["displacementmap_vertex"],
        THREE.ShaderChunk["morphtarget_vertex"],
        THREE.ShaderChunk["skinning_vertex"],
        THREE.ShaderChunk["project_vertex"],
        THREE.ShaderChunk["logdepthbuf_vertex"],
        THREE.ShaderChunk["clipping_planes_vertex"],
    
        "vUv = uv;",
        "vViewPosition = - mvPosition.xyz;",
    
        THREE.ShaderChunk["worldpos_vertex"],
        THREE.ShaderChunk["envmap_vertex"],
        THREE.ShaderChunk["shadowmap_vertex"],
    
    "}",
    ].join("\n");
    
    BlendMapFragmentShader = [
    "#define PHONG",
    
    "varying vec2 vUv;",
    
    "uniform vec3 diffuse;",
    "uniform vec3 emissive;",
    "uniform vec3 specular;",
    "uniform float shininess;",
    "uniform float opacity;",
    
    "uniform sampler2D TextureBlendMap;",
    "uniform sampler2D TextureBackground;",
    "uniform sampler2D TextureR;",
    "uniform sampler2D TextureG;",
    "uniform sampler2D TextureB;",
    
    THREE.ShaderChunk["common"],
    THREE.ShaderChunk["packing"],
    THREE.ShaderChunk["color_pars_fragment"],
    THREE.ShaderChunk["uv_pars_fragment"],
    THREE.ShaderChunk["uv2_pars_fragment"],
    THREE.ShaderChunk["map_pars_fragment"],
    THREE.ShaderChunk["alphamap_pars_fragment"],
    THREE.ShaderChunk["aomap_pars_fragment"],
    THREE.ShaderChunk["lightmap_pars_fragment"],
    THREE.ShaderChunk["emissivemap_pars_fragment"],
    THREE.ShaderChunk["envmap_pars_fragment"],
    THREE.ShaderChunk["fog_pars_fragment"],
    THREE.ShaderChunk["bsdfs"],
    THREE.ShaderChunk["lights_pars"],
    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"],
    THREE.ShaderChunk["logdepthbuf_pars_fragment"],
    THREE.ShaderChunk["clipping_planes_pars_fragment"],
    
    "void main() {",
    
        THREE.ShaderChunk["clipping_planes_fragment"],
        "// THIS IS CUSTOM CODE TO OVERRIDE THE DIFFUSE COLOR WITH BLENDMAP TEXTURES",
        "vec4 cBlend = texture2D(TextureBlendMap, vUv);",
        "float bText = 1.0 - (cBlend.r + cBlend.g + cBlend.b);",
        "vec2 tiledCoords = vUv * 40.0;",
        "vec4 cBack = texture2D(TextureBackground, tiledCoords) * bText;",
        "vec4 cR = texture2D(TextureR, tiledCoords) * cBlend.r;",
        "vec4 cG = texture2D(TextureG, tiledCoords) * cBlend.g;",
        "vec4 cB = texture2D(TextureB, tiledCoords) * cBlend.b;",
        "vec4 cTot = cBack + cR + cG + cB;",
    
        "vec4 diffuseColor = vec4( diffuse, opacity );",
        "diffuseColor.r = cTot.r;",
        "diffuseColor.g = cTot.g;",
        "diffuseColor.b = cTot.b;",
        "ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
        "vec3 totalEmissiveRadiance = emissive;",
    
        THREE.ShaderChunk["logdepthbuf_fragment"],
        THREE.ShaderChunk["map_fragment"],
        THREE.ShaderChunk["color_fragment"],
        THREE.ShaderChunk["alphamap_fragment"],
        THREE.ShaderChunk["alphatest_fragment"],
        THREE.ShaderChunk["specularmap_fragment"],
        THREE.ShaderChunk["normal_flip"],
        THREE.ShaderChunk["normal_fragment"],
        THREE.ShaderChunk["emissivemap_fragment"],
    
        "// accumulation",
        THREE.ShaderChunk["lights_phong_fragment"],
        THREE.ShaderChunk["lights_template"],
    
        "// modulation",
        THREE.ShaderChunk["aomap_fragment"],
    
        "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",
    
        THREE.ShaderChunk["envmap_fragment"],
    
        "gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
    
        THREE.ShaderChunk["premultiplied_alpha_fragment"],
        THREE.ShaderChunk["tonemapping_fragment"],
        THREE.ShaderChunk["encodings_fragment"],
        THREE.ShaderChunk["fog_fragment"],
    "}",
     ].join("\n");