Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Static Lightmaps + Dynamic Lights =)

Author
Message
anwserman
15
Years of Service
User Offline
Joined: 20th May 2011
Location: Wisconsin
Posted: 26th Jul 2011 14:09 Edited at: 26th Jul 2011 14:16
Hey everyone!
I came up with a great idea for using both static lightmaps and dynamic lights within a level. I came up with a solution to incorporate both features into one.

Basically, lightmap are great because they're static. They don't move, and thus are good for static objects. They provide excellent detail to a level and are very processor friendly. But they're not for dynamic objects - ones that move around the map. For dynamic objects, you'd either need to use shaders for lighting, DirectX hardware lights, or come up with your own custom vertex-lighting scheme.

For my project, I don't want to use shaders for lighting or shadows - eVolved's shader demos alone bring my PC down to 15 frames per second. I don't feel like programming my own vertex-lighting system, as it probably would suck and not work well at all. Which leads me to DirectX hardware lights.

DirectX hardware lights do the job. However, they don't consider other objects in the map; if a light and object Z are within range of each other, object Z will be illuminated by said light even if a million other objects are in-between it. In addition, you're only limited to 8 lights at one time.



So, using Cartography shop, I placed a couple light entities in my map and rendered them. However, I also parsed these entities into my program and threw them into EXTENDS, so then they become part of the virtual lighting system - allowing you to dynamically swap in and out lights during runtime.

Here's the sample datatypes:


Pos holds position
Color holds color, form of RGB255
Range holds the max distance the light will travel
Style holds an EXTENDS value for blinking the light, etc.
lightID holds the internal index for the light in EXTENDS
workingRange holds the 'working' distance the light will travel

.....

So what do you do?

Each frame, iterate through the list of lights. Reset each value of 'workingRange' to the value of 'Range'. In addition, perform a raycast from the light's position to the position of any dynamic item of your choice.

Now, we need to see if we need to update the value of 'workingRange'. This changes depending on the location of dynamic objects in the map.

~~~If the raycast doesn't return a collision, don't do anything to 'workingCollision', you want to keep it at its original, maximum value.

~~~If there IS a raycast collision, get the distance of the ray. If this distance is less than 'workingCollision', set 'workingCollision' to that distance. This means that there's a solid object between the selected dynamic object and the light, and we don't want it to bleed through if it is active.

After doing all of the raycasts, update each light to their new 'workingRange' value. Viola! Dynamic lights + lightmaps in your app.

Here's some sample code to explain further...


SOME CONSIDERATIONS

As my code is right now, it's highly unoptimized. In it's current state, each dynamic object would get checked against each light (n objects * m lights).... which could easily turn into thousands of raycasts and checks per frame.

So, if you narrowed down whatever lights you have in your map to the current active ones (EXTENDS limits you to a maximum of 7 active lights at once) and only checked them against the dynamic objects, you'd trim off a lot of unnecessary calculations.

74 lights x 20 dynamic objects = 1480 raycasts per frame
7 lights x 20 dynamic objects = 140 raycasts per frame

In addition, a light might have reduced visibility because of another dynamic mesh interfering with it - e.g., NPC. You could have a priority system, checking only the highest priority objects against the lights.

E.G., if a dynamic light would cause bleeding that would affect the looks of the player, reduce the range of the dynamic light. However, if the player raycast DOESN'T collide with the light and something else does, don't reduce the range because it would screw up how the player looks.

