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
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
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
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.