Jump to content


Photo
* * * * * 1 votes

Volumetric Lighting for 2d games


  • Please log in to reply
32 replies to this topic

#1 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2661 posts
  • Version:GM:Studio

Posted 30 November 2010 - 08:18 PM

Volumetric Lighting for 2d games

  • Description: Occlude objects with beams of light!
  • GM Version: GM 8
  • Registered: Yes (usage of surfaces)
  • File Type: *.gmk
  • File Size: 36.6 kB (~0.04 MB)
  • File Link: Download here from Host-A.
  • 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:

Posted Image

Posted Image


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:

// Create surface to render to
render_surface = surface_create(960, 600);

// Create the volumetric lighting surface
volumetric_surface = surface_create(960, 600);

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:

Posted Image

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:

// start rendering to the surface
surface_set_target(volumetric_surface);

// clear surface to have absoltely nothing on it
draw_clear_alpha(0, 0);

// draw the light
draw_sprite_ext(SprLightGlow, 0, mouse_x, mouse_y, 6, 6, 0, c_white, 1);

// draw the rendered scene in black (this is without (!!!) background elements, or it won't work)
draw_surface_ext(render_surface, 0, 0, 1, 1, 0, 0, 1);

// finish rendering to the surface and let GM draw to the game window again
surface_reset_target();

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:

Posted Image

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.

I think the code is pretty much self-explanatory:

// first draw the background of the scene
draw_set_color(c_white);
draw_clear(c_gray);

// draw the surface with the scene objects
draw_surface(render_surface, 0, 0);

// from the light's position, draw the volumetric lighting in an expanding way
texture_set_interpolation(1);
draw_set_blend_mode(bm_add); // use additive blend mode so white will be drawn and black won't
a = 1; 
repeat 15 // initiate loop ... higher repeat count means higher quality
begin
    a += 0.05; // increase scale

    // draw surface, positioned and scaled accordingly to the focus point
    draw_surface_ext(volumetric_surface, (mouse_x - a*mouse_x), (mouse_y - a*mouse_y), a, a, 0, c_white, 0.05);
end;
draw_set_blend_mode(bm_normal); // set default blend mode
texture_set_interpolation(0);

Notice how the "sampled" surfaces are drawn with an alpha of just 0.05.... this is to make sure the light isn't too bright.

The result looks like this:

Posted Image

Happy programming!

- Phantom107




Search Tags
  • GMCENGINE
  • GMCTUTORIAL
  • GMCLIGHTING
  • GMC2DLIGHTING

  • 9

#2 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 05 December 2010 - 01:38 PM

Looks amazing! I might use this (screw baking), but I hope this doesn't get overused so that it looks like fable 2&3!
  • 0

#3 link3000

link3000

    Link3000

  • GMC Member
  • 1130 posts
  • Version:GM8

Posted 05 December 2010 - 02:32 PM

Very elegant; I'll definitely be keeping this one. Nice work!
  • 0

#4 slayer 64

slayer 64

    GMC Member

  • GMC Member
  • 3814 posts
  • Version:GM8.1

Posted 05 December 2010 - 07:50 PM

this is pretty nice. runs at 26 fps for me =/

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.

you've done a great job explaining the technique in the topic post and there's MORE than enough comments in the gmk file.
  • 0

#5 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2661 posts
  • Version:GM:Studio

Posted 05 December 2010 - 08:03 PM

Thanks for the replies!

this is pretty nice. runs at 26 fps for me =/

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.
  • 0

#6 Dead1yM00

Dead1yM00

    GMC Member

  • New Member
  • 191 posts

Posted 06 December 2010 - 02:52 AM

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.

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

#7 freko

freko

    The Professional

  • GMC Member
  • 504 posts
  • Version:GM8

Posted 06 December 2010 - 06:16 AM

Fantastic! This will be very useful.:)

Edited by freko, 06 December 2010 - 06:17 AM.

  • 0

#8 Dylan93

Dylan93

    GMC Member

  • GMC Member
  • 867 posts
  • Version:GM8

Posted 07 December 2010 - 07:31 PM

Amazing and very usefull :)

Another great example by Phantom.

-Dylan

Edited by Dylan93, 07 December 2010 - 07:31 PM.

  • 0

#9 Adequate

Adequate

    GMC Member

  • GMC Member
  • 479 posts

Posted 11 December 2010 - 08:43 PM

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

#10 Eva unit-01

Eva unit-01

    GMC Member

  • New Member
  • 771 posts

Posted 12 December 2010 - 06:52 AM

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.
  • 0

#11 unscmaster

unscmaster

    GMC Member

  • New Member
  • 946 posts

Posted 13 December 2010 - 06:51 PM

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

#12 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2661 posts
  • Version:GM:Studio

Posted 13 December 2010 - 07:05 PM

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

Edited by Phantom107, 13 December 2010 - 07:11 PM.

  • 0

#13 Dead1yM00

