blitz-foundation / monkey2

zlib License
3 stars 0 forks source link

Weird jumping/flickering sprites problem #103

Closed Pharmhaus-2 closed 5 years ago

Pharmhaus-2 commented 5 years ago

Original Author: DruggedBunny

Hi Mark,

Bit of an odd one I've run into while trying to convert my rocket smoke from cubes to sprites, sort of narrowed it down to the sample below.

In short, I'm firing a stream of physics-controlled particles that cycles through white, yellow, orange, red, black, then fade out. It should look like this (extreme debug version using cubes):

particles

However, when using sprites, they start out correctly, then once a few of them are active at once, they start to flicker and jump.

You should be able to see it in the code below. Note that the class is duplicated, just that one uses cubes, other uses sprites.

Hold Space for a constant stream and note the cubes are fine, but the sprites start jumping and flickering. With short taps, the sprites are also OK, but held for a little longer, they start to mess up. (Tap Enter for single particles and note they only screw up if tapped rapidly.)

Thought it was some sort of alpha problem, but replacing alpha with a dummy variable (leaving entity alpha at 1.0 throughout) does the same thing.


Namespace myapp3d

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

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

' ---------------------- SPRITE version ----------------------

Class RocketParticle_Sprite Extends Behaviour

    Public

        Function Create:RocketParticle_Sprite (parent:Entity, thrust:Vec3f, size:Float = 0.5, fadeout:Float = 0.95)

'Game.MainCamera.CameraDistance = 4.0
            'RocketParticle.SpriteInit ()

            Local sprite:Sprite = New Sprite (New SpriteMaterial (), parent)

                Cast <SpriteMaterial> (sprite.Material).ColorFactor = Color.White

                'sprite.Move (Rnd (-0.1, 0.1), Rnd (-2.1, -2.5), Rnd (-0.1, 0.1))

                sprite.Move (0.0, -2.1, 0.0)

                sprite.Parent               = Null
                sprite.Scale                = New Vec3f (size, size, 0.0)
                sprite.Alpha                = 1.0

            Local sp:RocketParticle_Sprite          = New RocketParticle_Sprite (sprite)

                sp.thrust                   = thrust
                sp.update_fader             = fadeout

                sp.TMP_fake_alpha = 1.0

            Return sp

        End

    Private

        Method New (entity:Entity)

            Super.New (entity)

            AddInstance ()

        End

        Method OnStart () Override

            Local collider:BoxCollider  = Entity.AddComponent <BoxCollider> () ' Unexpected: Collider needs to be added BEFORE applying impulse!

            Local body:RigidBody        = Entity.AddComponent <RigidBody> ()
' No Boxf!
                body.Mass               = 0.01
                body.Restitution        = 0.5
                body.Friction           = 0.1

                body.CollisionMask      = 0'COLL_NOTHING

                body.ApplyImpulse (thrust)

                thrust                  = Null ' Don't need to keep temp Vec3f object

        End

        Method OnUpdate (elapsed:Float) Override

        '       Print Int (color_change * 5.0)

'               Cast <Sprite> (Entity).Material = SpriteMat [Int (Entity.Alpha * 5.0)] ' There are 5 sprite materials

'               Local sm:SpriteMaterial = Cast <SpriteMaterial> (Cast <Sprite> (Entity).Material)

                Local cs:Sprite = Cast <Sprite> (Entity)
                Local sm:SpriteMaterial = Cast <SpriteMaterial> (cs.Material)

'               Local cs:Model  = Cast <Model> (Entity)
'               Local sm:PbrMaterial    = Cast <PbrMaterial> (cs.Material)

                Select Int (color_change * 5.0) ' There are 5 sprite materials
                    Case 0
                        sm.ColorFactor = Color.Black
                    Case 1
                        sm.ColorFactor = Color.Red
                    Case 2
                        sm.ColorFactor = Color.Orange
                    Case 3
                        sm.ColorFactor = Color.Yellow
                    Case 4
                        sm.ColorFactor = Color.White
                End

                If sm.ColorFactor = Color.Black
                    Entity.Alpha = Entity.Alpha * 0.975 ' TODO: Needs adjusting for framerate!
                    'TMP_fake_alpha = TMP_fake_alpha * 0.975
                Else
                    color_change = color_change * update_fader ' TODO: Needs adjusting for framerate!
                End

                ' Slow particle down (air resistance)... very dependent on start speed and alpha fade amount...

                Entity.GetComponent <RigidBody> ().LinearDamping = (1.0 - color_change)' * 0.95 ' Trial and error!

                'If TMP_fake_alpha < 0.075'
                If Entity.Alpha < 0.075
                    Entity.Destroy ()
                Endif

        End

        ' Rocket thrust level -- need to temp-store here as OnStart can't be passed custom params!

        Field thrust:Vec3f
        Field update_fader:Float
        Field color_change:Float = 0.99

        Field TMP_fake_alpha:Float
End

' ---------------------- MESH version ----------------------

Class RocketParticle_Mesh Extends Behaviour

    Public

        Function Create:RocketParticle_Mesh (parent:Entity, thrust:Vec3f, size:Float = 0.5, fadeout:Float = 0.95)

'Game.MainCamera.CameraDistance = 4.0
            'RocketParticle.SpriteInit ()

'           Local sprite:Sprite = New Sprite (New SpriteMaterial (), rocket.RocketModel)
            Local sprite:Model = Model.CreateBox (New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5), 1, 1, 1, New PbrMaterial (Color.White), parent)'New Sprite (New SpriteMaterial (), rocket.RocketModel)

