A deferred shading pipeline – a few questions

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

A deferred shading pipeline – a few questions

Post by geomaster »

Hey all,

After a big pause in my work in the field of 3D graphics, I'm back to Ogre with a lot more knowledge and a mission to write a game that just maybe won't turn out to be a dead end. Anyhow, one of the first things I need to do, after building a game framework, is to implement a deferred shading pipeline in Ogre. At first, I thought the deferred shading demo might turn out just to suit my needs, but unfortunately it didn't. The first thing I didn't like is the use of compositors which I want to avoid at all costs because they seem a little clumsy to me. The next thing is apparent inferior performance (I'm not sure, but I have an 8600GS and with OpenGL, at 1920x1080, no MSAA and no shadows, I can barely get 35 FPS in the demo) which could maybe be optimized. That said, I'd like to experiment a little and try to create my own deferred shading pipeline without compositors. (Maybe implement an alternate light pre-pass (aka deferred lighting) technique?)

Anyways, I'm still thinking a little bit on the details. Yeah, I'd have a DeferredPipeline class that could be 'attached' to a viewport to enable deferred shading on it. That would include duplicating the viewport onto the MRTs, setting the scheme to a G-buffer creation one and registering a scheme-not-found listener. So that means that the G-buffer creation phase would not be a problem to me. However, then I need to override the usual rendering process on the original viewport, i.e. to render only the light geometry and never render the scene itself. That is where I'm not sure what to do. I can register a RenderTargetListener and listen on the preViewportUpdate event and render the geometry there directly using the render system, avoiding any overhead that the SceneManager may impose on me. Binding a GPU fragment program and using Ogre::RenderSystem::_render with a premade light geometry vertex/index data should suffice. However, then I need to suppress the usual rendering onto the viewport. How am I supposed to do that? I can set a visibility mask to 0, but that wouldn't skip the rendering step wholly, the scene manager would still traverse the scene graph, discarding all renderables based on the mask, but is that necessary? Can't I just tell the viewport to stop the update operation? Am I missing something or asking a moronic question?

And of course, does something like this already exist? I haven't been able to find such a deferred shading pipeline using Google and forum search, but maybe I'm not searching well enough.

I plan on releasing this as a GPL plugin when (and if) I get something usable :)

Thanks for all your replies!
AgentC
Kobold
Posts: 33
Joined: Tue Apr 24, 2012 11:24 am
x 5

Re: A deferred shading pipeline – a few questions

Post by AgentC »

You may be able to optimize bandwidth a bit compared to the deferred shading demo, which uses two 64-bit rendertargets, by using three 32-bit rendertargets instead (albedo, normals, depth), and by cutting down the amount of fullscreen quad passes if you can (for example by combining ambient lighting & fog resolve with the first directional light.) I quickly looked at the draw call timings of the demo with PIX and it seems that the filling of the G-buffer is the heaviest part due to significant overdraw and no real culling. The demo is also creating new vertex/index buffers and vertex declarations every frame for the light volumes, which should not really be happening. But to some degree, low performance of deferred shading at full HD resolution on an 8600GS is expected. Using light pre-pass may not help much as you will be doubling your draw calls.

I'd recommend reconsidering the license though, as there already are several permissively licensed open source engines (such as Horde3D) with full deferred rendering support.
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

My best bet is to cut down the G-buffer creation time by optimizing the render target formats, and to address some issues that the demo has—just as you mentioned, excess full screen quad passes where some of them could be combined together. The deferred light issue, with creation of the vertex/index data every frame also seems to be a problem, and in fact, it is mentioned in the source code of the demo. (How much impact does this have, as it is locking and unlocking these buffers every frame, which have to be transferred to the GPU?) Also, turning off the "Global Light" option seems to double the FPS which leads me to think that the volume of the light affects performance more than it should.
I am well aware that 8600GS is not a card on which to expect stunning deferred shading performance, but I feel that around 30 FPS is really too low—on 800x600 I'm having a 70 FPS average, again with no shadows. Also, using light pre-pass could cut down on the G-buffer bandwidth and thus, together with no overdraw for the second pass, compensate for twice the draw calls. I have been reading the Ogre code regarding viewport updates, and I think I might be able to do a manual update, skipping SceneManager::_renderScene and just issuing the render calls to the RenderSystem myself.
The license doesn't matter much to me, I just want the community to see as much benefit as possible from my work, it could be public domain for all I care.
AgentC
Kobold
Posts: 33
Joined: Tue Apr 24, 2012 11:24 am
x 5

