MeshCombineUtility.cs - UnityEngine.Mesh.SetTriangleStrip(int[], int)' is obsolete

I´ve upgraded my project to Unity 4. And every now and then i get another warning about obsolete code now. Would be nice when this one would come at once, and not piece by piece. It`s very disturbing when such warnings pops up in the console when you are busy with something else.

This time it is the MeshCombineUtility that tells me that the SetTriangleStrip method is obsolete.

As usual i am totally lost with the scripting reference and their description, better said missing description, of how to use the method. I simply don`t get what is meant here. A very frustrating and often repeated experience when looking into the scripting reference. I wish there would be a comment function for the scripting reference …

This is the warning i get:

Assets/Standard Assets/Scripts/Utility Scripts/MeshCombineUtility.cs(177,30): warning CS0618: `UnityEngine.Mesh.SetTriangleStrip(int[], int)' is obsolete: `Use SetTriangles instead. Internally this function will convert the triangle strip to a list of triangles anyway.'

This is the original code at line 177:

mesh.SetTriangleStrip(strip, 0);

And this doesn`t work:

mesh.SetTriangles (triangles : int[], submesh : int) : void
Assets/Standard Assets/Scripts/Utility Scripts/MeshCombineUtility.cs(177,59): error CS1525: Unexpected symbol `[', expecting `.'

What do i need to do to fix this issue?

Problem solved. This one does the trick:

mesh.SetTriangles(strip, 0);

and the other two trouble lines can be fixed by:

int curStripCount = combine.mesh.GetTriangles(combine.subMeshIndex).Length;

Thanks for listening.

hi there i have this problem also i am knew to unity and scripting how do i solve this? do i write that text in a knew script?

Aaaaah, the good old “it compiles hence it is correct” thing :smile:

The fact that a line does not raise a warning or an error does not imply it is correct, that’s one of the first things you need to learn when studying programming. Your program will happily shoot its own foot if you instruct it to do so in a syntactically and semantically correct way.

These annoying warnings pop up because the code in MeshCombineUtility uses an old function that is no longer supported. What you have to do to get cleanly rid of this warning is to replace the contents of the whole function whith something that does not use the deprecated functionnality. According to the (very useful) details provided in the console with the warning, you should not manipulate triangle strips directly in Unity 4 but rather work with plain triangles only. I propose the following fix : replace the original Combine function with this one …

	public static Mesh Combine (MeshInstance[] combines)
	{
		int vertexCount = 0;
		int triangleCount = 0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
			{
				vertexCount += combine.mesh.vertexCount;
			}
		}
		
		// Precompute how many triangles we need 
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
			{
				triangleCount += combine.mesh.GetTriangles(combine.subMeshIndex).Length;
			}
		}
		
		Vector3[] vertices = new Vector3[vertexCount] ;
		Vector3[] normals = new Vector3[vertexCount] ;
		Vector4[] tangents = new Vector4[vertexCount] ;
		Vector2[] uv = new Vector2[vertexCount];
		Vector2[] uv1 = new Vector2[vertexCount];
		Color[] colors = new Color[vertexCount];
		
		int[] triangles = new int[triangleCount];
		
		int offset;
		
		offset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
				Copy(combine.mesh.vertexCount, combine.mesh.vertices, vertices, ref offset, combine.transform);
		}

		offset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
			{
				Matrix4x4 invTranspose = combine.transform;
				invTranspose = invTranspose.inverse.transpose;
				CopyNormal(combine.mesh.vertexCount, combine.mesh.normals, normals, ref offset, invTranspose);
			}
				
		}
		offset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
			{
				Matrix4x4 invTranspose = combine.transform;
				invTranspose = invTranspose.inverse.transpose;
				CopyTangents(combine.mesh.vertexCount, combine.mesh.tangents, tangents, ref offset, invTranspose);
			}
				
		}
		offset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
				Copy(combine.mesh.vertexCount, combine.mesh.uv, uv, ref offset);
		}
		
		offset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
				Copy(combine.mesh.vertexCount, combine.mesh.uv1, uv1, ref offset);
		}
		
		offset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
				CopyColors(combine.mesh.vertexCount, combine.mesh.colors, colors, ref offset);
		}
		
		int triangleOffset=0;
		int vertexOffset=0;
		foreach( MeshInstance combine in combines )
		{
			if (combine.mesh)
			{
				int[]  inputtriangles = combine.mesh.GetTriangles(combine.subMeshIndex);
				for (int i=0;i<inputtriangles.Length;i++)
				{
					triangles[i+triangleOffset] = inputtriangles[i] + vertexOffset;
				}
				triangleOffset += inputtriangles.Length;
				
				vertexOffset += combine.mesh.vertexCount;
			}
		}
		
		Mesh mesh = new Mesh();
		mesh.name = "Combined Mesh";
		mesh.vertices = vertices;
		mesh.normals = normals;
		mesh.colors = colors;
		mesh.uv = uv;
		mesh.uv1 = uv1;
		mesh.tangents = tangents;
		mesh.triangles = triangles;
		
		return mesh;
	}
	
	static void Copy (int vertexcount, Vector3[] src, Vector3[] dst, ref int offset, Matrix4x4 transform)
	{
		for (int i=0;i<src.Length;i++)
			dst[i+offset] = transform.MultiplyPoint(src[i]);
		offset += vertexcount;
	}

	static void CopyNormal (int vertexcount, Vector3[] src, Vector3[] dst, ref int offset, Matrix4x4 transform)
	{
		for (int i=0;i<src.Length;i++)
			dst[i+offset] = transform.MultiplyVector(src[i]).normalized;
		offset += vertexcount;
	}

	static void Copy (int vertexcount, Vector2[] src, Vector2[] dst, ref int offset)
	{
		for (int i=0;i<src.Length;i++)
			dst[i+offset] = src[i];
		offset += vertexcount;
	}

	static void CopyColors (int vertexcount, Color[] src, Color[] dst, ref int offset)
	{
		for (int i=0;i<src.Length;i++)
			dst[i+offset] = src[i];
		offset += vertexcount;
	}
	
	static void CopyTangents (int vertexcount, Vector4[] src, Vector4[] dst, ref int offset, Matrix4x4 transform)
	{
		for (int i=0;i<src.Length;i++)
		{
			Vector4 p4 = src[i];
			Vector3 p = new Vector3(p4.x, p4.y, p4.z);
			p = transform.MultiplyVector(p).normalized;
			dst[i+offset] = new Vector4(p.x, p.y, p.z, p4.w);
		}
			
		offset += vertexcount;
	}

