Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!

1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!

Deferred shading issues?

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
18 replies to this topic

#1 GameDevGoro   Members   -  Reputation: 109


Posted 18 June 2010 - 08:36 AM

Yes, well. Here we go.

My first post here so I'm sorry for any inconvenience. Like if this thread doesn't belong in this forum and that sort of thing.
Since this issue is concerning deferred shading and I've seen other threads here about it, then maybe it just is the right place?
I've been searching for answer a long time and finally came to the conclusion that maybe I should just ask it myself.

Anyway on to business:

My problem is regarding the position portion of my deferred shading implementation, at least I believe it is, since I've kinda narrowed it down to that.
The problem being that transformations of object have no effect on the lighting at all, the lighting on the objects is stationary even though they shouldn't even be affected by it (with me moving the object away from the light).
Lights look great, the attenuation produces wanted results but the positions are all messed up.

I am working in CG (and OpenGL) in my engine so, coming from a HLSL background I can't say I understand how CG's matrices work exactly.

Worth noting: I am right now storing raw positions in a 32bit buffer, I don't use depth right now, but I will probably use it later on.
I understand that I have to transform positions passed in my vertex shader with some matrix (possibly the world matrix?) but I'm unsure of which one it is in CG's terms?

How do I solve this?
What is it that I'm missing here?


#2 wiegje85   Members   -  Reputation: 151


Posted 18 June 2010 - 08:44 AM

Are you sure everything is in the same space? i.e. all vertices, pixels and lights must be in world space (for example) - this is what you want, really. That is what you probably mean with "some matrix", everything needs to be in the same space.

When it comes to CG's matrices... CG uses whatever matrix you set. In memory, both row-major and column-major are the same (it's just 64 linear bytes), it's the operations on the matrices that differ.

#3 GameDevGoro   Members   -  Reputation: 109


Posted 18 June 2010 - 08:51 AM

Oh ok.

Then what matrix is it in when I just do this: Position(out) = Position(in)?
I just pass the position the shader receives?

Edit: I'm asking this since I do this with my normals, tangents and bitangents.

#4 GameDevGoro   Members   -  Reputation: 109


Posted 18 June 2010 - 12:44 PM

OK. I feel that I could give more information of what I'm actually experiencing instead of explaining them. So I brought some screenshots of the issues, that should help right? :)

Fair warning, I'm going to link the images instead of putting them in the post, two of the images are pretty big and the other three are not as important.

So here ->Image<- we have the output as I have it right now.

You can see that the lights look pretty good, and I enlarged the intermediate render of the position buffer. And this is when I'm not transforming the position with anything at all, I just pass the position I receive in the vertex shader straight to the fragment shader untouched.

Now here ->Image<- is when I move that cage-thingy away from the lights. And as you can see the same lights affect that model exactly as much as it did when it was close to them.

Does this give a better view of what the problem is? I hope so. :)

Here are some additional images of just the output of different matrix multiplications:
Here is the ModelViewProjection matrix,
here is the Modelview matrix
and here is the projection matrix.

Thanks in advance! :D

Edit: What's that "[Tinypic]" thing on the links? :O

#5 wiegje85   Members   -  Reputation: 151


Posted 18 June 2010 - 08:15 PM

that looks very much like what i thought it would be. you treat every light as if it were inside the MODEL SPACE (i.e. local space) of EACH model. so your light's position is relative to the model's. it should be relative to the world. both should be in this space. it doesnt matter in what space really, aslong as its all in the same space. this can (and is) a bitch to get right! :)

what you want to do with your normals, tangents and binormals is: multiply them with the transformation part of your object's world matrix, this way they rotate along with your object. otherwise they just stay in their original position.


float3x3 rotWorld = (float3x3)g_World; // extract the transformation matrix, leave out the translation, where g_World is the absolute transform of the model.
out.normal.xyz = normalize(mul(rotWorld, in.normal.xyz)); // you dont HAVE to normalize if both the in.normal and rotWorld are normalized already.

same goes for your tangent space vectors. your in.position should be multiplied with the entire g_World matrix. this puts the vertices from model space to world space.

#6 GameDevGoro   Members   -  Reputation: 109


Posted 19 June 2010 - 03:55 AM

Thank you, wiegje85 :)

Though I've tried similar stuff before and it always ended badly, I'll try again though. I really want to get this to work right. :)

Anyway thanks :)

#7 GameDevGoro   Members   -  Reputation: 109


Posted 19 June 2010 - 08:57 AM

Hmmm. OK. I've run into some odd behavior concerning matrices I think.

It seems that the object's world matrix I am now passing to the GBuffer vertex shader is... uh... Gruesomely out or proportion or something.
Every time I multiply something with it it turns the result either completely white or completely black. Normalizing the multiplication seems to turn it gray. :O

Am I wasting my time with this "storing-position-inside-the-buffer" thing? Should I just put all my effort into storing the depth instead and reconstructing the position from there?

#8 mightypigeon   Members   -  Reputation: 560


