Light from items

Started by
9 comments, last by imontheverge7 9 years, 6 months ago

In order to create a day/night cycle in my game, I decreased the r,g and b values of the Color variable after a certain amount of time has passed. This worked as expected. I am wondering in order to create light from an item, like a fire or lamp, could I create a circle around the item and set the color in that circle to be white? Or is there a better way for accomplishing this in 2d?

Advertisement

Is your game tile based?

If so, custom animated tiles for the fire and surrounding ground, that light it appropriately and show the play of shadows and flickering.

A white circle is the worst way to do it graphically. If you can't make custom tiles, then just use the daylight color within the circle, and only change the color outside (use it as a mask).

I use a tile engine to build my map but I don't want to see the tiles. What do you mean in your last sentence by using it as a mask?

First of all, I would advise you not to change the r,g,b; leave them constant as an albedo description of the material. Just add a light intensity variable that varies from 0 to 1, the final color should be r*lightIntensity, g*lightIntensity, b*lightIntensity(you can even go as far as adding color to the light materialColor*lightColor*lightIntensity). Then for the fire/lamp you can regard it as a point light in 3d, basically have a range that it affects and you can add some attenuation factors. The intensity of the light from the center of the fire/lamp outwards should diminish with distance. What is used for the attenuation over distance is: lightIntensity/(constantAttenuation + linearAttenuation*distance + quadraticAttenuation*distance*distance).

Later you should add support for the non-static objects - like the player - he should receive light from the lamp/fire too.

Pseudo-code:


For each object
output.r = object.material.r*sun.r*intensity // intensity varies from 0 to 1 depending on the time of the day
output.g = object.material.g*sun.g*intensity
output.b = object.material.b*sun.b*intensity

//...

For each lamp
/* Draw ovals that are blended with the background behind. Each oval has a color depending on its radius. Basically oval.color = lamp.color/(constantAttenuation + linearAttenuation*ovalRadius + quadraticAttenuation*ovalRadius*ovalRadius)
 The blending could be additive) */

First of all, I would advise you not to change the r,g,b; leave them constant as an albedo description of the material.

Well, I have no idea about 2D wrok really or tile based engines, but in a night / day cycle the light color has to change, else it will look off. Actually, the light color is even more important than the light intensity as light intensity can be affected by an overcast sky or a full moon, but the color will most of the time stay the same depending on the time of day.

There are exceptions, like heavy fog or stuff like that.

@ OP:

I think what StarMire was talking about is that, as long as your light falloff is limited to a single tile, you don't need to have any light affect the background, but you can use a special tile which will look like its lit by a lamp in the middle. How this would work for sprites moving into the lamp range IDK, but might save you significant draw time for the background tiles at least.

The intensity variable was for the max(cos(alpha),0) from Lambert's cosine law. You can easily get some value for that variable from the current time of the day - basically anything between 0 and 1. 1 let's say for noon and 0.1 for night. And you can still change the color of the light this way. Basically:


alpha = getLightRaysAngle( timeOfDay );
litColor = material.color * light.color * max( cos(alpha), 0 );
//this way you have control over the diffuse properties of the material, the light color and the time of the day

The intensity variable was for the max(cos(alpha),0) from Lambert's cosine law. You can easily get some value for that variable from the current time of the day - basically anything between 0 and 1. 1 let's say for noon and 0.1 for night. And you can still change the color of the light this way. Basically:


alpha = getLightRaysAngle( timeOfDay );
litColor = material.color * light.color * max( cos(alpha), 0 );
//this way you have control over the diffuse properties of the material, the light color and the time of the day

Ok, I wasn't sure what is possible in a 2D solution. I am more used to 3D Engines.

And of course, you are totally right, you need to define a light intensity per time of day (or better, define some values on an intensity "curve" you lerp between to get a smooth intensity change, or use some mathematical function to calculate the value... you can do the same for the color). I just wanted to point out that actually intensity in real life will vary more than color, and make a point why change in color is important.

If you really want to, you could give each of your days a small chance to be an "overcast day", in which case it will follow a different intensity / color curve than a "sunny day".... you could even change between the curves (clouds building up and disappearing again) for some additional eye candy.

I have a variable Ambient which decreases or increases determined by the current time and multiply the r, b, and g variables by that.But lightbulb has the right Idea I think

I use a tile engine to build my map but I don't want to see the tiles. What do you mean in your last sentence by using it as a mask?

You wouldn't see the tiles, they just need to be made properly.

It can be a falloff of more than one tile, but you need several unique tiles to accomplish it.

With this method, It's best to use an alternate tile set for day and night. It looks so much better than just darkening your tiles, since you can make the right things glow. It's not like they take much memory anymore, and that gives the artist full control.
You can even do fancy things like making otherwise invisible runes glow in the moonlight, and make certain flowers open only during the day (or only at night), glowing mushrooms, whatever you like. The artist then gets full control over the appearance.

Regarding using a mask: You'd need to use a pixel shader. Use the mask (an image, or could be a second invisible layer of tiles which is drawn to a buffer) to define how the light falls off from the fire, and how the colors change.

Earlier this year, I was playing around with RGBA values to give the sort of day / night cycle effect that you're trying to do. Ultimately, I abandoned the technique between issues i had and not being so sure what it added to gameplay.

If you use a circle that is filled with a gradient where the center is the most white and if you play with different types of blending using multiple layers, you can get some ok results. To get it just right, you need the right combination of blending operations (I forget precisely what I did) otherwise the light sources can add to each other which isn't really what you want. I had a few frames of circles like this that were filled with gradients using different falloffs and randomly switched between each frame to get a campfire flicker effect that I liked.

Some drawbacks:
- The technique is great for lighting the ground but not quite right for things standing on the ground as there were no shadows being cast by the light source. I think this article on 2d shadow mapping might have an idea for dealing with that but I never got into it because of the hardware limitations I had.
- The hardware limitation was something that came up when trying to do blending using multiple layers. It probably could've been cleared up with an updated driver but that sort of thing was locked down on the laptop I was using.
- If I was ever going to have a really wide field of light, I can't imagine that this technique would be at all practical.
- Though I never got far into using this technique, I figured that I'm likely going to be limited to having a set number of sizes of light fields. There'd be too many different textures otherwise taking up too much memory.
- I took a stab at manually drawing a gradient circle every frame but it's quite a slow technique to use. It might be ok if you don't mind the light's falloff being less than smooth. Or maybe there's something that can be done with shaders to improve performance (I know nothing about them).

There's probably much better ways to go about doing this with multiple tilesets or shaders. And it will probably never be the most ideal setup because you're working with 2d sprites. But I found it to be a bit of a learning experience and it was pretty cool to play with for awhile. Had the hardware issue not been a concern I'd probably wouldn't have abandoned what I had.

This topic is closed to new replies.

Advertisement