blitz-research / monkey2

zlib License
131 stars 44 forks source link

Need a way to rotate meshes #443

Open DruggedBunny opened 5 years ago

DruggedBunny commented 5 years ago

This is a very messy WIP test using two Google Poly models, an island and a plane.

When I load the plane, it's rotated 180 degrees on the y-axis, so faces the camera, so I can only fly with my plane pointing in reverse, as this loaded orientation is what the CylinderCollider's Axis.Z aligns with.

Blitz3D had a RotateMesh command to take care of this, but there doesn't seem to be any way to do the same thing in mojo3d.

This is the crap demo, controls are weird (not taking into account proper plane movement) and plane flies backwards!

island.zip

DruggedBunny commented 5 years ago

Unimportant source update, but much better control-wise, at least for arcade purposes! Just that little thing of... flying backwards... need media from zip above.

#Import "<std>"
#Import "<mojo>"
#Import "<mojo3d>"
#Import "<mojo3d-loaders>"

#Import "assets/"

Using std..
Using mojo..
Using mojo3d..

Class MyWindow Extends Window

    Field scene:Scene
    Field camera:Camera
    Field light:Light

    Field ground:GroundBehaviour
    Field plane:PlaneBehaviour

    Method New( title:String="Place app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )

        Super.New( title,width,height,flags )
    End

    Method OnCreateWindow() Override

        'create (current) scene
        scene=New Scene
        scene.ClearColor = New Color( 0.2, 0.6, 1.0 )
        scene.AmbientLight = scene.ClearColor * 0.25
        scene.FogColor = scene.ClearColor
        scene.FogNear = 1.0
        scene.FogFar = 5120.0

        'create camera
        camera=New Camera()
'       camera.AddComponent<FlyBehaviour>()
    '   camera.Move( 0,0,-512 )
        camera.Far = 10240.0

        'create light
        light=New Light
        light.CastsShadow=True
        light.Rotate( 45, 45, 0 )

        'create ground
        Local ground_size:Float = 4096 * 0.5

        Local ground_box:Boxf = New Boxf( -ground_size,-ground_size * 0.5,-ground_size,ground_size,0,ground_size )
        'Local groundMaterial:=New PbrMaterial( Color.Lime )
        Local ground_model:Model=Model.Load ("asset::model_gltf_6G3x4Sgg6iX_7QCCWe9sgpb\model.gltf")'CreateBox( groundBox,1,1,1,groundMaterial )
        ground_model.Mesh.FitVertices (ground_box, False)

'       ground_model.Scale = New Vec3f (100, 100, 100)
'       ground_model.Move (0, 100, 0)

        ground_model.CastsShadow=True

        ground = New GroundBehaviour (ground_model)

        Local ground_collider:MeshCollider  = ground.Entity.AddComponent <MeshCollider> ()

        ground_collider.Mesh = Cast <Model> (ground.Entity).Mesh

        Local ground_body:RigidBody     = ground.Entity.AddComponent <RigidBody> ()

            ground_body.Mass                = 0.0

        Local plane_size:Float = 16.83 * 0.5
        Local plane_box:Boxf = New Boxf (-plane_size, -plane_size, -plane_size, plane_size, plane_size, plane_size)

        Local plane_model:Model = Model.Load ("asset::1397 Jet_gltf_3B3Pa6BHXn1_fKZwaiJPXpf\1397 Jet.gltf")

        plane_model.Mesh.FitVertices (plane_box)

        camera.Parent = plane_model
        camera.Move (0, 0, -20)
        Local plane_coll_radius:Float = plane_size * 0.5
        Local plane_coll_length:Float = plane_size * 1.5

        Local plane_vis:Model = Model.CreateCylinder (plane_coll_radius, plane_coll_length, Axis.Z, 16, New PbrMaterial (Color.White), plane_model)
        plane_vis.Alpha = 0.25
        plane_vis.Visible = False

        plane_model.Move (0.0, 5.0, 0.0)
'       plane_model.Rotate (0.0, 180.0, 0.0)

        plane = New PlaneBehaviour (plane_model)

'       Local plane_collider:SphereCollider = plane.Entity.AddComponent <SphereCollider> ()
        Local plane_collider:CylinderCollider   = plane.Entity.AddComponent <CylinderCollider> ()

'       apply to collider??? plane_model.Basis.Rotate (0.0, 180.0, 0.0)

        plane_collider.Radius = plane_coll_radius
        plane_collider.Axis = Axis.Z
        plane_collider.Length = plane_coll_length

        Local plane_body:RigidBody      = plane.Entity.AddComponent <RigidBody> ()

            plane_body.Mass             = 1.0
            plane_body.Restitution      = 0.5
            plane_body.AngularDamping   = 0.5
            plane_body.LinearDamping    = 0.5

    '       plane_body.ApplyTorqueImpulse (New Vec3f (0.0, 0.0, -15.0))

            plane_body.ApplyImpulse (plane.Entity.Basis * New Vec3f (0.0, 0.0, 33.0))

    End

    Method OnRender( canvas:Canvas ) Override

        'camera.PointAt (plane.Entity)

'       camera.FOV = 200.0 - Clamp (Float (camera.Position.Distance (plane.Entity.Position)), 22.5, 150.0)

        If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()

        Local speed:Float = 1.0

        Local roll_rate:Float = 25.0
        Local pitch_rate:Float = 33.0

        ' -Scene.GetCurrent ().World.Gravity.Y
        plane.Entity.GetComponent <RigidBody> ().ApplyForce (plane.Entity.Basis * New Vec3f (0.0, -Scene.GetCurrent ().World.Gravity.Y, 75.0))

        If Keyboard.KeyDown (Key.LeftShift)
            speed = speed * 2.0
        Endif

        If Keyboard.KeyDown (Key.Left)
            plane.Entity.GetComponent <RigidBody> ().ApplyTorque (plane.Entity.Basis * New Vec3f (0.0, 0.0, roll_rate))
        Endif

        If Keyboard.KeyDown (Key.Right)
            plane.Entity.GetComponent <RigidBody> ().ApplyTorque (plane.Entity.Basis * New Vec3f (0.0, 0.0, -roll_rate))
        Endif

        If Keyboard.KeyDown (Key.Up)
            plane.Entity.GetComponent <RigidBody> ().ApplyTorque (plane.Entity.Basis * New Vec3f (pitch_rate, 0.0, 0.0))
            plane.Entity.GetComponent <RigidBody> ().ApplyForce (plane.Entity.Basis * New Vec3f (0.0, Scene.GetCurrent ().World.Gravity.Y * 0.5, Scene.GetCurrent ().World.Gravity.Y * 0.5))
        Endif

        If Keyboard.KeyDown (Key.Down)
            plane.Entity.GetComponent <RigidBody> ().ApplyTorque (plane.Entity.Basis * New Vec3f (-pitch_rate, 0.0, 0.0))
            plane.Entity.GetComponent <RigidBody> ().ApplyForce (plane.Entity.Basis * New Vec3f (0.0, -Scene.GetCurrent ().World.Gravity.Y * 0.5, Scene.GetCurrent ().World.Gravity.Y * 0.5))
        Endif

        RequestRender()
        scene.Update()
        camera.Render( canvas )
        canvas.DrawText( "FPS="+App.FPS,0,0 )
        canvas.DrawText( "FOV="+camera.FOV,0,20 )

    End

End

Function Main()

    New AppInstance

    New MyWindow

    App.Run()
End

Class PlaneBehaviour Extends Behaviour

    Method New (entity:Entity)

        Super.New (entity)
        AddInstance ()

    End

    Method OnStart () Override

        'Local spacer:Float = 50.0

        'Entity.Move (Rnd (-spacer, spacer), Rnd (-spacer, spacer), Rnd (-spacer, spacer))

        Local model:Model = Cast <Model> (Entity)

        For Local mat:Material = Eachin model.Materials
            mat.CullMode = CullMode.Back    
        Next

    End

    Method OnUpdate (elapsed:Float) Override

        'Local body:RigidBody = Cast <Model> (Entity).GetComponent <RigidBody> ()

        'body.ApplyForce (Scene.GetCurrent ().World.Gravity * New Vec3f (1.0, -1.0, 1.0))   

    End

End

Class GroundBehaviour Extends Behaviour

    Method New (entity:Entity)

        Super.New (entity)
        AddInstance ()

    End

    Method OnStart () Override

        Local model:Model = Cast <Model> (Entity)

        For Local mat:Material = Eachin model.Materials
            mat.CullMode = CullMode.Back    
        Next

    End

    Method OnUpdate (elapsed:Float) Override

    End

End

Function Degrees:Float (radians:Float)
    Return radians * RAD_DIVIDER
End

Function Radians:Float (degrees:Float)
    Return degrees * DEG_DIVIDER
End

Const RAD_DIVIDER:Float = 180.0 / Pi
Const DEG_DIVIDER:Float = Pi / 180.0
DoctorWhoof commented 5 years ago

This works for me:

Local matrix := AffineMat4f.Rotation( 0, Radians(180), 0 )
plane_model.Mesh.TransformVertices( matrix )
DoctorWhoof commented 5 years ago

On a side note, ground model shadows are totally killing the performance on my little laptop, like around 20 fps. Turning them off with ground_model.CastsShadow=False jumps to 60fps, and I still get the plane's shadow on the ground. I wonder if it's related to the model size.

DruggedBunny commented 5 years ago

Oh, thanks, DW, will give that a go later. I'd ended up setting model alpha to 0 and loading (and rotating) a parented copy to work around it!

Interesting about the shadows, a lot of self-shadowing going on, I suppose...

It's only going to be a very simple 'how-to' physics demo anyway.

DruggedBunny commented 5 years ago

Just stuck it in -- that's worked a treat, thanks very much!

Current version much more controllable and with my rocket game camera hacked-in, looks pretty nice -- will just tidy this up (a lot) and tweak a bit more.


#Import "<std>"
#Import "<mojo>"
#Import "<mojo3d>"
#Import "<mojo3d-loaders>"

#Import "assets/"

Using std..
Using mojo..
Using mojo3d..

Class MyWindow Extends Window

    Const WINDOW_WIDTH:Int = 1920
    Const WINDOW_HEIGHT:Int = 1080
    Const WINDOW_FLAGS:WindowFlags = WindowFlags.Fullscreen

'   Const WINDOW_WIDTH:Int = 640
'   Const WINDOW_HEIGHT:Int = 480
'   Const WINDOW_FLAGS:WindowFlags = WindowFlags.Resizable

    Field scene:Scene
    'Field camera:Camera
    Field camera:GameCamera

    Field light:Light

    Field ground:GroundBehaviour
    Field plane:PlaneBehaviour

    Method New( title:String="Place app",width:Int=WINDOW_WIDTH,height:Int=WINDOW_HEIGHT,flags:WindowFlags=WINDOW_FLAGS )

        Super.New( title,width,height,flags )
    End

    Method OnCreateWindow() Override

        'create (current) scene
        scene=New Scene
        scene.ClearColor = New Color( 0.2, 0.6, 1.0 )
        scene.AmbientLight = scene.ClearColor * 0.25
        scene.FogColor = scene.ClearColor
        scene.FogNear = 128.0
        scene.FogFar = 2048.0

'       'create camera
'       camera=New Camera()
''      camera.AddComponent<FlyBehaviour>()
'   '   camera.Move( 0,0,-512 )
'       camera.Far = 10240.0
'       camera.Viewport = App.ActiveWindow.Rect
'
        camera=New GameCamera(App.ActiveWindow.Rect, Null, 10240)

'       camera.AddComponent<FlyBehaviour>()
    '   camera.Move( 0,0,-512 )
        'camera.Far = 10240.0
        'camera.Viewport = App.ActiveWindow.Rect

        'create light
        light=New Light
        light.CastsShadow=True
        light.Rotate( 45, 45, 0 )

        'create ground
        Local ground_size:Float = 4096 * 0.5

        Local ground_box:Boxf = New Boxf( -ground_size,-ground_size * 0.5,-ground_size,ground_size,0,ground_size )
        'Local groundMaterial:=New PbrMaterial( Color.Lime )
        Local ground_model:Model=Model.Load ("asset::model_gltf_6G3x4Sgg6iX_7QCCWe9sgpb\model.gltf")'CreateBox( groundBox,1,1,1,groundMaterial )
        ground_model.Mesh.FitVertices (ground_box, False)

'       ground_model.Scale = New Vec3f (100, 100, 100)
'       ground_model.Move (0, 100, 0)

        ground_model.CastsShadow=True

        ground = New GroundBehaviour (ground_model)

        Local ground_collider:MeshCollider  = ground.Entity.AddComponent <MeshCollider> ()

        ground_collider.Mesh = Cast <Model> (ground.Entity).Mesh

        Local ground_body:RigidBody     = ground.Entity.AddComponent <RigidBody> ()

            ground_body.Mass                = 0.0

        Local plane_size:Float = 16.83 * 0.5
        Local plane_box:Boxf = New Boxf (-plane_size, -plane_size, -plane_size, plane_size, plane_size, plane_size)

        Local plane_model:Model = Model.Load ("asset::1397 Jet_gltf_3B3Pa6BHXn1_fKZwaiJPXpf\1397 Jet.gltf")

        plane_model.Mesh.FitVertices (plane_box)

        Local matrix := AffineMat4f.Rotation( 0, Radians(180), 0 )
        plane_model.Mesh.TransformVertices( matrix )

        ' -------------------------------------------------
        ' HACK! To work around lack of Mesh.Rotate!
        ' -------------------------------------------------

'       Local plane_dummy:Model = plane_model.Copy ()
'       plane_dummy.Parent = plane_model
'       plane_dummy.Rotate (0, 180, 0)
'       
'       plane_model.Alpha = 0.0
'       
        ' -------------------------------------------------

'       camera.Camera3D.Parent = plane_model
'       camera.Move (0, 0, -20)
        Local plane_coll_radius:Float = plane_size * 0.5
        Local plane_coll_length:Float = plane_size * 1.5

        Local plane_vis:Model = Model.CreateCylinder (plane_coll_radius, plane_coll_length, Axis.Z, 16, New PbrMaterial (Color.White), plane_model)
        plane_vis.Alpha = 0.25
        plane_vis.Visible = False

        plane_model.Move (0.0, 5.0, 0.0)
'       plane_model.Rotate (0.0, 180.0, 0.0)

        plane = New PlaneBehaviour (plane_model)

'       Local plane_collider:SphereCollider = plane.Entity.AddComponent <SphereCollider> ()
        Local plane_collider:CylinderCollider   = plane.Entity.AddComponent <CylinderCollider> ()

'       apply to collider??? plane_model.Basis.Rotate (0.0, 180.0, 0.0)

        plane_collider.Radius = plane_coll_radius
        plane_collider.Axis = Axis.Z
        plane_collider.Length = plane_coll_length

        Local plane_body:RigidBody      = plane.Entity.AddComponent <RigidBody> ()

            plane_body.Mass             = 1.0
            plane_body.Restitution      = 0.5
            plane_body.AngularDamping   = 0.9
            plane_body.LinearDamping    = 0.5
            plane_body.Friction         = 0.0

    '       plane_body.ApplyTorqueImpulse (New Vec3f (0.0, 0.0, -15.0))

            plane_body.ApplyImpulse (plane.Entity.Basis * New Vec3f (0.0, 0.0, 33.0))

        Mouse.PointerVisible = False

    End

    Method OnRender( canvas:Canvas ) Override

        'camera.PointAt (plane.Entity)

'       camera.FOV = 200.0 - Clamp (Float (camera.Position.Distance (plane.Entity.Position)), 22.5, 150.0)

        If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()

        Local speed:Float = 1.0

        Local roll_rate:Float = 50.0
        Local pitch_rate:Float = 30.0

        Local plane_body:RigidBody = plane.Entity.GetComponent <RigidBody> ()

        ' -Scene.GetCurrent ().World.Gravity.Y
        plane_body.ApplyForce (plane.Entity.Basis * New Vec3f (0.0, -Scene.GetCurrent ().World.Gravity.Y, 75.0))

        If Keyboard.KeyDown (Key.LeftShift)
            speed = speed * 2.0
        Endif

        If Keyboard.KeyDown (Key.Left)
            plane_body.ApplyTorque (plane.Entity.Basis * New Vec3f (0.0, 0.0, roll_rate))
        Endif

        If Keyboard.KeyDown (Key.Right)
            plane_body.ApplyTorque (plane.Entity.Basis * New Vec3f (0.0, 0.0, -roll_rate))
        Endif

        If Keyboard.KeyDown (Key.Up)
            plane_body.ApplyTorque (plane.Entity.Basis * New Vec3f (pitch_rate, 0.0, 0.0))
            plane_body.ApplyForce (plane.Entity.Basis * New Vec3f (0.0, Scene.GetCurrent ().World.Gravity.Y * 0.5, Scene.GetCurrent ().World.Gravity.Y * 0.5))
        Endif

        If Keyboard.KeyDown (Key.Down)
            plane_body.ApplyTorque (plane.Entity.Basis * New Vec3f (-pitch_rate, 0.0, 0.0))
            plane_body.ApplyForce (plane.Entity.Basis * New Vec3f (0.0, -Scene.GetCurrent ().World.Gravity.Y * 0.5, Scene.GetCurrent ().World.Gravity.Y * 0.5))
        Endif

        RequestRender()
        scene.Update()

        camera.Update (plane)'Render( canvas )
        camera.Camera3D.Render (canvas)

        canvas.DrawText( "FPS="+App.FPS,0,0 )
        canvas.DrawText( "FOV="+camera.Camera3D.FOV,0,20 )

    End

End

Function Main()

    New AppInstance

    New MyWindow

    App.Run()
End

Class PlaneBehaviour Extends Behaviour

    Method New (entity:Entity)

        Super.New (entity)
        AddInstance ()

    End

    Method OnStart () Override

        'Local spacer:Float = 50.0

        'Entity.Move (Rnd (-spacer, spacer), Rnd (-spacer, spacer), Rnd (-spacer, spacer))

        Local model:Model = Cast <Model> (Entity)

        For Local mat:Material = Eachin model.Materials
            mat.CullMode = CullMode.Back    
        Next

    End

    Method OnUpdate (elapsed:Float) Override

        'Local body:RigidBody = Cast <Model> (Entity).GetComponent <RigidBody> ()

        'body.ApplyForce (Scene.GetCurrent ().World.Gravity * New Vec3f (1.0, -1.0, 1.0))   

    End

End

Class GroundBehaviour Extends Behaviour

    Method New (entity:Entity)

        Super.New (entity)
        AddInstance ()

    End

    Method OnStart () Override

        Local model:Model = Cast <Model> (Entity)

        For Local mat:Material = Eachin model.Materials
            mat.CullMode = CullMode.Back    
        Next

    End

    Method OnUpdate (elapsed:Float) Override

    End

End

Function Degrees:Float (radians:Float)
    Return radians * RAD_DIVIDER
End

Function Radians:Float (degrees:Float)
    Return degrees * DEG_DIVIDER
End

Const RAD_DIVIDER:Float = 180.0 / Pi
Const DEG_DIVIDER:Float = Pi / 180.0

' -----------------------------------------------------------------------------
' What is it?
' -----------------------------------------------------------------------------

Class GameCamera

    Public

        Property CameraDistance:Float ()
            Return camera_distance
            Setter (distance:Float)
                camera_distance = distance
        End

        Property Camera3D:Camera ()
            Return real_camera
            Setter (new_cam:Camera)
                real_camera = new_cam
        End

        Method New (viewport:Recti, current_camera:GameCamera, range_far:Float)

            If current_camera Then current_camera.Destroy ()

            camera_pivot = New Pivot

            Camera3D            = New Camera (camera_pivot)
            Camera3D.Near       = 0.01
            Camera3D.Far        = range_far * Sqrt (3.0) ' Terrain cube diagonal
            Camera3D.FOV        = 90.0 ' Mojo3d default

            Camera3D.Viewport = viewport

            ' Chase target -- position camera tries to move towards...

            chase_target                    = Model.CreateSphere (1, 32, 32, New PbrMaterial (Color.Red))
            chase_target.Alpha              = 0.5
            chase_target.Material.CullMode  = CullMode.None
            chase_target.Visible            = False

            up = New Vec3f (0.0, up_y_default, 0.0)

            Reset ()

        End

        Method Destroy ()

            camera_pivot?.Destroy ()
            real_camera?.Destroy ()
            chase_target?.Destroy ()

        End

        Method Reset ()

            Camera3D.FOV = 90.0

'           chase_target.Position = New Vec3f (Game.CurrentLevel.SpawnX, Game.CurrentLevel.SpawnY, Game.CurrentLevel.SpawnZ)
'           camera_pivot.Position = New Vec3f (Game.CurrentLevel.SpawnX, Game.CurrentLevel.SpawnY, Game.CurrentLevel.SpawnZ - 10.0)

            lastvel = New Vec3f (0, 0, 15)
            prevvel = lastvel

        End

        Method Update (target:PlaneBehaviour)

            ' Camera positioning...

            prevvel = lastvel

            Local plane_body:RigidBody = target.Entity.GetComponent <RigidBody> ()
            Local plane_model:Model = Cast <Model> (target.Entity)

'           If plane_body.LinearVelocity.XZ.Length > 5.0
                lastvel = lastvel.Blend (plane_body.LinearVelocity, 0.045)
'           Endif

            chase_target.Position = (plane_model.Position + up) - (lastvel * CameraDistance)

            camera_pivot.Move ((chase_target.Position - camera_pivot.Position) * 0.95, True)
            camera_pivot.PointAt (plane_model)

            Local cam_dist:Float = plane_model.Position.Distance (Camera3D.Position)

            Local closeup:Float = 10.5
            Local closer:Float = 0.1

            If cam_dist < closeup
                Camera3D.FOV = Blend (Camera3D.FOV, TransformRange (cam_dist, 1.0, closeup, 130.0, 90.0), closer)
                up.Y = Blend (up.Y, 3.0, 0.01)
            Else
                Camera3D.FOV = Blend (Camera3D.FOV, 90.0, 0.075)
                up.Y = Blend (up.Y, up_y_default, 0.01)
            Endif

        End

        'Method ShortestVec:Vec3f (v1:Vec3f, v2:Vec3f)
        '   If v1.Length < v2.Length Then Return v1 Else Return v2
        'End

        'Method LongestVec:Vec3f (v1:Vec3f, v2:Vec3f)
        '   If v1.Length > v2.Length Then Return v1 Else Return v2
        'End

        Method Move (tv:Vec3f, localSpace:Bool = False)
            camera_pivot.Move (tv, localSpace)
        End

        Method Move (tx:Float, ty:Float, tz:Float)
            camera_pivot.Move (tx, ty, tz)
        End

        Method PointAt (target:Entity)
            camera_pivot.PointAt (target)
        End

        Method Position (v3:Vec3f)
            camera_pivot.Position = v3
        End

    Private

        Field camera_pivot:Pivot
        Field real_camera:Camera

        Field chase_target:Model

        Field lastvel:Vec3f
        Field prevvel:Vec3f

        Field up:Vec3f
        Field up_y_default:Float = 2.5

        Field camera_distance:Float = 0.4

End

Function TransformRange:Float (input_value:Float, from_min:Float, from_max:Float, to_min:Float, to_max:Float)

    ' Algorithm via jerryjvl at https://stackoverflow.com/questions/929103/convert-a-number-range-to-another-range-maintaining-ratio

    Local from_delta:Float  = from_max  - from_min  ' Input range,  eg. 0.0 - 1.0
    Local to_delta:Float    = to_max    - to_min    ' Output range, eg. 5.0 - 10.0

    Assert (from_delta <> 0.0, "TransformRange: Invalid input range!")

    Return (((input_value - from_min) * to_delta) / from_delta) + to_min

End

Function Blend:Float (in:Float, target:Float, delta:Float = 0.1)
    If Abs (target - in) < Abs (delta) Then Return target
    Return in + ((target - in) * delta)
End
seyhajin commented 5 years ago

Maybe closed this issue.