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:
Type S4_Vector3
X as float
Y as float
Z as float
EndType
Type S4_VirtualLightType
pos as S4_Vector3
color as S4_Vector3
range as float
workingRange as float
lightID as integer
style as integer
EndType
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...
function updateVirtualLights(pX#, pY#, pZ#)
local i
local tHit as float
for i = 0 to get array size(S4_VirtualLights()) - 1
S4_VirtualLights(i).workingRange = S4_VirtualLights(i).range
tHit = SC_rayCast(0,S4_VirtualLights(i).pos.X, S4_VirtualLights(i).pos.Y,S4_VirtualLights(i).pos.Z, pX#, pY#, pZ#,0)
if tHit > 0
local tDist#
tDist# = SC_getCollisionDistance()
if tDist# < S4_VirtualLights(i).workingRange
S4_VirtualLights(i).workingRange = tDist#
endif
endif
l3d set virtual light range S4_VirtualLights(i).lightID, S4_VirtualLights(i).workingRange
next i
endfunction
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.