Code archives/3D Graphics - Effects/Unique Hardware-Processed Lighting Environments per entity
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| Controls: Right Mouse(with movement) makes the cam rotate around the entity Middle Mouse Resets the camera so it's behide the mesh. Normal Mouse Rotation steers the mesh around the environment Mouse Wheel moves the camera away or towards the entity. M shows light markers N shows Active Lights Standard WASD movement Num 4 and 6 rotates lights Num 5 stops them and turns on static mode. Update: Now demoing a better lighting options. This should be saficient for getting how you'll make a lighting engine. This is still testing code and i'll make a much cleaner system in the future. Still to add is fade in, fade out, light types. I get about 141fps on my machine. Update: To better demo the technique, i modded the code a bit to show how it works with many objects on the screen and to better prove how the lighting will work. Now with 100 objects all gettin their unqiue hardware processed lighting. Basicly, in this demo, 42 "lights" are created. I create a speical types called Objects and MavLights( maverick 2.0 is the name of my engine). Objects have a max value of 8 lights to work on it at once. MaxLights is a variable tho and can be set from 0 to 8. Then with that, the nearest number of lights will be turned on and then the object is to be rendered. It's important to note a few things: Though the light markers in the demo aren't, everything else has a default of hidden. The first renderworld doesn't show anything at all, instead, places everything into the Z buffer for later rendering. It's IMPORTANT to change the camera's clsmode to 0,0 after the first renderworld. The light searching system works pretty well, but i want to make some bigger improvements on it. In fact, this section of code probably won't be used in the engine at all. Because i'm gion to have something called LightPackages. That really help countdown pointless checks and controls a few other properties. If u plan to make a game using this technique. It's important to consider that if u want directional light and such like that. U'll have to make sure to create those properties in your lighting system. Also consider what lights u always want to be on. Directional light should probably always be one of your active lights. I just threw this together. In a few months, u should see more from my engine. For now, i think this techinque is important enough to share. Any comments are welcome. To see the true speed of the system, make sure no markers are on. | |||||
Graphics3D 800, 600,32, 2
SetBuffer BackBuffer()
HidePointer
Global Cam = CreateCamera()
Global ShowActiveLights
SeedRnd MilliSecs()
MoveMouse GraphicsWidth()/2, GraphicsHeight()/2
FlushMouse()
Type MavObject
Field Pivot
Field Mesh ; What's important to hidden
Field X#
Field Y#
Field Z#
Field ObjectType
Field MaxLights; How many lights can act on it
Field AmbR; What just a quick option for custom ambient light
Field AmbG
Field AmbB
End Type
Type MavLight
Field Pivot ; Something i might end up using later
Field Mesh ; Something I might end up using later
Field X#,Y#,Z#; Placement
Field R, G, B ; Color Values
Field LightRange# ; Sets the Range for the light
Field TriggerRange# ; Sets the Trigger Range, Used to see if it's even worth goin through the check. this is to help take up some processes
Field LightType; for later use, used for what type of light it is.
Field AngleIn# ; Used for SpotLights, later use
Field AngleOut#; Used for SpotLights, later use
Field Static;
Field Testing
End Type
Dim LC(8) ; Light Checkers( MavLight Handles) . basicly, the lights that will end up being used for the lighting system
Dim Dis#(8) ; Parallel with LC, it saves the distance of the light
Dim DyLC(8)
Dim DyDis#(8)
Dim TempCube(8); if light markers are on
Repeat
Locate 0,0
Cls
Flip 0
NumOfLights = Input("NumberOfLights(0 to 8) activiated: " )
Until NumOfLights > -1 And NumOfLights < 9
ST = CreateTexture(16,16, 4)
SetBuffer TextureBuffer(ST)
Color 0,0,0
Rect 0,0,16,16
Color 255,255,255
Oval 0, 0,16,16
SetBuffer BackBuffer()
Gray = 32
Mesh = CreateSphere(8)
ScaleEntity Mesh, 2.5, 2.5, 2.5
HideEntity Mesh
Ship.MavObject = New MavObject
Ship\Pivot = CreatePivot()
Ship\Mesh = Mesh
SHip\ObjectType = 1
ship\MaxLights = NumOfLights
Ship\AmbR = Gray
ship\AmbG = Gray
Ship\AmbB = Gray
;Not important for the techinque
;{
CamPointPivot = CreatePivot()
EntityParent Ship\Mesh, Ship\Pivot
EntityParent CamPointPivot, Ship\Pivot
EntityParent Cam, CamPOintPivot
MoveEntity Cam, 0, 0, -50
PositionEntity Ship\Pivot, 0,0, 0
CameraRange Cam, 0.01, 5000
;}
; This creates the lights, then hiddens them. I figure it'll be alil after than creating and destroying lights all the time.
Dim Light(8)
For I = 0 To 8
Light(I) = CreateLight(2)
HideEntity Light(I)
Next
ShowActiveLights = 1
Sign = 1
For X = -5 To 4
For Z = 0 To 9
ObjectCount = ObjectCount + 1
NO.MavObject = New mavobject ; New Object
NO\Pivot = CreatePivot()
NO\Mesh = CopyEntity(Mesh)
HideEntity No\Mesh
NO\MaxLights = NumOfLights
NO\AmbR = Gray
NO\AmbG =Gray
NO\AmbB = Gray
PositionEntity NO\Mesh, X * 45, 0, Z * 45
No\X = EntityX(No\Mesh)
No\Y = EntityY(no\mesh)
No\Z = EntityZ(no\mesh)
Next
Next
; Light Creation and Placement
RotationPivot = CreatePivot()
PositionEntity RotationPivot, 0, 0, 3 * 75
LightMesh = CreateSprite()
HideEntity LightMesh
EntityTexture LightMesh, ST
GLightRange = 45
GTriggerRange = 150
For X = -3 To 3 Step 1
For Z =0 To 5
count = count + 1
L.MavLight = New MavLight
L\R = Rand(255 * Sign)
L\B = Rand(255 * Sign)
L\G = Rand(255 * Sign)
L\LightRange = GLightRange
L\TriggerRange = GTriggerRange
L\X = X * (75)
L\Y = 7 ;Rand(5, 10)
L\Z = Z * (75)
markCube = CopyEntity(LightMesh)
HideEntity MarkCube
PositionEntity MarkCube, L\X, L\Y, L\Z
ScaleEntity MarkCube, .5, .5, .5
EntityColor MarkCube, Abs(L\R), Abs(L\G),Abs( L\B)
EntityFX MarkCube, 1
HideEntity markcube
L\Mesh = MarkCube
L\Pivot = L\Mesh
;PositionEntity L\Pivot, L\X, L\Y, L\Z
EntityParent L\Pivot, RotationPivot
Next
Next
LightStatic = 1
MoSpd# = 1.5
MeshSpd# = 1
Show_FPS_Counter=1
While KeyHit(1) < 1
;MUST OCCUR
;Camera Refreshes it's Z buffer( color buffer is optional )
CameraClsMode Cam, 1,1
RenderWorld(); This renders NOTHING, but puts things in the Z buffer, important for when u render More than one Object.
;Must Occur, make sure that the color and z buffer doesn't refresh one bit
CameraClsMode Cam, 0, 0
If CreateMarkers
RenderLightPlaceHolders()
EndIf
LightObjects(); The lighting rountie
;Mouse wheel allows for a up close look at the action
MouseZSpeed = MouseZSpeed()
MoveEntity Cam, 0, 0, MouseZSpeed * 5
MoveEntity Ship\Pivot, (KeyDown(32) - KeyDown(30))*MeshSpd, (KeyDown(57) - KeyDown(29)) * MeshSpd, (KeyDown(17) - KeyDown(31)) * MeshSpd
If MouseDown(2) ;Mouse Button 2 allows for All angle camera movement
TurnEntity CamPointPivot, -MouseYSpeed() * MoSpd, -MouseXSpeed() * MoSpd, 0
RotateEntity CamPointPivot, EntityPitch(CamPointPivot), EntityYaw(CamPointPivot), 0
Else
TurnEntity Ship\Pivot,0, -MouseXSpeed() * MoSpd, 0
EndIf
If MouseDown(3) ; Somewhat recenters the camera
RotateEntity CamPointPivot, 25, 0,0
EndIf
TurnEntity RotationPivot, 0, rotationspeed/100.0, 0
If KeyDown(76)
RotationSpeed = 0
LightStatic = 1
static(LightStatic)
EndIf
RotationTest = (KeyDown(75) - KeyDown(77))
If RotationTest <> 0
Rotationspeed = rotationspeed + RotationTest
If LightStatic = 1 Then
LightStatic = 0
Static(0)
EndIf
EndIf
;recenters mouse
MoveMouse GraphicsWidth()/2, GraphicsHeight()/2
NewLightRange# = (KeyDown(205) - KeyDown(203))
If newLightRange <> 0 Then
GLightRange = GLightRange + NewLightRange
AddLightRangeAll(NewLightRange)
EndIf
NewTriggerRange# = (KeyDown(200) - KeyDown(208))
If NewTriggerRange <> 0 Then
GTriggerRange = GTriggerRange + NewTriggerRange
AddTriggerRangeAll(NewTriggerRange)
EndIf
If KeyHit(50) Then
CreateMarkers = Not createMarkers
EndIf
If KeyHit(49) Then
ShowActiveLights = Not ShowActiveLights
EndIf
;Cheap instaneous FPS rate
If Show_FPS_Counter = True Then
EndingFPS = MilliSecs()
MilliDif% = EndingFPS - StartingFPS
If MilliDif < 1 Then
MilliDif = 1
EndIf
FPS_Count = 1000/MilliDif
Text 0,0, "FPS: " + FPS_Count
EndIf
StartingFPS = MilliSecs()
If (MilliSecs() - MilliLast) > 1000
AverFPS = FPSCount
MilliLast = MilliSecs()
FPSCount = 0
Else
FPSCount = FPSCount + 1
EndIf
Text 0, 20, "Object Count: " + ObjectCount
Text 0, 10, "Lights: " + count
Text 0, 40, "General Light Range: " + GLightRange
Text 0, 50, "General Trigger Range: " + GTriggerRange
Text 0, 60, "Rotation Speed: " + RotationSpeed
Text 0, 70, "Aver FPS: " + AverFPS
For I = 0 To ( NumOfLights -1 )
Text 0, I * 10 + 80, "Light " + DyLC(I) + " Dis: " + DyDis(I)
Next
Flip False
Wend
ShowPointer
End
Function LightObjects()
;For every mesh u put in MavObjects
For Obj.MavObject = Each MavObject
;Of course, this is important
ShowEntity Obj\Mesh
;for now, i just slapped this on the mesh
AmbientLight Obj\AmbR, obj\AmbG , obj\AmbB
;Dims all
Dim LC(obj\maxlights)
;A cheap lil way to make sure it grabs some near by lights.
For L.MavLight = Each MavLight
ActiveShown = 0
NewDis = EntityDistance(Obj\Mesh, L\Pivot)
If NewDis < (L\TriggerRange)
If Not L\Static
TFormPoint 0,0,0, L\Pivot, 0
L\X = TFormedX()
L\Y = TFormedY()
L\Z = TFormedZ()
EndIf
;This system here see how the NewDistance Compares with the current once.
;The system is built on a stack idea.
;Example:
;ArrayNumber - Handle - Distance
; 0-1-30
; 1-2-40
; 2-26-50
;If NewDis = 35 and MavLight Handle is 5, this basicly happens
; 0-1-30
; 1-5-35
; 2-2-40
;The 26-50 gets pushed upward. The idea is the closest light is 0 and the farthest is Obj\MaxLights-1
For X = 0 To Obj\MaxLights - 1
If LC(X) = 0 Then
DIS(X) = NewDis
LC(X) = Handle(L)
Exit
Else
If Dis(X) >= NewDis And LC(X) <> Handle(L)
;The stack push system
For II = Obj\maxLights - 2 To X Step -1
LC(II + 1 ) = LC(II )
Dis(II + 1) = Dis(II)
Next
Dis(X) = NewDis
LC(X) = Handle(L)
Exit
EndIf
EndIf
Next
EndIf
Next
For I = 0 To Obj\MaxLights -1
CurMavLight.MavLight = Object.MavLight( LC( I ) )
If CurMavLight <> Null
; If U want the current lights to have temp makers
LightCounter = LightCounter + 1
If ShowActiveLights
If Obj\ObjectType Then
ActiveShown = 1
TempCube(i) = CreateCube()
EntityColor TempCube(i), CurMavLight\R, CurMavLight\G, CurMavLight\B
PositionEntity TempCube(i), CurMavLight\X, CurMavLight\Y, CurMavLight\Z
EntityFX TempCube(i), 1
;ScaleEntity TempCube(i), 1.5, 1.5, 1.5
EndIf
EndIf
;Where all the light placement happens
PositionEntity Light(I), CurMavLight\X, CurMavLight\Y, CurMavLight\Z
LightColor Light(I), CurMavLight\R, CurMavLight\G, CurMavLight\B
LightRange Light(I), CurMavLight\LightRange
ShowEntity Light(I)
EndIf
Next
RenderWorld()
;resets everything
If ActiveShown
For I = 0 To LightCounter -1
FreeEntity TempCube(i)
Next
EndIf
If Obj\ObjectType = 1
For I = 0 To Obj\MaxLights - 1
DyLC(I) = LC(I)
DyDis(I) = Dis(I)
Next
EndIf
For i = 0 To Obj\MaxLights
HideEntity Light(I)
Next
;Hides the Entity
HideEntity Obj\Mesh
Next
End Function
Function RenderLightPlaceHolders()
For CurLight.MavLight = Each MavLight
ShowEntity CurLight\Mesh
RenderWorld()
HideEntity CurLight\Mesh
Next
End Function
Function AddLightRangeALL(AddThis#)
For L.MavLight = Each MavLight
L\LightRange = L\LightRange + AddThis
Next
End Function
Function AddTriggerRangeALL(AddThis#)
For L.MavLight = Each MavLight
L\TriggerRange = L\TriggerRange + AddThis
Next
End Function
Function Static(value)
For L.MavLight = Each MavLight
L\Static = value
If Value = 0
L\X = EntityX(L\Pivot)
L\Y = EntityY(L\Pivot)
L\Z = EntityZ(L\Pivot)
EndIf
Next
End Function |
Comments
| ||
| This is the correct way to do lighting for moving characters, vehicles, etc. |
| ||
| Thanks. After looking at games like Half Life 2 and unreal. I figured they must be using a system similar to this. Also, thanks for your help with the Z buffer Halo. |
| ||
| Mmm. I thought this was a bit naff at first - then, instead of 8 active lights, I just used 1 and now I see the effect. Best to start with 1 and increase the number to see the effect. I like this - in fact, excellent stuff. |
Code Archives Forum