Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Help with Shadow Mapping and Multi-Texturing


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
23 replies to this topic

#1 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 20 July 2012 - 11:31 PM

Hello again,

Trying to make a more specific topic to my problem, since I've realized my lighting was actually correct and has been correct (thank you, everyone!), but that my Shadow Mapping leaves something to be desired (as it's not working at all). It looks like the FBO/Shadow Map is rendering/creating the Shadow Map correctly, but that my use of it in my final Shader.

The basic idea is that I have two shader programs -- one renders the scene without shadows into the depth buffer of an FBO (or into a texture if the hardware isn't GL 3.0), and the second mixes that with the way the scene should be rendered.

Here's what the scene looks like, presently (normal view):

Posted Image

And this is the what the scene looks like from the Light's View:

Posted Image

The second uses the same projection and modelview matrices used by the Depth Buffer capture to render -- so it should be spot on, but here it looks like it's flipped the wrong way.

In the bottom right of both images, I'm just rendering the resulting Shadow Map on top of the scene post-final shader-render.

The code process is essentially:

1) Setup Shader Program to Grab Shadow Map
2) Run through rendering of all objects that generate shadows
3) Setup Shader Program to render everything AND shadow map on top of it
4) Render the Shadow Map in the bottom right corner and the other text data on the top-left.

Let's assume that I created the Shadow Map right -- and we can see the rendering of it on the bottom right. The rendering of it seems to be problematic.

Here's what my overall code looks like.

[source lang="csharp"] Rendering.ActivateShadowTextureUnit(); //Set's active Texture Unit to Unit 1 Rendering.EnableTextures(); //Enable Textures Gl.glBindTexture( Gl.GL_TEXTURE_2D, ShadowMapTextureID[0] ); //Uses the image that is rendered in the bottom right hand corner Rendering.ActivatePrimaryTextureUnit(); //Now activate the primary texture unit, where we render our normal textures in (Unit 0) Gl.glUseProgram( ViewerRenderProgram ); //Use the rendering GL Program Int32 LightModelViewProjectionMatrixLocation = Gl.glGetUniformLocation( ViewerRenderProgram, "LightModelViewProjectionMatrix" ); Gl.glUniformMatrix4fv( LightModelViewProjectionMatrixLocation, 1, Gl.GL_FALSE, LightProjectionViewMatrix ); //This is the Projection Matrix used to render light from (poorly named, sorry) Int32 WorldMatrixLocation = Gl.glGetUniformLocation( ViewerRenderProgram, "WorldMatrix" ); Gl.glUniformMatrix4fv( WorldMatrixLocation, 1, Gl.GL_FALSE, WorldMatrix ); //This is the World ModelView Matrix Int32 DiffuseMapLocation = Gl.glGetUniformLocation( ViewerRenderProgram, "DiffuseMap" ); Gl.glUniform1i( DiffuseMapLocation, 0 ); //Texture Unit 0 (where our normal textures are loaded and rendered through Int32 ShadowMapLocation = Gl.glGetUniformLocation( ViewerRenderProgram, "ShadowMap" ); Gl.glUniform1i( ShadowMapLocation, 1 ); //Texture Unit 1 (where the Shadow Map is currently bound to) Int32 MinimumShadowLocation = Gl.glGetUniformLocation( ViewerRenderProgram, "MinimumShadow" ); Gl.glUniform1f( MinimumShadowLocation, 0.8f ); //This is to run against the lambert as the "max value" -- eventually, it will be variable[/source]
Here's how I grab my Lighting Matrices...

[source lang="csharp"] Gl.glPushMatrix(); Gl.glMatrixMode( Gl.GL_PROJECTION ); Gl.glLoadIdentity(); Gl.glOrtho( -Configuration.Instance.RenderingSettings.Depth, Configuration.Instance.RenderingSettings.Depth, -Configuration.Instance.RenderingSettings.Depth, Configuration.Instance.RenderingSettings.Depth, -Configuration.Instance.RenderingSettings.Depth * 2.0d * Configuration.Instance.RenderingSettings.Zoom, Configuration.Instance.RenderingSettings.Depth * 2.0d * Configuration.Instance.RenderingSettings.Zoom ); Gl.glMatrixMode( Gl.GL_MODELVIEW ); Gl.glLoadIdentity(); Gl.glScaled( Tile.DIMENSION * Configuration.Instance.RenderingSettings.Zoom, Tile.DIMENSION * Configuration.Instance.RenderingSettings.Zoom, Tile.DIMENSION * Configuration.Instance.RenderingSettings.Zoom ); Gl.glRotated( -90.0d, 1.0d, 0.0d, 0.0d ); Gl.glRotated( Configuration.Instance.RenderingSettings.LightAngle, 1.0d, 0.0d, 0.0d ); Gl.glRotated( -90.0d, 0.0d, 0.0d, 1.0d ); Gl.glGetFloatv( Gl.GL_PROJECTION_MATRIX, LightProjectionViewMatrix ); Gl.glPopMatrix();[/source]