Re: A deferred shading pipeline – a few questions

Post by AgentC »

Indeed, it will depend on the scene whether LPP has an advantage. I remember comparing it & deferred shading on a mostly overdraw-free scene on an 8400GS (laptop version) and there was a very minor performance benefit for LPP.

If thinking of just the combined read/write bandwidth to fullscreen buffers (not taking material textures or overdraw into account), deferred shading and LPP actually come up pretty much equal, assuming material specular power handling, but no splitting of light accumulation into separate diffuse/specular buffers:

Deferred shading:
G-buffer: write 3 RT's (albedo, normals + spec.power, depth)
Lighting: read 3 RT's, write 1
total: 7

LPP:
G-buffer: write 2 RT's (normals + spec power, depth)
Lighting: read 2 RT's, write 1
Final pass: read 1 RT, write 1
total: 7

Final note on Ogre's draw call performance, they're not your usual 3D engine draw calls, but something extra-slow :) due to the whole fixed function state being rewritten (even if you use shaders) for *each* draw call, due to the way SceneManager & RenderSystem interact.
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

You should check out my project www.gritengine.com -- I've been using deferred shading in Ogre for a long time now. I need to start using instancing to render the light cubes, at the moment I'm uploading fresh geometry every time.

I do use the compositor framework but I regret this. I am planning to change it to explicit renders into explicit buffers. I'm not getting anything out of the compositor framework, it's just introducing more complexity. Especially when I start adding DoF and bloom etc.

When I test on an 8800, I never bother going above 1024x768. I don't find commercial games using deferred shading (e.g. GTA4) perform well above this either.
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

AgentC wrote: Final note on Ogre's draw call performance, they're not your usual 3D engine draw calls, but something extra-slow :) due to the whole fixed function state being rewritten (even if you use shaders) for *each* draw call, due to the way SceneManager & RenderSystem interact.
Yeah. That needs a rewrite :)
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: A deferred shading pipeline – a few questions

Post by al2950 »

I suggest you also look at last years GSOC. There was some really good work done there, although not entirely finished, but I believe they used the new instancing system to draw the light volumes. Also as a side not, one of my plans is to do some heavy work on the RTSS and one of the results will hopefully be a highly configurable G-Buffer Sub Render State, which will help people experiment with there deferred setups. Need to find some magic time though!!
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

AgentC wrote:Final note on Ogre's draw call performance, they're not your usual 3D engine draw calls, but something extra-slow :) due to the whole fixed function state being rewritten (even if you use shaders) for *each* draw call, due to the way SceneManager & RenderSystem interact.
Does this refer to RenderSystem::_render and similar calls, or just to calls that need to go through SceneManager?
Instancing is a good idea, but it proves to be pretty tricky to use instancing when rendering spotlight geometry because a cone has more than one variable. With spheres (omni lights) you can just set up different world matrices to scale the spheres to the desired radius, but that doesn't work well with cones—after all, you have the height and the FOV of a light. I don't know how one goes about instancing cones with different properties... Although I can always use bounding boxes for spotlights, as sparkprime suggested, and use instancing to render them. My guess would be that this is beneficial when you have really A LOT of lights whose effect can be seen on screen at a time. When there is a few lights in the view frustum whose volumes cover most of the screen, I don't see much benefit from instancing and related techniques.
And yeah, everyone, thanks for the replies. I started working on the pipeline a while ago and hopefully I'll be able to show some progress soon :)
AgentC
Kobold
Posts: 33
Joined: Tue Apr 24, 2012 11:24 am
x 5

Re: A deferred shading pipeline – a few questions

Post by AgentC »

geomaster wrote:Does this refer to RenderSystem::_render and similar calls, or just to calls that need to go through SceneManager?
Calls that go through the SceneManager, particularly SceneManager::renderSingleObject().

About spotlights: in my engine I've managed rendering spotlight volumes with different FOVs, aspect ratios and light ranges by scaling the same cone mesh non-uniformly.
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

Well, if it's only SceneManager-related, I can maybe see some performance boost from doing it directly through the RenderSystem. As for the spotlights, that crossed my mind but I discarded the thought, can't even remember why... So that's scaling on the Y axis for range control and scaling on the X&Z axes for FOV?
AgentC
Kobold
Posts: 33
Joined: Tue Apr 24, 2012 11:24 am
x 5

