So I wrote this script for moving objects, but especially in VR this will result in a considerable impact on performance when moving about 4 objects at the same time:
IEnumerator MoveObject (GameObject OBJ, Vector3 pos0, Vector3 pos1, float stepSize, float waitTime) {
Vector3 currentPos;
for (float i = 0.0f; i < 1.0f; i += stepSize) {
currentPos = Vector3.Lerp(pos0,pos1,i);
OBJ.transform.position = currentPos;
yield return new WaitForSeconds(waitTime);
}
}
Well, you can cache the transform so that youāre not using the ātransformā property. Even though they claimed to have cached it for you now, Iāve heard itās still not performing very well (though havenāt measured it myself - I always cache it).
You can also put the ānew WaitForSeconds(waitTime)ā outside of the for loop in a variable to avoid allocating new memory for it on each iteration (and invoking the GC).
Iād guess itās not the code itself thatās hurting performance; Iād guess youāre moving an object that has a Collider but no Rigidbody, which is a long-standing Unity issue. If itās an object with a Collider, add a Rigidbody to it and check āIs Kinematicā - the rest of the Rigidbody fields donāt matter - then it should move more smoothly.
Thanks for your help, @JasonBricco !
I was thinking about caching the transform before, but I thought it wouldnāt make a big difference.
However, I will try caching it! The YieldInstruction, too, of course!
Maybe this already solves the problem.
Just to make sure, this is how it would look like, right?:
IEnumerator MoveObject (GameObject OBJ, Vector3 pos0, Vector3 pos1, float stepSize, float waitTime) {
Transform objTransform = OBJ.transform;
Vector3 currentPos;
YieldInstruction _waitTime = new WaitForSeconds(waitTime);
for (float i = 0.0f; i < 1.0f; i += stepSize) {
currentPos = Vector3.Lerp(pos0,pos1,i);
objTransform.position = currentPos;
yield return _waitTime;
}
}
Thank you for the suggestion! Itās good to know! If I remember correctly, though, I didnāt use a collider on the object because it was supposed to be some visual effect only. Anyway, Iām not positive and when I run into some issues again, I will make sure to take another look at Collider / Rigidbody components as you suggested!
The reason Iām thinking itās something unrelated to the code is that while Jason is correct that fixing those things may give you a tiny bump in performance, that code should not be having any āconsiderable impact on performanceā with only 4 objects. If you were moving 4000 objects then maybe, but for only 4 that shouldnāt even be a blip. You can use the Profiler window and turn on āDeep Profilingā and run to see what is taking up the most time each frame; I doubt that itās that code.
Oh, four objects. Didnāt catch that. Yeah, with only four it definitely shouldnāt be causing problems as is. Thatās fairly strange. Iād have to agree with using the profiler to see whatās going on.
My guess, is that you are wrong about what you are thinkingā¦ What is happening in your script is Every X seconds, you move an object from one point to another, and because this is not smooth, you feel that it is hitting performance. You honestly have to run this at the fixed Update level and have thousands of them doing this for it to affect performance.
The next part, is that you are stepping a Lerp, which is really not going to be a good idea anyways. You would want to use MoveTowards with the distance divided by the steps. Still, you are only approximating what you should be doing.
This of course, if each of these objects is ānormalā or not super high poly count.
Super high polycounts would probably give monster performance issues.
This being said, you should transform this into a simple controller that happens each Update cycle, and try not to use coroutines.
Here is an alternate implementation of what you are trying to achieve.
// this code moves each block
using UnityEngine;
using System.Collections;
public class MovingObject : MonoBehaviour
{
public Vector3 target;
public float speed = 3;
public GameObject callBackObject;
void Update()
{
if (target == null) return;
if ((target - transform.position).sqrMagnitude == 0 && callBackObject != null)
callBackObject.BroadcastMessage("MoveFinished", gameObject, SendMessageOptions.DontRequireReceiver);
var position = transform.position;
position = Vector3.MoveTowards(position, target, speed * Time.deltaTime);
transform.position = position;
}
// callback for moving this obj
void Move()
{
target = transform.position + Random.insideUnitSphere * 20;
this.target = target;
}
}
// this is a master controller to add more blocks to the scene
using UnityEngine;
using System.Collections;
public class MovingMasterController : MonoBehaviour
{
// Add obj to the controller
void AddObject(GameObject obj)
{
if (obj == null)
obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
var controller = obj.GetComponent<MovingObject>();
if (controller == null) controller = obj.AddComponent<MovingObject>();
controller.callBackObject = gameObject;
MoveFinished(obj);
}
// callback on controller obj
void MoveFinished(GameObject obj)
{
obj.BroadcastMessage("Move", SendMessageOptions.DontRequireReceiver);
}
float nextObject = 0;
float timePerObject = 2;
void Update()
{
if (nextObject <= 0)
{
AddObject(null);
nextObject = timePerObject;
}
nextObject -= Time.deltaTime;
}
}
For reference, moving static colliders in UT5+ is no longer an issue - or at least not as much as it was with previous versions. http://blogs.unity3d.com/2014/07/08/high-performance-physics-in-unity-5/
I agree that moving only four objects shouldnāt be too much of an issue, however that also heavily depends upon what those objects are and how many child objects they contain. Moving terrain for example can be quite heavy due to the time it takes to reconfigure culling. Moving one object with many children will also come with addition overhead.
Yeah, as bigmisterb said, what your script actually does is cause the object to warp from one spot to the next every āwaitTimeā secondsā¦ I assumed thatās what you wanted it to do. Maybe youāre seeing that and assuming itās a bad framerate. If you want it to move smoothly:
Thank you for all of your replies and sample scripts!
This may be somewhat OT now as it doesnāt seem to be an issue after all, but how would I be caching a Transform?
Transform objTransform = OBJ.transform;
// or
Transform objTransform = OBJ.GetComponent<Transform>();
Thatās not the issue actually. When I use stepSize and waitTime small enough, I will get a decently looking, smooth and accurate animation from one point in space to the other. The issue is that when reducing the waitTime to make it smooth, the impact on performance will be visible due to lag of the first-person controller.
Maybe in the next days I will take a deeper look into the profiler again and let you know what I find.
The objects were very basic spheres (Iām not sure if Unityās internal spheres, which would have included a Collision component, which I might not have removed), but the poly count was probably < 1000. Also, the objects didnāt have any children attached and a very basic (reflective semi-transparent) material.
EDIT:
Just to make sure, I usually pass values at about that size:
waitTime = 0.01f
stepSize = 0.02f
Maybe it is a problem solved by caching after all? After all, I am calling the for loop 100 times per second (ideally).
EDIT2:
Oh and Iād really like to use a coroutine as I donāt want to play it all the time and checking a bool each frame seems unnecessary, right? Especially when I want to have quite an amount of objects moving and not necessarily all at the same time (resulting in a bool for each object). It also makes sure the object transitions all the way through to pos1 instead of stopping in the middle when it needs to be cancelled.
Can you explain why I shouldnāt use a coroutine?
I just tested the coroutine using 48 standard Unity spheres, which is 160k verts. Resulted in about 110fps - I guess thatās okay? Will have to test in VR scenario to be positive, though.
Also, I couldnāt see any change in performance when removing the sphere collider.
EDIT:
In the test scenario, I just tried to use the same script but without caching. This will result in a fps loss of about 5-10. Not sure if this is enough to make a difference in the VR scenario.
I dont think co-routines are designed for this sort of thing for oneā¦ they generate garbage if you dont know what youre doing, which is never a good thing.
Those performance results are abysmal, but I dont know what hardware youre running.
I can get much better performance moving hundreds of gameobjects
Yes, thatās true, but the thing is: I want to access other things from the GameObject, too. So it makes sense passing the GameObject? Iām not sure if caching a component about once per second (after each animation) is better or additionally passing Transform.
I donāt know what to tell you. Thatās just how it is. With caching both the YieldInstruction and the Transform, I get about 105-120fps (average 112,5fps). Without caching, I get about 95 - 110fps 102,5 (average 102,5fps).
So you use MoveTowards in Update()? I just try to avoid using Update as much as possible for things like that, because I want a clean way to animate things without creating a mess, yet being able to keep things variable. For example, if I want the resulting position to change, I will have a problem when doing this during Update as I donāt know at which state the object is. When running the coroutine, I can set a new pos1 exactly after it reaches pos0 again.
Here are some of my specs (not used for VR, but used for test scene):
Unity 5.2.2
Retina Macbook Pro 2015, 2,8 GHz i7, quad-core, 16 GB RAM, Intel Iris Pro 1536 MB
OSX 10.11.5
EDIT:
I just ran an empty scene and get about 90 - 140 fps (about 3/4 of the time around 90), so average about 102,5 fps, which is kind of weird. It actually runs faster with 48 spheres and the script that caches the YieldInstruction and the Transform and about just as fast as with the script that doesnāt cache.
You should really use the Profiler window and look at what is taking up time in your frames. Click in the āCPU Usageā section and youāll get a list of everything in order thatās taking up time. If āMoveObjectā isnāt near the top of that list, then itās unlikely that itās having much of an effect.
Just to make sure I wasnāt crazy, I copied and pasted the exact script from your original post and put it on 1000 spheres and set the wait time really low so that it basically ran every frame, and there was no discernible difference between whether the transform was cached. Caching the WaitForSeconds reduced garbage a bit but not enough that it impacted the framerate. I have a much less beefy computer than you and I got 200+ FPS with a thousand spheres. With only four spheres I got 2000+ FPS. If youāre only seeing 100 FPS with only four spheres, something else is going on.
If you need a reference to GameObject and Transform, just pass them both to the functionā¦ but this really is micro optimization so I shouldnāt worry too much. It certainly sounds like you have bigger issues reducing your performance. Perhaps something outside of UT eating your CPU?