Sign in to follow this  

How can I implement light beams with DirectX 9 or 11?

This topic is 1100 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Although lighting is very fundamental in DirectX programming, but there's one pitfall that can sometimes reduce the fun of a game: we can't SEE the LIGHT itself! Instead, only when the light strikes some object in the game scene can we know that it really exists! But sometimes, if we can ''directly see'' the light itself, the effects would be more interesting. For example, in many games, while holdinga flashlight at night, you can directly see the light beam emitted by it.

 

The problem is: what do we need to do in order to implement it? We already know that in real life, the reason for our being able to see a light beam is that the atmosphere is full of tiny particles; but in games, basically everything exists in vacuum, and it's of course impractical to create many small particles and let them reflect the light. So what can we do?

 

I think this technique is a bit like producing shadows. But am I right?smile.png

Share this post


Link to post
Share on other sites

Not really like shadows, no. You may be looking for what are commonly called "god rays," which can be done with blurring in one or more passes in a shader. More commonly, however, for light cones and such, "volumetric light" is used. You create a quad or box, textured with a transparent texture, and render it with alpha blending so the background scene shows through.

Edited by Buckeye

Share this post


Link to post
Share on other sites

I once implemented volumetric light effect . My method was this:

- Render enough planes . These planes are parallel to the near plane which means they are always facing the camera . How many you may ask? The more the better ;)

- When rendering each of these planes in the pixel shader determine the attenuation of the light on it. Also you can use a shadow map to get shadows.

 

This way you get fairly good result . 

 

Nowadays , but I see modern games use more interesting approaches . For example take a look at the Kill Zone : Shadow Fall . They basically use the same idea but without multiple draw calls to render the planes . They ray march through the cone or sphere (based on the Light type) and do the same things (attenuation , Shadows , etc).

Share this post


Link to post
Share on other sites

The simplest approach IMO would be to use a cone mesh for your flashlight, and use an inscattering pixel shader on it with additive blending - no culling or depth testing.

 

To get a correct result for your beam though, you only want the light accumulated from the front of the mesh to the back, not from the camera to the back (which is what you'll get if you use the inscatter shader on it's own). To fix this you'll need to subtract the front face results from the back face (you can use SV_IsFrontFace or VFACE to determine front faces and then multiply the output by -1 if it's a front face). This will remove the contribution from the front faces, giving you only the inscattering through the beam from the front to the back. You'll also need to use the depth buffer to avoid your beams going through surfaces (volumeDepth = min( sceneDepth, meshDepth )). smile.png

 

Essentially what I'm describing is this.

 

If you need something with a little more flexibility, you can ray march your light volume or voxelize it (in light space, view space or world space). All of the approaches come with their own benefits and tradeoffs, so it's really up to you to decide which will suit your needs. For a simple flashlight I'd go with the beam approach because it can be done at full resolution, is very fast, doesn't suffer from limited resolution or limited sampling and has perfect temporal stability since it's essentially just a cone mesh with a fancy shader on it.

 

 

Edit: Here's some pseudo-code. Make sure your winding order is correct when picking the front faces or this won't work properly!

float sceneDepth = tex2D( depthMap, IN.texCoord.xy ); // Linear depth, make sure it's 0-Far Plane and not 0-1 for this shader.
float meshDepth = IN.meshDepth; // Same as above, but from the vertex shader of this mesh.

float volumeDepth = min(meshDepth, sceneDepth); // Minimum of scene depth and mesh depth for the inscattering integral.

float3 viewDir = normalize( IN.viewDir.xyz ); // world position - camera position


float inscattering = InScatter(cameraPos, viewDir, lightPos, volumeDepth); // Function from Macklin's blog.
inscattering *= isFrontFace ? -1.0f : 1.0f; // isFrontFace = SV_IsFrontFace

return inscattering; // Output
Edited by Styves

Share this post


Link to post
Share on other sites

This topic is 1100 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this