And this is the World Matrix:

[source lang="csharp"] Gl.glPushMatrix(); Gl.glMatrixMode( Gl.GL_MODELVIEW ); Gl.glLoadIdentity(); Gl.glScaled( Tile.DIMENSION * Configuration.Instance.RenderingSettings.Zoom, Tile.DIMENSION * Configuration.Instance.RenderingSettings.Zoom, Tile.DIMENSION * Configuration.Instance.RenderingSettings.Zoom ); Gl.glRotated( -Configuration.Instance.RenderingSettings.Tilt, 1.0f, 0.0f, 0.0f ); Gl.glRotated( Configuration.Instance.RenderingSettings.Rotation, 0.0f, 0.0f, 1.0f ); Gl.glTranslated( -pX, -pY, -pZ ); //pX, pY, pZ is the "center" of the scene that I render at Gl.glGetFloatv( Gl.GL_MODELVIEW_MATRIX, WorldMatrix ); Gl.glPophMatrix();[/source]

And finally, my Shader Code looks something like this:

[source lang="cpp"]//VERTEX uniform mat4 LightModelViewProjectionMatrix; uniform mat4 WorldMatrix; varying vec3 Normal; varying vec4 LightCoordinate; // Position in model view projection space from the lights view. varying vec4 WorldPosition; // Position in world space. void main() { Normal = gl_Normal; WorldPosition = WorldMatrix * gl_Vertex; LightCoordinate = LightModelViewProjectionMatrix * gl_Vertex; gl_Position = ftransform(); // Transform via fixed function into the viewer's view gl_TexCoord[0] = gl_MultiTexCoord0; }//FRAGMENT uniform sampler2D DiffuseMap; uniform sampler2D ShadowMap; uniform mat4 WorldMatrix; uniform float MinimumShadow; varying vec3 Normal; varying vec4 LightCoordinate; varying vec4 WorldPosition; void main() { // Direct lighting // ------------------------------ vec4 Color = gl_LightSource[0].ambient; vec3 l = normalize(gl_LightSource[0].position.xyz); // direction to the light source vec3 view_normal = normalize(gl_NormalMatrix * Normal); vec3 view_light_direction = normalize(vec3(gl_LightSource[0].position)); //(WorldMatrix * vec4( LightPosition.x, LightPosition.y, LightPosition.z, 0 ) ).xyz; //float lambert = max(dot(view_normal, view_light_direction), MinimumShadow); float lambert = max(dot(Normal, l), MinimumShadow); Color.xyz *= lambert; //Blend in Color from primary texture unit Color.wxyz *= texture2D(DiffuseMap, vec2(gl_TexCoord[0])).wxyz; // Shadow mapping // ------------------------------ vec4 lcoord = LightCoordinate; // Fragment position in light space. lcoord /= lcoord.w; // Project to cartesian space lcoord.xy = lcoord.xy * 0.5 + 0.5; // Scale since light clipping space is in [-1,1] but texture space is [0,1] float fragmentDepth = lcoord.w; // Depth of the fragment in light space. float shadowMapDepth = texture2D(ShadowMap, lcoord.xy).x; // Depth in the shadow map. float eps = 0.1; // depth bias float shadow = fragmentDepth - eps > shadowMapDepth ? 0.5: 1.0; gl_FragColor = Color * shadow;[/source]

I had assumed before, when I had a fixed position light (not a directional one), that I had been showing shadows -- this was just an error on my part. If I commented out everything under "Shadow Mapping" in the Fragment Shader, no difference was made! So, my lighting is correct. Getting the Shadow Map appears to be correct. The problem appears to be in how I'm rendering it. Perhaps I'm making a mistake? Also going to include my Shadow Map Capture stuff as well:

[source lang="cpp"]//VERTEX varying vec4 LightPosition; void main() { gl_Position = ftransform(); LightPosition = gl_Position; }//FRAGMENT varying vec4 LightPosition; void main() { gl_FragColor = vec4(LightPosition.z / LightPosition.w); }[/source]

Hopefully someone can give me some insight into what I'm doing wrong. I've been struggling to get this working for a while and I've had a lot of help from various members in the community. The issue I have appears to be the *actual* shadow mapping. And again, the resulting texture of the Shadow Map is showing in the bottom right hand corner of the screen (with glColor3f(1.0f, 1.0f, 1.0f);).

Here's also how I'm constructing the actual FBO and using it...

