create a shadow volume

Blitz3D Forums/Blitz3D Programming/create a shadow volume

ok here's somethin gto play with, until we get a real solution by somebody who's actually knowing what he's doing, so not by me o_O

This is the fixed version of the Linepicking Volume creator. Wit this settings it's working pretty nicely, say about 99.5% correctly, although of course still slow with high poly stuff, but you may try it with some low poly geometry and see. Maybe somebody can add a faster Linepick:
;create shadow volume with the help of Linepick:
;-----------------------------------------------


; make silhouette mesh / shadow volume

; works 99%, pretty slow with high poly stuff (linepick exponential slowdown).


Graphics3D 640,480,32,2
SetBuffer BackBuffer()




Global helper=CreatePivot()
Global helper2=CreatePivot()

; you can easily destroy it when editing these parameters :)
Global infi#=50 ; length shadow volume
Global pick_radius#=0.0001 
Global pick_back#=50 ; pick from n behind light
Global divi#=3.0


plane=CreatePlane() ; map
TranslateEntity plane,0,-5,0
EntityColor plane,0,255,0

Global camera=CreateCamera()
TranslateEntity camera,0,0,-12

light=CreateLight()
RotateEntity light,45,45,45

;cube=CreateSphere(5) ;CreateCube() ; object to cast shadow
;cube=CreateCube() ; object to cast shadow
;cube=CreateCylinder(10) ; object to cast shadow
cube=CreateCone(10) ; object to cast shadow
RotateEntity cube,45,45,0
EntityPickMode cube,2

lime=CreateSphere() ; position of light
ScaleEntity lime,0.1,0.1,0.1
PositionEntity lime,4,4,0


While KeyDown(1)=0
 a=(a +2) Mod 360
 PositionEntity lime,Sin(a)*4.0,4,Cos(a)*4.0
 t1=MilliSecs()
 vol=make_volume(cube,lime)
 t2=MilliSecs()
 UpdateWorld
 RenderWorld()
 Text 0,0,"tris "+TrisRendered()
 Text 0,16,"ms "+(t2-t1)
 Text 0,32,"space=pause"
 Flip
 While KeyDown(57) 
  Delay 1
 Wend 
 FreeEntity vol
Wend
End




End




Function make_volume(source,lite)
 ; for every triangle create 2 tris in the shadow volume, where one is 
 ; transposed by "infi" in the direction of lightrays
 TFormPoint EntityX(lite),EntityY(lite),EntityZ(lite),0,source
 PositionEntity helper2,TFormedX(),TFormedY(),TFormedZ()
 tri_count=0
 vol=CreateMesh()
 su2=CreateSurface(vol)
 For s=1 To CountSurfaces(source)
  su=GetSurface(source,s)
  For tri=0 To CountTriangles(su)-1
   vx0#=VertexX(su,TriangleVertex(su,tri,0))
   vy0#=VertexY(su,TriangleVertex(su,tri,0))
   vz0#=VertexZ(su,TriangleVertex(su,tri,0))

   vx1#=VertexX(su,TriangleVertex(su,tri,1))
   vy1#=VertexY(su,TriangleVertex(su,tri,1))
   vz1#=VertexZ(su,TriangleVertex(su,tri,1))

   vx2#=VertexX(su,TriangleVertex(su,tri,2))
   vy2#=VertexY(su,TriangleVertex(su,tri,2))
   vz2#=VertexZ(su,TriangleVertex(su,tri,2))
   
   v0=AddVertex(su2,vx0,vy0,vz0)
   v1=AddVertex(su2,vx1,vy1,vz1)
   v2=AddVertex(su2,vx2,vy2,vz2)

   PositionEntity helper,vx0,vy0,vz0
   PointEntity helper,helper2
   MoveEntity helper,0,0,-infi
   v0_b=AddVertex(su2,EntityX(helper),EntityY(helper),EntityZ(helper))

   PositionEntity helper,vx1,vy1,vz1
   PointEntity helper,helper2
   MoveEntity helper,0,0,-infi
   v1_b=AddVertex(su2,EntityX(helper),EntityY(helper),EntityZ(helper))

   PositionEntity helper,vx2,vy2,vz2
   PointEntity helper,helper2
   MoveEntity helper,0,0,-infi
   v2_b=AddVertex(su2,EntityX(helper),EntityY(helper),EntityZ(helper))

   AddTriangle su2, v0  ,v1  ,v1_b
   AddTriangle su2, v0_b,v0  ,v1_b

   AddTriangle su2, v1_b,v1,v2_b
   AddTriangle su2, v1,v2,v2_b

   AddTriangle su2, v2,v0_b,v2_b
   AddTriangle su2, v2,v0,v0_b

   tri_count=tri_count+6

  Next
 Next
 UpdateNormals vol
 EntityPickMode vol,2
 EntityFX vol,1 
 EntityColor vol,0,0,255
 RotateEntity vol, EntityPitch(source),EntityYaw(source),EntityRoll(source),1


