ShaderMaterial particles not receiving shadows

I’ve been following Edan Kwan’s guide on shadows: http://blog.edankwan.com/post/three-js-advanced-tips-shadow . Specifically, I’ve been trying to apply the concepts to a field of Points. So the idea is that the particles can both cast shadows and receive shadows. I was able to cast shadows using customDistanceMaterial (since I’m using PointLights).

But I noticed that the ShaderChunk.shadowmap_fragment.glsl no longer exists, so I’m not really sure how to approach the problem of receiving shadows. I’ve tried using ShaderChunk.shadowmask_pras_fragment.glsl method - getShadowMask() , but I’m not quite sure if I’m doing it right (or even for the right purpose). Cause, I’m getting the value 1.0f for all vertices no matter what.

Just to make it clear, I’d like to receive shadows from other particles and other objects in the scene.
------------------------- (removed link, no longer relevant)

index.js:

var geo = new THREE.BufferGeometry();
geo.addAttribute( 'position', new THREE.BufferAttribute( position, 3 ));
geo.addAttribute( 'displacement', new THREE.BufferAttribute( displacement, 1 ));

var mat = new THREE.ShaderMaterial({
    uniforms: THREE.UniformsUtils.merge([
        THREE.UniformsLib.shadowmap,
        {
            color1: { type: 'c', value: undef },
            color2: { type: 'c', value: undef }
        }
    ]),
    vertexShader: shaderParse(document.getElementById( 'vertexShader' ).textContent),
    fragmentShader: shaderParse(document.getElementById( 'fragmentShader' ).textContent),
    blending: THREE.NoBlending
});

mat.uniforms.color1.value = new THREE.Color( 0x20cc31);
mat.uniforms.color2.value = new THREE.Color( 0x2095cc);

var mesh = new THREE.Points( geo, mat );

mesh.customDistanceMaterial = new THREE.ShaderMaterial( {
    uniforms: THREE.UniformsUtils.merge([
        THREE.UniformsLib.shadowmap,
        {
            lightPosition: {type: 'v3', value: new THREE.Vector3(0, 700, 0)},
        }
    ]),
    vertexShader: shaderParse(document.getElementById( 'distanceVertexShader' ).textContent),
    fragmentShader: shaderParse(document.getElementById( 'distanceFragmentShader' ).textContent),
    depthTest: true,
    depthWrite: true,
    side: THREE.BackSide,
    blending: THREE.NoBlending
});

mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);

// . . .

var pointLight = new THREE.PointLight( 0xffffff, 1, 700 );
pointLight.castShadow = true;
pointLight.shadow.camera.near = 10;
pointLight.shadow.camera.far = 1000;
pointLight.shadow.bias = 0.1;
pointLight.shadow.mapSize.width = 4096;
pointLight.shadow.mapSize.height = 4096;
lights.add( pointLight );

vertexShader.vert:

attribute float displacement;
varying float pos;

// chunk(shadowmap_pars_vertex);

void main() {
    vec4 worldPosition = modelMatrix * vec4( position.xyz, 1.0 );
    vec4 mvPosition = viewMatrix * worldPosition;
    // chunk(shadowmap_vertex);
    pos = displacement;
    gl_Position = projectionMatrix * mvPosition;
    gl_PointSize = 1300.0 / length( mvPosition.xyz ) * 0.1;
}

fragmentShader.frag:

// chunk(common);
// chunk(packing);
// chunk(fog_pars_fragment);
// chunk(bsdfs);
// chunk(lights_pars_begin);
// chunk(shadowmap_pars_fragment);
// chunk(shadowmask_pars_fragment);

varying float pos;

uniform vec3 color1;
uniform vec3 color2;

void main() {

    vec3 outgoingLight = mix(color2, color1, pos);

    // chunk(fog_fragment);

    outgoingLight *= getShadowMask();

    gl_FragColor = vec4( outgoingLight, 1.0) );

}

Thanks in advance.

EDIT :
Apparently, the reason why getShadowMask() always returns 1.0f is because the following piece of code: shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; inside ShaderChunk.shadowmask_pars_fragment.glsl

I’ve ran some tests and pointLight.shadow is never set anywhere, so it never executes getPointShadow. On the other hand, getPointShadow always returns 0.0f … So I’m really not sure what’s happening here, maybe there’s something wrong with what I’m doing or maybe it’s just broken.

1 Like

The link I gave is no longer relevant to the discussion, but I’ve managed to solve the initial problem I had.

If you want a custom shader to receive shadows correctly, you need to pass THREE.UniformsLib.lights uniforms and set lights: true on the shader options. Like the following:

var renderShader = new THREE.ShaderMaterial( {
    uniforms: THREE.UniformsUtils.merge([
        THREE.UniformsLib.shadowmap,
        THREE.UniformsLib.lights,
        THREE.UniformsLib.ambient,
        {
            positions: { type: "t", value: null },
            pointSize: { type: "f", value: 1 },
            color1: { type: 'c', value: ( new THREE.Color( 0x2095cc) ) },
            color2: { type: 'c', value: ( new THREE.Color( 0x20cc31) ) }
        } ]),
    vertexShader: shaderParse(document.getElementById( 'render.vert' ).textContent),
    fragmentShader: shaderParse(document.getElementById( 'render.frag' ).textContent),
    lights: true,
    blending: THREE.NoBlending
} );
3 Likes

Were you ever able to figure out why getPointShadow always returns 0? I’m having the same issue with trying to add shadows to my particles but getting undesirable results because getShadowMask is always either 1 or 0.