[source lang="csharp"] Gl.glGenTextures( 1, ShadowMapTextureID ); Gl.glBindTexture( Gl.GL_TEXTURE_2D, ShadowMapTextureID[0] ); Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, Configuration.Instance.RenderingSettings.ShadowDimension, Configuration.Instance.RenderingSettings.ShadowDimension, 0, Gl.GL_RGBA, Gl.GL_FLOAT, IntPtr.Zero ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_BORDER ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_BORDER ); Gl.glTexParameterfv( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BORDER_COLOR, Video.Instance.ClearColor ); Gl.glGenTextures( 1, DepthMapTextureID ); Gl.glBindTexture( Gl.GL_TEXTURE_2D, DepthMapTextureID[0] ); Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_DEPTH_COMPONENT24, Configuration.Instance.RenderingSettings.ShadowDimension, Configuration.Instance.RenderingSettings.ShadowDimension, 0, Gl.GL_DEPTH_COMPONENT, Gl.GL_UNSIGNED_BYTE, IntPtr.Zero ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST ); ShadingMethodsAllowed = ShadingMethods.None | ShadingMethods.NonFBO; Gl.glGenFramebuffersEXT( 1, ShadowMapFramebuffer ); Gl.glBindFramebufferEXT( Gl.GL_FRAMEBUFFER_EXT, ShadowMapFramebuffer[0] ); Gl.glFramebufferTexture2DEXT( Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT, Gl.GL_TEXTURE_2D, ShadowMapTextureID[0], 0 ); Gl.glFramebufferTexture2DEXT( Gl.GL_FRAMEBUFFER_EXT, Gl.GL_DEPTH_ATTACHMENT_EXT, Gl.GL_TEXTURE_2D, DepthMapTextureID[0], 0 ); string ExtensionsSupported = Gl.glGetString( Gl.GL_EXTENSIONS ); if ( Gl.glCheckFramebufferStatusEXT( Gl.GL_FRAMEBUFFER_EXT ) != Gl.GL_FRAMEBUFFER_COMPLETE_EXT ) { ShadingMethodsAllowed |= ShadingMethods.FBO; } Gl.glBindFramebufferEXT( Gl.GL_FRAMEBUFFER_EXT, 0 );[/source]

Thanks for all the help in advance -- if someone can point me in a direction so that I can progress forward, I would greatly appreciate it! I apologize for all of the funky spaghetti code!

Sponsor:

#2 beans222   Members   -  Reputation: 1137

Like
2Likes
Like

Posted 21 July 2012 - 01:08 AM

The line "lcoord /= lcoord.w;" is probably resulting 'w' always being 1 which then used later on. But this isn't all that wrong, I think.

If you are in fact multiplying the input vertex by the Light mvP matrix to get "LightCoordinate", you don't need any extra division by 'w' when using an Ortho matrix as it'll be one anyway. Just use .z as "fragmentDepth" (still do the scale on xy) . Make sure that the shadow texture being sampled is actually a depth component texture (it looks like it is in what you posted, I think). Also, I suggest using the .z off of the texture2D call (even though it probably returns the same in all xyzw for depth texture) just because it looks more "correct".

Hope that helps Posted Image

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#3 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 21 July 2012 - 08:27 AM

Thank you for the response!

That didn't fix it at all, unfortunately. It didn't do anything, and I do have some valleys and peaks in the scene, so there should be something there.

So, a good question (since I've been getting a lot of help) -- is something maybe wrong with the format of it? ShadowMapTexture is :

[source lang="csharp"] Gl.glGenTextures( 1, ShadowMapTextureID ); Gl.glBindTexture( Gl.GL_TEXTURE_2D, ShadowMapTextureID[0] ); Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, Configuration.Instance.RenderingSettings.ShadowDimension, Configuration.Instance.RenderingSettings.ShadowDimension, 0, Gl.GL_RGBA, Gl.GL_FLOAT, IntPtr.Zero ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_BORDER ); Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_BORDER ); Gl.glTexParameterfv( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BORDER_COLOR, Video.Instance.ClearColor );[/source]

I also have the DepthMapTexture, which I'm not sure what it really is for (if you look in the code above). I'm not sure why I have a ShadowMap and a DepthMap.

The fragment shader of the shadow map capture gl_FragColor = vec4(LightPosition.z / LightPosition.w); should just put the "depth" as a scalar across all channels of RGBA -- correct?

There has to be something wrong with the Shadow Map projection here in the Fragment shader -- either I'm not setting up something correctly or the code isn't projecting things correctly... Or should I be passing in the DepthMapTexture instead of Shadow?

#4 beans222   Members   -  Reputation: 1137

Like
2Likes
Like

Posted 21 July 2012 - 12:20 PM

Use the depth component texture instead. Ditch the RGBA one. Using only a depth buffer will render it faster, and you can use simpler shaders. The fragment shader can just an empty main ("void main(){}") and the vertex shader main contain just the ftransform() line. I think the call is "glDrawBuffer(GL_NONE);" in order to not have a color buffer in the framebuffer object.