Re: A deferred shading pipeline – a few questions

Post by AgentC »

Yes, I'm just using different axes (cone direction is along positive Z axis)

Code: Select all

float yScale = tanf(fov_ * M_DEGTORAD * 0.5f) * range_;
float xScale = aspectRatio_ * yScale;
Vector3 scale(xScale, yScale, range_));
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

I used cubes for everything, including cones. Obviously the advantage of close-fitting geometry manifests with large lights (in screen space), whereas simple geometry is better when you have lots of small lights. I don't know at what point the cross-over is. I implemented only cubes because they were simpler and it hasn't caused a problem with large lights yet.
TheSHEEEP
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 972
Joined: Mon Jun 02, 2008 6:52 pm
Location: Berlin
x 65

Re: A deferred shading pipeline – a few questions

Post by TheSHEEEP »

How do you want to go without the compositor framework without hard-coding everything related on every change?

Or is hard-coding not a problem in your case?
My site! - Have a look :)
Also on Twitter - extra fluffy
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

The deferred shading compositor is hardcoded because all of the renderables have to know about it, and it contains custom rendering passes and other stuff. Modifying anything at this level needs a rebuild anyway. The other compositors (bloom, ssao, dof) I just need to toggle on and off, which is easy to do. At the moment I have a nasty situation where parts of the logic are in scripts (compositor/material/program scripts) and part is in C++, and if they don't match it will crash. It's all very complicated and I don't gain anything from the complexity at all.

I'm expecting the code to be somewhat simpler after I've abstracted the basic 'draw a screenspace quad on rendertarget R using shader S and textures T1,T2,T3',... functionality.
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

TheSHEEEP wrote:How do you want to go without the compositor framework without hard-coding everything related on every change?

Or is hard-coding not a problem in your case?
Well, all the shaders I'm using are dynamically generated based on a lot of variables, a lot of options (including the G-Buffer layout and lighting models, among others) are settable through the main class, so I'm aiming for a completely flexible pipeline without the need of hardcoding at all. I'm not yet at the point of rendering light geometries, I've been doing G-Buffer optimization in the past few days and I've been able to get away with three R8G8B8A8 textures and leave two components for future use. The depth is packed into R8G8 of the third RT but can be easily extended onto the full texture (currently B8A8 are empty, as I said, it's a huge waste :) )

So, currently, I can create procedural cones, spheres and screen-aligned quads (cones and spheres were a little bit of pain because of all the low level vertex/index-buffer related stuff and some stupidity on my side) and I can render them directly using the RenderSystem onto a viewport, completely bypassing the SceneManager. But something else came into my mind... How do I render the stuff that doesn't belong to deferred shading, say, transparent objects? My idea was to clear the color buffer of one of the MRTs, render the non-deferred objects (so that they are correctly occluded by other objects) and write their RGBA values onto the color buffer. Then, when compositing albedo, I alpha blend this color buffer too. Is this the right way to go—something obvious I'm missing? Any things I should look out for?

Just for the record, rendering ~44k triangles onto the G-buffer results in around 140FPS on my 8600GS at 1280x720. Scaling to ~400k triangles cuts the FPS to around 100. I have no idea if all that's good or bad. The deferred shading demo page shows a screenshot of a G-buffer being rendered, and at ~64k triangles drawn the FPS is 360, but I have no idea what hardware the author had used so it's not of much help to me. If anyone can tell me (from experience) how is this performance, relatively, it would mean a lot.

Thanks
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

The thing about flexibility is that if you're doing an open source project, you are automatically completely flexible. The question is how easy it is to achieve different levels of customisation. I believe that fundamental changes to the rendering pipeline are sufficiently complex (and overarching) that having to modify c++ code to achieve it is not a big deal in comparison to the high-level trouble involved. Also, it will typically be done by a single (highly-trained) individual, and only once per project. So what if you can do it by modifying some scripts on disk? It's going to be so flaky and complicated that noone will dare touch it except people who know exactly what they're doing.

I allow vast amounts of script-based customisation, from materials to physical behaviour, particle systems, and gameplay logic, and will be allowing some degree of shader customisation without having to touch the c++ and rebuild, but NOT the fundamental graphics pipeline. This makes the design tractable.

