- Home /
Coroutine does nothing sometimes.
This is really odd. I have a Coroutine that Tessellates a plane for the purpose of LOD creation. Initially it was a function that worked pretty well on its own but as I added more components to my game I needed it to not hog the CPU. I set it as a Coroutine so that it would calculate a number of vertices and triangles before waiting for the next frame. It works well except every now and again it reaches a level of Tesselation and doesn't do anything until it is called again at which point it resumes working.
E.g. I have a key that cycles through LODs, it goes from low to high detail. I press it once and it goes to the next level of tessellation I press it again and it works, I press it again and nothing happens, I press it one more time and it goes to the next level of tessellation as if I hadn't pressed the key previously.
IEnumerator Tessalate (int n){
for (int i = 0; i < n; i ++) {
int cycle = 0;
int count = triangles.Count;
List<TriangleIndices> tempTris = new List<TriangleIndices>();
for (int u = 0; u < count; u ++){
cycle ++;
if (cycle > 50){
cycle = 0;
yield return new WaitForEndOfFrame();
}
int v = verts.Count;
TriangleIndices t = triangles[u];
Vector3 point1 = verts[t.v1];
Vector3 point2 = verts[t.v2];
Vector3 point3 = verts[t.v3];
Vector3 point1a = MeshTools.getMidPoint(point1,point2);
Vector3 point2a = MeshTools.getMidPoint(point2,point3);
Vector3 point3a = MeshTools.getMidPoint(point3,point1);
point1a = MeshTools.putOnSphere(point1a,seed);
point2a = MeshTools.putOnSphere(point2a,seed);
point3a = MeshTools.putOnSphere(point3a,seed);
TriangleIndices t1 = new TriangleIndices(t.v1,v,v+1);
verts.Add(point1a);
verts.Add(point3a);
v = verts.Count;
TriangleIndices t2 = new TriangleIndices(t.v2,v,v+1);
verts.Add(point2a);
verts.Add(point1a);
v = verts.Count;
TriangleIndices t3 = new TriangleIndices(t.v3,v,v+1);
verts.Add(point3a);
verts.Add(point2a);
v = verts.Count;
TriangleIndices t4 = new TriangleIndices(v,v+1,v+2);
verts.Add(point1a);
verts.Add(point2a);
verts.Add(point3a);
tempTris.Add(t1);tempTris.Add(t2);tempTris.Add(t3);tempTris.Add(t4);
}
triangles = tempTris;
}
}
Where it fails in the sequence varies if I change how many cycles it must go through before yielding.
Any ideas?
Forgot to say at no point is the object destroyed or deactivated. The code for the key press for debug purposes is in the same script as this.
Also the cycle number is higher than I originally intended it; I altered it to see the effect on the bug.
Is there a particular reason why you use 'yield return new WaitForEndOfFrame()' ins$$anonymous$$d of 'yield return null' (Wait for next frame) I don't think it has any impact on your problem, but you might give it a try...
Also I suppose that you don't get any errors? (Because errors inside a coroutine ter$$anonymous$$ates them)
And how/when/where do you call the StartCoroutine?
I have tried to debug the problem myself, the WaitForEndOfFrame() is there because originally it was null and I wanted to be sure that it wasn't some weirdness with that.
I think I have spotted the problem. Will post as an answer if it's true.
Answer by Cunnah · Nov 25, 2014 at 03:37 PM
Solved!
Just in case anyone else has this kind of weirdness ensure that no other functions are reliant on your Coroutine otherwise it will execute without any input from the Coroutine. For example.
void Update(){
if (Input.GetKeyUp(KeyCode.T)) {
StartCoroutine(Tessalate(1));
CompileMesh();
}
}
The co-routine uses a temporary list for all new vertices and doesn't update the master list until it is finished. Funnily enough trying to compile before the Coroutine is finished will just end up using the old master file!
EDIT: sorry this was more an example of what not to do and an explanation why. I have moved CompileMesh() to the end of the Coroutine the correct code looks like this;
void Update(){
if (Input.GetKeyUp(KeyCode.T) {
StartCoroutine(Tessalate(1));
}
}
with the CompileMesh() at the end of the Coroutine.
Uhm, this doesn't really answer your question. It just shows your wrong code. This code should be part of your question and not part of an answer. The answer should show correct code.
StartCoroutine returns at the first yield, so your Compile$$anonymous$$esh method will be executed before the coroutine is finished. To solve this you usually do everything in one coroutine or you use a callback which is called from the coroutine when done.
btw: Some time ago i made some helpers to subdivide a mesh. It seems you're not taking care of normals / colors / uvs / ...
That was my point that Compile$$anonymous$$esh() is in the wrong place and executing before the Coroutine could finish. I have moved to be executed at the end of the coroutine problem solved. Compile$$anonymous$$esh deals with normals and the like, The triangleIndicies struct can store color information since I am going for a flat shaded low res look I want each triangle to be a uniform color. If I don't give it a color it defaults to grey.
There are no UV's as there are no textures everything is handled via the shader.