Credit: Just put ' Volumentric Lighting by Phantom107 ' in the credits, please.

An introduction for Volumetric Lighting. What does it mean?

Volumetric lighting is a technique used in computer graphics to add lighting effects to a rendered scene. It allows the viewer to see beams of light shining through the environment; seeing sunbeams streaming through an open window is an example of volumetric lighting. The term seems to have been introduced from cinematography and is now widely applied to graphics and rendering. In volumetric lighting, the light cone emitted by a light source is modeled as a transparent object and considered as a container of a "volume": as a result, light has the capability to give the effect of passing through an actual three dimensional medium (such as fog, dust, smoke, or steam) that is inside its volume, just like in the real world.

Why should this be used in video games?

Volume lights can greatly enhance the quality of almost any game scene. It enhances a certain sense of immersiveness and ambience, because of the way the light interacts with the environment. And video games are all about interaction, right? People often underestimate the power of game lighting. Imagine a forest where the sun shines through the tree leafs, or a hefty explosion where the objects are occluded by lighting caused by the bright flash. There are a lot of possibilities. Have you ever witnessed huge volumes of sunlight pass through gaps in the clouds? Such effect can be achieved with this technique.

So how does it look?

Here are two screenshots from the example to (hopefully) get your attention:

What about efficiency? Will my computer catch fire?

The example is setup to be pretty efficient. By using surfaces, only 1 render of the scene is required per step, as you'd normally do anyway. Computation speed varies on your quality preference. In the example I'm using 15 samples of the volume light-surface, which is in my opinion not much at all.

How it works

A quick note...

You will be required to be pretty fluent with GML. I'm using surfaces so it's not an easy copy-paste trick. You have to understand what everything does, but I'll do my best to explain it. This is not intended for beginners, but if you are one, I think this will be quite helpful, as it deals with arrays, surfaces, and overruling GM's drawing order.

Step 1 - Rendering the scene to a surface

Every step (or frame, if you will) the scene needs to be rendered to a seperate surface. I'm intentionally seperating the game objects from the background, so the Volumetric Lighting doesn't affect the background, which is undesirable, unless you use parrallax backgrounds. But even then it's completely compatible with this technique.

In the controller's create event, 2 surface are created. One to render the game objects to, and another one to compute the volume light-image:

In the step event, the game objects are drawn to the first surface. All game objects have been set to not-visible, so GM won't draw them again in the draw event. They can be any shape or any kind of sprite, even with different alpha values. This gives you great freedom, and even allows for semi-transparent windows with different kinds of colored glass scattered all over. Imagine the possibilities!

A "with" statement is used to "force"-draw the game objects on the surface. It's not required to set texture interpolation to true, but in the examples the objects are rotating constantly so they required a smooth look. Smooth sprites make the light look a bit smoother aswell!

// start rendering to the surface
surface_set_target(render_surface);
// clear surface to have absoltely nothing on it
draw_clear_alpha(0, 0);
// draw the objects in the scene on the surface
texture_set_interpolation(1);
with Object
draw_sprite_ext(sprite_index, 0, x, y, 1, 1, image_angle, c_white, 1);
texture_set_interpolation(0);
// finish rendering to the surface and let GM draw to the game window again
surface_reset_target();

It will look like this internally:

Note that the gray squares in the background are to indicate 100% transparency.

Step 2 - Computing the volume light-image

Computing the volume light-image is essential in this technique. Basically it creates the image that is "sampled" on top of the scene in the draw event.It is computed like so:

You might be wondering why I'm drawing the rendered scene on top of it in black. This is what creates the "gaps" in the light. By using an additive blend mode, all the white colors are drawn while the black ones are not. This way I'm able to only draw the light.

Using the additive blend mode, the computed light volume-image would look like this:

Notice the "gaps" in the light created by the objects!

Step 3 - Drawing the lighting in the draw event

The drawing order needs to be fixed:

1. Draw the game's background (this was not rendered to the surface in the step event!). I don't have an actual background in the example, so I'm using draw_clear(c_gray) to use a gray color as the background.2. Draw the rendered game objects image in the step event (the first surface).3. Draw the volume light-image in a "sampled" manner. This means the image is drawn multiple times. In this case the image is also scaled, to create the beams of light.

Is that all? What are your specs then...? Because this runs 346 fps on my laptop and 600 fps on my desktop. Does your PC have a low drawing fillrate?

i think the effect can be achieved using models though, instead of drawing 15 scaled surfaces. the only drawback would be making those models, kinda a pain when you have an image like that dragon.

That wouldn't work the same way, since that prevents partial volume lights. Only objects in front of the light should affect the shafts, and models prevent that because then you're using the entire model for the light, no matter what. Even parts that shouldn't have light volumes because the light is too far away.

You've done a good job with this example. However, I have one major suggestion. For some reason (for me anyway), occasionally GM fails to handle alpha correctly when using surfaces. When I loaded up your example, it didn't work. Fortunately, restarting my computer usually fixes this problem.

I made my own volumetric lighting system a few years ago and it is very similar to yours (except mine has few extra graphical tweaks). However, when I made my system I did not use any alpha values for casting the shadows, I did it just using the RGB values (ie I used white to indicate transparency and black for opaque). This got around the alpha problem, and it can occasionally give a nicer result.

