Tile based forward rendering?

Started by
5 comments, last by Krypt0n 12 years, 6 months ago
Hi! I would like ask opinion on idea, because i don't want to waste my time implementing something that is stupid right from the start.

Story is i don't want to do deferred because i love and need transparency, max amount of possible materials and anti-aliasing plus dont have time to implement sophisticated systems to get that kind of things to work well with deferred.

Im using DX 11 only.

So im thinking about this:

1. Render all scene depth only
2. Calculate view-space minZ-maxZ value for each tile (one tile could be about 16x16 pixels) in compute shader
3. In compute shader- calculate for each light what tiles it intersects and add light index to that tile
4. Render scene normally and light like this:
4.1 Determine what tile this pixel lies withing
4.2 For each light index in tile light list -> lookup it from the global light table and calculate lights

I know there is this: http://visual-comput...rred_rendering/ but it still uses G-Buffers.
Advertisement
What you're describing is essentially a modern variant of light-indexed deferred rendering, and it definitely doesn't sound stupid. You could actually take it even further and compute the list of lights per-pixel rather than per-tile, and then store it as a bitmask in a texture with a UINT format.
I use that also, for my mobile engine, as memory transfers due to fat GBuffers are extremely slow, and as a nice side effect, it allows to shade transparent surfaces properly (which is another bad thing of deferred shading).

One problem, tho, is that different light/projector types need a special code path. if you do it deferred, you barely care about this, but forward indexed rendering needs all the light types in one shader. beside that, adding lights per pixel, will make the buffer quite big and cause again a lot of traffic for quite redundant data. from my benchmarks it's best to use the thread-granularity for fragments units to get the fastest results. that's:

8x4 on nvidia

8x8 on ati

8x8 on adreno

16x16 on powerVR (but I had some issues benchmarking that properly)








Hi! I would like ask opinion on idea, because i don't want to waste my time implementing something that is stupid right from the start.

Story is i don't want to do deferred because i love and need transparency, max amount of possible materials and anti-aliasing plus dont have time to implement sophisticated systems to get that kind of things to work well with deferred.

Im using DX 11 only.

So im thinking about this:

1. Render all scene depth only
2. Calculate view-space minZ-maxZ value for each tile (one tile could be about 16x16 pixels) in compute shader
3. In compute shader- calculate for each light what tiles it intersects and add light index to that tile
4. Render scene normally and light like this:
4.1 Determine what tile this pixel lies withing
4.2 For each light index in tile light list -> lookup it from the global light table and calculate lights

I know there is this: http://visual-comput...rred_rendering/ but it still uses G-Buffers.

Thought, this is an interesting way to avoid deferred shading/lighting , I can't see the benefit for transparency. I my opinion your approach is partly isomorph to standard deferred shading, that is, you use the depth pass to determine the tile AABBs to calcuculate dependent lights, but on the other hand, the z-buffer doesn't consider transparency. This lead to wrong lit geometry which is behind a tile AABB.

Thought, this is an interesting way to avoid deferred shading/lighting , I can't see the benefit for transparency. I my opinion your approach is partly isomorph to standard deferred shading, that is, you use the depth pass to determine the tile AABBs to calcuculate dependent lights, but on the other hand, the z-buffer doesn't consider transparency. This lead to wrong lit geometry which is behind a tile AABB.

you can use the zbuffer to cull lights in general (based on the max depth per tile), based on the min depth, you can figure out which lights affect solid geometry, all lights not culled (per tile) can be added in a seperate list that are passed for transparent object.
simplyfied my addlight function per tile looks kinda like



function add(pLight,ForTransparency)

{

if( ForTransparency)

LightVec[CounterTransparent++]=pLight;

else

{

LightVec[CounterTransparent++]= LightVec[CounterSolid];

LightVec[CounterSolid++]=pLight;

}

}



when I draw a solid object, I setup the texture having the solid counter, for transparent drawcalls I set the transparent-counter-texture.

I have about 2000 lightssources in a common level, after occlusion culling it's like 30 (it's very conservative to avoid errors, as I cull on low resolution), per tile it's usually 1-8 lights for solids and up to 16when including transparent lights, but I'd guess in average there are 3 lightsources per tile

I'm considering to combine big light sources into spherical harmonics, I think that will work nicely if you don't move, I'm stil afraid of some kind of aliasing/moire effects when moving, as the min/max depth might change rapidly per tile and so the the reference position for the light source fusion. but that could be an acceptable way to deal with light sources that exceed the "tile-buckets". 16+ lightsources on an 8x8 tile seem quite excessive to me.





