garrysmod-issues icon indicating copy to clipboard operation
garrysmod-issues copied to clipboard

Cascading Shadow Map - ProjectedTextures needs an DepthRange function and why

Open xoticdev opened this issue 5 years ago • 10 comments

Hello, this is one of my favorite games thank you for your time. I noticed a major issue with certain maps where Shadow detail wasn't up to a dynamic standard. We have Garry's Mod 64bit now, but shadow casting always needed to be able to change sun angles during runtime. This is a costly render process, and CSM is not recommended for small maps, but for larger environments... Yes, we have BSP baked shadows... But basic shadows isn't dynamic to rotate on time-of-day time lapse. With Cascading Shadow Mapping, (CSM) we would provide our experiences with ultimate control over shadow quality, If done correctly!

A CSM method is a shadow shading technique used for larger landscapes and environments to provide dynamic shadows image

The photo above is using Projected Textures to draw the shadows on the top left, however looking at the far left hand side you'll notice that the CSM is done incorrectly. The reason for this is as follows: If I set the CSM matrix to follow the PITCH of the camera, the next photo shows a correct CSM math: image

Now you will notice in the second picture, the entire scene is completely covered by the Orthographic Matrices drawing as they should in a CSM within any game engine (DirectX, or Vulkan).

(The blue matrix is faint, but still holds shadow quality)

I set the Cascades into different colors so you can take a look.

The problem is that we're having clipping problems. You'll notice that the shadows level of detail (Smaller == higher quality) are overlapping the other larger layers. To complete Cascading Shadow maps, within the GLSL shaders (DirectX's shaders) one would use what us Garry's Mod Lua Coders call a render.DepthRange.

If I had GMOD source, I'd add another function to ProjectedTexture called DepthRange.

Doing so, would allow for me to cull out the layers based on depth. It's a hard thing to explain but I'll demonstrate what I mean:

image

The picture above shows a great example, depending on the thin depth test, one can eliminate the extra chunks of useless ProjectedTexture clipping. This would end up making the shadows look seamless as appose to the first picture shown, it covers the entire camera's view frustum. The problem is that the layering of projected textures makes the shadows look fake. Now I know what you're thinking ProjectedTextures can be swapped for a circle radiant and would make shadows look better. Now it is a viable option to cope without this feature, shadows would look 100% realistic with the suggestion I have provided vs using a hacky method to render the shadows. Also, this would allow the maps to have moving shadows via time lapses.

Another photo of the overlapping cascades: image

Without a depth test, the best option is to avoid using the pitch system which defeats majority of CSMs. When on the ground, it looks okay, but still noticeable.

image Although the above picture looks decent, you'll notice the seams overlap causing a distortion of light. This would be solved since only 1 ProjectedTexture would display on that depth amount.

I want to be able to control the depth range of ProjectedTexturess so that the CSM will look blended correctly, making the shadows look higher detailed.

image The last photo is CSM in a different game, except this time there is a depth clamp, causing seamless shadows. This is ideal for shadow casting, but it's a good reference of how the shadows would look after the depth clamping.

Lastly I wanna offer you an example code of how it may or may not work in theory:

local self = LocalPlayer()
local lamp = ProjectedTexture()
	self.lamp = lamp
	lamp:SetTexture( "effects/flashlight/hard" )
	lamp:SetFarZ( 500 )
	//lamp:SetNoDraw();      Disables drawing light normally
	lamp:SetPos( self:GetPos() )
	lamp:SetAngles( self:GetAngles() )
	lamp:Update()

local lamp2 = ProjectedTexture()
	self.lamp = lamp
	lamp2:SetTexture( "effects/flashlight/hard" )
	lamp2:SetFarZ( 500 )
	//lamp2:SetNoDraw();      Disables drawing light normally
	lamp2:SetPos( self:GetPos() )
	lamp2:SetAngles( self:GetAngles() )
	lamp2:Update()


hook.Add("PreDrawOpaqueRenderables", "ThisIsATest", function()
	lamp:SetPos( self:GetPos() + Vector( 0,0,100) )
	lamp:SetAngles( self:GetAngles() )
	lamp:Update()

	lamp2:SetPos( self:GetPos() + Vector(0,0,100) - self:GetAngles():Forward() * -100 )
	lamp2:SetAngles( self:GetAngles() )
	lamp2:Update()

	// ProjectedTexture has a depth range so that Layering for Cascading shadow maps is possible.
	// I.E. Selecting a specific lamp, and clamping it's drawing according to DEPTH...
	
	render.DepthRange(0.0, 0.5); // THIS is important, with this, the layering can be possible.
		lamp:DrawModel()
	render.DepthRange(0.5, 1.0); // THIS is important, with this, the layering can be possible.
		lamp2:DrawModel()
end )

If you can get this added in, I'll 100% share my CSM code so that way people can do stuff like this:

https://youtu.be/gwgjKxcPZ1o?t=27

Thank you for your time, I will actively strive to get Garry's Mod higher quality shadows, if you allow me to proceed!!!! I appreciate the team that makes this game possible though out the years!!

xoticdev avatar Apr 17 '20 01:04 xoticdev

I apologize for posting it here, I couldn't find the request place. But if you want I can remake the topic there, but this is important to me. In all seriousness. I need this to work.

xoticdev avatar Apr 17 '20 04:04 xoticdev

I did some digging looking into ProjectedTexture content, and I found a video of someone else trying to do what I'm doing however you can notice the seams on the shadows. Again, you can use techniques but you cannot get SEAMLESS shadows. This idea would make shadows complete. The whole purpose of CSM is to use a depth test, period. Otherwise it's just Angle(0,EyeAngles().y), 0)......