I'm not sure but I think using an RGBA texture like that should work how you have it, but using a depth texture should just work (easier and faster).

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#5 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 21 July 2012 - 12:30 PM

Well, that still doesn't solve the issue of the shadows... Is there a way to just render shadows only? I was assuming I could get rid of all the texture stuff at the top to calculate light and just set the variable Color as 1,1,1,1 -- then multiply by the Shadow Map to see if shadows are correctly rendered. When I do that, though, the screen just stays a solid color.

#6 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 21 July 2012 - 12:32 PM

For some reason, it's not letting me edit my prior post, but I did this:

[source lang="cpp"] varying vec3 Normal; varying vec4 LightCoordinate; varying vec4 WorldPosition; void main() { // Direct lighting // ------------------------------ vec4 Color = gl_LightSource[0].ambient; vec3 l = normalize(gl_LightSource[0].position.xyz); // direction to the light source vec3 view_normal = normalize(gl_NormalMatrix * Normal); vec3 view_light_direction = normalize(vec3(gl_LightSource[0].position)); //(WorldMatrix * vec4( LightPosition.x, LightPosition.y, LightPosition.z, 0 ) ).xyz; //float lambert = max(dot(view_normal, view_light_direction), MinimumShadow); float lambert = max(dot(Normal, l), MinimumShadow); Color.xyz *= lambert; //Blend in Color from primary texture unit Color.wxyz *= texture2D(DiffuseMap, vec2(gl_TexCoord[0])).wxyz; // Shadow mapping // ------------------------------ vec4 lcoord = LightCoordinate; // Fragment position in light space. //lcoord /= lcoord.w; // Project to cartesian space lcoord.xy = lcoord.xy * 0.5 + 0.5; // Scale since light clipping space is in [-1,1] but texture space is [0,1] float fragmentDepth = lcoord.z; // Depth of the fragment in light space. float shadowMapDepth = texture2D(ShadowMap, lcoord.xy).z; // Depth in the shadow map. float eps = 0.001; // depth bias float shadow = fragmentDepth - eps > shadowMapDepth ? 0.5: 1.0; gl_FragColor = vec4(1,1,1,1) * shadow; }[/source]

So basically I avoid the color stuff at all -- just calculate the shadow. My screen is pure white, and that's it.

#7 beans222   Members   -  Reputation: 1137

Like
1Likes
Like

Posted 21 July 2012 - 02:20 PM

At this point, it looks like the shader should work. After taking a closer look at the matrix code:

glPush/PopMatrix have different stacks per MatrixMode, so technically I think there should be Push/Pop around altering both MODELVIEW and PROJECTION, although if both are going to be overwritten immediately for the next pass/render it doesn't really matter.

It appears that the projection matrix for the light is being retrieved, but the modelview is not even though it appears to be modified. They need to be multiplied manually before being assigned to the LightModelViewProjectionMatrix uniform. I'm not sure about this though, as I only use GL3+ which deprecates the matrix functions.

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#8 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 21 July 2012 - 02:36 PM

Would it help to confirm that the Matrix is the exact same going in at both locations when I get them?

My goal is to have this code working on a netbook in addition to a high-end machine -- so unfortunately, I have to stick with GL 2.0 and before -- with few optimizations here and there for GL3.

#9 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 21 July 2012 - 02:45 PM

And that being said -- do I need the Model View * Projection to be multiplied for the actual display? That may be my problem... I'm not sure if that's the correct parameter, because I think I remember it being Projection -- not Projection * ModelView -- but if it is both, that should be a relatively simple fix, yes? :-)

#10 beans222   Members   -  Reputation: 1137

Like
1Likes
Like

Posted 21 July 2012 - 02:59 PM

Yes, you need the full MVP that was used for rendering the shadow map for the actual display otherwise you haven't transformed the display vertex into the right light-relative space in order to be comparing with the shadow map. It should be a simple fix, just get the modelview as well as the projection; simply send the modelview separately into the vertex shader and do the multiply there (lightProj*lightMV*vertex).

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#11 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 21 July 2012 - 05:32 PM

Beans,

THANK YOU for pointing out my BIG mistake. Lookie what I got working...

Posted Image

Mind you, it's still not perfectly correct. But it's closer! While I get a shadow, it does not seem to be correct when rendering, so I need to figure out any other gotcha's. The other problem that is prevalent in this image, is that the water is transparent at all -- I assume the problem is with the Alpha channel not being preserved. I think, perhaps, I had better be multiplying my color by only XYZ instead of XYZW. XYZW should correspond to RGBA, yes? I'd assume that if an image is in ARGB format (specified in the texture creation), then XYZW would map A => X, and so forth, yes?

Thanks for all of your help!

