2
\$\begingroup\$

I'm working in Unity and getting some crazy weird motion behavior. I have a plane and I'm moving it. It's ever so slightly getting about 1 pixel bigger and smaller. It looks like the it's kind of getting squeezed sideways by a pixel. I'm moving a plane by cos and sin so it will spin on the x and z axes. If the planes are moving at Time.time, everything is fine. However, if I put in slower speed multiplier, I get an amazingly weird jerk in my animation. I get it with or without the lerp. How do I fix it? I want it to move very slowly. Is there some sort of invisible grid in unity? Some sort of minimum motion per frame?

I put a visual sample of the behavior here.

Here's the relevant code:

public void spin()
{

         for (int i = 0; i < numPlanes; i++ )
    {   
        GameObject g = planes[i] as GameObject;

        //alt method 
        //currentRotation += speed * Time.deltaTime * 100;
        //rotation.eulerAngles = new Vector3(0, currentRotation, 0);
        //g.transform.position = rotation * rotationRadius; 

        //sine method
        g.GetComponent<PlaneSetup>().pos.x = g.GetComponent<PlaneSetup>().radiusX * (Mathf.Cos((Time.time*speed) + g.GetComponent<PlaneSetup>().startAngle));
        g.GetComponent<PlaneSetup>().pos.z = g.GetComponent<PlaneSetup>().radius * Mathf.Sin((Time.time*speed) + g.GetComponent<PlaneSetup>().startAngle);
        g.GetComponent<PlaneSetup>().pos.y = g.GetComponent<Transform>().position.y;
        ////offset
        g.GetComponent<PlaneSetup>().pos.z += 20;

        g.GetComponent<PlaneSetup>().posLerp.x = Mathf.Lerp(g.transform.position.x,g.GetComponent<PlaneSetup>().pos.x, .5f);

        g.GetComponent<PlaneSetup>().posLerp.z = Mathf.Lerp(g.transform.position.z, g.GetComponent<PlaneSetup>().pos.z, .5f);
        g.GetComponent<PlaneSetup>().posLerp.y = g.GetComponent<Transform>().position.y;
        g.transform.position = g.GetComponent<PlaneSetup>().posLerp; 

    }


    Invoke("spin",0.0f);
}

The full code is on github.


There is literally nothing else going on. I've turned off all other game objects so it's only the 40 planes with a texture2D shader.

I removed it from Invoke and tried it in Update -- still happens. With a set frame rate or not, the same problem occurs. Tested it in Fixed Update. Same issue.

The script on the individual plane doesn't even have an update function in it. The data on it could functionally live in a struct.

I'm getting between 90 and 123 fps. Going to investigate and test further. I put this in an invoke function to see if I could get around it just occurring in update. There are no physics on these shapes. It's a straight procedural animation.

Limited it to 1 plane - still happens. Thoughts?


Removed the shader - still happening.

\$\endgroup\$
  • 5
    \$\begingroup\$ Unity can be such a jerk. \$\endgroup\$ – Engineer Apr 20 '14 at 19:25
  • \$\begingroup\$ Please edit your question to provide updates. The answers section is for answers only. \$\endgroup\$ – MichaelHouse Apr 20 '14 at 20:24
  • \$\begingroup\$ Can you further describe exactly what its behavior is? "some crazy weird motion behavior" is pretty open to interpretation. This will be useful for those of us that don't wish to download your example. \$\endgroup\$ – MichaelHouse Apr 20 '14 at 20:25
  • \$\begingroup\$ Yep did that just now. Your solution produces the same problem as mine if you slow it down enough. Are you on a windows or mac? I'm starting to suspect this is a bug and I need to find another way to accomplish this. \$\endgroup\$ – Phoenix Perry Apr 21 '14 at 9:49
  • 1
    \$\begingroup\$ You should not invoke GetComponent multiple time to fetch the same component. Just fetch it once. \$\endgroup\$ – sharvey Apr 23 '14 at 14:23
2
\$\begingroup\$

The simple example of:

public float speed = 2;

void Start () {
    spin ();
}

public void spin() {
    Vector3 newPos = this.transform.position;
    newPos.x = 20 * Mathf.Cos((Time.time*speed));
    newPos.z = 20 * Mathf.Sin((Time.time*speed));

    this.transform.position = newPos;
    Invoke("spin",0.0f);
}

Works just fine for me. Increasing the speed makes the plane orbit faster. I suspect you have an issue somewhere else in your code.

Or you're having performance issues that's causing the animation to not be smooth. If you're making this call on a number of planes, it can be slow. Using Invoke requires reflection, which can be slower than just calling the method itself. Do some profiling to find out if it's a performance issue. Or you can simply try hitting the "Stats" button in the top right of the editor window to see your FPS and time per frame.

\$\endgroup\$
0
\$\begingroup\$

You should be manipulating a fixed frame rate which calls Update() on your GameObjects. You should not be using Invoke() for timing your game loop, and especially not rendering or physics updates. Using the wrong timing mechanisms will often cause temporal artifacts such as that which you're currently seeing.

Application.targetFrameRate should give you the control you desire.

\$\endgroup\$
  • \$\begingroup\$ Yep, didn't do anything. I had it in update. I put it in Invoke to test it. Tried everything from recursively calling it in a loop to fixed update and every possible variant of Time.time and a plain old counter. It only shows up when you go very slowly. \$\endgroup\$ – Phoenix Perry Apr 21 '14 at 9:57
0
\$\begingroup\$

Couple of quick thoughts:

  1. Did you mean to reference g.GetComponent().radius instead of g.GetComponent().radiusZ perhaps?

  2. The inclusion of the start angle into the Cos and Sin functions may be resulting in an unexpected value. Perhaps try removing it and seeing if the jerkyness removes? Same goes with the offset.

Because removing the speed value from the trig functions fixes your issues, I believe that your problem lies in those two lines.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.