Thx
Code: Select all
; English forum: http://www.purebasic.fr/english/viewtopic.php?t=15568&postdays=0&postorder=asc&start=30
; Author: Dreglor (updated for PB 4.00 by Andre)
; Date: 23. June 2005
; OS: Windows
; Demo: Yes
;/Title: PBRay
;/Author: Dreglor
;/Date: 6-21-05
;/Version: Alpha
;/Function: Renders scenes using raytracing
;/Notes: Special Thanks to MrMat for helping me :)
;/Todo: fix bugs, phong lighting, shadows ,Refractions
;- Constants
#Version="Alpha"
#Tolerance=0.0001
#ObjectType_Null=0
#ObjectType_PointLight=1
#ObjectType_Sphere=2
#MaxChildren=3
#EPSILON=0.0001
;- Structures
Structure xyz
x.f
y.f
z.f
EndStructure
Structure Matrix
e11.f
e12.f
e13.f
e21.f
e22.f
e23.f
e31.f
e32.f
e33.f
EndStructure
Structure Camera
Origin.xyz
Direction.xyz
ViewingAngle.xyz
EndStructure
Structure Color
Red.f
Green.f
Blue.f
EndStructure
Structure Material
SoildColor.Color
Diffuse.f
Reflect.f
Refract.f
EndStructure
Structure PointLight
Color.Color
Origin.xyz
EndStructure
Structure Sphere
radius.f
EndStructure
; Structure Plane ;incomplete
; normal.xyz
; Distance.xyz ;???
; EndStructure
; Structure Triangle ;incomplete
; v1.xyz
; v2.xyz
; v3.xyz
; normal.xyz
; EndStructure
Structure Object
Type.b
Material.Material
Origin.xyz
Direction.xyz
IsLight.b
Primitive.l ;points to a memory that get[primitive]structure will use to fill a structure with
EndStructure
Structure Scene
Ambient.Color
ScreenWidth.w
ScreenHeight.w
HalfScreenWidth.w
HalfScreenHeight.w
EndStructure
;- Globals
Global MainScene.Scene
Global NewList ObjectList.Object()
;- Declares
Declare.l TestLoop();tester
Declare.b RenderScene(*Scene.Scene, *ViewPort.Camera)
Declare.l TraceRay(*Origin.xyz, *Direction.xyz, depth.b)
Declare.f TestSphere(*Origin.xyz, *Direction.xyz, *Sphere.Object)
Declare.l Shade(*Intersection.xyz,*Normal.xyz,*Direction.xyz,*Material.Material,depth.b)
Declare.b RemoveObject(objectHandle)
Declare.b AddSphereObject(*Sphere.Object,radius.f)
Declare.b GetObjectStructure(ObjectPointer,*destination.Object)
Declare.b SetObjectStructure(ObjectPointer,*source.Object)
Declare.b AddPointLightObject(*Light.PointLight)
Declare.w MatrixScalarDivision(*a.Matrix, Scalar.f, *result.Matrix);divides a matrix to a scalar
Declare.w MatrixScalarMuiltply(*a.Matrix, Scalar.f, *result.Matrix);muiltplies a matrix to a scalar
Declare.w MatrixSubtract(*a.Matrix, *b.Matrix, *result.Matrix);subtract 2 matrice together
Declare.w MatrixAdd(*a.Matrix, *b.Matrix, *result.Matrix);adds 2 matrice together
Declare.w MatrixInverse(*this.Matrix);returns the inverse of a matrix
Declare.w MatrixTranspose(*this.Matrix, *result.Matrix);returns the transpose of a matrix
Declare.f MatrixDeterminant(*this.Matrix);returns the determiant of a matrix
Declare.f VectorTripleScalarProduct(*a.xyz, *b.xyz, *c.xyz);returns triple scalar product of 3 vectors
Declare.b VectorScalarDivide(*a.xyz, b.f, *result.xyz);returns a pointer to a vector that has been divided
Declare.b VectorScalarMuilply(*a.xyz, b.f, *result.xyz);returns a pointer to a vector that has been muiltiplied
Declare.b VectorSubtract(*a.xyz, * b.xyz, *result.xyz);returns a pointer to a vector that has been Subtracted
Declare.b VectorAdd(*a.xyz, * b.xyz, *result.xyz);returns a pointer to a vector that has been added
Declare.b VectorCrossMuiltply(*a.xyz, *b.xyz, *result.xyz);returns a pointer to a vector that has been crossed muiltiplied
Declare.b VectorReverse(*this.xyz);reverses a Vector
Declare.b VectorNormalize(*this.xyz);normilzes a vector
Declare.f VectorDotProduct(*a.xyz, *b.xyz)
Declare.f VectorMagnitude(*this.xyz);returns the maginitude of a Vector
Declare.b ColorRangeCheck(*a.Color)
Declare.b ColorAdd(*a.Color, *b.Color, *result.Color);returns a pointer to a Color that has been added
Declare.b ColorMuilply(*a.Color, *b.Color, *result.Color);returns a pointer to a Color that has been muiltiplied
Declare.b ColorScalarMuilply(*a.Color, b.f, *result.Color);returns a pointer to a Color that has been muiltiplied by a scalar
;- Procedures
;- Color Math
Procedure.b ColorScalarMuilply(*a.Color, b.f, *result.Color);returns a pointer to a Color that has been muiltiplied by a scalar
*result\Red = *a\Red * b
*result\Green = *a\Green * b
*result\Blue = *a\Blue * b
EndProcedure
Procedure.b ColorMuilply(*a.Color, *b.Color, *result.Color);returns a pointer to a Color that has been muiltiplied
*result\Red = *a\Red * *b\Red
*result\Green = *a\Green * *b\Green
*result\Blue = *a\Blue * *b\Blue
EndProcedure
Procedure.b ColorAdd(*a.Color, *b.Color, *result.Color);returns a pointer to a Color that has been added
*result\Red = *a\Red + *b\Red
*result\Green = *a\Green + *b\Green
*result\Blue = *a\Blue + *b\Blue
EndProcedure
Procedure.b ColorRangeCheck(*a.Color)
If *a\Red>1
*a\Red=1
EndIf
If *a\Green>1
*a\Green=1
EndIf
If *a\Blue>1
*a\Blue=1
EndIf
EndProcedure
;-Vector Math
Procedure.f VectorMagnitude(*this.xyz);returns the maginitude of a Vector
ProcedureReturn Sqr((*this\x * *this\x)+(*this\y * *this\y)+(*this\z * *this\z))
EndProcedure
Procedure.f VectorDotProduct(*a.xyz, *b.xyz)
ProcedureReturn *a\x * *b\x + *a\y * *b\y + *a\z * *b\z
EndProcedure
Procedure.b VectorNormalize(*this.xyz);normilzes a vector
m.f = Sqr(*this\x * *this\x + *this\y * *this\y + *this\z * *this\z)
If m > #Tolerance
*this\x = *this\x / m
*this\y = *this\y / m
*this\z = *this\z / m
EndIf
If Abs(*this\x) < #Tolerance
*this\x = 0
EndIf
If Abs(*this\y) < #Tolerance
*this\y = 0
EndIf
If Abs(*this\z) < #Tolerance
*this\z = 0
EndIf
EndProcedure
Procedure.b VectorReverse(*this.xyz);reverses a Vector
*this\x = -*this\x
*this\y = -*this\y
*this\z = -*this\z
EndProcedure
Procedure.b VectorCrossMuiltply(*a.xyz, *b.xyz, *result.xyz);returns a pointer to a vector that has been crossed muiltiplied
*result\x = *a\y * *b\z - *a\z * *b\y
*result\y = -*a\x * *b\z + *a\z * *b\x
*result\z = *a\x * *b\y - *a\y * *b\x
EndProcedure
Procedure.b VectorAdd(*a.xyz, *b.xyz, *result.xyz);returns a pointer to a vector that has been added
*result\x = *a\x + *b\x
*result\y = *a\y + *b\y
*result\z = *a\z + *b\z
EndProcedure
Procedure.b VectorSubtract(*a.xyz, *b.xyz, *result.xyz);returns a pointer to a vector that has been Subtracted
*result\x = *a\x - *b\x
*result\y = *a\y - *b\y
*result\z = *a\z - *b\z
EndProcedure
Procedure.b VectorScalarMuilply(*a.xyz, b.f, *result.xyz);returns a pointer to a vector that has been muiltiplied
*result\x = *a\x * b
*result\y = *a\y * b
*result\z = *a\z * b
EndProcedure
Procedure.b VectorScalarDivide(*a.xyz, b.f, *result.xyz);returns a pointer to a vector that has been divided
*result\x = *a\x / b
*result\y = *a\y / b
*result\z = *a\z / b
EndProcedure
Procedure.f VectorTripleScalarProduct(*a.xyz, *b.xyz, *c.xyz);returns triple scalar product of 3 vectors
ProcedureReturn *a\x * (*b\y * *c\z - *b\z * *c\y)+(*a\y * (-*b\x * *c\z + *b\z * *c\x))+(*a\z * (*b\x * *c\y - *b\y * *c\x))
EndProcedure
;-Matrix Math
Procedure.f MatrixDeterminant(*this.Matrix);returns the determiant of a matrix
ProcedureReturn *this\e11 * *this\e22 * *this\e33 - *this\e11 * *this\e32 * *this\e23 + *this\e21 * *this\e32 * *this\e13 - *this\e21 * *this\e12 * *this\e33 + *this\e31 * *this\e12 * *this\e23 - *this\e31 * *this\e22 * *this\e13
EndProcedure
Procedure.w MatrixTranspose(*this.Matrix, *result.Matrix);returns the transpose of a matrix
*result\e11 = *this\e11
*result\e21 = *this\e12
*result\e31 = *this\e13
*result\e12 = *this\e21
*result\e22 = *this\e22
*result\e32 = *this\e23
*result\e13 = *this\e31
*result\e23 = *this\e32
*result\e33 = *this\e33
EndProcedure
Procedure.w MatrixInverse(*this.Matrix);returns the inverse of a matrix
d.f = MatrixDeterminant(*this)
If d = 0
d = 1
EndIf
*this\e11 = (*this\e22 * *this\e33 - *this\e23 * *this\e32)/d
*this\e21 = -(*this\e12 * *this\e33 - *this\e13 * *this\e32)/d
*this\e31 = (*this\e12 * *this\e23 - *this\e13 * *this\e22)/d
*this\e12 = -(*this\e21 * *this\e33 - *this\e23 * *this\e31)/d
*this\e22 = (*this\e11 * *this\e33 - *this\e13 * *this\e31)/d
*this\e32 = -(*this\e11 * *this\e23 - *this\e13 * *this\e21)/d
*this\e13 = (*this\e21 * *this\e32 - *this\e12 * *this\e31)/d
*this\e23 = -(*this\e11 * *this\e32 - *this\e12 * *this\e31)/d
*this\e33 = (*this\e11 * *this\e22 - *this\e12 * *this\e21)/d
EndProcedure
Procedure.w MatrixAdd(*a.Matrix, *b.Matrix, *result.Matrix);adds 2 matrice together
*result\e11 = *a\e11 + *b\e11
*result\e12 = *a\e12 + *b\e12
*result\e13 = *a\e13 + *b\e13
*result\e21 = *a\e21 + *b\e21
*result\e22 = *a\e22 + *b\e22
*result\e23 = *a\e23 + *b\e23
*result\e31 = *a\e31 + *b\e31
*result\e32 = *a\e32 + *b\e32
*result\e33 = *a\e33 + *b\e33
EndProcedure
Procedure.w MatrixSubtract(*a.Matrix, *b.Matrix, *result.Matrix);subtract 2 matrice together
*result\e11 = *a\e11 - *b\e11
*result\e12 = *a\e12 - *b\e12
*result\e13 = *a\e13 - *b\e13
*result\e21 = *a\e21 - *b\e21
*result\e22 = *a\e22 - *b\e22
*result\e23 = *a\e23 - *b\e23
*result\e31 = *a\e31 - *b\e31
*result\e32 = *a\e32 - *b\e32
*result\e33 = *a\e33 - *b\e33
EndProcedure
Procedure.w MatrixScalarMuiltply(*a.Matrix, Scalar.f, *result.Matrix);muiltplies a matrix to a scalar
*result\e11 = *a\e11 * Scalar
*result\e12 = *a\e12 * Scalar
*result\e13 = *a\e13 * Scalar
*result\e21 = *a\e21 * Scalar
*result\e22 = *a\e22 * Scalar
*result\e23 = *a\e23 * Scalar
*result\e31 = *a\e31 * Scalar
*result\e32 = *a\e32 * Scalar
*result\e33 = *a\e33 * Scalar
EndProcedure
Procedure.w MatrixScalarDivision(*a.Matrix, Scalar.f, *result.Matrix);divides a matrix to a scalar
*result\e11 = *a\e11 / Scalar
*result\e12 = *a\e12 / Scalar
*result\e13 = *a\e13 / Scalar
*result\e21 = *a\e21 / Scalar
*result\e22 = *a\e22 / Scalar
*result\e23 = *a\e23 / Scalar
*result\e31 = *a\e31 / Scalar
*result\e32 = *a\e32 / Scalar
*result\e33 = *a\e33 / Scalar
EndProcedure
;-FrameWork
Procedure.b AddPointLightObject(*Light.PointLight)
If CountList(ObjectList())>0
*Old_Element = @ObjectList()
EndIf
AddElement(ObjectList())
ObjectList()\Type=#ObjectType_PointLight
ObjectList()\Material\SoildColor\Red=*Light\Color\Red
ObjectList()\Material\SoildColor\Green=*Light\Color\Green
ObjectList()\Material\SoildColor\Blue=*Light\Color\Blue
ObjectList()\Origin\x=*Light\Origin\x
ObjectList()\Origin\y=*Light\Origin\y
ObjectList()\Origin\z=*Light\Origin\z
ObjectList()\IsLight=#True
ObjectList()\Primitive=#Null
result.l=@ObjectList()
If *Old_Element<>#Null
ChangeCurrentElement(ObjectList(), *Old_Element)
EndIf
ProcedureReturn result
EndProcedure
Procedure.b AddSphereObject(*Sphere.Object,radius.f)
If CountList(ObjectList())>0
*Old_Element = @ObjectList()
EndIf
AddElement(ObjectList())
;copy object data into the new object
CopyMemory(*Sphere,@ObjectList(),SizeOf(Object))
;put any primtive specific data into there places
ObjectList()\Primitive=AllocateMemory(4)
PokeF(ObjectList()\Primitive,radius)
ObjectList()\Type=#ObjectType_Sphere
result.l=@ObjectList()
If *Old_Element<>#Null
ChangeCurrentElement(ObjectList(), *Old_Element)
EndIf
ProcedureReturn result
EndProcedure
Procedure.b GetObjectStructure(ObjectPointer,*destination.Object)
If CountList(ObjectList())>0
*Old_Element = @ObjectList()
EndIf
ChangeCurrentElement(ObjectList(), ObjectPointer)
;copy object data into the new object
CopyMemory(@ObjectList(),*destination,SizeOf(Object))
If *Old_Element<>#Null
ChangeCurrentElement(ObjectList(), *Old_Element)
EndIf
EndProcedure
Procedure.b SetObjectStructure(ObjectPointer,*source.Object)
If CountList(ObjectList())>0
*Old_Element = @ObjectList()
EndIf
ChangeCurrentElement(ObjectList(), ObjectPointer)
;copy object data into the new object
CopyMemory(*source,@ObjectList(),SizeOf(Object))
If *Old_Element<>#Null
ChangeCurrentElement(ObjectList(), *Old_Element)
EndIf
EndProcedure
Procedure.b RemoveObject(ObjectPointer)
If CountList(ObjectList())>0
*Old_Element = @ObjectList()
EndIf
ChangeCurrentElement(ObjectList(), ObjectPointer)
If ObjectList()\Primitive<>#Null
FreeMemory(ObjectList()\Primitive)
EndIf
DeleteElement(ObjectList())
If CountList(ObjectList())>0 And *Old_Element<>#Null
ChangeCurrentElement(ObjectList(), *Old_Element)
EndIf
EndProcedure
Procedure.l Shade(*Intersection.xyz,*Normal.xyz,*Direction.xyz,*Material.Material,depth.b)
*Old_Element=@ObjectList()
*result.Color
Color.Color
Light.xyz
Relfection.xyz
*reflectcolor.Color
ReflectOrigin.xyz
Accumalated.Color
tempvec.xyz
ResetList(ObjectList())
For Object=0 To CountList(ObjectList()) - 1
NextElement(ObjectList())
If ObjectList()\IsLight=#True
VectorSubtract(ObjectList()\Origin,*Intersection,Light) ;Origin - Intersection;
VectorNormalize(Light)
If *Material\Diffuse > 0
dot.f=VectorDotProduct(*Normal,Light)
If dot>0
diff.f=dot * *Material\Diffuse
ColorMuilply(*Material\SoildColor,ObjectList()\Material\SoildColor,Color) ;Accumalated += diff * MaterialColor * LightColor
ColorScalarMuilply(Color,diff,Color)
ColorAdd(Color,Accumalated,Accumalated)
EndIf
If *Material\Reflect>0
r.f=2*VectorDotProduct(*Direction,*Normal)
VectorScalarMuilply(*Normal,r,tempvec)
VectorSubtract(*Direction,tempvec,Relfection);Direction - 2 * DOT( Direction, normal ) * normal
VectorScalarMuilply(Relfection,#EPSILON,ReflectOrigin)
VectorAdd(*Intersection,ReflectOrigin,ReflectOrigin);Intersection+Reflection*EPSILON
*reflectcolor=TraceRay(ReflectOrigin,Relfection,depth+1)
ColorScalarMuilply(*reflectcolor,*Material\Reflect,Color)
ColorMuilply(Color,*Material\SoildColor,Color)
ColorAdd(Color,Accumalated,Accumalated);Accumalated += MaterialReflect * reflectcolor * MaterialColor
EndIf
EndIf
EndIf
Next Object
ColorRangeCheck(Accumalated)
ChangeCurrentElement(ObjectList(), *Old_Element)
ProcedureReturn @Accumalated
EndProcedure
Procedure.f TestSphere(*Origin.xyz,*Direction.xyz,*Sphere.Object)
offset.xyz
VectorSubtract(*Origin, *Sphere\Origin, offset)
radius.f = PeekF(*Sphere\Primitive)
b.f = 2 * (*Direction\x * offset\x + *Direction\y * offset\y + *Direction\z * offset\z)
c.f = offset\x * offset\x + offset\y * offset\y + offset\z * offset\z - radius * radius
d.f = b * b - 4 * c
If d > 0 ;hit the sphere
t.f = (-b - Sqr(d)) * 0.5 ; Could return +ve or -ve number!
EndIf
ProcedureReturn t
EndProcedure
Procedure TraceRay(*Origin.xyz,*Direction.xyz,depth.b)
Intersection.xyz
Normal.xyz
*Old_Element=@ObjectList()
*result.Color
If depth<#MaxChildren
Closesthandle=-1
ClosestT.f=-1
ResetList(ObjectList())
For Object=0 To CountList(ObjectList()) - 1
NextElement(ObjectList())
Select ObjectList()\Type
Case #ObjectType_Sphere
t.f=TestSphere(*Origin,*Direction,@ObjectList())
If t>0
If t<ClosestT Or ClosestT=-1
Closesthandle=Object
ClosestT=t
EndIf
EndIf
;other cases will be added
EndSelect
Next Object
If ClosestT>0
t=ClosestT
SelectElement(ObjectList(),Closesthandle)
VectorScalarMuilply(*Direction,t,Intersection) ;Calulate Interesction point with
VectorAdd(*Origin,Intersection,Intersection) ;Origin + Direction * T;
If ObjectList()\Type=#ObjectType_Sphere ;normal Calulations are diffrent per object
VectorSubtract(Intersection ,ObjectList()\Origin,Normal)
VectorScalarDivide(Normal,PeekF(ObjectList()\Primitive),Normal)
;other cases will be added
EndIf
*result = Shade(Intersection,Normal,*Direction,ObjectList()\Material,depth)
EndIf
EndIf
ChangeCurrentElement(ObjectList(), *Old_Element)
If *result=0
Black.Color
Black\Red=0
Black\Green=0
Black\Blue=0
*result=@Black
ProcedureReturn *result
Else
ProcedureReturn *result
EndIf
EndProcedure
Procedure.b RenderScene(*Scene.Scene,*ViewPort.Camera)
*Color.Color
For y = -*Scene\HalfScreenHeight To *Scene\HalfScreenHeight - 1
For x = -*Scene\HalfScreenWidth To *Scene\HalfScreenWidth - 1
*ViewPort\Direction\x = x
*ViewPort\Direction\y = y
*ViewPort\Direction\z = 0
VectorSubtract(*ViewPort\Direction,*ViewPort\Origin,*ViewPort\Direction)
VectorNormalize(*ViewPort\Direction)
*Color=TraceRay(*ViewPort\Origin,*ViewPort\Direction,0)
If *Color<>0 Or *Color\Red<>0 Or *Color\Green<>0 Or *Color\Blue<>0
Plot(*Scene\HalfScreenWidth + x, *Scene\HalfScreenHeight + y,RGB(*Color\Red*255,*Color\Green*255,*Color\Blue*255))
EndIf
Next x
Next y
EndProcedure
Procedure TestLoop() ;tester
Sphere1.Object
Sphere1Radius.f
Sphere2.Object
Sphere2Radius.f
Light1.PointLight
light2.PointLight
MainCamera.Camera
MainScene.Scene
Sphere1\Origin\x=-150
Sphere1\Origin\y=0
Sphere1\Origin\z=200
Sphere1\Material\SoildColor\Red=0.25
Sphere1\Material\SoildColor\Green=0.25
Sphere1\Material\SoildColor\Blue=0.25
Sphere1\Material\Diffuse=1
Sphere1\Material\Reflect=0
Sphere1\Material\Refract=0
Sphere1Radius=150
AddSphereObject(Sphere1,Sphere1Radius)
Sphere2\Origin\x=150
Sphere2\Origin\y=0
Sphere2\Origin\z=100
Sphere2\Material\SoildColor\Red=0
Sphere2\Material\SoildColor\Green=0
Sphere2\Material\SoildColor\Blue=0.25
Sphere2\Material\Diffuse=1
Sphere2\Material\Reflect=0
Sphere2\Material\Refract=0
Sphere2Radius=100
AddSphereObject(Sphere2,Sphere2Radius)
Light1\Origin\x=-20
Light1\Origin\y=50
Light1\Origin\z=50
Light1\Color\Red=1
Light1\Color\Green=1
Light1\Color\Blue=1
AddPointLightObject(Light1)
light2\Origin\x=20
light2\Origin\y=-50
light2\Origin\z=-50
light2\Color\Red=1
light2\Color\Green=1
light2\Color\Blue=1
AddPointLightObject(light2)
MainCamera\Origin\x=0
MainCamera\Origin\y=0
MainCamera\Origin\z=-256
MainCamera\ViewingAngle\x=0
MainCamera\ViewingAngle\y=0
MainCamera\ViewingAngle\z=0
; MainScene\Ambient\Red=0.125
; MainScene\Ambient\Green=0.125 ;not active
; MainScene\Ambient\Blue=0.125
MainScene\ScreenWidth=320
MainScene\ScreenHeight=240
MainScene\HalfScreenWidth=MainScene\ScreenWidth/2
MainScene\HalfScreenHeight=MainScene\ScreenHeight/2
InitSprite()
OpenWindow(0,0,0,MainScene\ScreenWidth,MainScene\ScreenHeight,"PBRay - FPS: 0",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,MainScene\ScreenWidth,MainScene\ScreenHeight,0,0,0)
Repeat
frame+1
start=ElapsedMilliseconds()
ClearScreen(RGB(0, 0, 0))
StartDrawing(ScreenOutput())
RenderScene(MainScene,MainCamera)
StopDrawing()
FlipBuffers(0)
stop=ElapsedMilliseconds()
; CallDebugger
If (stop-start2)>=1000
start2=ElapsedMilliseconds()
fps=frame
frame=0
EndIf
SetWindowTitle(0,"PBRay - FPS: "+Str(fps)+" RenderTime: "+Str(stop-start))
Until WindowEvent() = #PB_Event_CloseWindow
EndProcedure
TestLoop()
; IDE Options = PureBasic v4.02 (Windows - x86)
; Folding = ------
; DisableDebugger