Skip to main content
GameDev.net gamedev.net
🔒 Locked

Rendering with only 8 lights active

Started by noatom Dec 14, 2013 at 7:02 PM 11 replies 2.7k views
Original Post
noatom
noatom

Scenario:

you have a scene with 1000 lights,but you can only have 8 active at a time.

How do you go about rendering your meshes in a performance wise mode?

Samith
Samith

You'll have to select the 8 most important lights for each draw call you make. There are a lot of ways to do this. One way is to create an oct-tree or some other kind of spatial data structure that can store all your lights. A light is stored inside an oct-tree node when that light's volume intersects the node's volume. Then, when you wish to draw a surface, you will iterate through each light stored inside each oct-tree node that your surface's volume intersects. If a light volume and the surface volume intersect, then you keep track of that light. Once you've tested all the relevant lights, if you have 8 or fewer lights that intersect your surface's volume, you can select those lights and render. If you have more than 8 lights, you'll have to do some more computation to see which lights are the most important (brightest, closest, whatever) and select those 8 lights.

Veiled Glitch
Veiled Glitch

Hi, (I'm no Dx9 expert, so I'm not sure whether this is even possible)

Samith has a good point. And if your target is performance, I'd recommend to follow his method. But if you really want to render more than 8 lights:

Store your lights in your own structure, saving them somewhere. Then when rendering your mesh, do the following: (Not checked for bugs)


.. 
// Split all your lights in the scene up to arrays* with 8 elements in each
// Make sure that at least one element is returned, even though that is has
// 0 lights, making sure that the mesh is drawn
std::vector<std::vector<LightType>> lights;
SplitLights(&lights, 8);

// lights could look like this::
// Element: ( max 8 )
//     LightA
//     LightB 
//     LightC
// Element: (max 8, ideally these lights should be in element 0, but you get the idea...)
//     LightD
//     LightE 
//     LightF

// Render the mesh without any lights
RenderMesh();

EnableAdditiveBlending();

for( int i = 0; i < lights.size(); i++)
{
    until(lights[i].size()) SetDXLight(light[i]);

    // Render the mesh with ONLY the lights
    RenderMesh();
}

This might not be the best nor fastest, but it should work and provide you your results.

EDIT: You might need to enable some kind of additive blending.

Hope this helps.

-MIGI0027

TheChubu
TheChubu

From the lights that the camera can see in the current frame, pick the 8 closest to the camera.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"   My journals: dustArtemis ECS framework and 
wintertime
wintertime

Wouldn't that look bad if you have 8 lights near the camera and some objects together with more lights that you ignore and outside the range of those 8 lights?

TheChubu
TheChubu

Yep, but if you have to specify a limit on the lights you can draw, well, if you have more lights in the viewable scene that you can draw, it will look bad regardless of what you do. Light popping in/out of existence.

The best you can do is to select which lights you're going to draw as best as possible (ie, the ones that will have most impact in the scene).

That's why when an engine has a hard limit on the amount of lights of certain types, level designers do their best to make scenes that work and look good under those limits.

Say for example, the limit on shadow casting lights for Skyrim is 4. Go over that and the lights fck up. Thus no single interior cell* in the entire game (a game which has hundreds of hand crafted interior cells) has more than 4 shadow casting lights.

* I don't remember exactly if the limit was per interior cell or just by room/bounding volume + whatever room you see through the portals.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"   My journals: dustArtemis ECS framework and 
cozzie
cozzie
One of the keys to this is to not make huge meshes, so in practice up to 8 lights lighting one mesh is more then enough. In practice I found out that even 4 is reasonably ok (for bw compatibility if you need it, performance wise).

This is what I do:
- cull all positional lights against frustum
- for each renderable/ mesh store the 8 closest lights that effect the mesh
(simple boundingsphere vs boundingsphere radius check)
- send only these lights to the shader
Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me
Krohm
Krohm

Personally, if I'd have a realistic test case in which I need to have more than 100x the amount of supported lights, I'd start considering other methodologies, such as deferred shading.

Previously "Krohm"
WhiskyJoe
WhiskyJoe

Personally, if I'd have a realistic test case in which I need to have more than 100x the amount of supported lights, I'd start considering other methodologies, such as deferred shading.

This.

Unless there is a specific reason you want to do forward rendering with 1000 lights, I would do some research in deferred shading and perhaps use that.

It also depends a bit on how the lights are spread through the scene though, although some kind of spatial data structure is recommended regardless. If you're going to have a high density of lights within your view, it's very likely never going to be looking good regardless of how you do it (with forward rendering), unless you give up performance for some fancy alghorithm which I am not sure if it would be feasible if it exists.

If it's going to be something along the line of a city, at least where most of the lights are occluded by something, you should certainly have some kind of spatial data structure and probably checks if the light is even worth using (fully occluded by a wall you're standing next to for example).

meeshoo
meeshoo

Deferred shading is the way to go with so many lights, but artistically speaking there are too many lights in there. There are different "kind" of lights you want in a scene:

1. lights you want to see (i.e. light bulbs). You can use some halo textures and light maps to bake these in, having little performance impact

2. lights that you want to see reflected, like if you have a car in a show room and you want lots of lights bouncing off its surface, you usually solve this using some environment texture mapping effect

3. light that actually affect stuff which can be also per-vertex or per-pixel, the later being the real performance hogs.

From an artistic point of view however the less lights you use, the less confusing is for the player and the more dramatic effects you can obtain. If you look at professional films and photos you can see there are only a few lights that are used in a clever way to produce astounding effects. The more lights you add, the more fatigue and confused the player will get.

cozzie
cozzie
I think the number of lights is from a point of view of the whole scene.
I strongly doubt that a mesh looks better when you let more then 8 individual lights affect it (unless it's a very big mesh in world space)
Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me
DwarvesH
DwarvesH

One thing to note is that the 8 light limit is only for the fixed pipeline. Which is not really that relevant anymore in 2014. For shader lighting, you have 2-3 light in pixel shader 2.0 and a lot more in pixel shader 3.0+. The problem changes with shaders. It is still a difficult problem to handle unless you have very small levels. If you are rendering 2.5D performers or levels where you have to deal with a handful of rooms or corridors, there is zero difficulty to render probably as many lights as you need. As cozzie said, you don't need a ton of lights on a single mesh to make it look good.

Now if you are rendering big levels, you will need:

  • a good high performance light manager using spatial partitioning. This component will give you in roughly constant cost the exact light that shine one one mesh, whether you have 5 light or 1000. This will also pre-filter your light based on distance and frustum, so you don't get up to 1000.
  • a lot of shader permutations if you care about performance. If a shader can render 5 or 10 lights, if you used the 10 light version to render 5 lights after you have parametrized it to render only 5, it will be slower than one that is optimized to render only 5 lights.
  • if you are rendering a lot of objects and a lot of lights, you will also need damn good batching and state management. Based on you shaders and lighting scheme, you will probably won't be able to use instancing.

Or you can go deferred, but I would never recommend that to a beginner. You give up on MSAA and dealing with transparent objects is nasty business. Especially if you try things like depth peeling.

Krohm
Krohm




I strongly doubt that a mesh looks better when you let more then 8 individual lights affect it (unless it's a very big mesh in world space)
I agree. According to an article by GSC Game World, they used to have ~5 lights per pixel in closed spaces and less than 1 in open areas. It's worth noticing this was some years ago but it's still worth having this data.
Previously "Krohm"

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.