Download

Changing contact shadow length of light in C++ during gameplay... possible?

I am trying to change the value for a lights contact shadow length during gameplay… reason is that I have an isometric view with zoom, and all the length values show artefacts at some point when you zoom in… basically there is a different optimal value for each zoom level.

My solution for that would have been to set the contact shadow length value of all lights in the level with contact shadows enabled to a different value as the player zooms in or out, so the contact shadows would always look as good as possible with as little artefacting as possible.

But while I got the basic code to work, it seems like assigning a new value to the lights is doing nothing… the lights seem stuck with the initial value set in the editor before hitting play. Any idea what I could try else?

Here is the current code (results of some minutes of mad hacking by a C++ noob, so don’t cruzify me for any follishness… critique on how to write better code always welcome though):



                for (ALight* light : lightArray) {
                    (*light).GetLightComponent()->ContactShadowLength = FMath::Abs(foundComp->GetRelativeTransform().GetLocation().X) / 9333.0f;
                }


Camera zoom works by moving the camera closer to the ground… that is why I use the X axis for that. Probably not the best solution.

Testing this further, it seems setting the public fields of a light to a different value has no effect (setting castShadows to false for example), whereas calling the setter for the same field does have an effect (calling setCastShadows(false) for example)…

Is there a reason for that? Do the setters more than just change the fields? Is there a method I need to call so the light reloads those settings? Is this simply an omission not yet implemented, or is there a technical limitation to this?

Hi there,

If you take a look at some of the native engine Setter functions, you can see that you need to explicitly mark the render state as dirty, so for example:


// The closer we are to the player, the longer the shadows should be, the further out, the smaller (as objects are smaller on screen)
float NewContactShadowLength = FMath::Lerp(ContactShadowLengthAtMinZoom, ContactShadowLengthAtMaxZoom, T);
if (NewContactShadowLength != DirectionalLight->ContactShadowLength)
{
    DirectionalLight->ContactShadowLength = NewContactShadowLength;
    DirectionalLight->MarkRenderStateDirty();
}

This will force the object to update the object in the render thread at the end of the frame, along with your new property values.