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 fredborg
(Posted 23 years ago)
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

Filax
(Posted 23 years ago)
Thanks ! An idea for colouring shadow ?

fredborg
(Posted 23 years ago)
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


Filax
(Posted 23 years ago)
Thanks fredborg !

Filax
(Posted 23 years ago)
Do you think it is possible to do the same with multi light ?

fredborg
(Posted 23 years ago)
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.

Olive
(Posted 23 years ago)
Cool effect thx Fredborg.

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

erbbysam
(Posted 22 years ago)
I tried to use this but it does cause some pretty massive slow downs in any complex scenes, because, as fredborg said it would.

D4NM4N
(Posted 22 years ago)
is there a way of applying alpha to shadows ie. not black

Code Archives Forum