best way to shadowmap a terrain with objects

Blitz3D Forums/Blitz3D Programming/best way to shadowmap a terrain with objects

stayne(Posted 2006) [#1]
I have a blitz terrain with mulitiple objects (trees, architecture, etc). My terrain is already shadowmapped so I just need the objects shadowmapped to the terrain. At the moment I'm using the old copy/rotate/snapshot method that shadowmaps everything during game launch and then I run swift's old texture blur routine.

Anyone have a better method for this?


Danny(Posted 2006) [#2]
I have a similar problem although I'm using vertex lighting on static scene elements in stead of shadowmaps, but the problem is the same - if you got a brightly lit object lying in a dark corner, that will look rubbish.

I haven't tested this (but should work I think) is to use EntityColor() on the dynamic objects. Coloring it black will make it black (ie max darkness) and coloring it white will show it in full brightness. You then have to manually do a raytrace (linepick) to the light sources to determin the exact amount of light (in the range from black to white) the dynamic objects should get. This will 'darken' en 'lighten' them in real time.

The tricky side is that this will require a linepick (expensive function) and probably a distance check as well (meaning you need a SQR = also expensive function) in order to define the fall off for each light. So a routine that handles this must be load-balanced in order not to leach too many milliseconds per frame or it will clog up your performance...

In my case I'm using ODE physics on my dynamic objects, so I can check if they are 'moving' or not. And so, if they are moving they will get 'lit' by that routine. If they are not moving (just lying around somewhere) they are skipped and assumed they have been previously lit properly...

hope this helps,
Danny.


Danny(Posted 2006) [#3]
Not totally sure if this is of any help to you, but here's some fuctions from my own (not completely finished, but this works) lighting routines... You can't run this code (without the 57 other include files :) but the code in the LIGHT_GetLightAtPosition function might help you out or give you an idea?! It was originally written for vertex lighting (and is still used for it), but it basically calculates the amount of light a certain xyz point should receive - you can apply the resulting RGB value to a vertex or EntityColor as you wish...


Global LIGHT_VALUE[2]					; RGB storage container for Vertex Lighting routines

Const LIGHT_RET_BUSY	= 0				; lighting routine has NOT FINISHED lighting the entire entity YET.
Const LIGHT_RET_DONE	= 1				; lighting routine HAS FINISHED lighting the entity, and ready for the next one.

;Light shapes
Const LIGHT_SHAPE_DIRECTIONAL	= 1
Const LIGHT_SHAPE_POINTLIGHT	= 2
Const LIGHT_SHAPE_SPOTLIGHT		= 3
Const LIGHT_SHAPE_LINEAR		= 4		; Note: VERTEX light only!
Const LIGHT_SHAPE_AREA			= 5		; Note: VERTEX light only!
Const LIGHT_SHAPE_ENTITY		= 6		; Note: VERTEX light only!

;Light types
Const LIGHT_TYPE_VERTEX			= 0		; pre-calculated vertex light
Const LIGHT_TYPE_DX7			= 1		; live DirectX7 light (note: max 7 or 8!)


Type node_light
	
	Field entity.node_entity			; handle back to entity (to quickly parse through lights!)
	
	Field lightShape					; light type (0=ambient, 1=direction, 2=point, 3=spot)
	Field lightType						; see LIGHT_TYPE_ consts
	
	Field red, green, blue				; light color (seriously!)
	Field intensity#					; value between typically between -1.0 and 1.0 (-1 = negative light)
	Field doFallOff						; toggle
	Field FallOffNear#,FallOffFar#		; intensity falloff (all light types)
	Field innerAngle#, outerAngle#		; for spotlights
	
	Field ShadowCaster					; true is this lamp casts shadows
	Field shbrightness#					; shadow brightness (0=black, 1=full shadow color)
	Field shRed, ShGreen, shBlue		; shadow color
	
	Field prjMapFilename$			;*	; RESERVED BUT NOT USED YET! - filename of projection map/texture
	
	;live entity handles
	Field prjMapHandle					; IMAGE handle to projection map
	Field light							; blitz entity handle
	
End Type

Function LIGHT_RenderEntityColor( ent.node_entity )
	
;| Lights the entity by setting it's entity color to make it dark or full bright.
;|
;| Used on DYNAMIC entities. 
	
	;Set shading FX on entity (for Entity Coloring)
	EntityFX ent\model\mesh, 1+ent\model\refModel\Fx 
	
	;prevent picking itself
	ENT_setPickMode ent, 0, False
	
	;calc light
	LIGHT_GetLightAtPosition ent, EntityX#(ent\master,1), EntityY#(ent\master,1), EntityZ#(ent\master,1)
	
	;set entity color
	EntityColor ent\model\mesh, LIGHT_VALUE[0],LIGHT_VALUE[1],LIGHT_VALUE[2]
	
	;restore pickmode
	ENT_setPickMode ent, 2, True
	
	Return LIGHT_RET_DONE
	
End Function

Function LIGHT_GetLightAtPosition( ent.node_entity, vx#,vy#,vz# )
	
;| NOTE: Assumes the entity has been tested to have a MODEL NODE!
;| NOTE: Uses the LIGHT_VALUE[3] global array for returning final RGB values for given coordinates
	
	;reset vertex color
	LIGHT_VALUE[0] = 0 ;Red channel
	LIGHT_VALUE[1] = 0 ;Green channel
	LIGHT_VALUE[2] = 0 ;Blue channel
	
	;check if entity receives shadow
	doShadow = ent\model\refmodel\ShadowReceive
	
	;now parse EVERY LIGHT
	For light.node_light = Each node_light
		If (light\entity\enabled) And (light\lightType = LIGHT_TYPE_VERTEX) Then
			
			;get light data
			lx# = EntityX#(light\light,1)
			ly# = EntityY#(light\light,1)
			lz# = EntityZ#(light\light,1)
			
			lR=0 : lG=0 : lB=0
			
			;act pending shape of vertex light
			Select light\lightShape
				
				Case LIGHT_SHAPE_POINTLIGHT
					
					DoFade = False		; fade between COLOR and SHADOW colors within Fallof range!
					
					;get lamp-vertex vector
					dx# = vx-lx
					dy# = vy-ly
					dz# = vz-lz
					
					;check for FALLOFF
					If light\doFallOff Then
						
						;get distance
						dist# = Sqr(dx*dx + dy*dy + dz*dz)
						
						;check range
						If dist# <= light\falloffNear# Then
							mult# = 1.0
						ElseIf dist# <= light\falloffFar#
							;calc falloff
							mult# = 1.0-(dist#-light\falloffNear#) / (light\fallofffar#-light\falloffNear#)
							doFade = True
						Else
							;out of range
							mult = 0
						EndIf
					Else
						;no fallof, so always color shadow (if any detected next)
						mult# = 1.0
					EndIf
					
					;check for shadowcasting
					If doShadow Then
						If (light\shadowCaster=True) And (mult > 0) Then
							;ray
							pickMesh = LinePick(lx#,ly#,lz#, dx#,dy#,dz#)
							If pickMesh <> 0 Then
								;RAY hit Something - get distance between vertex & picked point
								pvx# = PickedX#()-vx#
								pvy# = PickedY#()-vy#
								pvz# = PickedZ#()-vz#
								pdist# = Sqr( pvx*pvx + pvy*pvy + pvz*pvz )
								;when ray stopped SHORT, it must be blocked: SHADOW
								If pdist# > 0.01 Then
									mult# = mult# * light\shBrightness#
									doFade = True ; COLOR SHADOW!
								EndIf
							Else
								;Ray Stopped short or overshot, but didn't hit anything!
								;do nothing to keep current mult!
							EndIf
						EndIf
					EndIf
					
					If doFade Then
						;Mix between light & shadow color
						LR = Interpolate_Linear1D((light\red   * light\intensity#), light\shRed   , 1-mult#)
						LG = Interpolate_Linear1D((light\green * light\intensity#), light\shGreen , 1-mult#)
						LB = Interpolate_Linear1D((light\blue  * light\intensity#), light\shBlue  , 1-mult#)
					Else
						;Mix between light & shadow color
						LR = Interpolate_Linear1D((light\red   * light\intensity#), light\shRed * mult#   , 1-mult#)
						LG = Interpolate_Linear1D((light\green * light\intensity#), light\shGreen * mult#, 1-mult#)
						LB = Interpolate_Linear1D((light\blue  * light\intensity#), light\shBlue * mult# , 1-mult#)
					EndIf
					
				Default
					;unsupported / unkown light shape
					
			End Select
			
			;ADD LIGHT result to VERTEX color
			LIGHT_VALUE[0] = LIGHT_VALUE[0] + lR
			LIGHT_VALUE[1] = LIGHT_VALUE[1] + lG
			LIGHT_VALUE[2] = LIGHT_VALUE[2] + lB
			
		EndIf
	Next
	
	;check the GLOBAL LIGHT_VALUE[RGB] for results!
	;          ------
	
End Function

Function Interpolate_Linear1D#( A#, B#, tween# )
	
	Return ((1.0-tween#) * A#) + (tween# * B#)
	
End Function


Danny