Funnel, Tube extension, Helix and many balls

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

Funnel, Tube extension, Helix and many balls

Post by applePi »

a continuation of the Tubes and pipes Tubes and pipes subject . here is the balls falling into a funnel and a tube extension then marching through a helical tube then falling to the ground , and after falling into the dark space their entities are deleted if its height (EntityY) are less than -7 (the ground are on Y = -6, i have learned Linked lists 2 days ago and used it in the procedure balls() so if there are errors please report, i replace the for/next loop. it seems the Entities deletions works okay .
about 1/10 of the balls escape the funnel and helix through the thin walls.

Image

Code: Select all

Enumeration
 #plane
 #cube
 #ball
 #Cone
 #Tube_extension
EndEnumeration

Declare Cone(incr.f) 
Declare tube_extension() ;  0.25 of a torus
Declare balls() 
Global meshesNum
#manyPi = 10 * #PI    ;PI For rotation 

#NUM_RINGS = 360
;#NUM_RINGS = 70
#NUM_BANDS = 32
;#RING_RAD  = 2.0
#BAND_RAD  = 0.5 ; thickness of the tube

Global stop = 1
Global.f rot = 1

Global Dim ball(1000)
Global num
Global stoneNum

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

Declare DrawTube (Rings.l, Bands.l, BandRadius.f)


Quit.b = #False
ExamineDesktops()
OpenWindow(3, 0, 0, DesktopWidth(0), DesktopHeight(0), "Helix tube with Balls, Arrow keys and mouse to move/rotate ... W .toggle wire/solid ", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

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

CreateMaterial(1, LoadTexture(1, "clouds.jpg"))
CreatePlane(#plane, 20, 20, 1, 1, 1, 1)
CreateEntity (#plane, MeshID(#plane), MaterialID(1))
MoveEntity(#plane,0,-6,0)
EntityPhysicBody(#plane, #PB_Entity_StaticBody)

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

CreateCamera(0, 0, 0, 100, 100)
MoveCamera(0, 0, 4, 12)
MoveCamera(0, 5, 10, 0)
;RotateCamera(0, -60,90,0)
CameraLookAt(0, 0, 2, 0)

;RotateCamera(0, -15, 0, 0)
;CreateMaterial(0, LoadTexture(0, "terrain_texture.jpg"))
CreateMaterial(0, LoadTexture(0, "wood.jpg"))
CreateMaterial(1, LoadTexture(1, "wood.jpg"))
MaterialCullingMode(0, #PB_Material_NoCulling)
;MaterialBlendingMode(0, #PB_Material_AlphaBlend )

MaterialShadingMode(0, #PB_Material_Wireframe)
DisableMaterialLighting(0, 1)
CreateMesh(1, #PB_Mesh_TriangleList, #PB_Mesh_Static )
SetMeshMaterial(1, MaterialID(0))

DrawTube (#NUM_RINGS, #NUM_BANDS, #BAND_RAD)
NormalizeMesh(1)
FinishMesh(1)

CreateEntity(1, MeshID(1), MaterialID(0))
MoveEntity(1,0,2,-2)
EntityPhysicBody(1, #PB_Entity_StaticBody  ,0.1)
RotateEntity(1,90,250,0)

CreateMesh(#Tube_extension, #PB_Mesh_TriangleList, #PB_Mesh_Static)
SetMeshMaterial(#Tube_extension, MaterialID(0))
tube_extension() ; calling the tube_extension proc , for making 1/4 of a torus
EntityPhysicBody(#Tube_extension, #PB_Entity_StaticBody   ,1,0.01,2)

CreateCube(#cube, 1) ; the block (fountain) wich direct the balls to the funnel
fountain = CreateEntity(#PB_Any,MeshID(#cube), MaterialID(1))
ScaleEntity(fountain,2,1,1)
MoveEntity(fountain,3,6,-1.5)
RotateEntity(fountain, 0, 0,135)
EntityPhysicBody(fountain,#PB_Entity_StaticBody ,100)

CreateMaterial(3, LoadTexture(3, "white.jpg"))
SetMaterialColor(3, #PB_Material_SelfIlluminationColor, RGB(255,0,0))
CreateSphere(#ball, 0.06)

CreateMesh(#Cone, #PB_Mesh_TriangleList, #PB_Mesh_Static)
Cone(0.05) ; the Funnel construction
EntityPhysicBody(#Cone, #PB_Entity_StaticBody   ,1,0.01,2)

Global NewList Spheres()


ExamineKeyboard()
Global.f keyX, ketY, MouseY, MouseX
Repeat
  Event = WindowEvent()
  
  If KeyboardReleased(#PB_Key_W)
    If wire=1
    MaterialShadingMode(0, #PB_Material_Wireframe)
    wire = 0
  ElseIf wire = 0
    MaterialShadingMode(0, #PB_Material_Solid)
    wire = 1
  EndIf
  EndIf
  If ExamineMouse()
        MouseX = -MouseDeltaX()/10
        MouseY = -MouseDeltaY()/10
      EndIf
      
      
      If ExamineKeyboard()
        If KeyboardReleased(#PB_Key_G)
          If gravity = 0
            WorldGravity(1)
            Else
            WorldGravity(-9.806)
          EndIf
          gravity ! 1
        EndIf
        
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -0.5
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = 0.5
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -0.5
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = 0.5
        Else
          KeyY = 0
        EndIf
        
      EndIf
      
      RotateCamera(0, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera  (0, KeyX, 0, KeyY)
  
  ;Delay(10)
  balls()
    
  RenderWorld()
  FlipBuffers()
   
   ExamineKeyboard()
   If KeyboardPushed(#PB_Key_Escape)
      Quit = #True
    EndIf
Until Quit = #True Or Event = #PB_Event_CloseWindow


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





Procedure  DrawTube (Rings.l, Bands.l, BandRadius.f)

  x.f: y.f: z.f
   op.f = 1
   txu.f : txv.f
   For i = 0 To rings + 1
          current_point.vector3d
        next_point.vector3d
        T.vector3d
        B.vector3d
        N.vector3d
        p.f
        
        ;center point
        p = op * i * #manyPi / rings
        current_point\x = Cos(p) 
        current_point\y = Sin(p)
        current_point\z = 0.2 * p

        ;next point For Frenet square
        p = op * (i + 1) * #manyPi / rings
        next_point\x = Cos(p)
        next_point\y = Sin(p) 
        next_point\z = 0.2 * p

        ;T  = P' - P
        vector_sub(next_point, current_point, T)

        ;N = P' + P
        vector_add(next_point, current_point, N)

        ;B = T x N
        vector_cross(T, N, B)

        ;N = B x T
        vector_cross(B, T, N)

        ;Normalize vectors Or Else it won't work
        vector_normalize(B)
        vector_normalize(N)
        
        For j = 0 To bands - 1
              new_point_x.f
              new_point_y.f
              
              ;rotate around the current point using normal rotation makes bands
            new_point_x = Sin(j * 2*#PI / bands) * #BAND_RAD
            new_point_y = Cos(j * 2*#PI / bands) * #BAND_RAD
            
                ;this is the coords of our point along the curve
            x = N\x * new_point_x + B\x * new_point_y + current_point\x
            y = N\y * new_point_x + B\y * new_point_y + current_point\y
            z = N\z * new_point_x + B\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/rings 
         txu = txu + 1/bands 
      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  


 EndProcedure
 
 Procedure Cone(incr.f) ;  incr determines the radius of the bigger nozzle
  x.f: y.f :z.f : u.f: v.f: r.f
      majorOrbit.l = 100 : minorOrbit.l = 20
      majorStep.f   = 2 * #PI / majorOrbit
      minorStep.f   = 2 * #PI / minorOrbit
      i.l: j.l: txu.f : txv.f
 
      SmallNozzle.f = 1 ; dertmine the radius of the smaller nozzle
      For i = 0 To majorOrbit
        If i > 40 ; the beginning point of the wider circles than the tube circles
          SmallNozzle.f  + incr ; incr determines the radius of the bigger nozzle
        EndIf 
        v = i * majorStep
        For j = 0 To minorOrbit
          u = j * minorStep
          r = 4 * (1 - (Cos(u)/2))
          
          
          x = Cos(u)*10 * SmallNozzle 
          y = Sin(u)*10 * SmallNozzle
          ;z = Sin(v)
          z+0.02
          
          MeshVertexPosition(x, y, z);
          MeshVertexTextureCoordinate(txu, txv)
          MeshVertexNormal(x, y, z)
          ; texture the whole bottle with one picture stretched
          txv = txv + 1/minorOrbit ; texture coordinates
          
        Next
        txv = 0
        txu = txu + 1/majorOrbit 
      Next
      For i = 0 To majorOrbit-1
      For j = 0 To minorOrbit
          MeshFace(t,t+1,t + minorOrbit+1)
          MeshFace(t + minorOrbit+1,t + minorOrbit+2,t+1 )
          If i=majorOrbit-1 And j=minorOrbit-1 ;bypass the last triangle
            minorOrbit-1
          EndIf 
          t + 1   
          
     Next
     
   Next  
      
    NormalizeMesh(#Cone)
    FinishMesh(#True)
    CreateEntity(#Cone, MeshID(#Cone), MaterialID(0)) 
    ScaleEntity(#Cone,0.03, 0.03, 0.03)
     
    MoveEntity(#Cone, 1.5, 4.5, -1.1,#PB_Absolute) 
    
  RotateEntity(#Cone,-90,0,0)
    
EndProcedure


Procedure tube_extension()
 x.f: y.f :z.f :  u.f=0 :txu.f : txv.f

      rMajor.f = 2 : rMinor.f = 0.5

      majorRadius.f = 2: minorRadius.f = 0.5: numMajor.l = 50: numMinor.l = 25
      majorStep.f   = 0.5 * #PI / (numMajor+0);
      minorStep.f   = 2 * #PI / (numMinor+0)
      i.l: j.l
 
      For i = 0 To numMajor
        t.f = i * majorStep;
        
        For j = 0 To numMinor
          u.f = j * minorStep;
          x = Cos(t) * (majorRadius + minorRadius * Cos(u))
          y = Sin(t) * (majorRadius + minorRadius * Cos(u))
          z.f = minorRadius * Sin(u)
          tt+1
          ;If tt>1326 :Break:EndIf
          MeshVertexPosition(x, y, z);
          MeshVertexTextureCoordinate(txu, txv)
          MeshVertexNormal(x, y, z)
          txv = txv + 1/numMinor ; texture coordinates
          
        Next
        txv = 0
        txu = txu + 1/numMajor ;texture coordinates
      Next
      ;Debug tt: Debug t
     v.l=0 :tt=0
     For i = 0 To numMajor
       For j = 0 To numMinor-1
         tt+1
          If tt>1273 :Break:EndIf
          MeshFace(v,v+1,v + numMinor+1)
          MeshFace(v + numMinor+1,v + numMinor+2,v+1 )
          If i=numMajor-1 And j=numMinor-1 ;bypass the last triangle
            ;numMinor-1
          EndIf 
          v + 1 
                    
     Next
     
   Next 
   
   ;last vertex to connect:
      
    NormalizeMesh(#Tube_extension)
    FinishMesh(#True)
    CreateEntity(#Tube_extension, MeshID(#Tube_extension), MaterialID(0))  
    RotateEntity(#Tube_extension, 0,0,-90)
    MoveEntity(#Tube_extension,-0.4,4.0, -1.1,#PB_Absolute) 
EndProcedure

Procedure balls()
                      
            OneBall = CreateEntity(#PB_Any, MeshID(#ball), MaterialID(3), 2.0, 6.6, -1.5)
            
            AddElement(Spheres()) : Spheres() = OneBall
            SetMaterialColor(3, #PB_Material_SelfIlluminationColor, RGB(255,0,0))
            EntityPhysicBody(OneBall, #PB_Entity_SphereBody, 1)
            ApplyEntityImpulse(OneBall, 0, 2,0)
            
            meshesNum = ListSize(Spheres())
            
            If meshesNum > 300
              
              ForEach Spheres()
               
                TempMesh = Spheres()
                
                ;If IsEntity(TempMesh)
                 If EntityY(TempMesh) < -7 Or EntityY(TempMesh) > 40
                   FreeEntity(TempMesh)
                   DeleteElement(Spheres() ) 

                EndIf 
                ;EndIf
              Next
            EndIf
          
EndProcedure 
Last edited by applePi on Fri Nov 15, 2013 1:54 pm, edited 2 times in total.
Fred
Administrator
Administrator
Posts: 18247
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Funnel, Tube extension, Helix and many balls

Post by Fred »

Very cool example like always applePi !
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: Funnel, Tube extension, Helix and many balls

Post by applePi »

thanks Fred , it is your programming language efficiency which makes it a pleasure to design things exactly like a painting process.
link0101
User
User
Posts: 34
Joined: Mon Jul 14, 2008 5:03 pm

Re: Funnel, Tube extension, Helix and many balls

Post by link0101 »

Just amazing what you do with 3D in Purebasic ApplePi ! , ever thought of writing a tutorial for Purebasic folks like me that started in the 80s programming and are struggling with the 3D aspects of Purebasic and ogre?
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: Funnel, Tube extension, Helix and many balls

Post by applePi »

Thanks link0101 , yes i thought before many times to write at least what i understand from the 3D geometric aspects , my knowledge in colors and materials are limited Samuel know much more in this area in a pro way.
i know only a tiny subset from purebasic language equal to the famous quick basic sometimes i put it at work using the purebasic facilities .
so you have encouraged me to write something step by step and slowly over the years under the title (( from a beginner to beginners an adventure in PureBasic 3D Graphics and Physics)) at least for the new users such as the students who want to use the Ogre graphics and physics, i will think what it should be the first lesson suitable to be as a zero beginning. then will post it here. but the community should see the first lesson firstly to evaluate if it is suitable or not.
thanks for your suggestion
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: Funnel, Tube extension, Helix and many balls

Post by applePi »

someone suggested to reverse the gravity and to see what will happen so added to toggle between WorldGravity(1) and WorldGravity(-9.806) when pressing " G "
to the above code
i have amazed that after waiting until the balls reach the helix bottom and press G and the balls will move to the upper side of the tubes (move down to see this) then they will crawl up and return to the funnel then up to the darkness and will be deleted after height Entity(Y) > 40
so we can simulate a distillation factory !!!
just needed more precise positioning
Post Reply