Posted 19 June 2010 - 01:42 PM

Original post by GameDevGoro
Am I wasting my time with this "storing-position-inside-the-buffer" thing? Should I just put all my effort into storing the depth instead and reconstructing the position from there?

My original implementation was just stuffing the world space XYZW into a fp16 rendertarget. I noticed quite a significant performance increase when I changed over to using the depth buffer, since there's much less bandwidth required for the texture sampling (and slightly better precision too, 24 bits Z vs 16 bits Z).

Can we see your vertex and pixel shader for both filling the g buffer and doing the lighting? It looks like your light vectors might not be getting calculated properly (and your normals and tangents aren't getting transformed as per wiegje85's post)

#9 GameDevGoro   Members   -  Reputation: 109


Posted 19 June 2010 - 02:00 PM

Hello. :)

Oh, totally sure. I was going to post it anyway since it seems my explanation of the problem is a bit vague still.

G-Buffer vertex shader:

void main( in float4 position : POSITION,
in float2 texCoords : TEXCOORD0,
in float3 normal : NORMAL,
in float3 tangent : TEXCOORD2,
in float3 bitangent : TEXCOORD3,

out float4 positionOUT : POSITION,
out float2 texCoordsOUT : TEXCOORD0,
out float4x4 TBNOUT : TEXCOORD1,
out float4 posOUT : TEXCOORD5)
positionOUT = mul(glstate.matrix.mvp, position);
texCoordsOUT = texCoords;

//TBN matrix
TBNOUT = float4x4(tangent.x, bitangent.x, normal.x, 0,
tangent.y, bitangent.y, normal.y, 0,
tangent.z, bitangent.z, normal.z, 0,
0, 0, 0, 1 );
//Here I pass the position raw as it is, this probably is the problem?
posOUT = position;

G-Buffer fragment shader:

void main( in float4 colorIN : COLOR0,
in float2 texCoords : TEXCOORD0,
in float4x4 inTBN : TEXCOORD1,
in float4 posIN : TEXCOORD5,

out float4 colorOUT : COLOR0,//Normals
out float4 depthOUT : COLOR1,//Depth
out float4 aux1OUT : COLOR2,//Diffuse

uniform sampler2D decal : TEXUNIT0,
uniform sampler2D normal : TEXUNIT1)
//Normals multiplied with the TBN matrix
float4 NormalMap = tex2D(normal, texCoords);
colorOUT.xyz = mul(inTBN, (NormalMap * 2 - 1));
//Depth pass (position for now)
depthOUT = posIN;
//Aux1 pass (diffuse color)
float4 Diffuse = tex2D(decal, texCoords);
if(Diffuse.w < 0.5f) discard;//Any alpha from the pixels is discarded
aux1OUT.xyz = Diffuse.xyz;


Lighting pass vertex shader:

void main( in float4 position : POSITION,
in float2 texCoords : TEXCOORD0,

out float4 positionOUT : POSITION,
out float2 texCoordsOUT : TEXCOORD0)
positionOUT = mul(glstate.matrix.mvp, position);
texCoordsOUT = texCoords;

Lighting pass fragment shader:

void main( float2 UV: TEXCOORD0,
uniform float3 LightColor,
uniform float4 LightPos,
uniform float3 EyePosition,

uniform sampler2D DiffuseTexture,
uniform sampler2D DepthTexture,
uniform sampler2D NormalTexture,

out float4 oColor: COLOR)
float4 tDiffuse = tex2D(DiffuseTexture, UV);
float4 tPosition = tex2D(DepthTexture, UV);
float4 tNormal = tex2D(NormalTexture, UV);

//See here: The position is raw from the texture, might be a problem?
float3 LightDir = LightPos - tPosition.xyz;
float dist = length(LightDir);
float atten = max(0.0f, 1.0f - saturate((dist) / (LightPos.w)));
float3 EyeDir = normalize(EyePosition.xyz - tPosition.xyz);
float3 Half = normalize(normalize(LightDir.xyz) + EyeDir.xyz);

float diffuse = max(dot(normalize(tNormal.xyz), normalize(LightDir)), 0);
float3 specular = pow(saturate(dot(tNormal.xyz, Half)), 64);
float3 lighting = atten * (((diffuse * tDiffuse.xyz) * LightColor));

oColor.xyz = lighting * 2.5f;//I multiply it here, more powerful lighting ;)
oColor.w = 1.0f;

Now I had to reformat them a little though, and I added some comments. But they should run as they are.

Just tell me if you (or someone else) needs anything else. :)

#10 wiegje85   Members   -  Reputation: 151


Posted 20 June 2010 - 01:58 AM


Read this. Deferred Shading in Killzone 2 (note that the official term is Deferred Lighting ;))

#11 GameDevGoro   Members   -  Reputation: 109


Posted 20 June 2010 - 04:20 AM

Thanks, wiegje85! :)