#12 beans222   Members   -  Reputation: 1137

Like
1Likes
Like

Posted 21 July 2012 - 06:03 PM

I don't think the mapping would change in the shader. XYZW/RGBA/STPQ. W=A=Q. But you can use any of those to mean whichever spot in the vec4 you want. Not sure if you can go .xgq, but why not use .a for alpha, and the rest when refering to color? Also, when you multiply in the diffuse component from the texture, you don't need any swizzles there (wxyz also looks strange on both sides).

What does MinimumShadow do? That line usually prevents lambert from being negative with zero usually being in place of MinimumShadow.
I'm curious how your lighting works. Usually I see something like (ambient * DiffuseTexel) + (lambert * DiffuseTexel). I'm going to guess that MinimumShadow is there to prevent things from being all black when lambert would otherwise be zero?

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#13 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 22 July 2012 - 08:50 AM

OK, so after a bit of cleanup, I've managed to maintain my transparency, but I believe the shadows are not correctly projecting onto the image...

Yes, MinimumShadow prevents the Lambert from being 100% black, so it never completely scales to completely black.

Here's what my end-result of a Shader looks like for the Fragment Shader (everything else has remained the same in code):

[source lang="cpp"] uniform sampler2D DiffuseMap; uniform sampler2D ShadowMap; uniform mat4 WorldMatrix; uniform float MinimumShadow; varying vec3 Normal; varying vec4 LightCoordinate; varying vec4 WorldPosition; void main() { // Direct lighting // ------------------------------ vec4 Color = gl_LightSource[0].ambient; vec3 View_Light = normalize(gl_LightSource[0].position.xyz); vec3 View_Normal = Normal; float Lambert = max(dot(View_Normal, View_Light), MinimumShadow); Color *= Lambert; //Blend in Color from primary texture unit Color *= texture2D(DiffuseMap, vec2(gl_TexCoord[0])); // Shadow mapping // ------------------------------ vec4 lcoord = LightCoordinate; // Fragment position in light space. lcoord /= lcoord.w; // Project to cartesian space lcoord.xy = lcoord.xy * 0.5 + 0.5; // Scale since light clipping space is in [-1,1] but texture space is [0,1] float fragmentDepth = lcoord.z; // Depth of the fragment in light space. float shadowMapDepth = texture2D(ShadowMap, lcoord.xy).z; // Depth in the shadow map. float eps = 0.001; // depth bias float shadow = fragmentDepth - eps > shadowMapDepth ? 0.5: 1.0; Color.rgb *= shadow; gl_FragColor = Color; }[/source]

The alpha channel is now preserved, thankfully. However, still some issues...

I'm passing in the ShadowMapTexture (well, the active texture is what I'm passing in, but I'm BINDING the shadow map) as the sampler2D ShadowMap, which appears to be correct. It seems like the shadow's coordinates aren't generating correctly, or that I'm doing something wrong still. Using the DepthMap does not ever make it look correct.

When I setup the scene for shadows, I do:

PushMatrix
LoadLightProjection
LoadLightModelView
PushMatrix
Translate into Scene Center
RenderScene
PopMatrix
PopMatrix

When I get the Light ModelView and Projection, I do...

PushMatrix
LoadLightProjection
LoadLightModelView
Translate into Scene Center
GetProjection into Variable
GetModelview into Variable

Multiply the two matrices together to form an uber matrix that will be sent in.
PopMatrix

I'm assuming that this approach isn't correct, as whenever I move the location of the camera, the entire set of shadows disappear. Another interesting thing is that it seems like if I pull out the Translate, the shadows stay, but they do not move with the scene...

Here's the code for my matrix multiplication, so I don't have to do it in GLSL:

[source lang="csharp"] public static void MultiplyMatrices( int pDimension, float[] pMatrixA, float[] pMatrixB, ref float[] pResult ) { for ( int i = 0; i < pDimension; i++ ) { for ( int j = 0; j < pDimension; j++ ) { int index = i * pDimension + j; pResult[index] = 0.0f; for ( int k = 0; k < pDimension; k++ ) { pResult[index] += ( pMatrixA[i * pDimension + k] * pMatrixB[k * pDimension + j] ); } } } }[/source]

Which I believe is correct and I lifted from another site... Any thoughts?

#14 beans222   Members   -  Reputation: 1137

Like
1Likes
Like

Posted 22 July 2012 - 10:15 PM

Please keep in mind that Push/PopMatrix only affect the current matrix mode, ModelView and Projection have completely
separate stacks. I might also be confused about which one of those set of steps was creating a depth map and which rendering
the final scene. In a few of those steps it looks like Push/Pop are not matching up. I think basically that list of steps has me confused (sorry 'bout that).

If the camera is causing a problem like that it sounds like Push/Pop are not matched up correctly, or the wrong MatrixMode
is sticking around past where it's supposed to be. Otherwise, the main camera shouldn't be affecting shadow map generation.

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#15 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 23 July 2012 - 04:59 PM

I have a feeling that the Light Projection and View Matrix are not correct.

So, I have a "Debug" mode that I implemented that loads the Light Projection and View Matrices (instead of the scenes), and when I use that, it looks wrong still. For example, if the sun is rising from the East, I'll have shadows on the Eastern side of the scene, not on the Western side. This uses the same code and same steps to produce it as the scene rendering from the light's view. I have now replicated the steps I take so that the Push/Pop and Translate/etc are all working together correctly.

If I do a Translate on the Light to center it with my scene (when updating the Light Matrix that is sent into the Rendering Shader), the second I move from center, everything goes DARK or LIGHT, which leads me to think that there HAS to be something wrong with the Light's Position or the Light's Matrix or something like that.

I believe the Ambient Lighting for the scene is fine and without any flaws. That has to mean that something is wrong with how either I calculate the LightCoordinate or the Light's Matrix.

I'll post my code again and maybe you'll see a problem... Again, I've made changes...

[source lang="cpp"]//CAPTURE//VERTEX varying vec4 LightPosition; void main() { gl_Position = ftransform(); LightPosition = gl_Position; }//FRAGMENT varying vec4 LightPosition; void main() { gl_FragColor = vec4(LightPosition.z / LightPosition.w); }//RENDER//VERTEX uniform mat4 LightModelViewProjectionMatrix; uniform mat4 WorldMatrix; varying vec3 Normal; varying vec4 LightCoordinate; // Position in model view projection space from the lights view. varying vec4 WorldPosition; // Position in world space. void main() { Normal = gl_Normal; WorldPosition = WorldMatrix * gl_Vertex; LightCoordinate = LightModelViewProjectionMatrix * gl_Vertex; gl_Position = ftransform(); // Transform via fixed function into the viewer's view gl_TexCoord[0] = gl_MultiTexCoord0; }//FRAGMENT uniform sampler2D DiffuseMap; uniform sampler2D ShadowMap; uniform mat4 WorldMatrix; uniform float MinimumShadow; varying vec3 Normal; varying vec4 LightCoordinate; varying vec4 WorldPosition; void main() { // Direct lighting // ------------------------------ vec4 Color = gl_LightSource[0].ambient; vec3 View_Light = normalize(gl_LightSource[0].position.xyz); vec3 View_Normal = normalize(Normal); float Lambert = max(dot(View_Normal, View_Light), MinimumShadow); Color *= Lambert; //Blend in Color from primary texture unit Color *= texture2D(DiffuseMap, vec2(gl_TexCoord[0])); // Shadow mapping // ------------------------------ vec4 lcoord = LightCoordinate; // Fragment position in light space. lcoord /= lcoord.w; // Project to cartesian space lcoord.xy = lcoord.xy * 0.5 + 0.5; // Scale since light clipping space is in [-1,1] but texture space is [0,1] float fragmentDepth = lcoord.z; // Depth of the fragment in light space. float shadowMapDepth = texture2D(ShadowMap, lcoord.xy).r; // Depth in the shadow map. float eps = 0.001; // depth bias float shadow = fragmentDepth - eps > shadowMapDepth ? 0.5: 1.0; Color.rgb *= shadow; gl_FragColor = Color; }[/source]
Whenever I set the matrices, I make sure I LoadIdentity() before I do any operations on them, so it should clear them and set them up as we desire. The order of operations is correct now as well...

I've noticed the code I borrowed also make ABSOLUTELY NO USE of the entire DepthMapTexture... They added it to the FBO, but use it nowhere else. There has to be some strange calculation that maybe I need to do on the texture to figure out where it should be on the ShadowMapTexture or to relate that into the coordinates that would be used...

Thoughts?

#16 beans222   Members   -  Reputation: 1137

Like
1Likes
Like

Posted 24 July 2012 - 01:09 PM

Ambient is supposed to be added in without being involved in the lambert calculations as part of its purpose is keeping things from being completely black, but that's obviously not important if the shadows are being stubborn.

As for the two textures, there's really no way to know what another coder was thinking if they didn't leave any notes. All shadow code I've seen disables color buffer drawing leaving it out of the FBO while only using the depth component texture in the shadow checking code.

Other than to try to using gluLookAt to build the light camera/view matrix, I'm out of ideas.

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

 


#17 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 26 July 2012 - 10:04 AM

Hey Beans,

OK, so I've been working on my engine and noticed I GROSSLY screwed up the normals.

That being said, I now do something like this:

[source lang="csharp"] public static Vertex CalculateNormal( Double pPoint1X, Double pPoint1Y, Double pPoint1Z, Double pPoint2X, Double pPoint2Y, Double pPoint2Z, Double pPoint3X, Double pPoint3Y, Double pPoint3Z ) { Vertex A, B, Result; A.X = pPoint2X - pPoint1X; A.Y = pPoint2Y - pPoint1Y; A.Z = pPoint2Z - pPoint1Z; //a.x = p2.x - p1.x; //a.y = p2.y - p1.y; //a.z = p2.z - p1.z; B.X = pPoint3X - pPoint1X; B.Y = pPoint3Y - pPoint1Y; B.Z = pPoint3Z - pPoint1Z; //b.x = p3.x - p1.x; //b.y = p3.y - p1.y; //b.z = p3.z - p1.z; Result.X = ( A.Y * B.Z ) - ( A.Z * B.Y ); Result.Y = ( A.Z * B.X ) - ( A.X * B.Z ); Result.Z = ( A.X * B.Y ) - ( A.Y * B.X ); //n.x = ( a.y * b.z ) - ( a.z * b.y ); //n.y = ( a.z * b.x ) - ( a.x * b.z ); //n.z = ( a.x * b.y ) - ( a.y * b.x ); Double UnitLength = Math.Sqrt( ( Result.X * Result.X ) + ( Result.Y * Result.Y ) + ( Result.Z * Result.Z ) ); if ( UnitLength != 0 ) { Result.X /= UnitLength; Result.Y /= UnitLength; Result.Z /= UnitLength; } //// Normalize (divide by root of dot product) //l = sqrt( n.x * n.x + n.y * n.y + n.z * n.z ); //n.x /= l; //n.y /= l; //n.z /= l; return Result; }[/source]
As you can see, I really just copied something out of the OpenGL wiki and then converted it to C#.

And then to actually add in the Normals I do...

[source lang="csharp"]//T1 TerrainTileVertices.Add( x ); TerrainTileVertices.Add( y ); TerrainTileVertices.Add( pTiles[Offset].Height ); TerrainTileVertices.Add( x ); TerrainTileVertices.Add( y + 1 ); TerrainTileVertices.Add( pTiles[Offset + Diameter].Height ); TerrainTileVertices.Add( x + 1 ); TerrainTileVertices.Add( y + 1 ); TerrainTileVertices.Add( pTiles[Offset + Diameter + 1].Height ); Normal = Auxiliary.CalculateNormal( TerrainTileVertices[TerrainTileVertices.Count - 9], TerrainTileVertices[TerrainTileVertices.Count - 8], TerrainTileVertices[TerrainTileVertices.Count - 7], TerrainTileVertices[TerrainTileVertices.Count - 6], TerrainTileVertices[TerrainTileVertices.Count - 5], TerrainTileVertices[TerrainTileVertices.Count - 4], TerrainTileVertices[TerrainTileVertices.Count - 3], TerrainTileVertices[TerrainTileVertices.Count - 2], TerrainTileVertices[TerrainTileVertices.Count - 1] ); for ( int i = 0; i < 3; i++ ) { TerrainTileNormals.Add( Normal.X ); TerrainTileNormals.Add( Normal.Y ); TerrainTileNormals.Add( Normal.Z ); } //T2 TerrainTileVertices.Add( x ); TerrainTileVertices.Add( y ); TerrainTileVertices.Add( pTiles[Offset].Height ); TerrainTileVertices.Add( x + 1 ); TerrainTileVertices.Add( y ); TerrainTileVertices.Add( pTiles[Offset + 1].Height ); TerrainTileVertices.Add( x + 1 ); TerrainTileVertices.Add( y + 1 ); TerrainTileVertices.Add( pTiles[Offset + Diameter + 1].Height ); Normal = Auxiliary.CalculateNormal( TerrainTileVertices[TerrainTileVertices.Count - 9], TerrainTileVertices[TerrainTileVertices.Count - 8], TerrainTileVertices[TerrainTileVertices.Count - 7], TerrainTileVertices[TerrainTileVertices.Count - 6], TerrainTileVertices[TerrainTileVertices.Count - 5], TerrainTileVertices[TerrainTileVertices.Count - 4], TerrainTileVertices[TerrainTileVertices.Count - 3], TerrainTileVertices[TerrainTileVertices.Count - 2], TerrainTileVertices[TerrainTileVertices.Count - 1] ); for ( int i = 0; i < 3; i++ ) { TerrainTileNormals.Add( Normal.X ); TerrainTileNormals.Add( Normal.Y ); TerrainTileNormals.Add( Normal.Z ); }[/source]

T1 and T2 are the two triangles that compose one quad/tile.

As you pointed out, my code also is horribly incorrect for calculating directional light (oops!). So, I've updated it...

[source lang="cpp"]//VERTEX uniform mat4 LightModelViewProjectionMatrix; uniform mat4 WorldMatrix; varying vec3 Normal; // The eye-space normal of the current vertex. varying vec3 LightDirection; // The eye-space direction of the light. varying vec4 LightCoordinate; // Position in model view projection space from the lights view. varying vec4 WorldPosition; // Position in world space. void main() { Normal = normalize(gl_NormalMatrix * gl_Normal); LightDirection = normalize(vec3(gl_LightSource[0].position)); WorldPosition = WorldMatrix * gl_Vertex; LightCoordinate = LightModelViewProjectionMatrix * gl_Vertex; gl_Position = ftransform(); // Transform via fixed function into the viewer's view gl_TexCoord[0] = gl_MultiTexCoord0; }//FRAGMENT uniform sampler2D DiffuseMap; uniform sampler2D ShadowMap; uniform mat4 WorldMatrix; uniform float MinimumShadow; varying vec3 Normal; // The eye-space normal of the current vertex. varying vec3 LightDirection; // The eye-space direction of the light. varying vec4 LightCoordinate; varying vec4 WorldPosition; void main() { vec4 Texel = texture2D(DiffuseMap, vec2(gl_TexCoord[0])); // Directional lighting //Build ambient lighting vec4 AmbientElement = gl_LightSource[0].ambient; //Build diffuse lighting float Lambert = max(dot(Normal, LightDirection), 0.0); vec4 DiffuseElement = ( gl_LightSource[0].diffuse * Lambert ); vec4 LightingColor = ( DiffuseElement + AmbientElement ); LightingColor.r = min(LightingColor.r, 1.0); LightingColor.g = min(LightingColor.g, 1.0); LightingColor.b = min(LightingColor.b, 1.0); LightingColor.a = min(LightingColor.a, 1.0); LightingColor *= Texel; // Shadow mapping // ------------------------------// vec4 lcoord = LightCoordinate; // Fragment position in light space.// lcoord /= lcoord.w; // Project to cartesian space// lcoord.xy = lcoord.xy * 0.5 + 0.5; // Scale since light clipping space is in [-1,1] but texture space is [0,1]// // float fragmentDepth = lcoord.z; // Depth of the fragment in light space.// float shadowMapDepth = texture2D(ShadowMap, lcoord.xy).r; // Depth in the shadow map.// // float eps = 0.001; // depth bias// float shadow = fragmentDepth - eps > shadowMapDepth ? 0.5: 1.0; //// Color.rgb *= shadow; gl_FragColor = LightingColor; }[/source]

Only problem is I think I still haven't quite gotten the scene lighting right, since some triangles appear to be incorrectly lit -- i.e. I'm expecting both triangles in a quad to be nearly identically lit. Unfortunately, that does not seem to be the case -- even for light shooting down from directly above.

I'm not sure what a good ambient/diffuse color set might be -- that may be my problem. But my understanding of diffuse and ambient is that they add together. I also wanted to make sure that the scene didn't get too bright -- I don't want light to be super-reflective and show the light color itself -- at most, I want the true RGBA of the texel to be shown, which is why I clamped each element (there may be a better way) in the LightingColor to be 1.0 at highest...

i.e.

Posted Image

The ambient and diffuse are the same color at the moment, to attempt to "build" this out... Which, sure, it makes sense that they add together here. But it looks like the normals may still be off for some triangles, which in reality, should be the same. The lower left side are all flat on the ground.

Any thoughts?

#18 dpadam450   Members   -  Reputation: 934

Like
1Likes
Like

Posted 26 July 2012 - 10:27 AM

The only reason I haven't posted anything, is your pictures are ridiculous. I have no what I am looking at. I know its some terrain but its insane. Get rid of the texturing/tiles if you are just work on the lighting alone.

Does your lighting shader work on other objects like a sphere?

Tips:
Make a function called Cross product that takes two vectors instead of this.
Result.X = ( A.Y * B.Z ) - ( A.Z * B.Y );
Result.Y = ( A.Z * B.X ) - ( A.X * B.Z );
Result.Z = ( A.X * B.Y ) - ( A.Y * B.X );

It looks like you are only doing face normals instead of blended vertex normals.

#19 Terin   Members   -  Reputation: 192

Like
0Likes
Like

Posted 26 July 2012 - 11:05 AM

I was hoping to do something flat like face normals. Is this a problem if that's the case? Good point on the method, which I've done.

I'm sorry the pictures are "ridiculous." I figured you'd still be able to tell, even with textures on. I haven't pushed anything else into the engine to test it. I figured a flat surface with occasional changes in height would be a good test.

#20 dpadam450   Members   -  Reputation: 934

Like
1Likes
Like

Posted 26 July 2012 - 04:49 PM

If your quads are supposed to be evenly lit, then you are probably taking the wrong vertices to cross and doing them in the wrong order causing some to be negative.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS