How do hardware lights work?

Blitz3D Forums/Blitz3D Programming/How do hardware lights work?

sswift(Posted 2003) [#1]
I know you can't light a level using hardware lights because you only get 8 of them, but it just occured to me that one could light a level and then have hardware lights in it for the entities. That doesn't solve the problem of having dynamic lights in your level, but it's a start.

Anyhow, what I was thinking is if I have like a hundred Blitz lights in my level, then EACH object will be lit by the closest 8 lights to that object... Is that correct?

If so then hardware lights are more useful than I was thinking they were for a long time. I mean they're still no good for lighting your level if you have a lot of bullets that cast light, but 8 lights is more than enough for making said bullets cast light on the individual entities in a level if in fact the 8 closest lights to an entity are used.


Bouncer(Posted 2003) [#2]
I thought you couldn't do more than eight lights with blitz... but it's cool if it is like you suggest.


Bot Builder(Posted 2003) [#3]
Ah yes. I remember people did a limited version of this. They wanted maplet lights to affect a charachter, so they made a list of light positions, and made the nearest 3 lights affect the player.

I don't think that's how blitz lights work.Though you can do somthing like it.

It's possible you might be able to create a whole bunch of lights all over your level, and simply showeentity the ones you need. As far as I know, there's no way to use dx lights on a speciphic object. Yet simply rendering the dx lights that are closest should be pretty effective, as the surfaces they affect are the ones your most likely to see. Though their might be "light popup" problems, whereit suddenly switches. Maybe maintain 5 lights at once, and use three more for transition lights. IE fade in the new lights as you fade the old out.

You might even try creating whole light priority system. priority would be greater for visible lights, closer lights, more intense lights, more important lights, etc.


Mustang(Posted 2003) [#4]
Cubemaps would be much better and faster solution for lighting entities on a (lightmapped) level... I hope that we get those and not just cubrmapped reflections when the new Blitz3D update arrives.


Jeremy Alessi(Posted 2003) [#5]
I created a light swapping routine for and interior and there is some light pop up but it's not terrible in the environment I was dealing with. What I don't get is why can't you use the lights for bullets or whatever? They may not look great but it would still have the same affect as other games.


sswift(Posted 2003) [#6]
"What I don't get is why can't you use the lights for bullets or whatever? They may not look great but it would still have the same affect as other games."

My tank game has a LOT of bullets. One of my bullets is the burst shot where you fire one bullet, and it explodes into 8 more after a couple seconds. That right there would nearly exceed the number of hardware lights available. Now imagine there's 4 people firing bullets around which can each spawn three, five, or even eight bullets.

And on top of that, I have powerups that I would like to cast light when they spawn.

So, using hardware lights for bullets and firing in my game just isn't realistic. It's not like a first person game where you can only see a few guys on the screen at once.


"Cubemaps would be much better and faster solution for lighting entities on a (lightmapped) level..."

And how do you figure that? Cubemaps require you to render six views of the current scene. Any object that's moving would need to be constantly updated.

There's no way that's faster than hardware lights.

The only thing it would be acceptable to use it for is outdoors. Then you could render a single cubemap of the light cast from the sun and refelcted from the ground and sky, blur it a lot, and use it so long as your character is standing on ground of a particular color.


sswift(Posted 2003) [#7]
"As far as I know, there's no way to use dx lights on a speciphic object."

That's not what I meant.

I meant the 3D card, or Direct3D, would choose the 8 nearest lights, and use them.

Well I guess there's a way to test it.


sswift(Posted 2003) [#8]
Okay I just tested using mark's trong demo. I made 50 lights, each a different color with little spheres so I could see where the lights were.

It looks like only the first 8 lights which are visible are acutally used to light anything in the world. The other lights cast no light at all no matter how far I am from the other lights.


Mustang(Posted 2003) [#9]
"Cubemaps would be much better and faster solution for lighting entities on a (lightmapped) level..."

And how do you figure that? Cubemaps require you to render six views of the current scene. Any object that's moving would need to be constantly updated.

There's no way that's faster than hardware lights.

The only thing it would be acceptable to use it for is outdoors. Then you could render a single cubemap of the light cast from the sun and refelcted from the ground and sky, blur it a lot, and use it so long as your character is standing on ground of a particular color.


Sswift,

Oop, no, I didn't meant that cube(s) would be better for "bullet lights"... just look/function better generally speaking. What I tried to say was that they are good for describing complex lighting setup with one simple cube - and that's why they are better/faster.

With complex I mean same kind of setup you described above. But I think that it would work well (good enough) with indoor level geometry too, although it would be incorrect in the far ends of the "room" too. Until I can test that, I don't know.


IPete2(Posted 2003) [#10]
Okay,

I don't know if this helps, but I am working a team currently who do a render pass for each light (in C++).

Now maybe with 8 lights you can get more out of them by doing multiple rendering, is there anyway of adding to a render pass?

Perhaps in Blitz this is not quite possible, just a thought.

IPete2.


Miracle(Posted 2003) [#11]
Note that you can fake lights any number of ways. The easiest is to make glowing things cast a big fuzzy "bright shadow." And there's always the fake vertex lighting stuff.

The 8 HW lights is a limitation of the graphics card, by the way, not Blitz or DX7. Some older cards can only do 4 or even 2.


sswift(Posted 2003) [#12]
Oh sure I could do multiple passes to render lights, but multiple passes aren't free.

Hm... My levels don't have too many vertices... maybe I could get away with vertex lighting manually. Just take every light in the level, calculate their distance from a vertex add them all together and then set each vertice's color once per render loop. Might be able to get away with it. My levels have less than 10K polys...

Hm.....


BlitzSupport(Posted 2003) [#13]
See if EdzUp's code is any use for your purposes...

http://www.blitzbasic.com/codearcs/codearcs.php?code=509


FlameDuck(Posted 2003) [#14]
Oh sure I could do multiple passes to render lights, but multiple passes aren't free.
Neither are multiple hardware lights. I think Miracle's "bright shadow" is probably the best way to do it.

Incidently the "8 lights restriction" is a T&L restriction. Before there was hardware T&L you could do as many as you wanted, but you had to do it all in software. Look up Gouraud Shading on Google for more info. Oh, and doing this manually in Blitz would probably be way too slow to also be practical.


sswift(Posted 2003) [#15]
I know that the 8 lights restriction is a T&L restriction, and what goraud shading is.

And I know that hardware lights aren't free, but they're a hell of a lot more free than multiple render passes.

As for your assetion that it's too slow to do it manually in Blitz, that may be true for a lot of cases, but if you don't have a lot of polygons to light then I think you might be able to get away with it. My shadow system probably is probably way more costly to render than some simple vertex lights.

And I don't know why you mention goraud shading. You don't have to do any goraud shading to do vertex lights. That's all done by the hardware. You just change the vertex colors.


_PJ_(Posted 2003) [#16]
I thought u could use up to 16 and maybe even more 'lights' in Blitz, only it was just some graphics cards that didnt like this?
(If i could find where it was written I'd insert the link)


FlameDuck(Posted 2003) [#17]
And I don't know why you mention goraud shading.
It was in response to "How does hardware lighting work". I figured that since you where asking the question, you wanted to know.
You don't have to do any goraud shading to do vertex lights. That's all done by the hardware.
Duh. Except the hardware can only do 8 lights, so if you want more you *will* have to do any Gouraud Shading. Manually. In software.
And I know that hardware lights aren't free, but they're a hell of a lot more free than multiple render passes.
Probably not. Although I haven't done any tests to confirm it, I see no reason why multiple lights should be "more free" than multiple renders.

What I'm really curious about tho', is since you know all of this already, why are you asking about it?


sswift(Posted 2003) [#18]
"Duh. Except the hardware can only do 8 lights, so if you want more you *will* have to do any Gouraud Shading. Manually. In software."


Uh, Flameduck, you do not have to do goraud shading to do more lights than the 8 supproted in hardware.

All you need to do is calculate the amount of light that hits each vertex and set the vertex colors on the mesh. The hardware does the interpolation.


"Although I haven't done any tests to confirm it, I see no reason why multiple lights should be "more free" than multiple renders."

Because Flameduck, hardware lights are done on the chip, and only need to do a calculation per vertex. Multiple render passes on the other hand require you to draw the scene completely two or more times. That requires a LOT of memory accesses and memory accesses are slow.

If you're getting 60fps with one pass, and you do two, your framerate will drop to 30fps. But if you add 8 hardware lights, you're unlikely to lose more than 5-10fps.


"What I'm really curious about tho', is since you know all of this already, why are you asking about it?"

Obviously you did not read my first post in this thread.

What I was asking was if I have 8 hardware lights, if each entity is lit by the 8 closest ones, or wehther only the first 8 lights you create cast any light at all.

I have since done a test of my own since nobody knew, and unfortunately it looks like only the first 8 you create cast any light.

If it had been the other way then you could stick lights all over the place and you would not have to worry about them cause as an entity moved about it would be lit by the 8 lights closest to it. But as it does not work that way, the best you can do is to manually hide all the lights but the 8 which are closest to the camera.

All this other discussion has been about how to implement lights with a partially software solution.


Shambler(Posted 2003) [#19]
I did a test for lights recently http://www.blitzbasic.com/bbs/posts.php?topic=25124

I've done another test today regarding speed hit for hardware lights and it went something like this.

I created 100 32 segment spheres and placed different numbers of lights in front of them and checked the millisecs for each frame with flip false.

No lights 7 ms
1 light 12ms
2 lights 18ms
3 lights 24ms
4 lights 30ms
5 lights 35ms
6 lights 40ms
7 lights 45ms
8 lights 50ms

quite a performance hit per light and meaning fps from 142fps for no lights to just 20fps with 8 lights on.

Something else I noticed which was quite worrying is that light range makes no difference to the fps =/

I set a light range of 1 for all 8 lights and moved them a huge distance away from the spheres so that no lighting could be seen on them and still got 50ms per frame.

This means my graphics card is not checking the light range to see which geometry it needs to calculate lighting on...something I wasn't expecting to see at all.

Maybe the card is so fast at calculating lighting that they didn't bother with an early out test to see if the lights are in range?


sswift(Posted 2003) [#20]
In that test, with just one light your framerate is cut in half, and with three it's cut in a third. Ouch.

You know though, this test assumes that all polygons in the world are affected by the lights. And you've got 400,000 polygons there.

Could you do a test with all the objects set to fullbright? I'd like to see if haivng objects set to fullbright means the lights cause no performance hit on them.


"I set a light range of 1 for all 8 lights"

A light range of 1 just means that the light STARTS falling off a that distance. It actually carries out quite a long ways from there. If the radius is 80, then the light will fall off completely 5200 units away from the light source. That's where it reaches 0.99 and gets clipped to 0.

I don't know if 3D cards stop having them affect objects even at that great a distance though.



The question is though not wehther hardware lights are slow, but whether dynamic lightmaps are slower.

You could do up to 9 passes to render 8 dynamic lights, with no other lightmaps. 10 passes if you have other lightmaps.

However, multitexturing would probably be possible and cut that down quite a bit. However you need to remember that to do just one dynamic lighting pass you actually need to use two texture units, one for X and Y axis mapping, and one for Z, to create a 3D sphere texture.

So, because most cards only have 4 texture units, you could only really cut that 9 passes in half. So you'd still need to do about 5 passes to render 8 lights plus your textures and maybe your lightmaps.


142fps / 5 = 30fps So that is faster than the 8 hardware lights IF you can do that lighting in just 5 passes.

But I'm not convinced that you CAN combine two dynamic lighting passes into one.

To do a dynamic lighting pass you need a 2d texture in texture channel 0 set to multiply, and a 1d texture in texture channel 1 set to multiply. Texture channel 1 darkens the result after texture channel 0 has been applied, and this creates the 3d texture. You then use ADD blending to add this dynamic light pass on top of the static lightmap pass.

But can you do this twice in one pass? I'm not sure you can with the way texture unit operations work.

But I could be wrong. It's complicated.


Anyhow, it's not cut and dry which is faster in this situation. However, with far fewer polygons in the scene, I think the scales might tip in favor of the hardware lights.


Jeremy Alessi(Posted 2003) [#21]

My tank game has a LOT of bullets. One of my bullets is the burst shot where you fire one bullet, and it explodes into 8 more after a couple seconds. That right there would nearly exceed the number of hardware lights available. Now imagine there's 4 people firing bullets around which can each spawn three, five, or even eight bullets.



Each player should have 1 light for all of their pojectiles and it could rotate around each one every frame or on a timer. This would also give off a twinking effect which you'd probably want anyway.

Then use the other 4 lights for the powerups.


Shambler(Posted 2003) [#22]
FullBright...
Fullbright does mean that the sphere is ignored by the hardware lights.

I get the same fps with no lights as I do with 8 lights and 100 fullbright spheres.


LightRange...
I set a light range of 1 and moved the lights somewhere really far away like PositionEntity hl(n),60000,60000,60000

LightRange should be the point at which the light has no effect and can be ignored.

At least that's what it does in C++/DirectX and the Blitz Docs state...


Description:

Sets the range of a light.
The range of a light is how far it reaches. Everything outside the range of the light will not be affected by it.

The value is very approximate, and should be experimented with for best results.




BackFace Culling...
EntityFX 16 ( Disable backface culling ) has no effect on performance, which tells me the lighting calculation is being done before backface removal, lighting faces that the camera can't see? O.o

Poly Count...
The number of poly in the scene does make a big difference.

With 8 lights on

3968 Tri = 1000 fps
7936 Tri = 1000 fps
15872 Tri = 500 fps

There appears to be a cutoff point, above which hardware lights give a very slight performance hit, this will of course be different on other hardware.


Mustang(Posted 2003) [#23]
LightRange should be the point at which the light has no effect and can be ignored.


that would be logical but it just isn't so... there was talk about in these forums (even Mark commented) but I can't find that post... I think that Sswift also posted the actual formula that is used (he got it from Mark) which clearly shows that LightRange command is NOT like the description would make you believe. ALL lights will affect your meshes, no matter how far they are.

Would be nice to have flags to lights/entities so that you could say that this light affects only this entity, but I don't know if it's possible.


Shambler(Posted 2003) [#24]
From what you say it looks like Blitz is setting the directx light parameter 'Range' to its maximum and that lightrange in blitz is actually setting the directx 'Attenuation' parameters.

This means that lighting has to be calculated for all entities(meshes) regardless on whether they are affected by the light or not.

Although this makes it easier to set up a light it does give us a performance hit when we want a localised hardware light and gives us less control over a lights parameters.

nm, maybe in BMax? ^^


_PJ_(Posted 2003) [#25]
AH- I knew it-


There is a DirectX limit on the number of lights available per scene - this is either 8 or 16 depending on your video card, but you should always assume 8.


So more than 8 lights IS possible (just not good for compatibility)


sswift(Posted 2003) [#26]
"At least that's what it does in C++/DirectX and the Blitz Docs state..."

The Blitz docs are wrong, and Blitz's lights work just like DirectX. I know this for a fact because I researched it thouroughly when developing my shadow system after I noticed that my shadows were not matching up with the falloffs of the hardware lights which were illuminating the world.

Here are the comments in my shadow system on the whole thing about how the lights work. And this is based on information straight from Mark, and the Direct 3D docs, and asking other 3D programers on Flipcode.

; DX7 Lighting equation:
; Attenuation = 1.0 / (C0 + C1*D + C2*D*D)
;
; In Blitz:
; C0,C2 = 0. C1=1
;
; So the revised lighting equation is:
; A = 1.0 / D
;
; With this equation, when D=1, A=1.
;
; Now in Blitz, a light has a radius, which defines where the light BEGINS to fall off.
; At this radius, A will equal 1.
; Inside this radius, A is greater than 1, reaching infinity when D = 0.
; Outside this radius the light falls off exponentially.
;
; So we change the equation to read like so:
; A = R / D
;
; And then all we need to do once we calculate A is multiply the light's color by it, and we get the
; color of our vertex at a distance of D.
;
; It is interesting to note that multiplying the light's color by a factor equal to the radius will
; give us the same results. That means that rather than thinking about radius as a mininium radius at
; which the light is fullbright, you can think about the radius as a brightness mutliplier instead.
;
; However, it is more useful to consider it as the radius inside of which the light is fullbright.


"The value is very approximate, and should be experimented with for best results."


Yeah I'll say it's very approximate. It's off by like 5000 units! :-)



"There appears to be a cutoff point, above which hardware lights give a very slight performance hit"

That drop there was just caused by the fact that 1000fps means each frame takes 1ms, and 500fps means each frame takes 2ms. Not a cuttoff point. Just the fact that your millisecond timer isn't precise enough to see the difference between the first two. The second is probably like 750fps but you cna't have 1.5ms.


sswift(Posted 2003) [#27]
Shambler:

Call this FPS code once per renderworld, and you will see that the FPS is over 1000, and that there is a difference between 1 and 2 lights.

This is much more accurate FPS code than your basic FPS code, because it counts the actual number of frames that happened in a second rather than trying to compute how much time an inidvidual frame took and extrapolating that to the entire second.

Global FPS_Timer
Global FPS_FrameCount
Global FPS_FPS

Function FPS()
	
	FPS_FrameCount = FPS_FrameCount + 1
	
	If MilliSecs() >= FPS_Timer
		
		FPS_FPS        = FPS_FrameCount
		FPS_FrameCount = 0  
		FPS_Timer      = MilliSecs() + 1000
		
	EndIf

	Return FPS_FPS
	
End Function



JoshK(Posted 2003) [#28]
The lights are useless because they don't use an inverse square falloff. Use vertex lighting for dynamic lights.


Shambler(Posted 2003) [#29]
I see , using your FPS code there is no cutoff point as such, just a linear falloff of performance as more poly are added to the scene.

Incidentaly I got 2000fps with 1 light and 1 sphere.

As far as range goes though this is what I remember from my C++ days.

The range parameter in a D3DLight structure had nothing to do with the attenuation formula.

I remember distinctly that setting the range parameter to a low value you could abruptly stop the light affecting vertices.

I remember it because it didn't look too good ^^ having a bright area around the light suddenly plunge into blackness even gouraud shading couldn't make that look nice.

What I believe blitz lights do is set the range parameter to maximum ( square root of 'FLT_MAX' ) so each light is pretty much infinite.

This means that even when the attenuation has got the light intensity down to 0, DirectX is still having to calculate vertex lighting.

The reason why blitz's light range is approximate, its trying to simplify things for the programmer so they don't have to get their head around the attenuation parameters.

Instead they just give it a range value and blitz calculates the attenuation parameters to try and get somewhere near.



@Malice the only card I could find that supported more than 8 lights could handle 32...cost £1500 though =)


sswift(Posted 2003) [#30]
"Instead they just give it a range value and blitz calculates the attenuation parameters to try and get somewhere near."

Nope. That's wrong. What I said is fact. :-)

There's three parameters which control the DX light behavior. Blitz has a certain setting for those. If you change those, you can change the falloff to be linear instead of expoential. That might be why you got a different result. Or, it could be because early versions of Direct3D used a different lighting equation.


Shambler(Posted 2003) [#31]
I think we agree but don't realise it =)

Where you quoted me, 'they' are Blitz programmers, I wasn't talking about what Blitz does behind the scenes.

Like I said, Blitz programmers just give it a range value e.g.

LightRange mylight,500


When you tell Blitz 'I want a light range of 500' Blitz doesn't set the range parameter of the DirectX light to 500 though.

It sets the attenuation parameters you spoke of to 'guesstimate' the correct attenuation so that the light intensity falls off 'roughly' around 500 units.

As you rightly say it is quite a way off.

The thing I am getting at is that because Blitz sets the range parameter of the light to its maximum this is telling DirectX to compute lighting even when the intensity of the light is extremely low.

Let me pull from the DirectX docs the meaning of the range parameter...


If d is greater than the light's range, that is, the Range member of a D3DLIGHT9 structure, Microsoft® Direct3D® makes no further attenuation calculations and applies no effects from the light to the vertex.



This range parameter did the same thing in DX7.

So to come to the point...what was it again? lol

Oh yes, Because blitz sets the range parameter to a very high value DirectX never stops having to calculate vertex lighting.

No matter how far an entity is away from the light, the way Blitz sets up the lighting, DirectX never stops having to light the entities verts and so causing a performance hit.


sswift(Posted 2003) [#32]
"It sets the attenuation parameters you spoke of to 'guesstimate' the correct attenuation so that the light intensity falls off 'roughly' around 500 units."


No, I didn't misunderstand you. You're WRONG. :-)

Blitz does not 'guesstimate' anything.

If you set the range to 500, that is the distance that the light BEGINS to fall off. It's like an "inner radius".

There is no way to set the "outer" radius. Technically the light falls off forever. The only thing that creates an effective "outer" radius to any light in Blitz is the fact that once the value of the light drops below 1, the closest integer RGB is 0,0,0.


"The thing I am getting at is that because Blitz sets the range parameter of the light to its maximum this is telling DirectX to compute lighting even when the intensity of the light is extremely low."


I concede that there may be a range parameter which Blits sets to infinity, or close to it.

However, that doesn't change the fact that you're still confused about the range parameters on the lights. :-)


LT(Posted 2003) [#33]
Here's a possible alternative approach. Instead of using multiple render passes, how about a light-culling mechanism where each object in the scene is rendered by itself with only the lights that are within range. CameraClsMode should be false, false, then set to true, true at the end of each frame.

As a quick test (without lights), I wanted to see what the frame rate hit was for rendering objects individually. I set up fifty spheres and a key that would toggle between rendering all at once or one at a time. The fps changed from 686 to 350 or so. 'Might be worth it to do it that way in some circumstances so I thought I'd pass that info along...


sswift(Posted 2003) [#34]
686fps = 1.45 ms per frame
350fps = 2.85 ms per frame

A difference of about 1.4 milliseconds.

Would you post the code to your demo so we can add stuff to it and try it ourselves?


LT(Posted 2003) [#35]
The test has nothing to do with lights and I literally spent about 15 minutes on it so I hadn't thought it worth posting, but just in case, here it is.

It would be interesting, I suppose, to find out the differences on various graphics cards.


; Test the frame rate difference between rendering
; 50 spheres at once or one at a time.

; The "1" key toggles between them.

Global msecs, test = False
Global fpsIndex, fpsTime, fpsOldMSecs, fpsCount

Type ent
	Field obj
End Type

Graphics3D ( 1024, 768, 32 )

cam = CreateCamera ()
PositionEntity ( cam, 10, 40, -100 )

For i = 1 To 50
	ents.ent = New ent
	ents\obj = CreateSphere ()
	PositionEntity ( ents\obj, Rand ( -100, 100 ), Rand ( 0, 100 ), 0 )
Next

While Not KeyHit ( 1 )

	msecs = MilliSecs ()
	If KeyHit ( 2 ) Then
		If test Then
			test = False
			CameraClsMode ( cam, True, True )
			For e.ent = Each ent
				ShowEntity ( e\obj )
			Next
		Else
			test = True
			CameraClsMode ( cam, False, False )
			For e.ent = Each ent
				HideEntity ( e\obj )
			Next
		End If
	End If

	If test Then
		For e.ent = Each ent
			ShowEntity ( e\obj )
			RenderWorld ()
			HideEntity ( e\obj )
		Next
	Else
		RenderWorld ()
	End If
	Color ( 0, 0, 0 )
	Rect ( 0, 0, 50, 25, True )
	Color ( 255, 255, 255 )
	Text ( 0, 0, fps() )
	Flip ( False )

Wend
EndGraphics
End


Function fps ()
	fpsIndex = fpsIndex + 1
	fpsTime = fpsTime + mSecs - fpsOldMSecs
	If fpsTime => 1000
		fpsCount = fpsIndex
		fpsTime = 0
		fpsIndex = 0
	End If
	fpsOldMSecs = mSecs
	Return fpsCount
End Function




AbbaRue(Posted 2003) [#36]
LT
I get 871 when I first start it.
Then 445 when I hit the 1 key.
You didn't say which is which.
And here is what I own: