Crysis using Deferred Shading ?!

Started by
36 comments, last by AndyTX 17 years, 6 months ago
That artifact looks more like an overactive fresnel term on a metal pixel shader...
Delphi C++ OpenGL Development: www.nitrogen.za.org
Advertisement
Quote:Original post by sepul
oh thanks for article, I now got it solved in the right way !

Yep that's the weirdness of D3D pixel/texel mapping that I was mentioning. Note that there's a similar article in the D3D SDK, albeit less detailed.

Also note for interest that IIRC D3D10 will switch to the same pixel/texel scheme as OpenGL (i.e. with pixel centers at .5's) and I believe the XBox360 has state to use the alternate pixel centers if you wish (ATI's control panel also includes this setting, although that's less useful).
Quote:Original post by Matt Aufderheide
Nothng is horribly wrong with differed shading. I just dont think its benefits outweigh its disadvantages.

There are three benefits that are huge in my books:

1) Depth (and neighborhood depth) available to fragment shader. This is true of all of the g-buffer data actually, but in particular having depth available (and writable on the first pass) makes a lot of volumetric or displacement algorithms quite simple.

2) Solves/eliminates combinatoral explosion of shaders with different lighting combinations. This is going to be a huge problem in the future since multipassing every light will simply not be an efficient option. It can be dealt with in other ways, but none are as ellegant or scale as well.

3) Computes light extents per-pixel (using arbitrary light geometry). The best you can do without something like deferred shading is per-object, and even that can be expensive.

The only disadvantages that I see:

1) Incompatible with MSAA. This might get easier in D3D10 when we have some control over the multi-sample resolve step. Even then, I'm not too interested in MSAA in the long term, although it is useful right now.

2) Incompatible with object sorting schemes (like alpha blended transparency). Again I'm not interested in alpha blended transparency in the long run (it's a hack anyways), but moreover you can always do these passes after deferred shading... so this isn't really even a problem.

Anyways I didn't mean to get back into deferred shading, but it's so good... I feel the need to spread the news ;) I have developed a forward renderer and deferred renderer from scratch that effectively use the same shader fragments and so are relatively interchangable (even at runtime). That said, the deferred renderer often offers many more possibilities for advanced algorithms and rarely (if ever) limits any.
Quote:Original post by AndyTX
Quote:Original post by Matt Aufderheide
Nothng is horribly wrong with differed shading. I just dont think its benefits outweigh its disadvantages.

There are three benefits that are huge in my books:

1) Depth (and neighborhood depth) available to fragment shader. This is true of all of the g-buffer data actually, but in particular having depth available (and writable on the first pass) makes a lot of volumetric or displacement algorithms quite simple.

2) Solves/eliminates combinatoral explosion of shaders with different lighting combinations. This is going to be a huge problem in the future since multipassing every light will simply not be an efficient option. It can be dealt with in other ways, but none are as ellegant or scale as well.

3) Computes light extents per-pixel (using arbitrary light geometry). The best you can do without something like deferred shading is per-object, and even that can be expensive.

The only disadvantages that I see:

1) Incompatible with MSAA. This might get easier in D3D10 when we have some control over the multi-sample resolve step. Even then, I'm not too interested in MSAA in the long term, although it is useful right now.

2) Incompatible with object sorting schemes (like alpha blended transparency). Again I'm not interested in alpha blended transparency in the long run (it's a hack anyways), but moreover you can always do these passes after deferred shading... so this isn't really even a problem.

Anyways I didn't mean to get back into deferred shading, but it's so good... I feel the need to spread the news ;) I have developed a forward renderer and deferred renderer from scratch that effectively use the same shader fragments and so are relatively interchangable (even at runtime). That said, the deferred renderer often offers many more possibilities for advanced algorithms and rarely (if ever) limits any.


YOU may not be interested in alpha transparency but 100% of the texture artists at my work are and probably 98.435% of the ones I've worked with in the past are as well...for the long run btw (meaning the next 3 or 4 games we ship). As far as being a "hack"...it's a damn good one and has served games well for a long time. I'll take those kind of hacks any day. Maybe our definitions of hacks are different.

per MSAA...fair enough...I can roll with that.

To further the discussion on deferred shading. Let's assume you are correct and it is the future...now what?

How do we move forward?

What are the steps we need to take as engine programmers to move forward with this without sacrificing backwards compatibility(as far back as GF3 given the numbers of those cards still around)?

Is it going to be a simple context switch at a high level to change techniques (much like moving between different shader versions) or a major engine overhaul? You mention a runtime switch in your app can you please describe at a high-level where the breakoff is? For example, am i going to have to rewrite the scene graph class?

Are light batching techniques like those found in ShaderX4 temporary solutions on the way to deferred shading or are they going to be final solutions (basically fast approximations that look "good enough")?
Quote:Original post by daktaris
As far as being a "hack"...it's a damn good one and has served games well for a long time. I'll take those kind of hacks any day. Maybe our definitions of hacks are different.

I only mean that it's a "hack" with respect to the proper way to compute transparency in a scene. i.e. one has to sort per-object rather than per-fragment. The "right" ways to do it are either raytracing (not that far off, and handles much more complex effects like refraction as well) or A-buffers (or something similar that sorts fragments... but the hardware necessary to do that would be unreal). Transparency information will certainly continue to be encoded into the alpha channel, but the way that we compute in the scene will probably change (i.e. not sorting the render order back to front).

