Code archives/3D Graphics - Effects/Realtime Shadows

This code has been declared by its author to be Public Domain code.

Download source code

Realtime Shadows by fredborg2004
Look at the code, and figure it out! :)

Only works for a single (directional or spot) light!
;
; Realtime Shadow thingy
;
; Created by Mikkel Fredborg
; Use as you please!
;

Type dl_receiver
	Field mesh
	Field surf
	Field orig
End Type

Type dl_light
	Field entity,camera
	Field width,height
	Field backcull
	Field lastx#,lasty#,lastz#
	Field lastpitch#,lastyaw#,lastroll#
End Type

Global dl_brush
Global dl_tex

Function DL_Init()

	ClearTextureFilters
	dl_tex = CreateTexture(512,512,1+16+32+256)
	TextureBlend dl_tex,5

	dl_brush = CreateBrush()
	BrushBlend dl_brush,2
	BrushFX dl_brush,1
	BrushTexture dl_brush,dl_tex	

End Function

Function DL_Free()

	For dlr.dl_receiver = Each dl_receiver
		FreeEntity dlr\mesh
		Delete dlr
	Next

	For dll.dl_light = Each dl_light
		Delete dll
	Next

	If dl_tex	Then FreeTexture dl_tex
	If dl_brush	Then FreeBrush dl_brush

	dl_tex		= 0
	dl_brush	= 0

End Function

Function DL_SetReceiver(mesh)

	dlr.dl_receiver = New dl_receiver
	dlr\mesh = CreateMesh(mesh)
	dlr\surf = CreateSurface(dlr\mesh)
	PaintSurface dlr\surf,dl_brush
	dlr\orig = mesh
	
End Function

Function DL_SetLight(entity,width=256,height=256,backcull=False)

	dll.dl_light = First dl_light

	If dll = Null
		dll.dl_light = New dl_light
	End If
	
	dll\camera	 = CreateCamera(entity)
	CameraProjMode dll\camera,0
	CameraRange dll\camera,1.0,1000.0
	CameraClsColor dll\camera,255,255,255
	CameraViewport dll\camera,0,0,width,height
	CameraZoom dll\camera,0.002 ;<--- This may need changing depending on the scene and light position
	
	dll\entity 	 = entity
	dll\width	 = width
	dll\height	 = height

	dll\backcull = backcull
		
End Function

Function DL_Update()

	dll.dl_light = First dl_light
	If dll = Null Then Return

	; Hide shadow meshes
	For dlr.dl_receiver = Each dl_receiver
		HideEntity dlr\mesh
	Next
	
	; Render shadow
	CameraProjMode dll\camera,2 ;<---- Works with perspective as well, but you need to change the zoom
	RenderWorld
	CopyRect 0,0,dll\width,dll\height,0,0,BackBuffer(),TextureBuffer(dl_tex)

	; Show shadow meshes
	For dlr.dl_receiver = Each dl_receiver
		ShowEntity dlr\mesh
	Next
	
	x# = EntityX(dll\entity,True)
	y# = EntityY(dll\entity,True)
	z# = EntityZ(dll\entity,True)

	pitch# 	= EntityPitch(dll\entity,True)
	yaw# 	= EntityYaw(dll\entity,True)
	roll# 	= EntityRoll(dll\entity,True)
		
	For dlr.dl_receiver = Each dl_receiver

		If dll\backcull
			
			;
			; Remove backfacing triangles
			If x<>dll\lastx Or y<>dll\lasty Or z<>dll\lastz Or pitch<>dll\lastpitch Or yaw<>dll\lastyaw Or roll<>dll\lastroll 
				ClearSurface dlr\surf
				n_surfs = CountSurfaces(dlr\orig)
				For s = 1 To n_surfs
					surf = GetSurface(dlr\orig,s)
					n_tris = CountTriangles(surf)-1
					For t = 0 To n_tris
						v0 = TriangleVertex(surf,t,0)
						v1 = TriangleVertex(surf,t,1)
						v2 = TriangleVertex(surf,t,2)
						
						ex0# = VertexX(surf,v1) - VertexX(surf,v0)				
						ey0# = VertexY(surf,v1) - VertexY(surf,v0)
						ez0# = VertexZ(surf,v1) - VertexZ(surf,v0)
		
						ex1# = VertexX(surf,v2) - VertexX(surf,v0)				
						ey1# = VertexY(surf,v2) - VertexY(surf,v0)
						ez1# = VertexZ(surf,v2) - VertexZ(surf,v0)
		
						; Triangle normal
						nx# = ey0 * ez1 - ez0 * ey1
						ny# = ez0 * ex1 - ex0 * ez1
						nz# = ex0 * ey1 - ey0 * ex1
						
						; Transform it compared to light
						TFormNormal nx,ny,nz,dlr\orig,dll\entity
						If TFormedZ()<0.0
							nv0 = AddVertex(dlr\surf,VertexX(surf,v0),VertexY(surf,v0),VertexZ(surf,v0))
							nv1 = AddVertex(dlr\surf,VertexX(surf,v1),VertexY(surf,v1),VertexZ(surf,v1))
							nv2 = AddVertex(dlr\surf,VertexX(surf,v2),VertexY(surf,v2),VertexZ(surf,v2))
							AddTriangle dlr\surf,nv0,nv1,nv2
						End If
					Next
				Next
			End If
			
		ElseIf CountVertices(dlr\surf) = 0
		
			;
			; No backface culling
			ClearSurface dlr\surf
			n_surfs = CountSurfaces(dlr\orig)
			For s = 1 To n_surfs
				surf = GetSurface(dlr\orig,s)
				n_tris = CountTriangles(surf)-1
				For t = 0 To n_tris
					v0 = TriangleVertex(surf,t,0)
					v1 = TriangleVertex(surf,t,1)
					v2 = TriangleVertex(surf,t,2)

					nv0 = AddVertex(dlr\surf,VertexX(surf,v0),VertexY(surf,v0),VertexZ(surf,v0))
					nv1 = AddVertex(dlr\surf,VertexX(surf,v1),VertexY(surf,v1),VertexZ(surf,v1))
					nv2 = AddVertex(dlr\surf,VertexX(surf,v2),VertexY(surf,v2),VertexZ(surf,v2))
					AddTriangle dlr\surf,nv0,nv1,nv2
				Next
			Next			
			
		End If
		
		;
		; Calculate uv's
		n_verts = CountVertices(dlr\surf)-1
		For v = 0 To n_verts
			TFormPoint VertexX(dlr\surf,v),VertexY(dlr\surf,v),VertexZ(dlr\surf,v),dlr\mesh,0
			CameraProject dll\camera,TFormedX(),TFormedY(),TFormedZ()
			tu# = ProjectedX()/Float(dll\width)
			tv# = ProjectedY()/Float(dll\height)
			VertexTexCoords dlr\surf,v,tu,tv
		Next
	Next

	; Update positions
	dll\lastx = x
	dll\lasty = y
	dll\lastz = z
	dll\lastpitch	= pitch
	dll\lastyaw		= yaw
	dll\lastroll	= roll

	; disable shadow camera
	CameraProjMode dll\camera,0
	
