Starting with cascaded shadow maps...

I want to implement cascaded shadow maps like STALKER and Crysis have. I want the same quality and detail those engines allow. I understand the basic idea behind CSM.

My immediate thoughts are on how to allocate the shadow area. If we start from a top-down area in front of the camera it is easy enough to visualize. You could shear the rendering matrix to give a tilt to the light direction.

But once you start thinking about arbitrary geometry instead of just shadowing a flat plane, it gets very complicated. Shearing the matrix would cause errors on tall vertical walls. The only proper way to do it would be to render the scene from the point of view of the light, with the frustum stretched out to enclose the whole camera frustum (or the part of it the shadow map covers). This would result in a lot of wasted space, maybe 35% of the shadow map texture wouldn’t even get used.

The simplest to visualize would be a series of squares around the camera, with the camera at the center. Each square uses the same resolution, but they cover more and more area. Shearing this matrix to tilt the light would be a little more reliable, since there would be a lot more room for error, but so much of the texture would be wasted, especially if the shadowmap was updated every frame. And if we are doing dynamic lighting, I think it should be.

Your thoughts?

Okay, I think the proper way to do this is first decide what distance you want to draw a shadowmap to. Then you split the camera frustum up into this volume, which has a center and a maximum possible radius. You use the volume radius as the width and height of the area you render to the shadow map, and the scale will never change on you, and it will always include everything in the frustum. It’s incredibly wasteful, but works consistently.

My next question is about texture formats. Below is my code for creating projected shadow textures. What should this look like if I want to create a shadow map?

	Method CreateShadowmap()
		shadowmap=CreateTexture()
		shadowmap.setfilter TEXTUREFILTER_SMOOTH
		shadowmap.bind()		
		glTexImage2D GL_TEXTURE_2D,0,GL_RGBA8,shadowMapResolution,shadowMapResolution,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
		glGenFramebuffersEXT 1,Varptr shadowmap.framebuffer[0]
		glGenRenderBuffersEXT 1,Varptr shadowmap.renderbuffer[0]
		glBindFramebufferEXT GL_FRAMEBUFFER_EXT,shadowmap.framebuffer[0]
		glFramebufferTexture2DEXT GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D,shadowmap.index(),0
		
		//glBindRenderbufferEXT GL_RENDERBUFFER_EXT,shadowmap.renderbuffer[0]
		//glRenderbufferStorageEXT GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,shadowMapResolution,shadowMapResolution
		//glFramebufferRenderbufferEXT GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,shadowmap.renderbuffer[0]
		
		Select glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)
			Case GL_FRAMEBUFFER_COMPLETE_EXT' ok!
			Case GL_FRAMEBUFFER_UNSUPPORTED_EXT
				Notify "FBO configuration unsupported",1
				End
			Default
				Notify "FBO error",1
				End
		EndSelect
		glBindFramebufferEXT GL_FRAMEBUFFER_EXT,0
	EndMethod

This is what I am trying now, but it says “incomplete attachment”:

		shadowmap=CreateTexture(shadowMapResolution,shadowMapResolution, GL_DEPTH_COMPONENT24)
		shadowmap.setfilter TEXTUREFILTER_SMOOTH
		shadowmap.bind()
		glGenFramebuffersEXT 1,Varptr shadowmap.framebuffer[0]
		glBindFramebufferEXT GL_FRAMEBUFFER_EXT,shadowmap.framebuffer[0]
		glFramebufferTexture2DEXT GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadowmap.index(),0
		glDrawBuffer GL_FALSE
		glReadBuffer GL_FALSE
		Select glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)
			Case GL_FRAMEBUFFER_COMPLETE_EXT' ok!
			Case GL_FRAMEBUFFER_UNSUPPORTED_EXT
				Notify "FBO configuration unsupported",1
				End
			Case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
				Notify "Incomplete FBO attachment.",1
				End
			Default
				Notify "FBO error"+glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT),1
				End
		EndSelect
		glBindFramebufferEXT GL_FRAMEBUFFER_EXT,0