(E.g., a pedestrian on another side of a wall that you can't see anyway would be better to have be illuminated incorrectly than having the player not be illuminated at all)..


Also, you need to factor in dynamic objects casting shadows. I don't have this implemented yet, but am looking into it.

I hope this helps someone! I would provide sample code, but there's a million and one ways to lightmap and load data into DarkBasic, but this should help anyone whose looking for a quick and easy solution. Yes, it's not perfect. But good enough for the lone programmer or indie-team looking for a good way to use their limited resources.
monotonic
20
Years of Service
User Offline
Joined: 24th Mar 2006
Location: Nottinghamshire, England
Posted: 26th Jul 2011 14:23
A couple of things to take into account here, say for instance you have a large object such as a tank, that just happens to be between a bumblebee (e.g a small object) and a light that is in range, the bumblebee would block the raycast thus resulting in the tank receiving no light when it should.

Also, Adjusting the range of the light to compensate for objects not receiving light due to it being blocked is a bad idea. What if you have two objects both of equal priority equidistant from the light source. Now one is blocked and one is not, using the method you mentioned above it is possible that the light range will be altered so that it doesn't affect the one object it should.

For optimisation you could check which lights are visible within the screen, if they're not visible or don't affect any visible objects then there is no point checking or updating them.

01100001 01101110 01101111 01110100 01101000 01100101 01110010
01110000 01101111 01101001 01101110 01110100 01101100 01100101 01110011
01110011 01110011 01101001 01100111
Max P
16
Years of Service
User Offline
Joined: 23rd Jan 2010
Location:
Posted: 26th Jul 2011 14:30
Quote: "the bumblebee would block the raycast thus resulting in the tank receiving no light when it should"

For this problem I suggest you fade the light in and out, so when there is a small object in front of the light, the only thing you will notice is the light fading out a little bit. Before the light is faded out the bumblebeel in this case is probally on another position, not blocking the light. So the light will fade back in. The player won't really notice this, but when there is a large object in front of the light the light will fade out to zero range.
monotonic
20
Years of Service
User Offline
Joined: 24th Mar 2006
Location: Nottinghamshire, England
Posted: 26th Jul 2011 14:34
Another option would be to perform a few raycast to different points on the target object which in this case would be the tank. So you could fire a ray to each corner and the centre, or whatever, that way you should minimise the effect, but not eradicate it.

01100001 01101110 01101111 01110100 01101000 01100101 01110010
01110000 01101111 01101001 01101110 01110100 01101100 01100101 01110011
01110011 01110011 01101001 01100111
anwserman
15
Years of Service
User Offline
Joined: 20th May 2011
Location: Wisconsin
Posted: 26th Jul 2011 15:06 Edited at: 26th Jul 2011 15:14
I don't get the bumble-bee and tank analogy. Perhaps I should have stated this clearer in the original post, but you're only raycasting against the static world. =) Also, it comes down to level design - you just can't throw this or any solution into a map and expect amazing results. A polished turd is still a turd.

Worst case scenario - the tank would drop down to the ambient lighting level of the map. Most maps have an ambient level of 64,64,64 or so, so its not like the tank would go completely dark. And even if the butterfly blocks the raycast for a frame, at 60 and even 30 FPS that's still too fast for the eye to notice a difference.

In addition, you also have the entire option - in your own design - to disable objects to be collided with that would be 'negligible'. Yes, that butterfly exists, but having it in there would be pointless for collision detection purposes. The affect it would have on a light (unless it's Mothra) would be negligible.

And anyways, I came up with this and programmed it in the last four hours. Is it perfect? No. But for my purposes, the game I'm programming ideally would be an action/arcade romp where the lights would just be a unnecessary 'nice touch'.

Your own mileage with this varies. It might not work with all projects, I'm not denying that. Search the forums. What exactly are your other options when it comes to doing something like this? Yes, I could spend ages learning how to write shaders or spend months trying to develop a custom lightmapping system. Heck, I could implement a way to do a raycast from each vertex on each mesh to each light. Yeah, that's overkill in my opinion. My time is better off developing something else in my program.

I'm just one person. If I had money and resources, I'd go for more impressive measures. But I don't, and what I made tonight made me happy, so I'm going for it =)
monotonic
20
Years of Service
User Offline
Joined: 24th Mar 2006
Location: Nottinghamshire, England
Posted: 26th Jul 2011 15:35
I'm not trying to rubbish your work buddy, you've done a good job. I'm just trying to offer up suggestions to improve it that's all.

The bumblebee might be a bit too small to include in collisions etc, but it was an example. I've implemented lighting like this in the past and spent a long time trying to get it the best I can, so I'm trying to offer you the results of my time spent in R&D with this.

01100001 01101110 01101111 01110100 01101000 01100101 01110010
01110000 01101111 01101001 01101110 01110100 01101100 01100101 01110011
01110011 01110011 01101001 01100111
TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 26th Jul 2011 15:58
Another problem:



The wall on the right wouldn't recieve light, would it?

TheComet

Max P
16
Years of Service
User Offline
Joined: 23rd Jan 2010
Location:
Posted: 26th Jul 2011 17:35
Quote: "The wall on the right wouldn't recieve light, would it?"

Why not? there is nothing in between the wall and the light.
monotonic
20
Years of Service
User Offline
Joined: 24th Mar 2006
Location: Nottinghamshire, England
Posted: 26th Jul 2011 17:42 Edited at: 26th Jul 2011 17:46
What TheComet is saying is what I pointed out earlier, at least I think so anyway.