One other addition I would recommend is that when you draw the objects to your "render_surface", use the d3d fog set to black so that your shapes can be any colour and still cast a black shadow.

This was awesome, and ran fine on like 50+ samples, just a little bright and over the top at that point, so 15 is perfect.
Currently trying to figure out how to apply this to explosions and stuff lol...I'm no good with surfaces.

One other addition I would recommend is that when you draw the objects to your "render_surface", use the d3d fog set to black so that your shapes can be any colour and still cast a black shadow.

Isn't that what I'm doing? In draw_surface_ext(), I set the draw color to 0 (black). Should be the exact same result.

Other than that, it is good to see such a well commented example.

Amazing and very usefull

Another great example by Phantom.

-Dylan

Fantastic! This will be very useful.

Thanks to all 3 of you!

Now I'm gonna try to somehow (unlikely) make this in Lite.

That'll probably be possible but very inefficient due to lack of surfaces.

This was awesome, and ran fine on like 50+ samples, just a little bright and over the top at that point, so 15 is perfect.Currently trying to figure out how to apply this to explosions and stuff lol...I'm no good with surfaces.

You should try to make the effect in an object on it's own, as every volume light would need it's own surface and sampling. It's not possible to make this work with multiple explosions using just 1 surface, as the effect is based on "scaling" on a focus point (the light). Glad you like it though.

i wonder if game maker is powerful enough to handle 3d volumetric lighting?

Yes! This example actually originates from my 3D Volumetric Lighting example. This 2D one does use a new and much faster technique though, so if you apply this to the 3D version that one will become a lot more efficient. Here it is: http://gmc.yoyogames...1

One other addition I would recommend is that when you draw the objects to your "render_surface", use the d3d fog set to black so that your shapes can be any colour and still cast a black shadow.

Isn't that what I'm doing? In draw_surface_ext(), I set the draw color to 0 (black). Should be the exact same result.

I guess I missed that line. You should use d3d anyway because then you can change the colour for greater artistic control. In my volumetric lighting system, I actually had two sprites for each object, one for the texture, and a mask for the transparency. Because I was using the RGB values, I could give an object a red mask, and it would be rendered as a semi-transparent red shape that cast semi-transparent red shadows. You could even have a multicoloured sprite for a rainbow like effect.

The 3d example doesn't look nearly as good as yours. For 3d would I just move the samples in a z direction too. Also does this work on partially transparent objects, and change the color based on the color of the partially transparent object. I guess it could have diferent colors on diferent samples to make it more realistic too(e.g. the sun would be yellow and white.)

Very nice tutorial, and relatively simple I might add. The effect looks beautiful. I wish it was a little faster, however, as on my computer (Intel 2.8ghz duo with 1gb vRAM) it only runs at a max of 125fps. Not that this is terrible, but it is certainly limiting to games that don't use many (if any) other graphical effects. Though I suppose this is more GM's fault, so well done.

0

NEWS FLASH!You can't get to heaven by your works. No chance. Hopeless. Give up now. No amount of works will get you anywhere, in fact all your efforts have been botched years ago because you already missed perfection the first time you lied, stole, or performed any of those other lovelies.

That said, do you want to go to heaven? Not the hellish picture given by cartoons. You know, the nightmarish one where you are renting a cloud and harp? I mean, holy crap, where did that come from? I am talking about a bonafide city, people, designed by God no less. Heck, read John's Revelation 21 if you want details. Getting to heaven is extremely simple, actually, the how and why is spelled out in Paul's letter to the Romans, summarized in Romans 10:9,10. God lived a perfect life and died in your place, covering every one of your mistakes and failures past and future. All you have to do is believe that He did what he said He did and accept the gift. Bam, you're saved. Done deal. Complicated, no? Questions? PM me.

And I have to say I'm quite amazed. It works efficiently for what it is, and looks great. I can only imagine what it would look like in a larger project rather than the example.

Well, I stumbled here by chance, as I've been asked if I had used Phantom's volumetric engine in my game. I actually saw this post long time ago, but implemented it a bit differently by my own, even if the principle is just the same.I have to say, I *love* god rays, used the effect extensively, and used every trick that came in my mind to emphasize it!I didn't use Phantom's engine, and sorry if it seems that I'm here to brag about what I did, but I want to stress the incredible amount of depth it adds. Yes, I'm an FX w*ore! Spot lights, trees, colored windows, leaves, cloud shadows, there're simply *tons* of ways to use an engine like Shadow's!

Spoiler

http://www.youtube.com/watch?v=5yfcH5q_sow

I didn't, but you may also consider using a lower resolution surface to draw everything on, by using d3d_ transformations to appropriately scale the shapes .

Just wondering, is there a way to do this with a surface the same size as the view I want to draw it in instead of the room's size? I'm working on a game that uses rooms that exceed sizes of 4000 x 4000 and as you might expect this makes the effect run a little slow.

however i've stumble upon a little problem using animated sprites. specifically with scaled objects (like flipping horizontally a character). the original object will always be drawn independently of whatever changes i make to it with code making it look like if theres a version of the character always looking right and when moving to the left another sprite being drawn looking to the left but overlapping the other one.