you can use the zbuffer to cull lights in general (based on the max depth per tile), based on the min depth, you can figure out which lights affect solid geometry, all lights not culled (per tile) can be added in a seperate list that are passed for transparent object.
simplyfied my addlight function per tile looks kinda like

Hmm.. interesting approach , much like the tile based rendering used in the frostbite engine. I use although a tile based approach for my deferred renderer, but I do not consider the zbuffer. How do you access the z-buffer ? Read it back or use some kind of software renderer on a very low resolution ?


I have about 2000 lightssources in a common level, after occlusion culling it's like 30 (it's very conservative to avoid errors, as I cull on low resolution), per tile it's usually 1-8 lights for solids and up to 16when including transparent lights, but I'd guess in average there are 3 lightsources per tile

I'm considering to combine big light sources into spherical harmonics, I think that will work nicely if you don't move, I'm stil afraid of some kind of aliasing/moire effects when moving, as the min/max depth might change rapidly per tile and so the the reference position for the light source fusion. but that could be an acceptable way to deal with light sources that exceed the "tile-buckets". 16+ lightsources on an 8x8 tile seem quite excessive to me.

I've a very dynamic light setup, a game related light source consists of up to 5 individual render light sources to break up the common light sphere. Addtionally certain particles act as light sources too, currently this sum up to around 70-90 culled lights. A 16+ light setup for a single pixel is quite common when looking down a lit hallway (I've no global illumination like the sun, everything is lit by "dynamic" light sources). Thought I could get rid of some light sources when utilising the zbuffer.

[quote name='Krypt0n' timestamp='1318851800' post='4873420']
you can use the zbuffer to cull lights in general (based on the max depth per tile), based on the min depth, you can figure out which lights affect solid geometry, all lights not culled (per tile) can be added in a seperate list that are passed for transparent object.
simplyfied my addlight function per tile looks kinda like

Hmm.. interesting approach , much like the tile based rendering used in the frostbite engine. I use although a tile based approach for my deferred renderer, but I do not consider the zbuffer. How do you access the z-buffer ? Read it back or use some kind of software renderer on a very low resolution ?
[/quote]I use my software occlusion culler ( http://www.gamedev.n...llion-polys-r85 ) as I render anyway the whole level in software for culling, culling lights is a low hanging fruite.
[quote name='Krypt0n' timestamp='1318851800' post='4873420']
I have about 2000 lightssources in a common level, after occlusion culling it's like 30 (it's very conservative to avoid errors, as I cull on low resolution), per tile it's usually 1-8 lights for solids and up to 16when including transparent lights, but I'd guess in average there are 3 lightsources per tile

I'm considering to combine big light sources into spherical harmonics, I think that will work nicely if you don't move, I'm stil afraid of some kind of aliasing/moire effects when moving, as the min/max depth might change rapidly per tile and so the the reference position for the light source fusion. but that could be an acceptable way to deal with light sources that exceed the "tile-buckets". 16+ lightsources on an 8x8 tile seem quite excessive to me.

I've a very dynamic light setup, a game related light source consists of up to 5 individual render light sources to break up the common light sphere. Addtionally certain particles act as light sources too, currently this sum up to around 70-90 culled lights. A 16+ light setup for a single pixel is quite common when looking down a lit hallway (I've no global illumination like the sun, everything is lit by "dynamic" light sources). Thought I could get rid of some light sources when utilising the zbuffer.
[/quote]

my setup is also quite dynamic, I have no static objects, the whole level (geometry+lights+projectors+fogvolumes+....) is just a container of objects, first frustum culled, then occlusion culling for solids, then culling of all transparent stuff (by that I mean everything except solids).


hallways are really bad motherf** if it comes to lights, looking nearly 90degree on a wall, you barely see a pixel, but every lightsource along it might need to be processed, which is especially bad in full-resolution deferred shader/lighting passes. Especially on consoles it caused a lot of trouble for the last game I've worked on. from that point of view, light indexed rendering is nice, as you can precalculate your min/max depth per tile, if you don't run into precision issues, it can speed up rendering a lot, compared to deferred techs. (sadly console hardware is not well suited for that, which shows how far ahead cell phones already are, if you ignore performance for a second)

I don't add particle light sources into light indexing, those are a special case for me. usually the light range is very small, but you have tons of those lights, so you probably wont see any specular (in reality you would, but the usual deferred shading optimization have a cutoff). For them I use still the deferred approach, to avoid writing a normal buffer, I use the depth and ddx/ddy dFdx/dFdy to have an approximated normal and just apply simplest diffuse+attenuation lighting (attenuation is just an intensity in the particle texture). Because of this approximation, I can calculate the lighting in the forward particle rendering pass, and as I need the depth anyway for soft particles, it's nearly free candy.

This topic is closed to new replies.

Advertisement