GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2010-04-20 13:25:34

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Surfaces as a 2D lighting engine. [Solved]

This is more of a theory or solution question than pertaining to actual code (as my code works as well as I can get it to work right now, anyway).  Also, I am working in GM7 (my project did not like being ported to 8... so I stuck with 7)


I am fairly new to surfaces, but I really enjoy how they work so far.  Let me explain what I have going on.

I have a mask that creates a day night cycle in my 2D game.  The mask is constantly drawing a square to a surface the size of the view with a ever shifting color based on the time of day.  I then display the surface with the blend modes set to emulate "multiply" in photoshop.

Begin Step event in mask Object:
01.jpg

The mask does this in it's "begin step".  This allows other objects to draw to this same surface before the mask object draws it to the screen in it's draw event.  In this manner, I layer shapes on top of shapes within the same surface to emulate lighting.

So, I have a light object in my room that in it's step event draws a circle that is one color on the inside and then the outside matches the same color as the background of the surface. (see below)  Then, in the light's end step event, it draws a solid circle that matches the inside color.  This gives my light a specified area of solid color, surrounded by a gradient that blends to the surface background.  When all is said and done, it's a pretty convincing effect.

Step Event:
02.jpg

End Step Event:
03.jpg

Effect In Action:
effect.jpg


However, a problem occurs when two lights intersect.

Problem one occurs when drawing the smooth circle in the step event.  When two circles drawn this way intersect, the one drawn last overwrites the previous one, breaking the illusion.
04.jpg

The second problem occurs when the lights are different colors.  Again, the one drawn last overwrites the previous one.
05.jpg

effectmisbehaving.jpg
The above issue is exacerbated by the fact that the "blend area" around the edges of the light are constantly shifting randomly to create a "flicker" effect.  Again, by itself it is very convincing, but when intersecting with other lights, the illusion breakage is jarring.

So, here are my questions.
1) I believe I could work around both issues with level and game design, however to do so I would need to be able to control which lights get drawn first.  Is there any way to control which order objects get updated?
2) Obviously the best fix would to make all of these shapes and gradients I am drawing blend with one another... is there any possible way of doing that (without totally hosing my performance)?

Thanks for your time in advance.

Last edited by Pixelated_Pope (2010-04-27 11:36:38)

Offline

#2 2010-04-24 15:31:44

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: Surfaces as a 2D lighting engine. [Solved]

Since light is an additive phenomenon, draw all of your lights onto a black shading surface with an additive blend mode. Then draw that using a multiplicative blend over your already drawn background.


Abusing forum power since 1986.

Offline

#3 2010-04-26 11:34:32

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

I will give that a try and then post the results.  Thanks, Xot.

Offline

#4 2010-04-26 13:48:16

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

Okay, so I think this could actually work really well, but I need to be able to combine the light overlay with the "time of day" overlay without it drawing to the screen...  Problem is, I've ran out of "steps".

Begin Step: Draw the Black Rectangle for the light surface and the colored rectangle for the timeofday surface.
Step: In all of the light objects - draw the soft graduated lights.
End Step: In all of the light objects - draw the solid circles of absolute light.
?? Step: Combine the light surface with the time of day surface.
Draw Step: Draw the time of day surface.

Is there any way I can guarantee that something will happen after the end step but before drawing?  Trying to combine the two surfaces in the draw event right before drawing occurs looks very very very messed up.  Alternatively, is there anyway to do something in the draw even (like drawing a surface to another surface) without it being displayed on screen?

Offline

#5 2010-04-26 14:33:12

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: Surfaces as a 2D lighting engine. [Solved]

You can do it all in one step, can't you?

I don't understand the need to separate anything, or to draw two kinds of light effects separately. I don't know what a "time of day" overlay is.

It is not possible to draw to a surface during the draw event, although you might be able to use surface_copy. Since it copies surface data directly blend modes won't work with it.

A single step approach:

1. Set render target to light surface.
2. Clear to black.
3. Set blend mode to (bm_one,bm_one) (additive)
4. with (light objects) {  draw the soft graduated lights  }
5. with (light objects) {  draw the solid circles of absolute light  }
6. Set blend mode to (bm_dest_color,bm_zero) (multiplicative)???
7. Draw timeofday surface???
8. Set blend mode back to normal.
9. Reset render target.


Abusing forum power since 1986.

Offline

#6 2010-04-26 15:32:52

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

Hmm...  Wow.  Yeah, I guess that makes sense.  lol.  I'll have to give that a shot and report back.

Offline

#7 2010-04-27 11:36:16

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

Got it all in and working great.  I seem to always over complicate things.  Thanks, Xot.

Offline

#8 2010-04-28 16:14:38

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: Surfaces as a 2D lighting engine. [Solved]

Cool! Glad to help.


Abusing forum power since 1986.

Offline

#9 2010-04-28 16:50:52

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

Actually... while I've got your attention, can I point you at another question I posted on the yoyogames forums?

http://gmc.yoyogames.com/index.php?showtopic=472035

I've used the method suggested by the one person who responded... and it looks awesome for when the player is standing in water... but it looks less awesome when standing in grass.  Any suggestions on how I could produce the same effect seen in those screenshots?

Offline

#10 2010-04-29 20:40:33

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: Surfaces as a 2D lighting engine. [Solved]

My only idea is if there is a way to detect when the player is touching a grass tile, to have the player object draw a grass sprite on top of itself.


Abusing forum power since 1986.

Offline

#11 2010-04-30 11:39:03

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

I can detect whether the player is on a grass tile (they are on their own tile layer.  So if there is a tile at depth X at player.x player.y then do something) but simply drawing a grass sprite on top of them doesn't really work.  The reason being, as the player moves around on the grass, the grass would be moving with the player... and that is not exactly a convincing illusion.  I even tried an effect where when a player was on a grass tile, the tile's depth would be changed to be on top of the player.  The problem that caused is as the player is walking from one tile to the next, during the transition, up to half of the character wouldn't be covered in grass... not very pleasing on the eye. 

The ideal solution in my mind would be if I could some how take a portion of the tile layer around the player's feet and draw it as a sprite on top of the player.  But I can't find any way to isolate a specific tile depth to to capture as a sprite for redrawing...

Hmm... I did just have another idea... let me go try that...

Offline

#12 2010-04-30 13:27:30

Pixelated_Pope
Member
Registered: 2009-07-30
Posts: 24

Re: Surfaces as a 2D lighting engine. [Solved]

Well, I came up with a good idea... it involves using draw_sprite_part_ext which is really hard to use when you are flipping the x scale of your sprites constantly...  So I couldn't get the bottom half of my sprite to line up perfectly with the top half.  But essentially what I was doing was creating a clone object that would draw the player's sprite at a depth below the grass, and then I would hide the bottom half of the player's sprite.  I got it to line up for one player, but a player of a different size didn't work (apparently the calculations weren't as universal as I had hoped).  I'm going to give up on this for now... it's not really worth the time I've already spent on it.

Thanks for your help again.

Offline

Board footer

Powered by FluxBB