Jump to content

Ray-Casting a Heightmap for Shadows


SpiderPig
 Share

Recommended Posts

Second go at this.  Not as hard as it looks to get something basic going.  I think the majority of the work will be performance improvements and making the shadows look nicer.

ShadowHeightmap.gif.25b0f2910ce772803a258eeb1543f15d.gif

It's "semi" real-time now.  Still on the CPU but on another thread who's sole purpose is to calculate the shadow map until the program quits.   Takes about 500 or so milliseconds to calculate the shadow map, hence the jitter as the sun get's higher.

I think I can improve the ray casting speed but I want to focus on smoothing out those shadows.  I'm wondering if signed distance fields can help... maybe by storing each pixels distance to the nearest shadow I can calculate the fragments distance and blend accordingly.  Works in my head anyway.  :D   I think I'll sleep on it.

Link to comment
Share on other sites

Wow, that is fast enough that it could be real-time. You said it takes 500 milliseconds, so if you used four threads that would go down to 125 msecs. But the whole things doesn't have to be updated all at once. You could easily cycle through and just do a limited number each frame, and a slow-moving light would look the same. Without threading, at 60 FPS it would take 30 frames to get through the entire job, so the whole thing would update twice each second.

If you use Collider::Pick instead of the world raycast function, that will get rid of a lot of overhead and should be thread-safe.

  • Like 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

My thoughts exactly.  A slow light would only need updating every second or so.  It's only a 512x512 terrain.  The slowest part is when the whole terrain is in light because then every ray cast dosnt hit somthing so is very long.  I allready stop the ray when it leaves the AABB of the terrain.  I also want to blend in the default shadow system when up close.  That should look real good.  Will have to match the shadow color.  Are the shadows in Ultra just multiplied over the final frag color?

Link to comment
Share on other sites

1 hour ago, SpiderPig said:

Are the shadows in Ultra just multiplied over the final frag color?

The lighting calculation is a bit complex in Ultra, so the shadow is checked first and if the pixel is in the shadow, that light is skipped.

  • Thanks 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I was trying something similar in the frag shader.  I just didn't call RenderLighting if the fragment was in shadow but I thought the results were too dark.  (the gif above)

if(enable_lighting == true)
{
	RenderLighting(material, materialInfo, vertexWorldPosition.xyz, n, v, NdotV, f_diffuse, f_specular, renderprobes, ibldiffuse, iblspecular);
}

Can I simply disable lighting like this to see the shadow or is this not the best approach?

Link to comment
Share on other sites

  • 1 month later...

This iteration is a bit slower but looks a lot nicer.  The shadows are just multiplied by the final color so fragments within the shadow are still having light calculated on them.  @Josh Can I make a bool variable in the fragment shader to simply not calculate lighting for certain pixels?

Something like this perhaps?  EDIT : There's a RENDERFLAGS_NO_LIGHTING right there.... I might play with that :D

if(canDoLighting == true) {
    if ((RenderFlags & RENDERFLAGS_NO_LIGHTING) == 0)
    {
        RenderLighting(material, materialInfo, vertexWorldPosition.xyz, n, v, NdotV, f_diffuse, f_specular, renderprobes, ibldiffuse, iblspecular);
        if (!renderprobes)
        {
            ibldiffuse = vec4(0.0f);
            iblspecular = vec4(0.0f);
            f_specular = vec3(0.0);// we don't want specular reflection in probe renders since it is view-dependent
        }
    }
    else
    {
        renderprobes = false;
        f_diffuse.rgb = materialInfo.c_diff * AmbientLight;
        f_specular = vec3(0.0f);// we don't want specular reflection in probe renders since it is view-dependent
    }
}

RayCastHeightMap_001.thumb.png.363fc74a73e65889f1f65fc8d96bc700.png

Link to comment
Share on other sites

Did this and it seems to work nice.

if (enable_lighting == true && (RenderFlags & RENDERFLAGS_NO_LIGHTING) == 0)

Only issue left to solve are the edges of the shadows are very harsh.  If I can use a single bit as a Boolean to disable lighting I may also be able to use a few bits to determine the distance from the light source so that I can soften the edges.  ^_^

RayCastHeightMap_002.thumb.png.f7daac98b7b1776377c5d8651334942c.png

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...