Useful Cylinder Deformations

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

Useful Cylinder Deformations

Post by applePi »

info for the new users to enjoy deforming meshes:
after creating a mesh (such as sphere, cylinder, robot, etc ) and then creating an entity (instance of a mesh) to use in the (real world: inside the screen)
how to deform that mesh ?? :
1- Load the mesh content to a special array using GetMeshData (contents:vertices positions+color+normal+uv)
2- change the values in the array \x\y\z according to a formula or any rule you want
3- save the contents of the array again to the mesh using SetMeshData
4- use UpdateMeshBoundingBox(mesh)
thats it all what is needed. after step 4 the mesh will have the new shape.
it seems interesting to change also the colors and normals, but i haven't tried it yet.

note: while deforming , i have found that using CreateEntityBody(#cyl, #PB_Entity_StaticBody contineously inside the deforming procedure will prevent the falling sphere from penetrating the deformed cylinder, when the sphere over the hole if we expand the hole radius the sphere will fall down correctly.
UpdateMesh(cyl, 0), UpdateMeshBoundingBox(cyl), DisableEntityBody(cyl, 0) in this special case does not work

infinity of shapes you can make by pressing the correct keys. for operations guide look the program Title bar
note 2: you can change the NbBaseSegments other than 16 such as 4

Image

tested with PB 5.42 beta 1 in windows xp 32, in older PB versions the cylinder spec may be different and the following code will not work as intended

Code: Select all

Enumeration
   #camera
   #Plane
      
EndEnumeration

Define.f KeyX, KeyY, MouseX, MouseY
Declare deform(radius.f, y.f)
Declare deformTop(radius.f, TopY.f)

Global Dim MeshData.PB_MeshVertex(0) ;array for loading and
Global.f angle, radius.f = 0.7, y.f, radiusTop = 3, topY=5
Global NbBaseSegments

ExamineDesktops()
If OpenWindow(0, 0, 0, DesktopWidth(0), DesktopHeight(0), "Arrows: to change hole diameter and position...J/K..LI same for top hole.... Space: wire/solid Frame...P stop/rotate ", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

If InitEngine3D()
  
  ;Add3DArchive(".", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts",#PB_3DArchive_FileSystem)
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
  OpenWindowedScreen(WindowID(0), 0, 20, WindowWidth(0)-50, WindowHeight(0)-60, 0, 0, 0) 
              
    CreateCamera(#camera, 0, 0, 100, 100)
    MoveCamera(#camera, 0, 10, 20, #PB_Absolute)
    CameraBackColor(#camera, RGB(250,250,250))
    CameraLookAt(#camera,0,0,0)
        
    CreateLight(0, RGB(255,255,255), 0, 0, 20)
    AmbientColor(RGB(200, 200, 200))

    CreateMaterial(5, LoadTexture(5, "Geebee2.bmp"))
    MaterialCullingMode(5, #PB_Material_NoCulling)
    MaterialShadingMode(5, #PB_Material_Wireframe)
    
    NbBaseSegments = 16
    CreateCylinder(5,3,10, NbBaseSegments, 2,0) 
           
    GetMeshData(5,0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)
    ;building the cylinder with hole in the bottom
    angle.f=0: radius.f = 0.7
    For i=0 To NbBaseSegments
      x.f=MeshData(i)\x 
      z.f=MeshData(i)\z 
      ;circle formula:
      x2.f=radius * Cos(angle)
      z2.f=radius * Sin(angle)
      y2.f = 0
      ;filling the array with the new vertices coordinates
      MeshData(i)\x = x2: MeshData(i)\z = z2: MeshData(i)\y = y2
      If i=0
      ;to save the coordinates of the last vertex in the circle to equal -->
      ;the coordinates of the first vertex in the circle  
        x3.f=x2: y3.f=y2: z3.f=z2
      EndIf
      
      angle.f + #PI*2/NbBaseSegments
    Next
    
    MeshData(NbBaseSegments)\x = x3
    MeshData(NbBaseSegments)\y = y3
    MeshData(NbBaseSegments)\z = z3
    
    SetMeshData(5, 0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)
    UpdateMeshBoundingBox(5)
    CreateEntity(5, MeshID(5), MaterialID(5), 0,0,0)
       
    CreateSphere(2, 0.8)
    CreateEntity(2, MeshID(2), GetScriptMaterial(1, "Color/Blue"), 0, 6,0 )
    
    CreateEntityBody(5, #PB_Entity_StaticBody , 1, 0.7, 1)
    CreateEntityBody(2, #PB_Entity_SphereBody , 1, 1, 1) 
   
    vert = 0: angle = 0: rot=1
    Repeat
       Repeat 
        event = WindowEvent()
       Until event = 0
      StartDrawing(WindowOutput(0))
      ;DrawText(440, 1, "FPS: "+ StrF(Engine3DStatus(#PB_Engine3D_CurrentFPS )))
      DrawText(440, 1, "Vertex No. : "+ Str(vert-1))
      StopDrawing()
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/20 
        MouseY = -MouseDeltaY()/20
      EndIf
      
          
      If ExamineKeyboard()
        If KeyboardPushed(#PB_Key_Left) ; widening or narrowing a hole
          radius + 0.02: angle=0: ;y=0
          deform (radius, y)
        ElseIf KeyboardPushed(#PB_Key_Right)
          radius - 0.02: angle=0: ;y=0
          deform (radius, y)
        ElseIf KeyboardPushed(#PB_Key_Down)
          y - 0.02:angle = 0
          deform(radius, y)
        ElseIf KeyboardPushed(#PB_Key_Up) 
         y + 0.02:angle = 0
          deform(radius, y) 
        EndIf
        
        If KeyboardPushed(#PB_Key_J)
          radiusTop + 0.02: angle=0
          deformTop(radiusTop, topY)
        ElseIf KeyboardPushed(#PB_Key_L)
          radiusTop - 0.02: angle=0
          deformTop(radiusTop, topY)
          ElseIf KeyboardPushed(#PB_Key_K)
          TopY - 0.02:angle = 0
          deformTop(radiusTop, topY)
          ElseIf KeyboardPushed(#PB_Key_I)
          TopY + 0.02:angle = 0
          deformTop(radiusTop, topY)
        EndIf
                  
    
        If KeyboardReleased(#PB_Key_P)  
          rot ! 1
        EndIf
                
        ;moving the camera ================================================
        If KeyboardPushed(#PB_Key_A)
          KeyX = -1
        ElseIf KeyboardPushed(#PB_Key_D)
          KeyX = 1
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_W)
          KeyY = -1
        ElseIf KeyboardPushed(#PB_Key_S)
          KeyY = 1
        Else
          KeyY = 0
        EndIf
        ;==================================================================
        ; wire or solid frame
        If KeyboardReleased(#PB_Key_Space)
          If wireFrame
             MaterialShadingMode(5, #PB_Material_Wireframe)
          wireFrame ! 1
        Else 
          MaterialShadingMode(5, #PB_Material_Solid)
          wireFrame ! 1
        EndIf
        EndIf
               
        
        If KeyboardReleased(#PB_Key_C) 
          ;To use this utility disable sphere physics and make it smaller
          ; its purpose to jupm to vertices in order according to its index
          MoveEntity(2, MeshData(vert)\x, MeshData(vert)\y, MeshData(vert)\z, #PB_Absolute)
          vert + 1
          If vert=MeshVertexCount(5, 0):vert=0:EndIf
        StartDrawing(WindowOutput(0))
            DrawText(440, 1, "Vertex No. : "+ "      ")
        StopDrawing()  
          
        EndIf

       EndIf
       
      RotateCamera(#camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera(#camera, KeyX, 0, KeyY)
      ApplyEntityImpulse(2, 0, 0, 0) ; to keep the sphere physicaly alive
      ;DisableEntityBody(2, 0)
      RotateEntity(5,0,rot/2,0,#PB_Relative)
      RenderWorld()
      FlipBuffers()
      
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  EndIf
  
Else
  MessageRequester("Error", "The 3D Engine can't be initialized", 0)
EndIf

End

Procedure deform(radius.f, y.f)
            For i=0 To NbBaseSegments-1
            x.f=MeshData(i)\x 
            z.f=MeshData(i)\z 
            x2.f=radius * Cos(angle)
            z2.f=radius * Sin(angle)
            y2.f = y
            MeshData(i)\x = x2: MeshData(i)\z = z2: MeshData(i)\y = y2
            ;to save the coordinates of the last vertex in the circle to equal -->
            ;the coordinates of the first vertex in the circle
            If i=0
              x3.f=x2: y3.f=y2: z3.f=z2 
            EndIf
            angle.f + #PI*2/NbBaseSegments
           Next
          MeshData(NbBaseSegments)\x = x3
          MeshData(NbBaseSegments)\y = y3
          MeshData(NbBaseSegments)\z = z3
          SetMeshData(5, 0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)
          
          CreateEntityBody(5, #PB_Entity_StaticBody , 1, 0.7, 1)
            
 EndProcedure
        
Procedure deformTop(radiusTop.f, topY.f)  
 
 For i=2*NbBaseSegments+2 To 2*NbBaseSegments+2+NbBaseSegments
            x.f=MeshData(i)\x 
            z.f=MeshData(i)\z 
            x4.f=radiusTop.f * Cos(angle)
            z4.f=radiusTop.f * Sin(angle)
            y4.f = topY
            MeshData(i)\x = x4: MeshData(i)\z = z4: MeshData(i)\y = y4
            ;to save the coordinates of the last vertex in the circle to equal -->
            ;the coordinates of the first vertex in the circle
            If i=2*NbBaseSegments+2
              x5.f=x4: y5.f=y4: z5.f=z4
            EndIf
            angle.f + #PI*2/NbBaseSegments
 Next
          MeshData(2*NbBaseSegments+2)\x = x5
          MeshData(2*NbBaseSegments+2)\y = y5
          MeshData(2*NbBaseSegments+2)\z = z5
          SetMeshData(5, 0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)
          
          CreateEntityBody(5, #PB_Entity_StaticBody , 1, 0.7, 1)         
          
EndProcedure
        
        
        
        
        
demo 2:
is a UFO from a cylinder. simpler than the above demo

Code: Select all

Enumeration
   #camera
   #Plane
   #Node
      
EndEnumeration

Define.f KeyX, KeyY, MouseX, MouseY

Global Dim MeshData.PB_MeshVertex(0) 

ExamineDesktops()
If OpenWindow(0, 0, 0, DesktopWidth(0), DesktopHeight(0), "Left/Right: stretch/ shrink the UFO... Space: wire/solid Frame....P stop rotation .... mouse + asdw for camera move", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

If InitEngine3D()
  
  ;Add3DArchive(".", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts",#PB_3DArchive_FileSystem)
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  ;OpenWindowedScreen(WindowID(0), 0, 0, DesktopWidth(0), DesktopHeight(0), 0, 0, 0)
   OpenWindowedScreen(WindowID(0), 0, 20, WindowWidth(0)-50, WindowHeight(0)-60, 0, 0, 0) 
              
    CreateCamera(#camera, 0, 0, 100, 100)
    MoveCamera(#camera, 0, 20, 70, #PB_Absolute)
    CameraBackColor(#camera, RGB(250,250,250))
    CameraLookAt(#camera,0,0,0)
        
    CreateLight(0, RGB(255,255,255), 0, 0, 20)
    AmbientColor(RGB(200, 200, 200))

    CreateMaterial(5, LoadTexture(5, "Geebee2.bmp"))
    MaterialCullingMode(5, #PB_Material_NoCulling)
    MaterialShadingMode(5, #PB_Material_Wireframe)
    
    NbBaseSegments = 32
    radius.f = 9
    CreateCylinder(5,3,10, NbBaseSegments, 2,0) ; "4" specify a square tank look the Docs.
    GetMeshData(5,0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)       
    
    angle.f=0
    
    
    For i=NbBaseSegments+1 To NbBaseSegments*2+1
      x.f=MeshData(i)\x 
      z.f=MeshData(i)\z 
      x2.f=radius * Cos(angle)
      z2.f=radius * Sin(angle)
      MeshData(i)\x = x2: MeshData(i)\z = z2: MeshData(i)\y = 0
      angle.f + #PI*2/NbBaseSegments
    Next
    SetMeshData(5, 0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)
    UpdateMeshBoundingBox(5)
    
    CreateEntity(5, MeshID(5), MaterialID(5), 0,0,0)
       
    CreateSphere(2, 0.3)
    CreateEntity(2, MeshID(2), GetScriptMaterial(1, "Color/Blue") )
   
    vert = 0: angle=0
    CreateNode(#Node , 0, 0, 0)
    AttachNodeObject(#Node, EntityID(5))
    
    MoveEntity(5, 20,0,0)
    
    rot=1
    Repeat
      Repeat 
        event = WindowEvent()
       Until event = 0
      StartDrawing(WindowOutput(0))
      ;DrawText(440, 1, "FPS: "+ StrF(Engine3DStatus(#PB_Engine3D_CurrentFPS )))
      DrawText(440, 1, "Vertex No. : "+ Str(vert-1))
      StopDrawing()
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/20 
        MouseY = -MouseDeltaY()/20
      EndIf
          
      If ExamineKeyboard()
        If KeyboardPushed(#PB_Key_Left) ; morphing the UFO
          angle=0: radius - 0.1: pressed = 1
            
        ElseIf KeyboardPushed(#PB_Key_Right)
            angle=0: radius + 0.1: pressed = 1
      EndIf

      If pressed
            For i=NbBaseSegments+1 To NbBaseSegments*2+1
            x.f=MeshData(i)\x 
            z.f=MeshData(i)\z 
            x2.f=radius * Cos(angle)
            z2.f=radius * Sin(angle)
            MeshData(i)\x = x2: MeshData(i)\z = z2: MeshData(i)\y = 0
            angle.f + #PI*2/NbBaseSegments
          Next
        SetMeshData(5, 0, MeshData(), #PB_Mesh_Vertex, 0, MeshVertexCount(5)-1)
        UpdateMeshBoundingBox(5)
        pressed = 0
      EndIf
      
         If KeyboardReleased(#PB_Key_P)  
          rot ! 1
        EndIf
        
        If KeyboardPushed(#PB_Key_A)
          KeyX = -1
        ElseIf KeyboardPushed(#PB_Key_D)
          KeyX = 1
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_W)
          KeyY = -1
        ElseIf KeyboardPushed(#PB_Key_S)
          KeyY = 1
        Else
          KeyY = 0
        EndIf
        If KeyboardReleased(#PB_Key_Space)
          If wireFrame
             MaterialShadingMode(5, #PB_Material_Wireframe)
          wireFrame ! 1
        Else 
          MaterialShadingMode(5, #PB_Material_Solid)
          wireFrame ! 1
        EndIf
        EndIf
       
        
        If KeyboardReleased(#PB_Key_C) 
          MoveEntity(2, MeshData(vert)\x, MeshData(vert)\y, MeshData(vert)\z, #PB_Absolute)
          vert + 1
          If vert=MeshVertexCount(5, 0):vert=0:EndIf
        StartDrawing(WindowOutput(0))
            DrawText(440, 1, "Vertex No. : "+ "      ")
        StopDrawing()  
          
        EndIf

       EndIf
       
      RotateCamera(#camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera(#camera, KeyX, 0, KeyY)
      
      RotateEntity(5, 0,-2,0, #PB_Relative)
      RotateNode(#Node, 0, rot, 0 , #PB_Relative)

      RenderWorld()
      FlipBuffers()
      
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  EndIf
  
Else
  MessageRequester("Error", "The 3D Engine can't be initialized", 0)
EndIf

End
at last you can make the code better and more general than my spaghetti code

references:
1- if you want an extra ordinary function look Psychophanta CreateTorusArc function here: http://purebasic.fr/english/viewtopic.p ... 60#p481492 .... very versatile and very general. to run it inside PB Ogre look here: http://purebasic.fr/english/viewtopic.p ... 75#p481693
2- Book: experiments in topology :by STEPHEN BARR : small book without mathematics but full of illustrations show us how to transform shape to other shape and more.
Last edited by applePi on Thu Feb 18, 2016 7:32 pm, edited 1 time in total.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Useful Cylinder Deformations

Post by davido »

@applePi,
Two very nice examples.
Thank you for sharing. :D
DE AA EB
User avatar
falsam
Enthusiast
Enthusiast
Posts: 630
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Useful Cylinder Deformations

Post by falsam »

Very good job ApplePi. Thank you for sharing.

➽ Windows 11 64-bit - PB 6.0 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect.
Post Reply