… and since I deleted the boolean parameter that used to indicate whever strips should be used (hey, they will never be used again since this is deprecated :wink: ), I also have to modify the Start() function if the CombineChildren class (in file CombineChildren.cs, located next to MeshCombineUtility.cs) accordingly so that it does not pass this parameter anymore :

	/// This option has a far longer preprocessing time at startup but leads to better runtime performance.
	void Start () {
		Component[] filters  = GetComponentsInChildren(typeof(MeshFilter));
		Matrix4x4 myTransform = transform.worldToLocalMatrix;
		Hashtable materialToMesh= new Hashtable();
		
		for (int i=0;i<filters.Length;i++) {
			MeshFilter filter = (MeshFilter)filters[i];
			Renderer curRenderer  = filters[i].renderer;
			MeshCombineUtility.MeshInstance instance = new MeshCombineUtility.MeshInstance ();
			instance.mesh = filter.sharedMesh;
			if (curRenderer != null  curRenderer.enabled  instance.mesh != null) {
				instance.transform = myTransform * filter.transform.localToWorldMatrix;
				
				Material[] materials = curRenderer.sharedMaterials;
				for (int m=0;m<materials.Length;m++) {
					instance.subMeshIndex = System.Math.Min(m, instance.mesh.subMeshCount - 1);
	
					ArrayList objects = (ArrayList)materialToMesh[materials[m]];
					if (objects != null) {
						objects.Add(instance);
					}
					else
					{
						objects = new ArrayList ();
						objects.Add(instance);
						materialToMesh.Add(materials[m], objects);
					}
				}
				
				curRenderer.enabled = false;
			}
		}
	
		foreach (DictionaryEntry de  in materialToMesh) {
			ArrayList elements = (ArrayList)de.Value;
			MeshCombineUtility.MeshInstance[] instances = (MeshCombineUtility.MeshInstance[])elements.ToArray(typeof(MeshCombineUtility.MeshInstance));

			// We have a maximum of one material, so just attach the mesh to our own game object
			if (materialToMesh.Count == 1)
			{
				// Make sure we have a mesh filter  renderer
				if (GetComponent(typeof(MeshFilter)) == null)
					gameObject.AddComponent(typeof(MeshFilter));
				if (!GetComponent("MeshRenderer"))
					gameObject.AddComponent("MeshRenderer");
	
				MeshFilter filter = (MeshFilter)GetComponent(typeof(MeshFilter));
				filter.mesh = MeshCombineUtility.Combine(instances);
				renderer.material = (Material)de.Key;
				renderer.enabled = true;
			}
			// We have multiple materials to take care of, build one mesh / gameobject for each material
			// and parent it to this object
			else
			{
				GameObject go = new GameObject("Combined mesh");
				go.transform.parent = transform;
				go.transform.localScale = Vector3.one;
				go.transform.localRotation = Quaternion.identity;
				go.transform.localPosition = Vector3.zero;
				go.AddComponent(typeof(MeshFilter));
				go.AddComponent("MeshRenderer");
				go.renderer.material = (Material)de.Key;
				MeshFilter filter = (MeshFilter)go.GetComponent(typeof(MeshFilter));
				filter.mesh = MeshCombineUtility.Combine(instances);
			}
		}	
	}

This is a rather violent method since it involves modifying the signature of the Combine function and removing one of its parameter : if you use code that calls this function, it will have to be modified also to remove the boolean parameter else it will not compile. On the bright side, the resulting compilation errors will help you locating possible obsolete code that would need to be upgraded.

If you do not want to have these errors, you can simply leave the old, now unused boolean parameter. The forst line of the Combine function would then be …

public static Mesh Combine (MeshInstance[] combines, bool ignoredParameter)
1 Like

Thanks so much for this!! I really don’t know what is going on in the script because I don’t have the time to delve into this concept. But, I recently started using MeshCombineUtilty and CombineChildren and reduced my draw calls by %40. I hated having those warnings though, and yeah you are right that just swapping in the different methods did not help at all. It was pretty dangerous and chaotic.

Could you make some guidlines on why you made each and every change? That would be awesome! I think that Unity should start publishing your version instead of their outdated version.

If you see the warning just replace the Word “GetTriangleStrip” for the word “GetTriangles”

// SUBOPTIMAL FOR PERFORMANCE

//int curStripCount = combine.mesh.GetTriangleStrip(combine.subMeshIndex).Length;

int curStripCount = combine.mesh.GetTriangles(combine.subMeshIndex).Length;

Same with the other Unity example standard asset scripts that have old code not updated.
Change in trigger script
Change this
targetGameObject.active = false;
For
targetGameObject.SetActive(false);

Mike

1 Like

Awesome thread…
Thanks a bunch!