Not flexible unless you know c++:
* resource handling and disk I/O
* issuing, ordering of drawcalls, culling algorithms, render targets
* lighting
* depth shadow casting / projection / cascading / receiving
* gbuffer configuration
* lighting passes
* post effects
Note that the above are all highly parameterised, but their structure is fixed.


For gbuffer performance: your overdraw should matter more than the number of triangles. Of course it matters what you're doing in your shader. If you're using diffuse, normal, spec maps with gloss, and you have a 4-way texture blend with parallax *and* a shitload of overdraw then you're not in a good place for performance :)


I am by the way doing everything pretty much as you are doing. I too am autogenerating shaders and materials (anything else these days is just daft). The mapping from my materials to ogre materials is not 1:1 as there are several situations where a different material has to be used, depending on mesh characteristics (e.g. number of bones), multipass renderings, and low level things like shadow casting, etc. My gbuffer format is:

depth: 24 bits
diffuse : 24bits
spec: 8 bits
shadow_attenuate: 8 bits (this is to avoid shadow artifacts in areas of harsh normal interpolation)
normal: 24 bits
gloss: 8 bits

The normal encoding is an interesting subject. If you do what I do, which is to write the normal into the 3 bytes in an obvious fashion, you get pixellated specular highlights because of the quantisation of the vector values. For example, this gta5 promo screenshot has this problem: http://admin.games.cz/uploads/v-4-1280- ... 221673.jpg

I'd be interested to know if you are doing anything clever with the normals. I have a few experiments to run, such as

* using polar coordinates
* borrowing a bit from shadow_attenuate for the z polarity, then coding x and y into the 24 bits, 12 bits each
* projecting to a cube and storing the face coordinate somehow
* doing what crytek did -- a lookup table to write a non-normalised 3d vector to the gbuffer, that normalises to the right thing in the lighting phase



For forward-shaded stuff, simply render to the same render target as you light the gbuffer into.

1) clear gbuffer depth
2) render deferred shaded passes to gbuffer (no sky)
3) render gbuffer to target buffer as a deferred shading pass, doing fog, sun, sun shadows, ambient, reflections, etc
4) additively render to target buffer small lights onto target buffer, referring to gbuffer of course
5) additively render to target buffer additional lighting (emissive, weird object-specific lighting components like phosphorescence, florescence, special reflective paint for emergency vehicles, etc)
6) render sky layers to target buffer, letting depth buffer clip sky fragments that are behind other geometry
7) finally alpha-blend alpha stuff to target buffer

If you want to do bloom or HDR tonemapping or whatever, use an RTT as the target buffer and go from there.
LBDude
Gnome
Posts: 389
Joined: Mon Jul 26, 2010 10:53 pm
x 22

Re: A deferred shading pipeline – a few questions

Post by LBDude »

I'm running a light pre-pass pipeline in my game using Ogre. It's nothing fancy really. The process:

-Reduced G Buffer generation
I manually create a render target, manually update it to produce the reduced G buffer.

The format is (EncodedNormal.x, EncodedNormal.y, gloss_value)

I got my normal encoding from here: http://aras-p.info/texts/CompactNormalStorage.html

Gloss value specifies glossiness of a material. The range of value can go from 0 to 2000+.
See here: http://seblagarde.wordpress.com/2011/08 ... ting-mode/ (okay admittedly I haven't got to the part of producing correct gloss map yet)

-Render light volumes (not optimized one bit) to produce Light Buffer
Currently I can only render point light and directional lights.

I produce diffuse and specular components based on the light. See this blog post about it: http://fdastero.wordpress.com/2012/08/1 ... yesterday/

BRDF is physically based Blinn-Phong based on Tri-Ace's paper (see: http://research.tri-ace.com/Data/course ... triace.pdf). The limitation is I'm bound to a single BRDF. I could switch BRDF based on light ID I suppose. However since my system is physically based, I can vary my materials types by changing fresnel factors. I also plan on doing a double layered Blinn-Phong BRDF.