'               Cast <SpriteMaterial> (sprite.Material).ColorFactor = Color.White

                'sprite.Move (Rnd (-0.1, 0.1), Rnd (-2.1, -2.5), Rnd (-0.1, 0.1))

                sprite.Move (0.0, -2.1, 0.0)

                sprite.Parent               = Null
                sprite.Scale                = New Vec3f (size, size, size)
                sprite.Alpha                = 1.0

            Local sp:RocketParticle_Mesh            = New RocketParticle_Mesh (sprite)

                sp.thrust                   = thrust
                sp.update_fader             = fadeout

                sp.TMP_fake_alpha = 1.0

            Return sp

        End

    Private

        Method New (entity:Entity)

            Super.New (entity)

            AddInstance ()

        End

        Method OnStart () Override

            Local collider:BoxCollider  = Entity.AddComponent <BoxCollider> () ' Unexpected: Collider needs to be added BEFORE applying impulse!

            Local body:RigidBody        = Entity.AddComponent <RigidBody> ()
' No Boxf!
                body.Mass               = 0.01
                body.Restitution        = 0.5
                body.Friction           = 0.1

                body.CollisionMask      = 0'COLL_NOTHING

                body.ApplyImpulse (thrust)

                thrust                  = Null ' Don't need to keep temp Vec3f object

        End

        Method OnUpdate (elapsed:Float) Override

        '       Print Int (color_change * 5.0)

'               Cast <Sprite> (Entity).Material = SpriteMat [Int (Entity.Alpha * 5.0)] ' There are 5 sprite materials

'               Local sm:SpriteMaterial = Cast <SpriteMaterial> (Cast <Sprite> (Entity).Material)

'               Local cs:Sprite = Cast <Sprite> (Entity)
'               Local sm:SpriteMaterial = Cast <SpriteMaterial> (cs.Material)

                Local cs:Model  = Cast <Model> (Entity)
                Local sm:PbrMaterial    = Cast <PbrMaterial> (cs.Material)

                Select Int (color_change * 5.0) ' There are 5 sprite materials
                    Case 0
                        sm.ColorFactor = Color.Black
                    Case 1
                        sm.ColorFactor = Color.Red
                    Case 2
                        sm.ColorFactor = Color.Orange
                    Case 3
                        sm.ColorFactor = Color.Yellow
                    Case 4
                        sm.ColorFactor = Color.White
                End

                If sm.ColorFactor = Color.Black
                    Entity.Alpha = Entity.Alpha * 0.975 ' TODO: Needs adjusting for framerate!
                '   TMP_fake_alpha = TMP_fake_alpha * 0.975
                Else
                    color_change = color_change * update_fader ' TODO: Needs adjusting for framerate!
                End

                ' Slow particle down (air resistance)... very dependent on start speed and alpha fade amount...

                Entity.GetComponent <RigidBody> ().LinearDamping = (1.0 - color_change)' * 0.95 ' Trial and error!

                'If TMP_fake_alpha < 0.075'
                If Entity.Alpha < 0.075
                    Entity.Destroy ()
                Endif

        End

        ' Rocket thrust level -- need to temp-store here as OnStart can't be passed custom params!

        Field thrust:Vec3f
        Field update_fader:Float
        Field color_change:Float = 0.99

        Field TMP_fake_alpha:Float
End

Class MyWindow Extends Window

    Field _scene:Scene
    Field _camera:Camera
    Field _light:Light
    Field _ground:Model

    Field pivot0:Pivot
    Field pivot1:Pivot

    Method New( title:String="Simple mojo3d 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 = 200.0

        'create camera
        _camera=New Camera( Self )
        _camera.AddComponent<FlyBehaviour>()
        _camera.Move( 0,2.5,-5 )
        _camera.Rotate (-25, 0, 0)

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

        'create ground
        Local groundBox:=New Boxf( -100,-1,-100,100,0,100 )
        Local groundMaterial:=New PbrMaterial( Color.Lime )
        _ground=Model.CreateBox( groundBox,1,1,1,groundMaterial )
        _ground.CastsShadow=False

        pivot0 = New Pivot
        pivot0.Move (-3, 7.5, 0)

        pivot1 = New Pivot
        pivot1.Move (3, 7.5, 0)

    End

    Method OnRender( canvas:Canvas ) Override

        Local spread:Float = 0.025

        If Keyboard.KeyHit (Key.Enter)
            RocketParticle_Mesh.Create (pivot0, New Vec3f (Rnd (-spread, spread), 0.1, Rnd (-spread, spread)))
            RocketParticle_Sprite.Create (pivot1, New Vec3f (Rnd (-spread, spread), 0.1, Rnd (-spread, spread)))
        Endif

        If Keyboard.KeyDown (Key.Space)
            For Local loop:Int = 1 To 1
                RocketParticle_Mesh.Create (pivot0, New Vec3f (Rnd (-spread, spread), 0.1, Rnd (-spread, spread)))
                RocketParticle_Sprite.Create (pivot1, New Vec3f (Rnd (-spread, spread), 0.1, Rnd (-spread, spread)))
            Next
        Endif

        If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()
        RequestRender()
        _scene.Update()
        _camera.Render( canvas )
        canvas.DrawText( "FPS="+App.FPS,0,0 )
        canvas.DrawText( "SPACE: Stream of particles",0,20 )
        canvas.DrawText( "ENTER: Single particles",0,40 )
        canvas.DrawText( "RocketParticle_Mesh on left",0,80 )
        canvas.DrawText( "RocketParticle_Sprite on right",0,100 )
    End

End

Function Main()

    New AppInstance

    New MyWindow

    App.Run()
End
Pharmhaus-2 commented 5 years ago

Fixed in develop