Search Unity

rotating loading feedback stutter problem

Discussion in 'Scripting' started by mmwizard, Nov 24, 2014.

  1. mmwizard

    mmwizard

    Joined:
    Mar 27, 2009
    Posts:
    65
    Hi,
    I'm trying to create a loading feedback consisting of a little rotating icon. But i have a problem with the continuity of the rotation. The problem is that the processes in the background are to cpu intensive. So i get some stutter during the loading. I've tried using a different thread but that doesn't solve it. see code below:

    void Awake()
    {
    this.transform.parent.position = newVector3(Screen.width*0.5f, Screen.height*0.5f,0);
    gameObject.transform.rotation = newQuaternion(0, 0, 0, 0);
    go = this.gameObject;
    thread = newThread(doLogic);
    thread.Start();
    }

    public static void doLogic() {
    while(isbusy){
    go.transform.Rotate(Vector3.back * rotateSpeed);
    }
    }

    voidOnDestroy(){
    thread.Abort();
    }
     
    Nanako likes this.
  2. Stoven

    Stoven

    Joined:
    Jul 28, 2014
    Posts:
    171
    You shouldn't need to use a Thread outside of Unity's main thread to perform the job that you want to do (Transformation update)

    Use a Coroutine instead

    Code (CSharp):
    1. void Awake()
    2. {
    3.     this.transform.parent.position = newVector3(Screen.width*0.5f, Screen.height*0.5f,0);
    4.     gameObject.transform.rotation = newQuaternion(0, 0, 0, 0);
    5.     go = this.gameObject;
    6.     this.StartCoroutine(doLogic());
    7. }
    8.  
    9. public IEnumerator doLogic()
    10. {
    11.     while(isbusy)
    12.     {
    13.         go.transform.Rotate(Vector3.back * rotateSpeed);
    14.         yield return null;
    15.     }
    16. }
    17.  
    18. void Destroy()
    19. {
    20.     isbusy = false; // this shouldn't be necessary, but just in case**
    21. }
    22.  
    The stutter you're experience likely has to do more with the fact that your Thread's execution of doLogic is not always updating the rotation on the same Frame that Unity performs an update. For example, your thread could run 3 times before Unity's update runs once, or run 1 time before Unity's update runs 4 times. In the former case, you've performed several rotations before a Frame has occurred. In the latter case, the rotation is moving slower than you'd expect. As a result, your object will look like its stuttering because its position is not updating with the Frame time.

    You would get similar behavior if you tried updating the position of a GameObject in FixedUpdate as opposed to Update (unless you're using Physics functions on a Rigidbody, then the Physics Engine will approximate the location of where the GameObject is supposed to be, as well as rotation).

    You should only use a Thread that runs outside of Unity's update cycle if you need to do something like an Asynch operation that doesn't rely on Unity's main thread, especially if you are doing a lot of rendering or sending shader information to the GPU from the main thread (or possibly doing other things that take up too much time on the main thread) but must process information from the Asynch operation as soon as its available.

    Lastly, if you want to ensure that your GameObject rotates relatively the same with different FPS, you'll want to use Time.deltaTime while you're modifying your GameObject's transform.

    Code (CSharp):
    1. go.transform.Rotate(Vector3.back * rotateSpeed * Time.deltaTime);
    Though upon doing this you'll have to change your rotateSpeed to a higher number to compensate for the small number from Time.deltaTime

    Edit: Another use case for Threads could be if you cannot break a function into an Async operation and must perform a lot of work at once. I can't think of many situations where one can't separate an action into smaller ones that can be processed one after another to do the same job as that one action, but they could exist.
     
    Last edited: Nov 24, 2014
  3. mmwizard

    mmwizard

    Joined:
    Mar 27, 2009
    Posts:
    65
    Hi Stoven,
    Thank you for you're response. But the problem isn't about wether or not it's in a thread or not. I have tried coroutines. The problem is that my app has a lot to do during the load. like filtering 5000 products, 10000 rules and finding the thumbnails and 3d models in the resource folder. So there are parts in my code where the processor is to busy to update my rotation. Here is a example of some code where i get the stutter. In this case i have to load 100 images with the GetMaterial method, serialised with protobuf.(edit: this protobuf deserialisation is earlier in the process. so that doesn't matter)
    Code (CSharp):
    1.  
    2. public Material GetMaterial(Platforms platform, Shader shader){
    3.             Material material;
    4.  
    5.             if (platform == Platforms.IOS) {
    6.                 material = new Material (shader);
    7.                 if (imageRGB == null)
    8.                     imageRGB = ProcessImage (iosRGBbytes,TextureFormat.PVRTC_4BPP_RGB);
    9.                 material.mainTexture = imageRGB;
    10.             } else if (platform == Platforms.ANDROID) {
    11.                 material = new Material (shader);
    12.                 if (imageRGB == null)
    13.                     imageRGB = ProcessImage (androidRGBbytes,TextureFormat.ETC_RGB4);
    14.                 material.mainTexture = imageRGB;
    15.             } else {
    16.                 material = new Material (shader);
    17.                 if (imageRGBA == null)
    18.                     imageRGBA = new Texture2D (512, 256);
    19.                 imageRGBA.LoadImage (RGBAbytes);
    20.                 imageRGBA.Apply ();
    21.                 material.mainTexture = imageRGBA;
    22.             }
    23.  
    24.             return material;
    25.         }
    26.  
    27.         Texture2D ProcessImage (byte[] bytes, TextureFormat format)
    28.         {
    29.             // header is allready removed while loading so no need for this
    30. //            int headerSize = 52;
    31. //            byte[] buffer = new byte[bytes.Length - headerSize];
    32. //            System.Buffer.BlockCopy (bytes, headerSize, buffer, 0, bytes.Length - headerSize);
    33.  
    34.             Texture2D tex = new Texture2D(512, 512, format, false, false);
    35.             tex.LoadRawTextureData(bytes);
    36.             tex.Apply();
    37.             return tex;
    38.         }
    39.  
    I'm looking for a option where i can load these as fast as possible without the stutter.
     
    Last edited: Nov 25, 2014
  4. Stoven

    Stoven

    Joined:
    Jul 28, 2014
    Posts:
    171
    Have you tried profiling the time it takes for one GetMaterial call to complete?
     
  5. mmwizard

    mmwizard

    Joined:
    Mar 27, 2009
    Posts:
    65
    well ehm, the profiler stops during the loading. But when i execute that part then it takes 986 ms to load these textures. for 93 pvrtc textures. so roughly 10 ms per texture