more Tubes , including animated Tube

Everything related to 3D programming
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

more Tubes , including animated Tube

Post by applePi »

more tubes, better version, than my old post http://purebasic.fr/english/viewtopic.p ... 2&p=425153
the first demo is animating sine tube with physics body and sphere inside the tube. the example is essentially the same as setmeshdata.pb in the purebasic distributions but with tubes instead of the 2D flag
to let the sphere fit inside the hollow tube we need to CreateEntityBody for the tube continuously, but i choose once every 4 times (you can change it from line 197:

Code: Select all

If tot = 4
    CreateEntityBody(1, #PB_Entity_StaticBody , 1, 1, 1)
if tot = 1 means better physics but more slow performance
if you don't want to play with physics just comment the all CreateEntityBody in the code and then it is okay in all PB versions
Image
note that using CreateEntityBody continuously is unofficial

better to try the animation with physics in PB 5.43/44

Code: Select all

DisableDebugger
#CameraSpeed = 0.5
#NUM_BANDS = 16 ;number of points every circle (band) on the tube made from
#BAND_RAD  = 0.5 ;tube thickness

Structure vector3d
  x.f
  y.f
  z.f
EndStructure

Global next_point.vector3d
Global current_point.vector3d
Global T0.vector3d 
Global N0.vector3d 
Global B0.vector3d

;procedures used with (Frenet method) to position a point perpendicular to a point on a 2D CURVE 
 Procedure vector_cross(*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = (*v1\y * *v2\z) - (*v2\y * *v1\z)
    *vout\y = (*v1\z * *v2\x) - (*v2\z * *v1\x)
    *vout\z = (*v1\x * *v2\y) - (*v2\x * *v1\y)
EndProcedure

Procedure.f vector_magnitude(*v.vector3d)
    mag.f
    mag = Sqr(*v\x * *v\x + *v\y * *v\y + *v\z * *v\z)
    If mag = 0:mag = 1:EndIf
    ProcedureReturn mag
EndProcedure

Procedure vector_normalize (*v.vector3d)
    mag.f
    mag = vector_magnitude(*v)
    *v\x = *v\x / mag
    *v\y = *v\y / mag
    *v\z = *v\z / mag
EndProcedure


Procedure vector_add (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x + *v2\x
    *vout\y = *v1\y + *v2\y
    *vout\z = *v1\z + *v2\z
EndProcedure

Procedure vector_sub (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x - *v2\x
    *vout\y = *v1\y - *v2\y
    *vout\z = *v1\z - *v2\z
  EndProcedure


Define.f KeyX, KeyY, MouseX, MouseY
Global rot = 1
Global rings, tot
Global.f AngleVague, WaveFrequency, WavePeriodX, WavePeriodZ, WaveAmplitude
WaveFrequency=2  ;=waves/second
WavePeriodX  =4  ;=1/Wave length
WavePeriodZ  =6 ;=1/Wave length
WaveAmplitude=2; try 0.2
Global Dim TubeData.PB_MeshVertex(0) 

Declare UpdateMatrix()

Global Dim vertex.vector3d(0)

Declare MakeTube (Bands.l,BandRadius.f)
Declare AnimateTube (Bands.l,BandRadius.f)

Quit.b = #False
ExamineDesktops()
OpenWindow(3, 0, 0, DesktopWidth(0), DesktopHeight(0), "tubes ,  W toggle Wire/Solid Frame. ...mouse + arrow keys: to move / rotate the Camera. ...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

;Initialize environment
InitEngine3D()
InitSprite()
InitMouse()
OpenWindowedScreen(WindowID(3), 0, 0, DesktopWidth(0), DesktopHeight(0), 0, 0, 0)
InitKeyboard()
;SetFrameRate(60)
Add3DArchive(".", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts",#PB_3DArchive_FileSystem)
Parse3DScripts()
  
CreateLight(0,RGB(255,255,255),-100,40,30)
AmbientColor(RGB(100,100,100))

CreateCamera(0, 0, 0, 100, 100)
MoveCamera(0, 0, 0, 75)
CameraLookAt(0, 0, 0, 0)
CameraBackColor(0, RGB(255,240,240))

GetScriptMaterial(3, "Scene/GroundBlend")
CreatePlane(3, 100, 100, 5, 5, 5, 5)
CreateEntity(3,MeshID(3),MaterialID(3), 0, -10, 0)
;EntityRenderMode(3, 0) 
CreateEntityBody(3, #PB_Entity_BoxBody, 0, 1, 1)

CreateMaterial(0, LoadTexture(0, "MRAMOR6X6.jpg")) ;"terrain_texture.jpg"
MaterialCullingMode(0, #PB_Material_NoCulling)
MaterialShadingMode(0, #PB_Material_Wireframe)
DisableMaterialLighting(0, #True)
CreateMaterial(2, LoadTexture(2, "Geebee2.bmp"))
MaterialCullingMode(2, #PB_Material_NoCulling)

CreateMesh(1, #PB_Mesh_TriangleList, #PB_Mesh_Static ) ; mesh to make the Tube
SetMeshMaterial(1, MaterialID(0))

MakeTube (#NUM_BANDS, #BAND_RAD )

CreateEntity(1, MeshID(1),MaterialID(0),  0, 4, 0)
ScaleEntity(1,3,3,3)

CreateEntityBody(1, #PB_Entity_StaticBody, 5, 0.4, 1)
GetMeshData(1,0, TubeData(), #PB_Mesh_Vertex | #PB_Mesh_Normal, 0, MeshVertexCount(1,0)-1)

CreateSphere(2,1)
CreateEntity(2, MeshID(2),MaterialID(2),  14, 4, 30)
CreateEntityBody(2, #PB_Entity_SphereBody, 1, 0.1, 5)

ExamineKeyboard()
;WorldDebug(#PB_World_DebugEntity)
;WorldDebug(#PB_World_DebugBody)

Repeat
  Repeat
    Event = WindowEvent()
  Until Event = 0
  If ExamineMouse()
     MouseX = -MouseDeltaX() * #CameraSpeed * 0.3
     MouseY = -MouseDeltaY() * #CameraSpeed * 0.3
   EndIf
  If KeyboardPushed(#PB_Key_Left)
      KeyX = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Right)
      KeyX = #CameraSpeed
      Else
      KeyX = 0
      EndIf
        
  If KeyboardPushed(#PB_Key_Up)
      KeyY = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Down)
      KeyY = #CameraSpeed
      Else
      KeyY = 0
    EndIf
    If KeyboardReleased(#PB_Key_W)
      If w
        MaterialShadingMode(0, #PB_Material_Wireframe) 
      Else
       MaterialShadingMode(0, #PB_Material_Solid)  
      EndIf
      
      w!1
    EndIf
    
          
    If KeyboardReleased(#PB_Key_Space)  ; drop a sphere
      sphere = CreateEntity(#PB_Any, MeshID(2),MaterialID(2),  16, 4, 30)
      CreateEntityBody(sphere, #PB_Entity_SphereBody, 1, 0.1, 5)
    EndIf  
  
   MoveCamera  (0, KeyX, 0, KeyY)
   RotateCamera(0,  MouseY, MouseX, 0, #PB_Relative)
   
    ; Waves
   UpdateMatrix() ; to animate the tube
   
   AngleVague = AngleVague+WaveFrequency ; for the animation equation
   
   RenderWorld()
   FlipBuffers()
   title$="FPS = "+Str(Engine3DStatus(#PB_Engine3D_CurrentFPS ))+" __ rendered triangles = "+Str(Engine3DStatus(#PB_Engine3D_NbRenderedTriangles ))
   title$ + "....'Space': drop a sphere "+".... 'W' toggle Wire/Solid Frame "+"... Mouse+keys: Camera"
   SetWindowTitle(3, title$ )
   
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      Quit = #True
    EndIf
Until Quit = #True Or Event = #PB_Event_CloseWindow

Procedure UpdateMatrix()
  Protected.l a, b, c
  i=0
  x.f = -6 :i = 0
  While x <= 6
    vertex(i)\y=Sin(Radian((AngleVague+i*WavePeriodX+i*WavePeriodZ)))*WaveAmplitude
    i + 1
    x+0.1
  Wend
  ;to make less impact on the 3D engine we do CreateEntityBody every 4 times, the best is every loop but with big impact especialy on versions >= 5.50
  tot+1
  If tot = 4
    CreateEntityBody(1, #PB_Entity_StaticBody , 1, 1, 1)
    tot=0
  EndIf
  
  AnimateTube(#NUM_BANDS, #BAND_RAD)
   
EndProcedure



Procedure  MakeTube (Bands.l, BandRadius.f)
  x.f: y.f: z.f
  txu.f : txv.f
  
  x = -6 :i = 0
  While x <= 6
      ReDim vertex.vector3d(i)
      vertex(i)\x   = x
      vertex(i)\y   = Sin(x); we will modify this value contineously during the animation procedure
      vertex(i)\z   = 10 ; we will TransforMesh the mesh Later by -10 to center it
      i + 1              ; so it rotate around itself and not in orbit
      x + 0.1
      
     Wend
     
     rings = i-1
    ;Debug rings
     For i = 0 To rings-1
        ;center point
        current_point\x = vertex(i)\x 
        current_point\y = vertex(i)\y
        current_point\z = vertex(i)\z

        ;next point (For Frenet square method)
        
        next_point\x = vertex(i+1)\x 
        next_point\y = vertex(i+1)\y
        next_point\z = vertex(i+1)\z

        ;T  = P' - P
        vector_sub(next_point, current_point, T0)
        ;N = P' + P
        vector_add(next_point, current_point, N0)
        ;B = T x N
        vector_cross(T0, N0, B0)
        ;N = B x T
        vector_cross(B0, T0, N0)
        ;Normalize vectors Or Else it won't work
        vector_normalize(B0)
        vector_normalize(N0)
        
        For j = 0 To bands - 0
           new_point_x.f
           new_point_y.f
              
            ;rotate around the current point using normal rotation to makes a band (ie a circle around the point on the 2D curve)
            new_point_x = Sin(j * 2 * #PI  / bands) * #BAND_RAD
            new_point_y = Cos(j * 2 * #PI  / bands) * #BAND_RAD
            
            ;this is the corrected coordinates of our point in the band (the circle) (we need 16 points to make a circle)
            x = N0\x * new_point_x + B0\x * new_point_y + current_point\x
            y = N0\y * new_point_x + B0\y * new_point_y + current_point\y
            z = N0\z * new_point_x + B0\z * new_point_y + current_point\z       
            MeshVertexPosition(x, y, z)
            MeshVertexTextureCoordinate(txu, txv)
            MeshVertexNormal(x, y, z)
            txv = txv + 1/bands ; for texturing
                         
         Next 
         txv = 0
         txu = txu + 1/bands ; for texturing
      Next 
      
      v.l
      
      For i = 0 To rings - 1
      For j = 0 To bands - 1
          MeshFace(v,v+1,v + bands+1)
          MeshFace(v + bands+1,v + bands+2,v+1 )
          
          v + 1   
          
      Next
    Next
    FinishMesh(1)
    UpdateMeshBoundingBox(1)
    NormalizeMesh(1)


  EndProcedure
  
  

Procedure  AnimateTube (Bands.l, BandRadius.f)
  ;we just make use of the contineously changing array vertex(i)\x|y|z to calculate -->
  ;the coordinates of TubeData(pnt)\x|y|z With SetMeshData To animate the Tube Mesh    
  pnt = 0
  x.f: y.f: z.f
  txu.f : txv.f
  
       For i = 0 To rings-1 ; number of rings is known from the MakeTube procedure
        ;center point
        current_point\x = vertex(i)\x 
        current_point\y = vertex(i)\y
        current_point\z = vertex(i)\z

        ;next point (For Frenet square method)
        
        next_point\x = vertex(i+1)\x 
        next_point\y = vertex(i+1)\y
        next_point\z = vertex(i+1)\z

        ;T  = P' - P
        vector_sub(next_point, current_point, T0)
        ;N = P' + P
        vector_add(next_point, current_point, N0)
        ;B = T x N
        vector_cross(T0, N0, B0)
        ;N = B x T
        vector_cross(B0, T0, N0)
        ;Normalize vectors Or Else it won't work
        vector_normalize(B0)
        vector_normalize(N0)
        
        For j = 0 To bands - 0
           new_point_x.f
           new_point_y.f
              
            ;rotate around the current point using normal rotation to makes a band (ie a circle around the point on the 2D curve)
            new_point_x = Sin(j * 2 * #PI  / bands) * #BAND_RAD
            new_point_y = Cos(j * 2 * #PI  / bands) * #BAND_RAD
            
            ;this is the corrected coordinates of our point in the band (the circle) (we need 16 points to make a circle)
            x = N0\x * new_point_x + B0\x * new_point_y + current_point\x
            y = N0\y * new_point_x + B0\y * new_point_y + current_point\y
            z = N0\z * new_point_x + B0\z * new_point_y + current_point\z
            
            TubeData(pnt)\x = x
            TubeData(pnt)\y = y
            TubeData(pnt)\z = z
                
          pnt + 1               
         Next 
         
      Next 
      SetMeshData(1, 0, TubeData(), #PB_Mesh_Vertex | #PB_Mesh_Normal, 0, MeshVertexCount(1,0)-1)
      ;UpdateMeshBoundingBox(1)
    EndProcedure

2- Toroidal spiral tube
Image

Code: Select all

#CameraSpeed = 0.2
#NUM_BANDS = 16 ;number of points every circle (band) on the tube made from
#BAND_RAD  = 0.7 ;tube thickness
Define.f KeyX, KeyY, MouseX, MouseY
Global rot = 1
Global rings
Global NbX = #NUM_BANDS
Global NbZ

Structure vector3d
  x.f
  y.f
  z.f
EndStructure

 Global next_point.vector3d
 Global current_point.vector3d
 Global T0.vector3d 
 Global N0.vector3d 
 Global B0.vector3d
 
;procedures used with (Frenet method) to position a point perpendicular to a point on a 2D CURVE 
 Procedure vector_cross(*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = (*v1\y * *v2\z) - (*v2\y * *v1\z)
    *vout\y = (*v1\z * *v2\x) - (*v2\z * *v1\x)
    *vout\z = (*v1\x * *v2\y) - (*v2\x * *v1\y)
EndProcedure

Procedure.f vector_magnitude(*v.vector3d)
    mag.f
    mag = Sqr(*v\x * *v\x + *v\y * *v\y + *v\z * *v\z)
    If mag = 0:mag = 1:EndIf
    ProcedureReturn mag
EndProcedure

Procedure vector_normalize (*v.vector3d)
    mag.f
    mag = vector_magnitude(*v)
    *v\x = *v\x / mag
    *v\y = *v\y / mag
    *v\z = *v\z / mag
EndProcedure


Procedure vector_add (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x + *v2\x
    *vout\y = *v1\y + *v2\y
    *vout\z = *v1\z + *v2\z
EndProcedure

Procedure vector_sub (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x - *v2\x
    *vout\y = *v1\y - *v2\y
    *vout\z = *v1\z - *v2\z
  EndProcedure

Global Dim vertex.vector3d(0)

Declare MakeTube (Bands.l,BandRadius.f)

Quit.b = #False
ExamineDesktops()
OpenWindow(3, 0, 0, DesktopWidth(0), DesktopHeight(0), "tubes  , 'W' toggle wire/solid Frame ... 'space' rotate/stop. ...mouse + arrow keys to move the Camera. ...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

;Initialize environment
InitEngine3D()
InitSprite()
InitMouse()
OpenWindowedScreen(WindowID(3), 0, 0, DesktopWidth(0), DesktopHeight(0), 0, 0, 0)
InitKeyboard()
;SetFrameRate(60)
Add3DArchive(".", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)

CreateLight(0,RGB(255,255,255),-100,40,30)
AmbientColor(RGB(100,100,100))

CreateCamera(0, 0, 0, 100, 100)
MoveCamera(0, 0, 0, 35,#PB_Absolute)
CameraLookAt(0, 0, 0, 0)

CreateMaterial(0, LoadTexture(0, "MRAMOR6X6.jpg")) ;"ground_diffuse.png" 
MaterialCullingMode(0, #PB_Material_NoCulling)
;MaterialShadingMode(0, #PB_Material_Wireframe)
DisableMaterialLighting(0, #True)

CreateMesh(1, #PB_Mesh_TriangleList, #PB_Mesh_Static )
SetMeshMaterial(1, MaterialID(0))

MakeTube (#NUM_BANDS, #BAND_RAD )

NormalizeMesh(1)
FinishMesh(1)

UpdateMeshBoundingBox(1)

CreateEntity(1, MeshID(1), MaterialID(0))

CreateLine3D(10,-15,0,0,RGB(255,0,0), 15,0,0,RGB(255,0,0))
CreateLine3D(11,0,-15,0,RGB(255,0,0), 0,15,0,RGB(255,0,0))
ExamineKeyboard()

Repeat
  Repeat
    Event = WindowEvent()
  Until Event = 0
  If ExamineMouse()
     MouseX = -MouseDeltaX() * #CameraSpeed * 0.5
     MouseY = -MouseDeltaY() * #CameraSpeed * 0.5
   EndIf
  If KeyboardPushed(#PB_Key_Left)
      KeyX = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Right)
      KeyX = #CameraSpeed
      Else
      KeyX = 0
      EndIf
        
  If KeyboardPushed(#PB_Key_Up)
      KeyY = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Down)
      KeyY = #CameraSpeed
      Else
      KeyY = 0
    EndIf
    If KeyboardReleased(#PB_Key_W)
      If w
        MaterialShadingMode(0, #PB_Material_Solid) 
      Else
       MaterialShadingMode(0, #PB_Material_Wireframe)  
      EndIf
      
      w!1
    EndIf
    
          
  If KeyboardReleased(#PB_Key_Space)  ; rotate left
    rot! 1 
  EndIf  
      
  ;RotateEntity(1,0,1*rot,0, #PB_Relative)
  RotateEntity(1,  0, 0.5*rot, 0, #PB_Relative)
   MoveCamera  (0, KeyX, 0, KeyY)
   RotateCamera(0,  MouseY, MouseX, 0, #PB_Relative)
   
   RenderWorld()
   FlipBuffers()
   
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      Quit = #True
    EndIf
Until Quit = #True Or Event = #PB_Event_CloseWindow


Procedure  MakeTube (Bands.l, BandRadius.f)

Protected.f x, y, z, a1, b1, n1
txu.f : txv.f
angle.f = 0: incr.f = 0.01
  i = 0
  a1 = 0.2: b1.f=0.8 : n1=10: x=0
      While angle <= 2*#PI
      
      x=(a1*Sin(n1*angle)+b1)*Cos(angle)
      y=(a1*Sin(n1*angle)+b1)*Sin(angle)
      z=a1*Cos(n1*angle)
      vertex(i)\x  = x*10; 10 is the amplification
      vertex(i)\y  = y*10
      vertex(i)\z  = z*10 
      
      i + 1
      angle + incr
      ReDim vertex.vector3d(i)
                  
    Wend
    ; another one point for the Ferret procedure (to calculate the last ring)
    ReDim vertex.vector3d(i+1)
    x=(a1*Sin(n1*angle)+b1)*Cos(angle)
    y=(a1*Sin(n1*angle)+b1)*Sin(angle)
    z=a1*Cos(n1*angle)
    vertex(i)\x   = x*10
    vertex(i)\y   = y*10
    vertex(i)\z   = z*10
      

    rings = i
    NbZ = rings
     ;Debug rings
     For i = 0 To rings
        ;center point
        current_point\x = vertex(i)\x 
        current_point\y = vertex(i)\y
        current_point\z = vertex(i)\z

        ;next point (For Frenet square method)
        
        next_point\x = vertex(i+1)\x 
        next_point\y = vertex(i+1)\y
        next_point\z = vertex(i+1)\z

        ;T  = P' - P
        vector_sub(next_point, current_point, T0)
        ;N = P' + P
        vector_add(next_point, current_point, N0)
        ;B = T x N
        vector_cross(T0, N0, B0)
        ;N = B x T
        vector_cross(B0, T0, N0)
        ;Normalize vectors Or Else it won't work
        vector_normalize(B0)
        vector_normalize(N0)
        
        
        For j = 0 To bands
           new_point_x.f
           new_point_y.f
              
            ;rotate around the current point using normal rotation to makes a band (ie a circle around the point on the 2D curve)
            new_point_x = Sin(j * 2 * #PI  / bands) * #BAND_RAD
            new_point_y = Cos(j * 2 * #PI  / bands) * #BAND_RAD
            
            ;this is the corrected coordinates of our point in the band (the circle) (we need 16 points to make a circle)
            x = N0\x * new_point_x + B0\x * new_point_y + current_point\x
            y = N0\y * new_point_x + B0\y * new_point_y + current_point\y
            z = N0\z * new_point_x + B0\z * new_point_y + current_point\z
            
            MeshVertexPosition(x, y, z)
            MeshVertexTextureCoordinate(txu, txv)
            MeshVertexNormal(x, y, z)
            txv = txv + 1/bands
                         
         Next 
         txv = 0
         txu = txu + 1/bands 
      Next 
   
  Protected.l a, b, c, Nb
  Protected.w P1, P2, P3, P4
     
  Nb=NbX+1
  NbZ = rings
  ;Debug NbZ
  For b=0 To NbZ-2
    For a=0 To NbX-1
      P1=a+(b*Nb)
      P2=P1+1
      P3=a+(b+1)*Nb
      P4=P3+1
     
      MeshFace(P3, P2, P1)
      MeshFace(P2, P3, P4)
    Next
  Next
 
 EndProcedure
 
 
  
3- Archimedean spiral tube expanded into 3D shape
Image

Code: Select all

#CameraSpeed = 0.5
#NUM_BANDS = 16 ;number of points every circle (band) on the tube made from
#BAND_RAD  = 0.7 ;tube thickness
Define.f KeyX, KeyY, MouseX, MouseY
Global rot = 1
Global rings
Global NbX = #NUM_BANDS
Global NbZ

Structure vector3d
  x.f
  y.f
  z.f
EndStructure

 Global next_point.vector3d
 Global current_point.vector3d
 Global T0.vector3d 
 Global N0.vector3d 
 Global B0.vector3d
 
;procedures used with (Frenet method) to position a point perpendicular to a point on a 2D CURVE 
 Procedure vector_cross(*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = (*v1\y * *v2\z) - (*v2\y * *v1\z)
    *vout\y = (*v1\z * *v2\x) - (*v2\z * *v1\x)
    *vout\z = (*v1\x * *v2\y) - (*v2\x * *v1\y)
EndProcedure

Procedure.f vector_magnitude(*v.vector3d)
    mag.f
    mag = Sqr(*v\x * *v\x + *v\y * *v\y + *v\z * *v\z)
    If mag = 0:mag = 1:EndIf
    ProcedureReturn mag
EndProcedure

Procedure vector_normalize (*v.vector3d)
    mag.f
    mag = vector_magnitude(*v)
    *v\x = *v\x / mag
    *v\y = *v\y / mag
    *v\z = *v\z / mag
EndProcedure


Procedure vector_add (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x + *v2\x
    *vout\y = *v1\y + *v2\y
    *vout\z = *v1\z + *v2\z
EndProcedure

Procedure vector_sub (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x - *v2\x
    *vout\y = *v1\y - *v2\y
    *vout\z = *v1\z - *v2\z
  EndProcedure

Global Dim vertex.vector3d(0)

Declare MakeTube (Bands.l,BandRadius.f)

Quit.b = #False
ExamineDesktops()
OpenWindow(3, 0, 0, DesktopWidth(0), DesktopHeight(0), "tubes , 'Space': rotate/stop. ...mouse + arrow keys to move the Camera. ...'W' Wire/Solid Frame", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

;Initialize environment
InitEngine3D()
InitSprite()
InitMouse()
OpenWindowedScreen(WindowID(3), 0, 0, DesktopWidth(0), DesktopHeight(0), 0, 0, 0)
InitKeyboard()
;Add3DArchive(".", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)

CreateLight(0,RGB(255,255,255),-100,40,30)
AmbientColor(RGB(100,100,100))

CreateCamera(0, 0, 0, 100, 100)
MoveCamera(0, 0, 15, 20)
CameraLookAt(0, 0, -10, 0)

CreateMaterial(0, LoadTexture(0, "MRAMOR6X6.jpg"))
MaterialCullingMode(0, #PB_Material_NoCulling)
;MaterialShadingMode(0, #PB_Material_Wireframe)
DisableMaterialLighting(0, #True)

CreateMesh(1, #PB_Mesh_TriangleList, #PB_Mesh_Static )
SetMeshMaterial(1, MaterialID(0))

MakeTube (#NUM_BANDS, #BAND_RAD )

NormalizeMesh(1)
FinishMesh(1)

UpdateMeshBoundingBox(1)

CreateEntity(1, MeshID(1), MaterialID(0))
RotateEntity(1, 90,0,0)

ExamineKeyboard()
y.f
Repeat
  Repeat
    Event = WindowEvent()
  Until Event = 0
  If ExamineMouse()
     MouseX = -MouseDeltaX() * #CameraSpeed * 0.5
     MouseY = -MouseDeltaY() * #CameraSpeed * 0.5
   EndIf
  If KeyboardPushed(#PB_Key_Left)
      KeyX = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Right)
      KeyX = #CameraSpeed
      Else
      KeyX = 0
      EndIf
        
  If KeyboardPushed(#PB_Key_Up)
      KeyY = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Down)
      KeyY = #CameraSpeed
      Else
      KeyY = 0
    EndIf
    If KeyboardReleased(#PB_Key_W)
      If w
        MaterialShadingMode(0, #PB_Material_Solid) 
      Else
       MaterialShadingMode(0, #PB_Material_Wireframe)  
      EndIf
      
      w!1
    EndIf
          
  If KeyboardReleased(#PB_Key_Space)  ; rotate left
    rot! 1 
  EndIf  
      
   RotateEntity(1,0,0,0.2*rot, #PB_Relative)
   MoveCamera  (0, KeyX, 0, KeyY)
   RotateCamera(0,  MouseY, MouseX, 0, #PB_Relative)
   
   RenderWorld()
   FlipBuffers()
   
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      Quit = #True
    EndIf
Until Quit = #True Or Event = #PB_Event_CloseWindow


Procedure  MakeTube (Bands.l, BandRadius.f)

Protected.f a1, b1, x, y, z

radius.f: incr.f=0.1: up.f
txu.f : txv.f
i = 0:angle.f
a1 = 0.4: b1=0.5
  
    While angle <= 6*#PI
      radius = a1 + b1*angle
      x = radius * Cos(angle)
      y = radius * Sin(angle)
      
      vertex(i)\x  = x
      vertex(i)\y  = y
      vertex(i)\z  = up
      i + 1      
      ReDim vertex.vector3d(i)
      angle + incr
      up.f + 0.1 ; for expanding into z direction from the 2D curve
      
    Wend
    
    ;another one point for the Ferret procedure (to calculate the last ring)
    ReDim vertex.vector3d(i+1)
    radius = a1 + b1*angle
      x = radius * Cos(angle)
      y = radius * Sin(angle)
      
      vertex(i)\x  = x
      vertex(i)\y  = y
      vertex(i)\z  = up
      

     rings = i
    NbZ = rings
     ;Debug rings
     For i = 0 To rings
        ;center point
        current_point\x = vertex(i)\x 
        current_point\y = vertex(i)\y
        current_point\z = vertex(i)\z

        ;next point (For Frenet square method)
        
        next_point\x = vertex(i+1)\x 
        next_point\y = vertex(i+1)\y
        next_point\z = vertex(i+1)\z

        ;T  = P' - P
        vector_sub(next_point, current_point, T0)
        ;N = P' + P
        vector_add(next_point, current_point, N0)
        ;B = T x N
        vector_cross(T0, N0, B0)
        ;N = B x T
        vector_cross(B0, T0, N0)
        ;Normalize vectors Or Else it won't work
        vector_normalize(B0)
        vector_normalize(N0)
        
        For j = 0 To bands - 0
           new_point_x.f
           new_point_y.f
              
            ;rotate around the current point using normal rotation to makes a band (ie a circle around the point on the 2D curve)
            new_point_x = Sin(j * 2 * #PI  / bands) * #BAND_RAD
            new_point_y = Cos(j * 2 * #PI  / bands) * #BAND_RAD
            
            ;this is the corrected coordinates of our point in the band (the circle) (we need 16 points to make a circle)
            x = N0\x * new_point_x + B0\x * new_point_y + current_point\x
            y = N0\y * new_point_x + B0\y * new_point_y + current_point\y
            z = N0\z * new_point_x + B0\z * new_point_y + current_point\z
            
            MeshVertexPosition(x, y, z)
            MeshVertexTextureCoordinate(txu, txv)
            MeshVertexNormal(x, y, z)
            txv = txv + 1/bands
                         
         Next 
         txv = 0
         txu = txu + 1/bands 
      Next 
      
  Protected.l a, b, c, Nb
  Protected.w P1, P2, P3, P4
     
  Nb=NbX+1
  NbZ = rings
  ;Debug NbZ
  For b=0 To NbZ-2
    For a=0 To NbX-1
      P1=a+(b*Nb)
      P2=P1+1
      P3=a+(b+1)*Nb
      P4=P3+1
     
      MeshFace(P3, P2, P1)
      MeshFace(P2, P3, P4)
    Next
  Next
    
 EndProcedure
 
Last edited by applePi on Tue May 01, 2018 4:00 pm, edited 2 times in total.
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: more Tubes , including animated Tube

Post by DK_PETER »

Most interesting, applePi.
Thanks for sharing. :)
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: more Tubes , including animated Tube

Post by IdeasVacuum »

That's brilliant stuff applePi - what brand of coffee are you on? :mrgreen:
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: more Tubes , including animated Tube

Post by Kwai chang caine »

Like usually very nice
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: more Tubes , including animated Tube

Post by applePi »

Thank you all
updating the second and third examples above, to reflect the fact that if the tube have 60 rings then we need 61 points on the curve, the extra point on the curve is necessary to orient the last tube ring correctly with the frenet procedure. look the picture
Image

the purpose is to make the ends of the tubes clean and circular, look at the tiny cut in the toroidal example you see it is clean and circular in contrast to the previous code. also i have used the setmeshdata.pb way of weaving the triangles.

for the toroidal spiral tube example line 162 change n1 to 0 and we get a torus, n1=20 more coils
play with a1, b1

the following demo plot Exponential Function y=2^x
https://people.richland.edu/james/lectu ... ntial.html
Image
Image

try also y=x^2 , but note when you change the equation in line 166 change it also in line 176 for the extra point

Code: Select all

#CameraSpeed = 0.3
#NUM_BANDS = 16 ;number of points every circle (band) on the tube made from
#BAND_RAD  = 0.2 ;tube thickness
Define.f KeyX, KeyY, MouseX, MouseY
Global rot = 1
Global rings
Global NbX = #NUM_BANDS
Global NbZ

Structure vector3d
  x.f
  y.f
  z.f
EndStructure

 Global next_point.vector3d
 Global current_point.vector3d
 Global T0.vector3d 
 Global N0.vector3d 
 Global B0.vector3d
 
;procedures used with (Frenet method) to position a point perpendicular to a point on a 2D CURVE 
 Procedure vector_cross(*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = (*v1\y * *v2\z) - (*v2\y * *v1\z)
    *vout\y = (*v1\z * *v2\x) - (*v2\z * *v1\x)
    *vout\z = (*v1\x * *v2\y) - (*v2\x * *v1\y)
EndProcedure

Procedure.f vector_magnitude(*v.vector3d)
    mag.f
    mag = Sqr(*v\x * *v\x + *v\y * *v\y + *v\z * *v\z)
    If mag = 0:mag = 1:EndIf
    ProcedureReturn mag
EndProcedure

Procedure vector_normalize (*v.vector3d)
    mag.f
    mag = vector_magnitude(*v)
    *v\x = *v\x / mag
    *v\y = *v\y / mag
    *v\z = *v\z / mag
EndProcedure


Procedure vector_add (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x + *v2\x
    *vout\y = *v1\y + *v2\y
    *vout\z = *v1\z + *v2\z
EndProcedure

Procedure vector_sub (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x - *v2\x
    *vout\y = *v1\y - *v2\y
    *vout\z = *v1\z - *v2\z
  EndProcedure

Global Dim vertex.vector3d(0)

Declare MakeTube (Bands.l,BandRadius.f)

Quit.b = #False
ExamineDesktops()
OpenWindow(3, 0, 0, DesktopWidth(0), DesktopHeight(0), "tubes , 'space' rotate/stop. .... W toggle wire/solid Frame ..... mouse and arrow keys to move the Camera. ...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

;Initialize environment
InitEngine3D()
InitSprite()
InitMouse()
OpenWindowedScreen(WindowID(3), 0, 0, DesktopWidth(0), DesktopHeight(0), 0, 0, 0)
InitKeyboard()
;SetFrameRate(60)
Add3DArchive(".", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)

CreateLight(0,RGB(255,255,255),-100,40,30)
AmbientColor(RGB(100,100,100))

CreateCamera(0, 0, 0, 100, 100)
MoveCamera(0, 0, 4, 25,#PB_Absolute)
CameraLookAt(0, 0, 4, 0)

CreateMaterial(0, LoadTexture(0, "ground_diffuse.png"))
MaterialCullingMode(0, #PB_Material_NoCulling)
;MaterialShadingMode(0, #PB_Material_Wireframe)
DisableMaterialLighting(0, #True)


CreateMesh(1, #PB_Mesh_TriangleList, #PB_Mesh_Static )
SetMeshMaterial(1, MaterialID(0))

MakeTube (#NUM_BANDS, #BAND_RAD )

NormalizeMesh(1)
FinishMesh(1)

TransformMesh(1,0,0,-10,1,1,1,0,0,0)
UpdateMeshBoundingBox(1)

CreateEntity(1, MeshID(1), MaterialID(0))

CreateLine3D(10,-3,0,0,RGB(255,0,0), 3,0,0,RGB(255,0,0))
CreateLine3D(11,0,0,0,RGB(255,0,0), 0,8,0,RGB(255,0,0))
CreateLine3D(12,0,8,0,RGB(255,255,0), 4,8,0,RGB(255,255,0))
ExamineKeyboard()
rot = 0
Repeat
  Repeat
    Event = WindowEvent()
  Until Event = 0
  If ExamineMouse()
     MouseX = -MouseDeltaX() * #CameraSpeed * 0.5
     MouseY = -MouseDeltaY() * #CameraSpeed * 0.5
   EndIf
  If KeyboardPushed(#PB_Key_Left)
      KeyX = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Right)
      KeyX = #CameraSpeed
      Else
      KeyX = 0
      EndIf
        
  If KeyboardPushed(#PB_Key_Up)
      KeyY = -#CameraSpeed
      ElseIf KeyboardPushed(#PB_Key_Down)
      KeyY = #CameraSpeed
      Else
      KeyY = 0
    EndIf
    If KeyboardReleased(#PB_Key_W)
      If w
        MaterialShadingMode(0, #PB_Material_Solid) 
      Else
       MaterialShadingMode(0, #PB_Material_Wireframe)  
      EndIf
      
      w!1
    EndIf
    
          
  If KeyboardReleased(#PB_Key_Space)  ; rotate left
    rot! 1 
  EndIf  
      
   RotateEntity(1,0,1*rot,0, #PB_Relative)
   MoveCamera  (0, KeyX, 0, KeyY)
   RotateCamera(0,  MouseY, MouseX, 0, #PB_Relative)
   
   RenderWorld()
   FlipBuffers()
   
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      Quit = #True
    EndIf
Until Quit = #True Or Event = #PB_Event_CloseWindow


Procedure  MakeTube (Bands.l, BandRadius.f)

Protected.f x, y, z
txu.f : txv.f
x.f = -3: i=0
    While x <= 3

      vertex(i)\x   = x
      vertex(i)\y   = Pow(2,x);try also Pow(x,2)
      vertex(i)\z  = 10
      i + 1              ; so it rotate around itself and not in orbit
      ReDim vertex.vector3d(i)
      x + 0.1 ; number of rings depends on x value
    Wend
    
    ; another one point for the Ferret procedure (to calculate the last ring)
    ReDim vertex.vector3d(i+1)
    vertex(i)\x   = x
    vertex(i)\y   = Pow(2,x); try also Pow(x,2)
    vertex(i)\z  = 10
      

    ;rings = i-1
    rings = i
    NbZ = rings
     ;Debug rings
     For i = 0 To rings
        ;center point
        current_point\x = vertex(i)\x 
        current_point\y = vertex(i)\y
        current_point\z = vertex(i)\z

        ;next point (For Frenet square method)
        
        next_point\x = vertex(i+1)\x 
        next_point\y = vertex(i+1)\y
        next_point\z = vertex(i+1)\z

        ;T  = P' - P
        vector_sub(next_point, current_point, T0)
        ;N = P' + P
        vector_add(next_point, current_point, N0)
        ;B = T x N
        vector_cross(T0, N0, B0)
        ;N = B x T
        vector_cross(B0, T0, N0)
        ;Normalize vectors Or Else it won't work
        vector_normalize(B0)
        vector_normalize(N0)
        
        
        For j = 0 To bands
           new_point_x.f
           new_point_y.f
              
            ;rotate around the current point using normal rotation to makes a band (ie a circle around the point on the 2D curve)
            new_point_x = Sin(j * 2 * #PI  / bands) * #BAND_RAD
            new_point_y = Cos(j * 2 * #PI  / bands) * #BAND_RAD
            
            ;this is the corrected coordinates of our point in the band (the circle) (we need 16 points to make a circle)
            x = N0\x * new_point_x + B0\x * new_point_y + current_point\x
            y = N0\y * new_point_x + B0\y * new_point_y + current_point\y
            z = N0\z * new_point_x + B0\z * new_point_y + current_point\z
            
            MeshVertexPosition(x, y, z)
            MeshVertexTextureCoordinate(txu, txv)
            MeshVertexNormal(x, y, z)
            txv = txv + 1/bands
                         
         Next 
         txv = 0
         txu = txu + 1/bands 
      Next 
      
      v.l
  Protected.l a, b, c, Nb
  Protected.w P1, P2, P3, P4
     
  Nb=NbX+1
  NbZ = rings
  ;Debug NbZ
  For b=0 To NbZ-2
    For a=0 To NbX-1
      P1=a+(b*Nb)
      P2=P1+1
      P3=a+(b+1)*Nb
      P4=P3+1
     
      MeshFace(P3, P2, P1)
      MeshFace(P2, P3, P4)
    Next
  Next
 
 EndProcedure
 
 
  
Post Reply