array out of range while updating mesh variables

Original Question :

I have a string that is converted to a custom text mesh.

Whenever the size of the Built-In arrays are changed, for the first frame/loop/cycle I get out of range errors :

Mesh.vertices is too small. The supplied vertex array has less vertices than are referenced by the triangles array.
UnityEngine.Mesh:set_vertices(Vector3[])
SText:UpdateTextChar() (at Assets/_Custom/Sprites/SText.js:145)
SText:UpdateText(String) (at Assets/_Custom/Sprites/SText.js:172)
UI_Manager:UpdateStats() (at Assets/_Scripts/UI_Manager.js:202)
UI_Manager:Update() (at Assets/_Scripts/UI_Manager.js:102)

Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
UnityEngine.Mesh:set_uv(Vector2[])
SText:UpdateTextChar() (at Assets/_Custom/Sprites/SText.js:146)
SText:UpdateText(String) (at Assets/_Custom/Sprites/SText.js:172)
UI_Manager:UpdateStats() (at Assets/_Scripts/UI_Manager.js:202)
UI_Manager:Update() (at Assets/_Scripts/UI_Manager.js:102)

Mesh.normals is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
UnityEngine.Mesh:set_normals(Vector3[])
SText:UpdateTextChar() (at Assets/_Custom/Sprites/SText.js:148)
SText:UpdateText(String) (at Assets/_Custom/Sprites/SText.js:172)
UI_Manager:UpdateStats() (at Assets/_Scripts/UI_Manager.js:202)
UI_Manager:Update() (at Assets/_Scripts/UI_Manager.js:102)

I cannot understand it, as this worked without error when running Unity 3.5.1, but now running 3.5.6 I have this error across all projects where I have used my sprite and text classes.

The arrays are set by the length of the string before the mesh is generated in UpdateTextMesh(). I have tried merging this function with UpdateTextChar() and using helloStringLength instead of .length in every subsequent for-loop, but it makes no diference. I cannot see how the arrays are being assigned the wrong length for the first cycle when helloStringLength changes size.

Here is my SText Script :

#pragma strict
@script RequireComponent(MeshFilter, MeshRenderer)

#if UNITY_EDITOR
@ContextMenu ("Construct sText")
function ConstructText() 
{
    Debug.Log("Constructing sText from ContextMenu");
	ConstructOnCreation();
}
	
function ConstructOnCreation() 
{
	if(!myTextMesh)
	{
		GetComponent(MeshFilter).mesh = myTextMesh = new Mesh();
		myTextMesh.name = "sTextMesh";
	}
	
	UpdateText( helloString );
}
#endif

public class SText extends MonoBehaviour
{
	public var textSheetInfo : TextAsset;
	public var textureWidth : int;
	public var textureHeight : int;
		
	public var helloString : String = "Hello";
	
	public var charSize : float = 1.0;
	public var _char_id : int[]; 
	public var _char_x : int[]; 
	public var _char_y : int[]; 
	public var _char_width : int[]; 
	public var _char_height : int[]; 
	public var _char_xoffset : int[]; 
	public var _char_yoffset : int[]; 
	public var _char_xadvance : int[]; 
		
	private var myTextMesh : Mesh;
	private var uv : Vector2[];
	private var verts : Vector3[];
	private var tris : int[];
	private var normals : Vector3[];
	private var size : Vector2 = Vector2.one;
	private var offset : Vector2 = Vector2(0.0, 0.0);
	private var uvSize : Vector2 = Vector2(1.0, 1.0);
	private var uvOffset : Vector2 = Vector2(0.0, 0.0);
	
	private var letter : String;
	private var textAlignX : float = 0.0;
	private var textAlignY : float = 0.0;
	public var textPaddingX : float = 0.0;
	
	
	function Awake() 
	{
		if(!myTextMesh)
		{
			GetComponent(MeshFilter).mesh = myTextMesh = new Mesh();
			myTextMesh.name = "sTextMesh";
		}
		
		UpdateText( helloString );
	}
	
	function Start() 
	{ 
		yield WaitForSeconds( 2.0 );
		
		UpdateText( "Droogie" );
		
		yield WaitForSeconds( 2.0 );
		
		UpdateText( "Droogie !..!, ('.') ,!..!" );
	}
	