Dead1yM00

    GMC Member

  • New Member
  • 191 posts

Posted 13 December 2010 - 11:51 PM


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.
  • 0

#14 unscmaster

unscmaster

    GMC Member

  • New Member
  • 946 posts

Posted 14 December 2010 - 01:29 AM

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.)
  • 0

#15 Binsk

Binsk

    -Insane Kid-

  • GMC Member
  • 2906 posts
  • Version:GM:Studio

Posted 09 January 2011 - 04:46 AM

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

#16 spicydeath82

spicydeath82

    Awesomesauce

  • New Member
  • 138 posts
  • Version:GM8

Posted 16 January 2011 - 07:34 PM

ah hahahaha!!!!</evil_laugh> now that that's outta the way i think i have a good use for this... i think it will look very nice.
  • 0

#17 Glen

Glen

    GMC Member

  • GMC Member
  • 841 posts
  • Version:GM:Studio

Posted 17 January 2011 - 10:51 PM

Amazing. I love it.
  • 0

#18 xXKiTheifXx

xXKiTheifXx

    GMC Member

  • New Member
  • 4 posts

Posted 15 May 2011 - 10:49 PM

I wonder how well this works with low res stuff.. and if it will be pixelated and amazing..

Edited by xXKiTheifXx, 15 May 2011 - 10:56 PM.

  • 0

#19 fredcobain

fredcobain

    GMC Member

  • GMC Member
  • 165 posts

Posted 15 May 2011 - 11:50 PM

Beautiful effect !!
You are very good!

Congrats!
  • 0

#20 The Shotgun guy

The Shotgun guy

    GMC Member

  • New Member
  • 61 posts

Posted 09 July 2011 - 02:57 PM

Truly wonderful. I never actually thought about this idea, but this is a beautiful engine. I will definitely include something like this in one of my games!
  • 0

#21 JonathanPzone

JonathanPzone

    GMC Member

  • GMC Member
  • 1215 posts
  • Version:GM:Studio

Posted 26 November 2011 - 11:27 PM

To be honest, I was a bit skeptical about this for the longest time.

It took me several times of seeing this topic being thrown around before actually trying it out.

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.

Keep up the great work! I recommend that others to try something like this and at the very least make it an option to include in their game.
  • 0

#22 Desert Dog

Desert Dog

    GMC Member

  • Retired Staff
  • 6409 posts
  • Version:Unknown

Posted 27 November 2011 - 06:36 AM

This is a very hungry effect, but looks veerrrry nice.
  • 0

#23 Hiric

Hiric

    GMC Member

  • GMC Member
  • 55 posts
  • Version:GM:Studio

Posted 12 February 2012 - 01:47 AM

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! :P
Spot lights, trees, colored windows, leaves, cloud shadows, there're simply *tons* of ways to use an engine like Shadow's!
Spoiler

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 .

Edited by Hiric, 12 February 2012 - 01:51 AM.

  • 0

#24 Nytek

Nytek

    GMC Member

  • New Member
  • 3 posts
  • Version:GM8

Posted 30 April 2012 - 10:21 PM

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.
  • 0

#25 coco13

coco13

    GMC Member

  • GMC Member
  • 201 posts

Posted 18 June 2012 - 10:27 PM

Thanks a bunch! This looks great with my game which would otherwise be extremely bland. Took me hours to get to work but well worth it!
  • 0

#26 killerheath

killerheath

    GMC Member

  • GMC Member
  • 236 posts
  • Version:GM8

Posted 05 March 2013 - 09:59 AM

How would i make this follow the screen, i put it in my game but when it leaves the 960 by 600 area it just doesn't show anymore.

[EDIT]
NVM, i got it

Edited by killerheath, 05 March 2013 - 10:45 AM.

  • 0

#27 tremor_al

tremor_al

    GMC Member

  • GMC Member
  • 1 posts
  • Version:GM:Studio

Posted 18 March 2013 - 09:04 PM

thanks a lot for this!!

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.

FYI no using volumetric lights eliminates this problem.

 

could someone help me with this? Thanks


  • 0

#28 fel666

fel666

    GMC Member

  • GMC Member
  • 642 posts
  • Version:GM:Studio

Posted 19 May 2013 - 12:42 PM

hey:) nice example!

 

i was trying to make it only render whats in the view, with view sized surfaces, but it didnt quite work. could someone help me with that?

 

also, i tried multipla lights, but the game crashed, doesd anyone know how i could fix that aswell?


  • 0

#29 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2661 posts
  • Version:GM:Studio

Posted 19 May 2013 - 12:54 PM

Don't bother, instead you should wait till shaders come around and then try to port it over. It'll be much, much faster.


  • 0

#30 fel666

fel666

    GMC Member

  • GMC Member
  • 642 posts
  • Version:GM:Studio

Posted 19 May 2013 - 06:32 PM

0.o shaders XD, man, i completely forgot about those! (will they work for 2d as well?)


  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users