End Function



;
; Example 
;
Graphics3D 800,600,0,2
SetBuffer BackBuffer()

HidePointer
AmbientLight 32,32,32
SeedRnd MilliSecs()

camera = CreateCamera()

bob = CreateCube()
ScaleMesh bob,15,5,5
EntityColor bob,255,255,255

For i = 0 To 20
	cube = CreateCube()
	ScaleMesh cube,Rnd(1,10),Rnd(1,10),Rnd(1,10)
	RotateMesh cube,Rnd(-90,90),Rnd(-180,180),Rnd(-180,180)
	PositionMesh cube,Rnd(-100,100),Rnd(-100,100),Rnd(-100,100)
	AddMesh cube,bob
	FreeEntity cube
Next

For i = 0 To 20
	sphere = CreateSphere()
	s# = Rnd(4,20)
	ScaleMesh sphere,s,s,s 
	PositionMesh sphere,Rnd(-100,100),Rnd(-100,100),Rnd(-100,100)
	AddMesh sphere,bob
	FreeEntity sphere	
Next

scene = CreateSphere(32)
ScaleEntity scene,100,100,100
FlipMesh scene

light = CreateLight()
RotateEntity light,70,40,0
PositionEntity light,0,1000,0
PointEntity light,scene

DL_Init()
DL_SetReceiver(scene)
DL_SetLight(light,512,512)

spd# = 2.0

zoom# = 1.0

a# = 0.0
b# = 0.0

Repeat

	MoveEntity camera,(KeyDown(205)-KeyDown(203))*spd,0,(KeyDown(200)-KeyDown(208))*spd
	TurnEntity camera,-MouseYSpeed()*0.25,-MouseXSpeed()*0.25,0
	RotateEntity camera,EntityPitch(camera,True),EntityYaw(camera,True),0

	If KeyDown(2) Or KeyDown(3)
		zoom# = zoom + (KeyDown(2)-KeyDown(3))*0.01
		CameraZoom camera,zoom
	End If

	MoveMouse 320,240

	b = b + 1

	RotateEntity light,90+(Sin(b)*20),20+(Cos(b)*20),0

	a# = a+1
	PositionEntity bob,Sin(a)*50,(Sin(a)*50)+100,Cos(a)*50
	TurnEntity bob,1,1,1

	HideEntity scene
	CameraProjMode camera,0
	EntityColor bob,0,0,0

	DL_Update()

	EntityColor bob,255,255,255	
	ShowEntity scene
	CameraProjMode camera,1

	RenderWorld
	
	Text 0,0,zoom
	Flip

Until KeyHit(1)

DL_Free()

End

Comments

Filax2004
Thanks ! An idea for colouring shadow ?


fredborg2004
Try changing:
	EntityColor bob,0,0,0

	DL_Update()

	EntityColor bob,255,255,255
To:
	EntityColor bob,28,50,100 
	EntityFX bob,1 

	DL_Update() 

	EntityColor bob,255,255,255
	EntityFX bob,0



Filax2004
Thanks fredborg !


Filax2004
Do you think it is possible to do the same with multi light ?


fredborg2004
Sure, but it will get pretty slow if you use it on a complex scene, as each light would make a clone of your level.


Olive2004
Cool effect thx Fredborg.

even if you are a borg...i won't be assimilated.


erbbysam2005
I tried to use this but it does cause some pretty massive slow downs in any complex scenes, because, as fredborg said it would.


D4NM4N2005
is there a way of applying alpha to shadows ie. not black


Code Archives Forum