-Third stage: (render scene again and sample reduced G'Buffer and Light Buffer)

In this stage I sample G buffer for the normal, and lighting buffer for the diffuse + specular components.

I compute ambient lighting in this stage as linear combination of two 5th order spherical harmonics. It's kind of stupid and expensive as hell. I do plan on changing it. I need this because I need to do "cave lighting" since my game is like Minecraft you can go under mountains and stuff.

I load diffuse and material textures here (material textures are not created yet, only a single material for the entire scene right now). The lighting equation is computed using data from the light buffer. The diffuse + specular components are multiplied by fresnel terms (approximated with N.L instead of N.H). I can vary refractive index here which I read from textures.

Performance:

I have a GTX 570. For a scene like this video http://www.youtube.com/watch?v=dm-NLZIVLko I'm rendering 32 batches and around 40k. I get 60fps with 10 spherical light volumes of size 32. Yeah it's kind shitty :). But like I said I do a lot of heavy and wasteful shader computations in the 3rd stage that I can optimize away hopefully.

I also compute SSAO. I also compute this thing called HFAO (used to "shadow" underground caverns; kind of stupid; wasteful). GUI is eating up a crazy amount of performance too.

A lot of room for optimization. But I figure I can run BF3 at medium settings so if I can get the FPS to a sweet spot based on that I should be okay.
My blog here.
Game twitter here
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

@sparkprime: My G-buffer is three 32-bit RTs (R8G8B8A8) and its layout is like this:

RT0: R8G8B8 (24 bits) for albedo, A8 (8 bits) for shininess
RT1: R8G8 for the packed first component of the encoded normal (16 bits), B8A8 for the second one (16 bits)
RT2: R8G8 is the packed depth and B8A8 are free for future use.

I encode normals using a spheremap transform, as described by Crytek in this presentation (see slides 12 and 13) and then pack the XY resulting components into 16 bits each. If I don't pack normals like that (i.e. just put Encoded.xy into rt1.rg) I can use B8A8 of RT1 for depth and then skip the usage of the third render target altogether, which is a huge bandwidth boost. However, this would introduce specularity artifacts as you mentioned so I think it would be OK to leave it like this in the default settings and let the user switch to the more compact 64 bit G-buffer if needed, and if he/she doesn't mind the loss of normal detail. My vertex shader uses 16 ALU instructions and my pixel shader uses 34 ALU and 1 TEX (diffuse map sampling, the demo I'm using currently doesn't include normal maps although they are supported). I have to test how much impact does complicating or simplifying a shader deliver to the rendering speed since I'm pretty much new to practical application of all these concepts. (Although, theoretically, I have read a shitload of papers :)) NVPerfHud is a big help in determining bottlenecks, debugging the render calls and whatnot, although I haven't been able to get my hands on PerfHUD 6.

@LBDude: HOW do you manage to get only 60 FPS on a GTX 570? What's your bottleneck? Seems really low to me... Or maybe I'm wrong...

I'll update you all when I manage to get something, no matter how slow and shitty it is, because computations are going to be underway :)
LBDude
Gnome
Posts: 389
Joined: Mon Jul 26, 2010 10:53 pm
x 22

Re: A deferred shading pipeline – a few questions

Post by LBDude »

Well I'm doing a lot of things and not just rendering 40k tris. I render shadows. I render a 3rd pass after light buffer. So total in that scene I render 120k tris in 32 batches each pass. It's probably less than 120k becuase the 40k figure is from the G buffer stage. Later stages benefits from z pre-pass (whether I actually have z pre-pass is another story; I need to check it). I haven't really begun to profile my shaders yet (i.e. bandwidth, fillrate, or ALU bound).

-shadows
This is very intensive operation. Without rendering shadows I get 80-90fps. 80-90 is with GUI on. With GUI off I get 160 FPS last time I checked. However FPS is not a linear degradation.

-SSAO
Currently doing it at full resolution.

-HFAO
Very similar to SSAO but computes shading for caves. Does jittering and multiple texture reads and ALU operations.

-ALU ops
Doing to inner produce on 5th order SH. Doing a bunch of other random stuff (ex: bunch of dot products for lighting). However I just checked ALU boundness by disabling all that ALU ops and my frame rate went up to 70s.

Oh I transform normals back to world space so I can sample the SH. I don't want to rotate SH into view space (normals are in view space) because...frankly SH rotation in a shader is a pain in the ass. I can't do this in tangent space precisely because of SH rotations. SH rotations into tangent space is a hard problem. (Recently saw a paper on fast arbitrary SH rotation.)

So yeah I haven't really profiled yet. I'm doing shadows. Also doing a bunch of other stuff. I'm probably rendering around 120k tris.
Last edited by LBDude on Tue Aug 21, 2012 7:09 pm, edited 1 time in total.
My blog here.
Game twitter here
LBDude
Gnome
Posts: 389
Joined: Mon Jul 26, 2010 10:53 pm
x 22

Re: A deferred shading pipeline – a few questions

Post by LBDude »

also I render out textures for SSAO and HFAO at full screen resolution.

In my 3rd stage I read diffuse from texture array (512x512 * 256). I read G buffer (full res). I read Light buffer (full res). A cube map. SSAO and HFAO buffers (full screen resolution). I read shadow maps (1024 * 3). That's a lot of high resolution textures I'm reading. Good thing I have z pre-pass.
My blog here.
Game twitter here
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

Great to see what everyone is doing. That normal storage page is great. I'll probably do the same thing with my normals then.

It seems everyone is using PBR these days. I actually started the switch to it last Friday myself, using exactly the same course notes as you posted :)
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

