Can I render only the shadows of an object into a rendertarget?

Hello,

what I want are really strong shadows at a particular point on my model but the rest of it should be well lit. In order to create them exactly the way I want I need multiple lights where some of them also fade out the shadows I want to keep and also light up the model on other parts too much. So, is there a way to render only the shadows into a rendertarget where I can process the shadows later? Or can I just simply access some kind of shadowmaps? Or is there even the possibility to limit the casting of shadows on an object to a specific area? Something like checking the coordinates and then discarding or keeping the shadow. Thanks in advance!

Hi @Wibke,

That’s an interesting problem. There isn’t an official API to get access to the shadow maps rendered, but you can try accessing a number of private properties attached on the light that is rendering the shadowmaps.

From there you can get access to the render target holding the shadowmaps and copy the result to another render target of yours.

Here is a glimpse of how that render target is created and referenced to the light component:

Thanks for the starting point. I added a script to my lightsource where I’m trying to copy the value of light.light._shadowCamera.renderTarget. I’m able to access different private properties of my lightsource (e.g. _shadowMatrix) but when I try to access _shadowCamera it returns null. Do I need to access the property in a specific context? Do I need to set my current camera as shadowcam and generate the shadowmap myself?

Hi @Wibke,

I don’t know that sadly, you can try and step through the browser debugger to see how/when these properties getting updated in the render loop.

If you don’t manage to solve this try submitting an feature request in the engine repo, maybe there is something useful here to be exposed as public api.

Hey @Leonidas ,

thanks for all the fast help :slight_smile:

1 Like

It feels like accessing depth shadow map might not be particularly useful for what you’re trying to do - as it stores depth information from the point of light, and that might not be easy to process / limit to an object.

What I would try instead is to change the shader which renders the object were you want to change shadow intensity on.

What I’ve tried is I created a new project in editor - this gives me a plane, a cube, a light … and cube casting shadow onto the plane. I captured the scene using SpectorJS and looked at the fragment shader of plane rendering. At the bottom, in the main function it calls this shadow function:

dAtten *= getShadowPCF3x3VS(light0_shadowMap, light0_shadowParams);

and the function is above:

float getShadowPCF3x3VS(SHADOW_SAMPLERVS shadowMap, vec3 shadowParams) {
    dShadowCoord = vMainShadowUv.xyz;
    dShadowCoord.z = saturate(dShadowCoord.z) - 0.0001;
    #ifdef SHADOWBIAS
        dShadowCoord.z += getShadowBias(shadowParams.x, shadowParams.z);
    #endif
    
    return _getShadowPCF3x3(shadowMap, shadowParams);
}

I then searched for it in engine source folder: engine/src/graphics/program-lib/chunks and found it in shadowStandardVS.frag.

That probably means you can copy it to your project, change it (to perhaps test a distance from some point and change intensity of shadow) and override chunk on material to use it.

It’s not going to be straightforward, but a path perhaps.

4 Likes

That’s quite useful, thanks for sharing @mvaligursky !

Thanks for the info and this approach. Sounds promising. I’ll check it in the next days.

Hey @mvaligursky,

thanks, it worked! It was good to know about SpectorJS, too. Unfortunately, I couldn’t figure out how to include the chunk shadowStandardVS.frag, so I edited the chunk shadowStandard.frag (which you have to call shadowStandardPS) I just needed to check the variable vPositionW in this Chunk and removed the texture(…)-part in the following lines where I didn’t want the shadow to be.

sum += uw0 * vw0 * texture(shadowMap, vec3(u0, v0, z));
sum += uw1 * vw0 * texture(shadowMap, vec3(u1, v0, z));
sum += uw0 * vw1 * texture(shadowMap, vec3(u0, v1, z));
sum += uw1 * vw1 * texture(shadowMap, vec3(u1, v1, z));

3 Likes

Fantastic, glad you got it to work!