i do the following to restore worldspace position for deferred shading:
initial pass, vs:
vViewPosition = gl_ModelViewMatrix*gl_Vertex;
fs:
vViewPosition /= vViewPosition.w;
//then i store (-vViewPosition.z) in the MRT
deferred lighting pass, fs:
// Depth = (-vViewPosition.z) read from MRT
float invTanHalfFOV = 1.0/tan( radians(FOV*0.5) );
vec3 Ray = vec3( ((gl_FragCoord.xy/vec2(Width, Height))-0.5)*2.0, -invTanHalfFOV );
Ray /= invTanHalfFOV;
vec4 Position = vec4( Ray*(Depth), 1.0 );
this works perfectly fine, but requires a floating-point color attachment to store (-vViewPosition.z), but i guess the same should be possible using a depth attachment. i got it working using some hacks, but lost too much precision.
Draw always convex volumes around the lights (pointlight: Sphere, Spotlight: Cone). A fullscreen quad for a global light can be drawn by unprojecting the nearplane or simpler by drawing a sphere that intersects all frustum sides. (Same position as the camera and disabled Z test)
Sometimes it’s recommend or required to draw the lightvolume with Frontface culling and glDepthFunc(GL_GREATER); (required if the nearplane is in the light volume)
Why do you divide view space position by view space W per fragment? You should divide in the vertex shader if you expect Wview != 1.
And why these complex calculations in the fragment shader if you could just pass in the point on the Z=1 plane through which the ray passes as interpolated coordinates?
varying vec2 rayDir;
position = vec3(rayDir * Depth, Depth);
this works perfectly fine, but requires a floating-point color attachment to store (-vViewPosition.z), but i guess the same should be possible using a depth attachment. i got it working using some hacks, but lost too much precision.
What exactly did you try? Remember that a depth attachment stores window space Z, i.e. (Zclip / Wclip) scaled and biased by the viewport transform.
Yes, using a vec2 for the raydirection is possible if gl_Position.w is 1.0 (not unpro.w). But it could be possible that anyone need the correct interpolated modelview position too (for example a light fog interaction) or working clipplanes on ATI cards (that don’t wotk without the ftransform)
A correct solution would be to declare the raydir (or unpro) as “noperspective varying” but that would require EXT_gpu_shader4 and won’t work in a non shader model 4.0 card.
As we speak of deferred shading: Does anybody have an idea how one would use completely different shaders with a deferred shading approach? For example I have a procedural shader for wood, another one for plastic and another one that does anisotropic metall. The only ideas I came up with so far would be a giant switch-like structure in the deferred shading shader (which probably means breaking the instruction limit) or using multipass rendering, one pass for each material, and blending the results. But this doesn´t sound too good to me either.
Are there other ways to work around this limitation of deferred shading?
ok there’s definitly something wrong with the way i try to linearize depth… the first shader reads the distance from the color attachment the way i did it before (see 1st post):
A small performance trick: Rewrite it on the form 1.0 / (a * z + b) to shave off one instruction from the computation. If my math is right, it would be:
a = (zNear - zFar) / (zFar * zNear);
b = -1.0 / zNear;
Far from all deferred shading implementations use a fullscreen quad. In fact, I’d say that’s probably limited to techdemos. Full scale implementations usually use either quads of the rectangular screen extents of each light (this is what I did in my recent deferred shading demo), or geometric representations of the light, like spheres and cones. The latter has the advantage that you can combine it with occlusion culling to find out if a light is visible or not and use stenciling to limit shading to the lit areas only.
This is tricky, but could be workable, depending on how diverse set of shaders and materials you plan to use. Most deferred shading implementations store a fixed set of data, but if you want something more generic you could store a material ID and then have a set of generic attributes that belongs to each material. This of course comes down to the big switch-case shader, but you may be able to merge the computations for different materials in smart ways to reduce this problem. Instead of the switch-case you may be able to store a bitfield with flags for what components to include, like diffuse, ambient, specular, anisotropic lighting etc. Could turn out heavy on dynamic branching though, but maybe less so that the big switch-case scenario.
I guess it depends on how many light sources you have, how far they extend and how complex the lighting equation is. If the latter is simple then bandwidth consumption becomes more important and it’s good to combine several lights in a single pass.
In the last sentence, do you mean rendering the light extends just to get visibility/lit areas, not for calculating the lighting itself?
btw. one of the best ways to store Z is to use a float depth buffer (unfortunately only a G80 extension currently) and store 1/Zeye.
these are my (simplified) shaders atm. do you see any obvious problems? the computed position still depends on both the camera’s and the light’s position/orientation:
The latter has the advantage that you can combine it with occlusion culling to find out if a light is visible or not and use stenciling to limit shading to the lit areas only.
how can you do that if you don’t have the scene’s depth buffer in the lighting pass?
anyway, can noone tell me what i’m doing wrong here?
deffered shading requires you to split up the data into different textures, so basically you output texture color into one texture shininess, glossiness and into another, normals into a third and so on(usually compressed together in some way).
So in the first step you can use several textures.
Then in the combiner shader you can then simulate most kinds of materials using only one universal material shader.
You DO have the scene’s depth buffer available. For the light-tagging and/or occlusion culling passes you use it as a depth buffer and for the lighting pass you use it as a texture.
It’s not immediately obvious why it’s not working for you. I haven’t done any deferred shading in OpenGL, only in DX. It should be similar, but not the same since GL and DX treat Z a bit differently.