	function Update() { 
	}
	
	
	// CONSTRUCTING Text
	
	function UpdateTextMesh() 
	{
		var helloStringLength : int = helloString.Length;
		
		verts = new Vector3[helloStringLength * 4];
		uv = new Vector2[helloStringLength * 4];
		tris = new int[helloStringLength * 6];
		normals = new Vector3[helloStringLength * 4];
		
		myTextMesh = this.transform.GetComponent(MeshFilter).mesh as Mesh;
		
		
		var readString : int = 0;
		textAlignX = 0;
		textAlignY = 0;
		
		for (readString = 0; readString < helloStringLength; readString ++)
		{
			letter = helloString.Substring( readString, 1 );
			
			var uniString : int = (letter[0]);
								
			uvSize = Vector2( parseFloat(_char_width[uniString]) / parseFloat(textureWidth), 
							 parseFloat(_char_height[uniString]) / parseFloat(textureHeight) );
			
			uvOffset = Vector2( parseFloat(_char_x[uniString]) / parseFloat(textureWidth), 
								parseFloat(_char_y[uniString]) / parseFloat(textureHeight) );
			
			size = Vector2( parseFloat(_char_width[uniString]), parseFloat(_char_height[uniString]) );
			
			offset = Vector2( parseFloat(_char_xoffset[uniString]), parseFloat(_char_yoffset[uniString]) );
			
			textAlignX += _char_xoffset[uniString];
			textAlignY = 0 -  ( _char_yoffset[uniString] * 0.5 );
			
			// BuildTextChar
			verts[(readString * 4) + 0] = new Vector3( ( textAlignX + offset.x ) * (charSize / 64), ( 0 - offset.y ) * (charSize / 64), 0);
			verts[(readString * 4) + 1] = new Vector3( ( textAlignX + offset.x + size.x ) * (charSize / 64), ( 0 - offset.y ) * (charSize / 64), 0);
			verts[(readString * 4) + 2] = new Vector3( ( textAlignX + offset.x ) * (charSize / 64), ( 0 - offset.y - size.y ) * (charSize / 64), 0);
			verts[(readString * 4) + 3] = new Vector3( ( textAlignX + offset.x + size.x ) * (charSize / 64), ( 0 - offset.y - size.y ) * (charSize / 64), 0);
			
			uv[(readString * 4) + 2] = new Vector2(uvOffset.x, 1.0 - uvOffset.y - uvSize.y);
			uv[(readString * 4) + 3] = new Vector2(uvOffset.x + uvSize.x, 1.0 - uvOffset.y - uvSize.y);
			uv[(readString * 4) + 0] = new Vector2(uvOffset.x, 1.0 - uvOffset.y);
			uv[(readString * 4) + 1] = new Vector2(uvOffset.x + uvSize.x, 1.0 - uvOffset.y);
			
			tris[(readString * 6) + 0] = (readString * 4) + 0;
			tris[(readString * 6) + 1] = (readString * 4) + 1;
			tris[(readString * 6) + 2] = (readString * 4) + 2;
			tris[(readString * 6) + 3] = (readString * 4) + 2;
			tris[(readString * 6) + 4] = (readString * 4) + 1;
			tris[(readString * 6) + 5] = (readString * 4) + 3;
		
			textAlignX += textPaddingX + _char_xadvance[uniString];
		}
		
		
		myTextMesh.vertices = verts;
		myTextMesh.uv = uv;
		myTextMesh.triangles = tris;
		myTextMesh.normals = normals;
		
		myTextMesh.RecalculateBounds();	
		myTextMesh.RecalculateNormals();
		
		// Calculate Tangents
		TangentSolver(myTextMesh);
		
	}
	
	
	// UPDATING Text
	
	public function UpdateText( textString : String )  // TEXT
	{
		helloString = textString;
		//transform.position = Vector3(posX, posY, layer); // transform.position.z
		//textPaddingX = padding; // 0.0;
		
		UpdateTextMesh();
	}
	
}

Here is the script I am using to update the speed :

public var speedText : SText;

function Update() 
{
	speedText.UpdateText( parseInt( currentSpeed ).ToString() );
}