Sources: https://github.com/Facepunch/garrysmod-requests/issues/765

Similar thread: https://github.com/Facepunch/garrysmod-requests/issues/1258

EDIT: When using "effects/flashlight/hard" for ProjectTextures CSMs like the top link, we're also losing quality since the texture only lights 80% of the whole canvas, so you're losing quality... Depth test would be ideal. There's not much more information out there to reference afaik.

xoticdev avatar Apr 17 '20 04:04 xoticdev

Is this similar to how valve implemented csm in csgo?

Caskoo avatar Apr 17 '20 19:04 Caskoo

Yes, CSM is used in modern games, in general it's used for a whole bunch of games. CSGO uses CSM most likely. Name any game, and this probably is included without people knowing. Source Engine has baked lighting, and cascades for props from light sources. It's an easy way to cover dynamic looking shadows since the maps never lapse time.

CSM just covers the entire screen with light sources (Ortho matrices) and makes the game appear to have dynamic shadows. It's sort of included anywhere you can look in modern games. Metro Life, Fallout, any game with large landscapes.

EDIT: Ideally, each of these projections has a render.RenderView, and a depth map somewhere, but I don't think we'll ever get access to the shaders in that regard. Perhaps it's also possible to improve the appearance of Garry's Mod through other means of Shadow casting.

xoticdev avatar Apr 17 '20 20:04 xoticdev

https://github.com/Facepunch/garrysmod-requests/issues/1258

This feature is in request for 2 years, oh wow... Close to what I was asking...

To be clear, so I'm not getting this wrong... What I'm asking for is again the ability to add a depth range cull. Overlapping multiple flashlights (projectedTextures) poses a problem for shadow casting.

Easiest way to include this goes like this:

  1. Locate ProjectedTexture Graphic Pipeline (Where it's processed realtime through the shaders)
  2. Inside the shaders where ProjectedTextures are drawn onto the map add two if statements;
  3. If depth of pixel is out of bounds (I.E. Too low, or two high. We need mins and maxes for depth to split the shadow cascades by depth and also by the exact pixel) then render that pixel unculled.

Looks like just a simple include of a variable inside the fragment shader could potentially make Gmod shadows look even more realistic. The other thread above that I linked would just be icing on the cake.

I am looking into this further, and maybe look into the source engine 2013 addition and see if I can offer you guys more assistance, if possible. Again it would make me happy to see a depth range for flashlights because you'd be making my maps look even cooler.

xoticdev avatar May 07 '20 07:05 xoticdev

image

As seen here, using mat_showmiplevels 1. this clearly demonstrates depth passes in which I'm referring to so that we can slice up the flashlights and make seamless shadows. This would resolve major shadow issues for maps! Adding a depth filter would be amazing, I must reiterate.

xoticdev avatar Jun 06 '20 12:06 xoticdev

image

Great! New update has a lot of features to check out. I'll follow up on the program and see if I can get better looking results. I'll follow back up on this.

xoticdev avatar Oct 31 '20 03:10 xoticdev

r_shadows_gamecontrol has been a great help. I'd try to use it to replace the old shadow system but... Problem with that is that it's a client cheat. image

xoticdev avatar Nov 13 '20 00:11 xoticdev

ProjectedTextures officially got better functionality since the last post. Did you get everything you needed? I'd love to see an update with what you're doing with them now.

jorjic avatar Dec 09 '21 22:12 jorjic

bumping, would like to see this added. P.S. shouldn't this be in garrysmods-requests?

Xenthio avatar Jun 27 '22 00:06 Xenthio