One more question for you guys, when do I apply fog? Since it overrides lighting, I guess it should be just modulated with the final light accumulation, using a full screen quad. But I recall someone in this thread mentioned joining the ambient pass, fog resolve and the first directional light into a single full screen quad pass. How is that possible?
AgentC
Kobold
Posts: 33
Joined: Tue Apr 24, 2012 11:24 am
x 5

Re: A deferred shading pipeline – a few questions

Post by AgentC »

You can get fog to blend in properly with lighting by reducing the albedo term in the G-buffer toward black the more a surface is fogged. Then you'd lay fog+ambient to the final rendertarget before lighting.

To also add a directional light to that:

finalColor = fogColor * fogBlend + (NdotL * dirLightColor + ambientColor) * albedo;

where fogBlend is 1 for fully fogged and 0 for not fogged. And like said above, for this to work albedo must have been multiplied with (1 - fogBlend) during the G-buffer pass.

However (to confuse you more) I actually prefer binding the final rendertarget already during G-buffer pass to lay fog+ambient right there. I need to do that because I also support vertex lights and per-object ambient lighting "gradients" which cannot be applied globally later. This is slightly more bandwidth, but also allows to lay down any emissive or environment mapping effects to the final target without a second pass.
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: A deferred shading pipeline – a few questions

Post by sparkprime »

Ideally you would do fog after lighting, because then it's trivial to lerp it over as a function of depth. However if you want to do it before lighting, you can (since light is additive) simply attenuate the light according to the amount of fog. I don't think it's an exact match unless you have linear fog, but should be close enough.

What I do is to do the fog after the sun (in the same pass as the sun) which is the same pass as shadows and environmental cube lighting / reflections. The fog is lerped right at the end of that. Then I do more passes for alpha, which also have to account for fog, and point lights, which include the fog in their contributions.

Doing the fog after alpha wouldn't really work because the depth would be wrong.

Doing it before alpha means you have to incorporate fog into the colour of your alpha blended pass. This counts the fog between the alpha fragment and the camera twice, so it's already "wrong".
geomaster
Gnoblar
Posts: 13
Joined: Tue Oct 19, 2010 12:28 pm

Re: A deferred shading pipeline – a few questions

Post by geomaster »

Okay, finally got my hands on to finish this project. School's coming over here in Serbia, but I managed to do some work. Now I can render directional lights and I'm working on omni's. I had to deal with some nasty hacks Ogre developers used, but that wasn't a problem in the end. Now I have a minor problem, and that is rendering light geometry. Before I render anything I set my scene blend mode to a classical additive blend (i.e. result=incoming+framebuffer) but now, since I turn off triangle culling, the lighting is computed twice and thus added twice into the scene in the areas where a backface fragment gets drawn and then overdrawn by a frontface one. I can deal with this, obviously, by enabling culling, but this introduces more problems. If the camera is inside the light volume, it gets culled completely and the result is that light is not applied at all. I suppose I could check if the camera is inside the volume and then invert the culling appropriately but in that case, when a volume boundary is near the camera, near plane clipping will occur and light geometry will have a "hole" in it. I'm currently dealing with this by turning on clockwise culling, rendering the volume, then turning on counter-clockwise culling and rendering the volume again. This introduces a twice-the-drawcall overhead, so I was wondering if this was OK or maybe I should seek a more sophisticated solution. Will rendering the light volumes twice deliver a big enough impact on the performance as a whole?