Quote:Original post by daktaris
What are the steps we need to take as engine programmers to move forward with this without sacrificing backwards compatibility(as far back as GF3 given the numbers of those cards still around)?

Supporting deferred shading only really "requires" floating point render targets (and not filtering). I think probably it will be reasonable to target GF6 as the low end by the (hypothetical) time that deferred shading is common.

Quote:Original post by daktaris
Is it going to be a simple context switch at a high level to change techniques (much like moving between different shader versions) or a major engine overhaul?

It's generally a high-level change to the rendering loop, but shader changes may be required depending on how tightly coupled they are. Using something like libsh or Cg interfaces can reduce the coupling drastically and make the changes pretty minimal. Effectively computation of the BRDF is now factored out of the surface shaders (which now simply output attributes that are input to the BRDF).

Quote:Original post by daktaris
You mention a runtime switch in your app can you please describe at a high-level where the breakoff is? For example, am i going to have to rewrite the scene graph class?

In my case, only the renderer needed to be modified/rewritten, and that was less than 1000 lines of relatively high level code. The scene graph can remain totally untouched. As I mentioned it was a bit easier in my case since I was using Libsh (and already had light shaders disjoint from surface shaders).

Thus the forward renderer has to:

1) Sort and group lights per-object as best it can.

2) Generate permutations of shaders with different lighting combinations.

3) Match the light sets from #1 with those from #2 (or generate/cull either as necessary) and render each object.

The deferred renderer has to:

1) Do a relatively simple register-allocation like pass to encode scene BRDF inputs into the G-buffer - it then tags simple encode/decode shaders (which are often just swizzles) onto the surface and light shaders in the scene.

2) Render objects (outputs go to G-buffer).

3) Render lights (input from G-buffer, output to framebuffer).

As you can probably imagine from the above, the deferred renderer is actually significantly shorter and more straightforward.

Because of the extra memory bandwidth required, the deferred renderer takes a constant-time hit in performance, but scales *much* better with scene and lighting complexity. Indeed one doesn't need to get very complex with the scene before the deferred renderer begins to win in performance.

Quote:Original post by daktaris
Are light batching techniques like those found in ShaderX4 temporary solutions on the way to deferred shading or are they going to be final solutions (basically fast approximations that look "good enough")?

I haven't read the actual chapter in ShaderX4, but if the techniques are at-all similar to what I've discribed above, they simply do not scale well to complex, dynamic scenes. I don't see it being worth doing these sorts of things in the long run when we can use the rasterizer to solve the problem elegantly, and at a much finer granularity (per-fragment).

In the end, deferred shading is really just a reorganization of the render loop, but one that decouples lighting and geometric complexity (into O(L) + O(G) instead of O(LG)).
They "kind of" use defferred shading... There main rendering is done traditionally but all their effects (particularly their atmoshpherics) rely on a depth texture pass that is then operated on in a "defferred shading" style.

They big disadvantage with DS in my opinion is it doesn't work well with anti-aliasing. Whenever you intelpolate values that aren't colors (e.g. normals, etc) as it they were you will get artifacts.

[Edited by - griffin2000 on September 25, 2006 4:08:40 PM]
Quote:As you can probably imagine from the above, the deferred renderer is actually significantly shorter and more straightforward.
Unfortunately in practice deferred renderer were most of the time slower up until DX9 hardware. I would bet the amount of people who implemented a deferred renderer for a game and had to remove it afterwards because it too slow is pretty high :-) ...
If you measure with real world data, you can find out that the theory does not work out very well especially on next-gen consoles like the PS3 and XBOX 360 (the available memory bandwidth for these consoles are public knowledge).

It is expected that DX10 cards will change this, but this was also expected from DX9 cards.
One of the major disadvantages of a deferred renderer is that it is not well suited for DX8 hardware or slower hardware. In case of slow memory bandwidth is never an option ... check out a 7600 GT to see what I mean :-).

The most famous game that uses a deferred renderer currently was not released so far (Stalker) ...
Can't you just perform a manual AA pass using an edge-blending filter ?
... it will not look as good as MSAA (multisampling + AA).

Wolf is right on the money. We tried out deferred rendering for a while. Its main drawback was/is bandwidth. Lack of MSAA support (which is big to us as well) is second, and a secondary alpha pass is a distant third (not that big of a deal). The bandwidth issue with GF6 series cards is a big problem. The framebuffer bandwidth is a problem along with texture bandwidth (since G-buffers are usually large uncompressed textures).

Personally, I love the relative simplicity of deferred rendering. I can live without MSAA and do it manually to some degree if it makes life much easier. Also, to be completely fair, the material params in G-buffers still are a limiting factor for some geometry. For our characters we ended up rendering them "forward-style" do be able to do more complex materials. We could have used up another render target , but that would have been even more expensive.

Without deferred you are left doing some more light sorting. Realistically this isnt' horrible as we were already doing this sort of stuff for previous gen. The problem is the extra PS ALU required if you are doing multiple lights per-pass, since some lights may not hit all of an object. Deferred does this much better. If you don't do multiple lights per pass, you can do some other optimizations (light stencil/scissor) but you end up rendering the geometry more often, sampling its textures each time (normal mapping etc), and using framebuffer bandwidth for each pass.

That said, I am always looking at deferred as a possible option because of its high points.

This topic is closed to new replies.

Advertisement