Ok finally here's a combination of the ICU method and the linepick method.
First it uses the ICU detection method that is pretty fast. But then there are still some enclosed Triangles left that should not be there. So I additionally use the Linepick method to get rid of them. It's a bit less accurate than the Linepick only version. However, the speed is around 9ms, compared to the linepickversion (230ms), the coldet version (50ms) and the plain ICU method(ca. 6ms, tho not accurate enough).
I have also seen as soon as I use smaller triangles (like a sphere with more segments), the rouding errors show up more oftenly. So I'd say: this may be useful for simple, rough geometry only.
Additionally there's the bitter fact that animated meshes cannot make use of this because VertexX etc. will ignore Animations and return the initial pose.
Well right now this is the best I can do. Maybe I'll try it again from scratch one day, with a completely diffrent method, preferably the official math way and not cheats like these.
First it uses the ICU detection method that is pretty fast. But then there are still some enclosed Triangles left that should not be there. So I additionally use the Linepick method to get rid of them. It's a bit less accurate than the Linepick only version. However, the speed is around 9ms, compared to the linepickversion (230ms), the coldet version (50ms) and the plain ICU method(ca. 6ms, tho not accurate enough).
I have also seen as soon as I use smaller triangles (like a sphere with more segments), the rouding errors show up more oftenly. So I'd say: this may be useful for simple, rough geometry only.
Additionally there's the bitter fact that animated meshes cannot make use of this because VertexX etc. will ignore Animations and return the initial pose.
;create shadow volume with a combination of Linepick and the ICU method: ;----------------------------------------------------------------------- ; works kind of, tho meshes with lots of little triangles will produce more rounding errors Graphics3D 640,480,32,2 SetBuffer BackBuffer() Global helper=CreatePivot() Global helper2=CreatePivot() Global icucam=CreateCamera() CameraProjMode icucam,0 Dim icu_seen(0) Global infi#=50 ;20 ; length shadow volume Global pick_radius#=0.00007;0.1 Global pick_back#=50 ;10 ; pick from n behind light Global divi#=3.0 lidis#=4 Global plane=CreatePlane() ; map TranslateEntity plane,0,-5,0 EntityColor plane,0,255,0 Global camera=CreateCamera() TranslateEntity camera,0,0,-12 light=CreateLight(2) RotateEntity light,45,45,45 cube=CreateSphere(5) ;CreateCube() ; object to cast shadow ;cube=CreateCube() ; object to cast shadow ;cube=CreateCone(10) RotateEntity cube,45,45,0 ;RotateEntity cube,245,245,0 EntityPickMode cube,2 ;TranslateEntity cube,1.2,0.5,1.3 lime=CreateSphere() ; position of light ScaleEntity lime,0.1,0.1,0.1 PositionEntity lime,4,4,0 a#=90 While KeyDown(1)=0 a=(a +2) Mod 360 PositionEntity lime,Sin(a)*lidis,lidis,Cos(a)*lidis ; PositionEntity light,Sin(a)*lidis,lidis,Cos(a)*lidis ; TurnEntity cube,1,2,3 If vol<>0 Then FreeEntity vol t1=MilliSecs() vol=make_volume(cube,lime) t2=MilliSecs() RenderWorld() Text 0,0,"tris "+TrisRendered() Text 0,16,"ms "+(t2-t1) Text 0,32,"space=pause" Flip While KeyDown(57) Delay 1 Wend 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 tri_count=0 TFormPoint EntityX(lite),EntityY(lite),EntityZ(lite),0,source PositionEntity helper2,TFormedX(),TFormedY(),TFormedZ() litemesh=lite lite=helper2 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)) ; create projected vertex coords PositionEntity helper,vx0,vy0,vz0 PointEntity helper,lite MoveEntity helper,0,0,-infi vx0_b#=EntityX(helper) vy0_b#=EntityY(helper) vz0_b#=EntityZ(helper) PositionEntity helper,vx1,vy1,vz1 PointEntity helper,lite MoveEntity helper,0,0,-infi vx1_b#=EntityX(helper) vy1_b#=EntityY(helper) vz1_b#=EntityZ(helper) PositionEntity helper,vx2,vy2,vz2 PointEntity helper,lite MoveEntity helper,0,0,-infi vx2_b#=EntityX(helper) vy2_b#=EntityY(helper) vz2_b#=EntityZ(helper) ; add all potential shadow volume tris and set their ID color ;- AddTriangle su2, v0 ,v1 ,v1_b vv0=AddVertex(su2,vx0,vy0,vz0) vv1=AddVertex(su2,vx1,vy1,vz1) vv2=AddVertex(su2,vx1_b,vy1_b,vz1_b) icu_code=(tri_count+10)+0 icu_red=(icu_code And $FF0000) Shr 16 icu_green=(icu_code And $FF00) Shr 8 icu_blue=(icu_code And $FF) VertexColor su2,vv0,icu_red,icu_green,icu_blue VertexColor su2,vv1,icu_red,icu_green,icu_blue VertexColor su2,vv2,icu_red,icu_green,icu_blue AddTriangle su2, vv0 ,vv1 ,vv2 ;- AddTriangle su2, v0_b,v0 ,v1_b vv0=AddVertex(su2,vx0_b,vy0_b,vz0_b) vv1=AddVertex(su2,vx0,vy0,vz0) vv2=AddVertex(su2,vx1_b,vy1_b,vz1_b) icu_code=(tri_count+10)+1 icu_red=(icu_code And $FF0000) Shr 16 icu_green=(icu_code And $FF00) Shr 8 icu_blue=(icu_code And $FF) VertexColor su2,vv0,icu_red,icu_green,icu_blue VertexColor su2,vv1,icu_red,icu_green,icu_blue VertexColor su2,vv2,icu_red,icu_green,icu_blue AddTriangle su2, vv0 ,vv1 ,vv2 ;- AddTriangle su2, v1_b,v1,v2_b vv0=AddVertex(su2,vx1_b,vy1_b,vz1_b) vv1=AddVertex(su2,vx1,vy1,vz1) vv2=AddVertex(su2,vx2_b,vy2_b,vz2_b) icu_code=(tri_count+10)+2 icu_red=(icu_code And $FF0000) Shr 16 icu_green=(icu_code And $FF00) Shr 8 icu_blue=(icu_code And $FF) VertexColor su2,vv0,icu_red,icu_green,icu_blue VertexColor su2,vv1,icu_red,icu_green,icu_blue VertexColor su2,vv2,icu_red,icu_green,icu_blue AddTriangle su2, vv0 ,vv1 ,vv2 ;- AddTriangle su2, v1,v2,v2_b vv0=AddVertex(su2,vx1,vy1,vz1) vv1=AddVertex(su2,vx2,vy2,vz2) vv2=AddVertex(su2,vx2_b,vy2_b,vz2_b) icu_code=(tri_count+10)+3 icu_red=(icu_code And $FF0000) Shr 16 icu_green=(icu_code And $FF00) Shr 8 icu_blue=(icu_code And $FF) VertexColor su2,vv0,icu_red,icu_green,icu_blue VertexColor su2,vv1,icu_red,icu_green,icu_blue VertexColor su2,vv2,icu_red,icu_green,icu_blue AddTriangle su2, vv0 ,vv1 ,vv2 ;- AddTriangle su2, v2,v0_b,v2_b vv0=AddVertex(su2,vx2,vy2,vz2) vv1=AddVertex(su2,vx0_b,vy0_b,vz0_b) vv2=AddVertex(su2,vx2_b,vy2_b,vz2_b) icu_code=(tri_count+10)+4 icu_red=(icu_code And $FF0000) Shr 16 icu_green=(icu_code And $FF00) Shr 8 icu_blue=(icu_code And $FF) VertexColor su2,vv0,icu_red,icu_green,icu_blue VertexColor su2,vv1,icu_red,icu_green,icu_blue VertexColor su2,vv2,icu_red,icu_green,icu_blue AddTriangle su2, vv0 ,vv1 ,vv2 ;- AddTriangle su2, v2,v0,v0_b vv0=AddVertex(su2,vx2,vy2,vz2) vv1=AddVertex(su2,vx0,vy0,vz0) vv2=AddVertex(su2,vx0_b,vy0_b,vz0_b) icu_code=(tri_count+10)+5 icu_red=(icu_code And $FF0000) Shr 16 icu_green=(icu_code And $FF00) Shr 8 icu_blue=(icu_code And $FF) VertexColor su2,vv0,icu_red,icu_green,icu_blue VertexColor su2,vv1,icu_red,icu_green,icu_blue VertexColor su2,vv2,icu_red,icu_green,icu_blue AddTriangle su2, vv0 ,vv1 ,vv2 tri_count=tri_count+6 Next Next EntityPickMode vol,2 EntityFX vol,1 Or 2 EntityColor vol,0,0,255 RotateEntity vol, EntityPitch(source),EntityYaw(source),EntityRoll(source),1 PositionEntity vol,EntityX(source),EntityY(source),EntityZ(source) ; vol is now a shadow volume, containing the silhouette and a lot of enclosed, hidden tris. ; ------------------------------- ; create a copy without the enclosed tris: vol3=CreateMesh() su3=CreateSurface(vol3) PositionEntity helper ,EntityX(lite),EntityY(lite),EntityZ(lite),1 PointEntity helper,source,0 MoveEntity helper,0,0,-pick_back PositionEntity icucam ,EntityX(litemesh),EntityY(litemesh),EntityZ(litemesh),1 PointEntity icucam,source MoveEntity icucam,0,0,-pick_back Dim icu_seen(tri_count) ; prepare scene for ICU scan sz=64;127 ; work around rounding Z errors... remx#=EntityX(source) remy#=EntityY(source) remz#=EntityZ(source) rempitch#=EntityPitch(source) remyaw#=EntityYaw(source) remroll#=EntityRoll(source) PointEntity source,litemesh MoveEntity source,0,0,.1 RotateEntity source, rempitch,remyaw,remroll ; eo work around EntityColor plane,0,0,0 EntityColor source,0,0,0 HideEntity litemesh CameraViewport icucam,0,0,sz+1,sz+1 ;CameraProjMode icucam,1;2 ; better? guess not ;CameraRange icucam,10,5000 ;CameraZoom icucam,10 CameraProjMode icucam,2 CameraRange icucam,0.0002,100 CameraZoom icucam,.0001 CameraProjMode camera,0 ; create ICU render and scan it for valid ID colors RenderWorld() SetBuffer BackBuffer() LockBuffer() For j=0 To sz For i=0 To sz rgb=ReadPixelFast(i,j) And $FFFFFF If( rgb > 0) And (rgb<=tri_count+10) icu_index=rgb-10 icu_seen(icu_index)=icu_seen(icu_index)+1 EndIf Next Next UnlockBuffer() ;PositionEntity source, remx,remy,remz EntityColor plane,0,255,0 EntityColor source,255,255,255 ShowEntity litemesh CameraProjMode icucam,0 CameraProjMode camera,1 ;Flip 0 ; use this for visual control of the ICU render ;WaitKey() ; create a new volume mesh containing the triangles with detected ICU ID colors (visible tris) For i=0 To tri_count-1 If icu_seen(i)>0 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)) 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 Next ; Goto skip_combi ; use this to see the ICU product only! FreeEntity vol ; release old volume vol=vol3 UpdateNormals vol EntityPickMode vol,2 EntityFX vol,1 Or 2 EntityColor vol,0,0,255 RotateEntity vol, EntityPitch(source),EntityYaw(source),EntityRoll(source),1 PositionEntity vol,EntityX(source),EntityY(source),EntityZ(source) ; now we create a new mesh and use the linepick method to scan trough the ; imperfect shadow volume mesh we just created using the ICU method. ; this Linepick method is more accurate, but much slower. Thanks to the ; ICU method we only have to scan a fraction of the first volume mesh. PositionEntity helper ,EntityX(litemesh),EntityY(litemesh),EntityZ(litemesh),1 PointEntity helper,source,0 MoveEntity helper,0,0,-pick_back vol3=CreateMesh() su3=CreateSurface(vol3) su2=GetSurface(vol,1) tri_count=CountTriangles(su2) 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 .skip_combi ; (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 ;so we first created a mesh containig every potential triangle required for the shadow volume mesh. ;then we used the ICU (Identification by Color Uniqueness) Method to make a rough copy of the ;silhouette triangles (= removing enclosed Triangles). This is not very accurate: there are ;still some triangles copied that should not be there. ;so finally we scan this rough silhouette mesh and create a third mesh, containing only the ;picked Silhouette Triangles. End Function
Well right now this is the best I can do. Maybe I'll try it again from scratch one day, with a completely diffrent method, preferably the official math way and not cheats like these.