EDIT :

From the advice I have received from Kryptos and phodges, the title of the question should now be :

How do I correctly create and optimize my meshes, and correctly modify the vertex information per change in vertices alone, and/or triangles & uvs length or values ?

Since I learned mesh generation, my procedure was as follows :

  • declare builtin arrays to store and calculate the vertex information

  • declare the size of these arrays

  • calculate verts / uvs / tris / normals

  • get the mesh filter / mesh

  • assign the mesh vertex arrays the same length as the builtin arrays’ lengths

  • assign all the values from the builtin arrays to the mesh vertices etc

  • RecalculateBounds and RecalculateNormals

when I am animating vertices per update :

  • use the builtin arrays and make calculations

  • simply assign mesh.vertices = builtin array verts;

this can be seen in the scripts of all my progressive mesh related questions :

So am now wondering : is the correct methd of creating and optimizing mesh generation and manipulation is to :

  • find the mesh filter mesh

  • directly assign the lengths to the different vertex arrays

  • directly assign values to the different vertex arrays

  • RecalculateBounds and RecalculateNormals

when I am animating vertices per update :

  • find the mesh filter mesh

  • clear the mesh

  • directly assign the lengths to the different vertex arrays

  • directly assign values to the different vertex arrays

  • RecalculateBounds and RecalculateNormals

If I am doing something wrong please let me know, I am self taught, only used Unity this year, coming from a very limited ability using basic and actionscript2 (mostly just logic-gate calcs and printout stuff) and admit I need to know more about many things (I don’t have a clue about shaders, stack and flow, many other optimization or efficiency techniques, or just the right way to use Unity). If you can guide me I am very grateful.


Don’t reuse a mesh, always create a new one (it is safer):

// don't do
myTextMesh = this.transform.GetComponent<MeshFilter>().mesh;    
// do that instead
myTextMesh = new Mesh();

// and after creation
this.GetComponent<MeshFilter>().mesh = myTextMesh;

Or if you don’t like recreating then don’t forget to clear the mesh (especially when the number of triangles changes):

myTextMesh.Clear();

edit: Sorry I mixed up C# and US. Now all my code example are in C#.

Are you taking the default mesh and adding values to it before setting its size?

I didn’t look too close but it looks like you are getting your mesh from the gameobject and then stuffing values into it. How do you know its the right size?

In your code, you are setting the arrays twice; once to some unused arrays of the same size as your data and then directly afterwards. That seems a little redundant so I would get rid of the first stage and also do as anisopany suggests and call clear on the mesh before the assignment.

In answer to your latest version, the reason that you see nothing is because you are assigning the arrays too early. Take a look at the following snippet as an example, it’s written in C# but only the comments are really important:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class MeshDemo : MonoBehaviour {

     void Awake() {
       	    CreateMesh();
     }

     void CreateMesh() {
        MeshFilter filter = GetComponent<MeshFilter>();
	    Mesh mesh = new Mesh();
	    
	    // Simple demo mesh
	    Vector3[] vx = new Vector3[4];
	    Vector2[] uv = new Vector2[4];
	    Vector3[] n = new Vector3[4];
	    int[] ix = new int[6];

	    // If you want to never see the mesh then assign properties here and comment out the lower assignments.
	    /*
	    mesh.vertices = vx;
	    mesh.uv = uv;
	    mesh.normals = n;
	    mesh.triangles = ix;
	    */

	    for (int i=0; i<4; ++i){
	        vx*.x = 0 != (i&1) ? -1f : 1f;*

_ vx*.z = 0 != (i&2) ? -1f : 1f;_
_ n = Vector3.up;
uv.x = 0 != (i&1) ? 0f : 1f;
uv.y = 0 != (i&2) ? 0f : 1f;
}
ix[0] = 0; ix[1] = 2; ix[2] = 1;
ix[3] = 1; ix[4] = 2; ix[5] = 3;
// Now that all the values are defined we can assign them to the mesh,
mesh.vertices = vx;
mesh.uv = uv;
mesh.normals = n;
mesh.triangles = ix;*_

* Debug.Log(“Mesh ready”);*
* filter.mesh = mesh;*
}
}