If two objects are receiving light and one is closer than the other but is blocked and the other isn't.

i.e.


Where A is the first object, L is the light, X is the blocking obstacle and B the second object.

The light would reduce it's range to meet the the blocking obstacle X so that Object B didn't get any light due to it being blocked by X, which is fine. However, Object A is further away, not blocked and still within the original range of the light meaning it should get lit by L. But because the light's range has reduced to meet X, Object A would wrongly be cut out of the lighting.

01100001 01101110 01101111 01110100 01101000 01100101 01110010
01110000 01101111 01101001 01101110 01110100 01101100 01100101 01110011
01110011 01110011 01101001 01100111
anwserman
15
Years of Service
User Offline
Joined: 20th May 2011
Location: Wisconsin
Posted: 26th Jul 2011 22:04
@Mono, sorry for being defensive. I take pride in some of my solutions

Anyway, reducing light visibility is something that the programmer would have to take into conderation. In your example mono, is object A or object B even visible on the screen? If the person can only see object A, ignore object B when it comes to light calculations.

So, in reality, you could....
Raycast camera to dynamic object, if collision occurs w/ static world, ignore object for lighting purposes (sans the main player model)
Raycast dynamic object to lights

This all could work out, but these are just considerations that would need to be taken in =)
TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 26th Jul 2011 22:59
Whoops, I meant to say "The wall on the left wouldn't receive light" lol And I still haven't mastered the "I" before "E" except after "C" rule...

Anyway, nice job on this, I'll probably implement that in my game when I come around to it

TheComet

anwserman
15
Years of Service
User Offline
Joined: 20th May 2011
Location: Wisconsin
Posted: 27th Jul 2011 00:49 Edited at: 27th Jul 2011 00:55
I just thought about this further, and I think that I found a possible solution with changing and updating a light's range with multiple objects.



Each light would need to store two variables with this datatype, labeled 'minRange' and 'maxRange'. 'minRange' holds information regarding the minimum distance an object needs to be illuminated from a light if there is direct line-of-sight. 'maxRange' holds information regarding the maximum distance a light can hold without affecting objects that don't have a direct line-of-sight with it.







At the start of each frame, reset the varibles to default values.

For MINRANGE, we want to increase the range value to include more objects, if we have direct line-of-sight



For MAXRANGE, we want to decrease the range value, as this is the limiting factor to make sure light doesn't bleed through solid objects.



Now we go through each object and and see if it is influenced by the light. There are three possible outcomes to this:

Raycast between light and current dynamic object, checking for collision against static world.
~~If there's no collision, check distance between light and current dynamic object. If distance is greater than the light's default range, do nothing. This object is not influenced by this light, so we ignore it
~~If there's no collision, and the distance between the light and current dynamic object, update the MINRANGE values.

if distance > MINRANGE.RANGE, minRANGE.RANGE = distance
MINRANGE.COUNT = MINRANGE.COUNT + 1
if MINRANGE.PRIORITY < dynamic object.priority, MINRANGE.PRIORITY = dynamic object.priority

~~If there's is a collision between the light, the dynamic object, and the static level, update the MAXRANGE values.

if raycast.distance < MAXRANGE.RANGE, MAXRANGE.RANGE = raycast.distance
MAXRANGE.COUNT = MINRANGE.COUNT + 1
if MAXRANGE.PRIORITY < dynamic object.priority, MAXRANGE.PRIORITY = dynamic object.priority

Now we need to figure out which setting to update the light's range to
~~~If MINRANGE.COUNT and MAXRANGE.COUNT both equal 0, update light to it's default range
~~~If MAXRANGE.PRIORITY > MINRANGE.PRIORITY, set light range to MAXRANGE.RANGE
~~~If MAXRANGE.PRIORITY < MINRANGE.PRIORITY, set light range to MINRANGE.RANGE
~~~If MAXRANGE.PRIORITY = MINRANGE.PRIORITY, then we need to do a tiebreaker
If MAXRANGE.COUNT > MINRANGE.COUNT, set light range to MAXRANGE.COUNT
if MAXRANGE.COUNT < MINRANGE.COUNT, set light range to MINRANGE.COUNT
if MAXRANGE.COUNT = MINRANGE.COUNT, come up with your own tiebreaker

I have yet to implement this in code, but I think this should work

Login to post a reply

Server time is: 2026-07-11 03:38:47
Your offset time is: 2026-07-11 03:38:47