; vol is now a shadow volume, containing the silhouette and a lot of enclosed, hidden tris.

;Return ; you may return here to watch this state...
; -------------------------------


; create a copy without the enclosed tris:


 ; (cosmetics)
 remx#=EntityX(source)
 remy#=EntityY(source)
 remz#=EntityZ(source)
 rempitch#=EntityPitch(source)
 remyaw#=EntityYaw(source)
 remroll#=EntityRoll(source)
 PointEntity source,lite
 MoveEntity source,0,0,.1
 RotateEntity source, rempitch,remyaw,remroll


 vol3=CreateMesh() ; this will be the final shadow volume
 su3=CreateSurface(vol3)

 PositionEntity helper ,EntityX(lite),EntityY(lite),EntityZ(lite),1
 PointEntity helper,source,0
 MoveEntity helper,0,0,-pick_back


 ; check the visibility of every triangle of the shadow volume from one "step" behind the light 
 ; using Linepicks:
 ; only silhouette tris should be pickable here! (since the source mesh obscures inner parts, 
 ; as well as the silhouette tris will do so - at least in theory o_O)


 For i=0 To tri_count-1
  x0#=VertexX(su2,TriangleVertex(su2,i,0))
  y0#=VertexY(su2,TriangleVertex(su2,i,0))
  z0#=VertexZ(su2,TriangleVertex(su2,i,0))

  x1#=VertexX(su2,TriangleVertex(su2,i,1))
  y1#=VertexY(su2,TriangleVertex(su2,i,1))
  z1#=VertexZ(su2,TriangleVertex(su2,i,1))

  x2#=VertexX(su2,TriangleVertex(su2,i,2))
  y2#=VertexY(su2,TriangleVertex(su2,i,2))
  z2#=VertexZ(su2,TriangleVertex(su2,i,2))

  x#=(x0+x1+x2)/divi ; get a triangles interpolated center point
  y#=(y0+y1+y2)/divi
  z#=(z0+z1+z2)/divi

  TFormPoint(x,y,z,vol,0)

  he=helper
  p=LinePick(EntityX#(he),EntityY#(he),EntityZ#(he)  ,TFormedX#()-EntityX#(he),TFormedY#()-EntityY#(he),TFormedZ#()-EntityZ#(he),pick_radius#)

  If (p=vol)
   If PickedTriangle()=i ; did we pick the tris of the corresponding center point?
    v0=AddVertex(su3,x0,y0,z0) ; yes, then it must be a silhouette tris
    v1=AddVertex(su3,x1,y1,z1)
    v2=AddVertex(su3,x2,y2,z2)
    AddTriangle(su3,v0,v1,v2)
   EndIf
  EndIf
 Next

 ; (undo cosmetics)
 PositionEntity source, remx,remy,remz


 FreeEntity vol ; release old volume
 vol=vol3
 EntityColor vol,255,0,0
 EntityFX vol,1 Or 16
 EntityAlpha vol,0.5
 RotateEntity vol, EntityPitch(source),EntityYaw(source),EntityRoll(source),1
 Return vol
End Function


additionally here's the same function, now demonstrating how it could be used in plain Blitz to create Stencil Shadows:
; stencil shadows in plain blitzbasic

; slow as hell due to LinePicks!

; creates  a shadow volume with the help of Linepick:


; experimental (please somebody successfully replace LinePick by Coldet rayintersection function)

Graphics3D 640,480,32,2
SetBuffer BackBuffer()


Global helper=CreatePivot()
Global helper2=CreatePivot()

Global infi#=50 ; length shadow volume
Global pick_radius#=0.0001 
Global pick_back#=50 ; pick from n behind light
Global divi#=3.0


;plane=CreatePlane() ; map
;TranslateEntity plane,0,-5,0
;EntityColor plane,0,255,0

; better use a nice terrain to show the stencil shadows in action
plane=CreateTerrain(64)
For j=0 To 63
 For i=0 To 63
  ModifyTerrain(plane,i,j,Rnd(0.0,1.0))
 Next
Next
ScaleEntity plane,10,7,10
TerrainShading plane,1
TranslateEntity plane,-320,-7,-320



Global camera=CreateCamera()
TranslateEntity camera,0,2,-12
TurnEntity camera,10,0,0



light=CreateLight()
;RotateEntity light,45,45,45


; object to cast shadow (note: highpoly stuff is extremly slow)
; -------------------------------------------------------------
;cube=CreateSphere(5)
cube=CreateCube()
;cube=CreateCylinder(10)
;cube=CreateCone(10)
RotateEntity cube,45,45,0
EntityPickMode cube,2


lime=CreateSphere() ; shows position of light
ScaleEntity lime,0.1,0.1,0.1
PositionEntity lime,4,4,0



img=CreateImage(GraphicsWidth(),GraphicsHeight()) ; used to mask nonintersection parts


While KeyDown(1)=0
 a=(a +2) Mod 360
 PositionEntity lime,Sin(a)*4.0,4,Cos(a)*4.0
 TurnEntity cube,1,2,3

 t1=MilliSecs()
 vol=make_volume(cube,lime)
 t2=MilliSecs()


 ; prepare scene for stencil shadow render
 EntityFX plane,1
 EntityFX cube,1
 EntityFX lime,1

 EntityColor plane,0,0,0
 EntityColor cube,0,0,0
 HideEntity lime
 EntityOrder cube,-1


 RenderWorld() ; render shadow volume
 GrabImage(img,0,0)
 MaskImage img,0,0,0
 ClsColor 96,96,96
 Cls
 DrawImage img,0,0
 GrabImage(img,0,0)
 MaskImage img,96,96,96


 ; restore scene for normal render
 EntityOrder cube,0
 EntityFX plane,0
 EntityFX cube,0
 EntityFX lime,0

 EntityColor plane,0,255,0
 EntityColor cube,255,255,255
 ShowEntity lime
 If KeyDown(57)<>1 Then HideEntity vol

 RenderWorld() ; render the scene for the audience

 ; add stencil shadow 2D layer (pixelperfect sprite may be used instead!)
 DrawImage img,0,0

 Text 0,0,"tris "+TrisRendered()
 Text 0,16,"ms "+(t2-t1)
 Text 0,32,"space=show volume"
 Text 0,48,ReadPixel(MouseX(),MouseY()) And $ff
 Flip
 FreeEntity vol
Wend

End






Function make_volume(source,lite)
 ; for every triangle create 2 tris in the shadow volume, where one is 
 ; transposed by "infi" in the direction of lightrays
 TFormPoint EntityX(lite),EntityY(lite),EntityZ(lite),0,source
 PositionEntity helper2,TFormedX(),TFormedY(),TFormedZ()
 tri_count=0
 vol=CreateMesh()
 su2=CreateSurface(vol)
 For s=1 To CountSurfaces(source)
  su=GetSurface(source,s)
  For tri=0 To CountTriangles(su)-1
   vx0#=VertexX(su,TriangleVertex(su,tri,0))
   vy0#=VertexY(su,TriangleVertex(su,tri,0))
   vz0#=VertexZ(su,TriangleVertex(su,tri,0))

   vx1#=VertexX(su,TriangleVertex(su,tri,1))
   vy1#=VertexY(su,TriangleVertex(su,tri,1))
   vz1#=VertexZ(su,TriangleVertex(su,tri,1))

   vx2#=VertexX(su,TriangleVertex(su,tri,2))
   vy2#=VertexY(su,TriangleVertex(su,tri,2))
   vz2#=VertexZ(su,TriangleVertex(su,tri,2))
   
   v0=AddVertex(su2,vx0,vy0,vz0)
   v1=AddVertex(su2,vx1,vy1,vz1)
   v2=AddVertex(su2,vx2,vy2,vz2)

   PositionEntity helper,vx0,vy0,vz0
   PointEntity helper,helper2
   MoveEntity helper,0,0,-infi
   v0_b=AddVertex(su2,EntityX(helper),EntityY(helper),EntityZ(helper))

   PositionEntity helper,vx1,vy1,vz1
   PointEntity helper,helper2
   MoveEntity helper,0,0,-infi
   v1_b=AddVertex(su2,EntityX(helper),EntityY(helper),EntityZ(helper))

   PositionEntity helper,vx2,vy2,vz2
   PointEntity helper,helper2
   MoveEntity helper,0,0,-infi
   v2_b=AddVertex(su2,EntityX(helper),EntityY(helper),EntityZ(helper))

   AddTriangle su2, v0  ,v1  ,v1_b
   AddTriangle su2, v0_b,v0  ,v1_b

   AddTriangle su2, v1_b,v1,v2_b
   AddTriangle su2, v1,v2,v2_b

   AddTriangle su2, v2,v0_b,v2_b
   AddTriangle su2, v2,v0,v0_b

   tri_count=tri_count+6

  Next
 Next
 UpdateNormals vol
 EntityPickMode vol,2
 EntityFX vol,1 
 EntityColor vol,0,0,255
 RotateEntity vol, EntityPitch(source),EntityYaw(source),EntityRoll(source),1


; vol is now a shadow volume, containing the silhouette and a lot of enclosed, hidden tris.


; -------------------------------


; create a copy without the enclosed tris:


 ; (cosmetics)
 remx#=EntityX(source)
 remy#=EntityY(source)
 remz#=EntityZ(source)
 rempitch#=EntityPitch(source)
 remyaw#=EntityYaw(source)
 remroll#=EntityRoll(source)
 PointEntity source,lite
 MoveEntity source,0,0,.1
 RotateEntity source, rempitch,remyaw,remroll


 vol3=CreateMesh() ; this will be the final shadow volume
 su3=CreateSurface(vol3)

 PositionEntity helper ,EntityX(lite),EntityY(lite),EntityZ(lite),1
 PointEntity helper,source,0
 MoveEntity helper,0,0,-pick_back


 ; check the visibility of every triangle of the shadow volume from one "step" behind the light 
 ; using Linepicks:
 ; only silhouette tris should be pickable here! (since the source mesh obscures inner parts, 
 ; as well as the silhouette tris will do so - at least in theory o_O)


 For i=0 To tri_count-1
  x0#=VertexX(su2,TriangleVertex(su2,i,0))
  y0#=VertexY(su2,TriangleVertex(su2,i,0))
  z0#=VertexZ(su2,TriangleVertex(su2,i,0))

  x1#=VertexX(su2,TriangleVertex(su2,i,1))
  y1#=VertexY(su2,TriangleVertex(su2,i,1))
  z1#=VertexZ(su2,TriangleVertex(su2,i,1))

  x2#=VertexX(su2,TriangleVertex(su2,i,2))
  y2#=VertexY(su2,TriangleVertex(su2,i,2))
  z2#=VertexZ(su2,TriangleVertex(su2,i,2))

  x#=(x0+x1+x2)/divi ; get a triangles interpolated center point
  y#=(y0+y1+y2)/divi
  z#=(z0+z1+z2)/divi

  TFormPoint(x,y,z,vol,0)

  he=helper
  p=LinePick(EntityX#(he),EntityY#(he),EntityZ#(he)  ,TFormedX#()-EntityX#(he),TFormedY#()-EntityY#(he),TFormedZ#()-EntityZ#(he),pick_radius#)

  If (p=vol)
   If PickedTriangle()=i ; did we pick the tris of the corresponding center point?
    v0=AddVertex(su3,x0,y0,z0) ; yes, then it must be a silhouette tris
    v1=AddVertex(su3,x1,y1,z1)
    v2=AddVertex(su3,x2,y2,z2)
    AddTriangle(su3,v0,v1,v2)
   EndIf
  EndIf
 Next

 ; (undo cosmetics)
 PositionEntity source, remx,remy,remz


 FreeEntity vol ; release old volume
 vol=vol3
 EntityColor vol,128,128,128
 EntityFX vol,1 Or 16
 EntityAlpha vol,0.5
 RotateEntity vol, EntityPitch(source),EntityYaw(source),EntityRoll(source),1
 Return vol
End Function