But yes, I'm well aware of how this all works, and I've read *many* PDFs and that sort of thing.
The problems I am having is with the application itself. Not the theory behind it all. The shader's I've written are not working as I'd expected, OpenGL doing some things differently from DirectX (mostly the world matrix and gl's Modelview) and things of that nature that are confusing the heck out of me.

But I WILL read it again though. Can't hurt. ;)

#12 BertS   Members   -  Reputation: 124


Posted 20 June 2010 - 05:17 AM

As Wiegje said, you need to make sure all your data is in the same coordinate space. Store everything either in eyespace or worldspace.

#13 wiegje85   Members   -  Reputation: 151


Posted 20 June 2010 - 07:16 AM

Alright, I actually got to a laptop right now where I could actually *see* your screenshots (was on a mobile phone before).

I look at the second screenshot and I can say with 99% certainty that: the lights are all in each object's relative space. Make sure that everything is in world space (or eye/view space as BertS said (which is the more common space when using deferred lighting)).

Multiply your IN.position with the world matrix of the object. Multiply your IN.normal, IN.tangent, IN.binormal with the world transform (i.e. the float3x3 part of the float4x4) and then do the lighting calculations on it. Then(!) make sure the lights are also in this same space.

#14 GameDevGoro   Members   -  Reputation: 109


Posted 20 June 2010 - 11:25 AM

Thank you. :)

Yeah I'm trying the best I can to make sure everything is in the same space.

So in my OpenGL code I'm just moving stuff by multiplying it with a custom matrix I'm building based on two vectors, one for rotations and one for positions. And that's it. I'm not keeping track of any world matrix or anything so I'm left with that matrix I'm moving the objects with.

But that is what you mean by referring to the "world matrix of the object" right?

If so, here's a problem with that. When I tried that the other day I had some very unpleasant stuff happen to the depth buffer output.
When I multiplied the In.position with the whole matrix, like I'm supposed to, it turned the output completely white. As soon as I removed the rotation part from the matrix and left those as identity the output went back to how it was before that multiplication, but even then the two objects with different positions and rotations displayed no change at all.
Any idea of what would cause the "white-out"?

And which one of these approaches (depth VS position) is easiest to implement?
I'm likely to try to implement the easiest first.
Because I'm pretty tired of fighting with this now I just want it to work, even if it does so poorly.

#15 wiegje85   Members   -  Reputation: 151


Posted 20 June 2010 - 11:40 AM

I'm sorry but to me it sounds like you need to get your scene graph working first :) I think you're a bit too eager to get working on pretty things when your base is not properly setup yet.

To me it sounds like - and I can be completely wrong - that you don't have a proper hierarchy in your scene. Get your head around the concept of relative and absolute space first. I know this can be quite a big thing to get your head around; it took me the greater part of the last two years to get it. Then again, I'm no math genious, I just happen to know where to apply what.

So concern yourself with the basics first, then you shall see that suddenly your shaders will work properly :)

#16 GameDevGoro   Members   -  Reputation: 109


Posted 20 June 2010 - 12:14 PM

Thanks, wiegje85. :)

There's some truth in your words. But I'm not completely new to relative and absolute spaces as they are.
I'm just a little new to dealing with these spaces inside shaders, and since I don't know what these spaces should look like in the output. >.<
And simply because deferred rendering has a few ways to do some of the things, it makes it harder to know if you've done something right or wrong. :S

But yeah OK, I'll take it easy for a while and work on some other stuff in the engine. I'll admit defeat this time, next time, though, I will be victorious! xD

Oh yeah, before I go. I'm not going to get by without any lighting at all so I'm going to assume forward rendering is the next best thing to deferred rendering.
So correct me if I am wrong- There IS a way to blend a lot of lights with forward rendering too, right? Say, like... Uh... Let's say 32 lights.
You could do that with forward rendering?
I know the performance wouldn't be to much speak of but I am not constrained to the old 8-lights-active-at-once-thing right?

#17 wiegje85   Members   -  Reputation: 151


Posted 20 June 2010 - 08:32 PM

just get this to work! you're but a multiplication or two away from working deferred shading, why give up now? forward rendering is SO 1995... ;)

#18 GameDevGoro   Members   -  Reputation: 109


Posted 21 June 2010 - 01:54 AM

I'm not talking about giving up exactly but it is apparent I don't know as much about matrices as I thought, especially in conjunction with shaders.
So I'm going to have to study OpenGL's matrices a fair bit, and how those tie in compared to DirectX's.
I'm also going to have to cram my head with the CG shader language details so I get a better idea of how these actually work compared to HLSL and GLSL. Though the difference hasn't been unbelievable yet, there just might be something I'm missing.

I'm sure I'll get this to work some day, but I'm no genius so it could take a while. ;P

#19 GameDevGoro   Members   -  Reputation: 109


Posted 21 June 2010 - 09:28 AM

Hello again.

I thought I'd just pop back in and say I got it to work. :D
And the answer was what you all said it was... *clears throat* Right...

I have this looming feeling that it's going to break down, it's just a matter of time, BUT at least I can put this behind me (for now) and continue working on some other stuff.

So thank you all! :D

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.