Creating Triangles From Verts?

Hey All,

I’m trying to follow this method for creating a neat 2D fluid effect: http://gamedev.tutsplus.com/tutorials/implementation/make-a-splash-with-2d-water-effects/ This is my first time with procedural mesh generation, so be gentle :smile:

My problem is creating the triangle strips from the vertices in the mesh I generated. I’m generating 200 points right now for the surface of the water, and an additional 200 to form the base. Obviously, manually assigning all of the triangles would be a major pain, but I can’t think of a better way of doing it.

Any and all help would be appreciated!

Here’s what I got so far:

using UnityEngine;
using System.Collections;


public class Wave_Mesh : MonoBehaviour 
{
    Mesh myMesh;
	static int size = 200; // Number of vertices
	
	public Vector3[] waveVerts = new Vector3[size];
		Vector3[] wave_depthVerts = new Vector3[size];
		Vector3[] totalVerts = new Vector3[size*2];
	Vector2[] waveUVs = new Vector2[size];
	int[] 	  waveTris = new int[size-2];
	Mesh 	  waveMesh;

	public float waterDepth = 10f;
	
    static float velocityDamping = 0.999999f; // Proprotional velocity damping, must be less than or equal to 1.
    static float timeScale = 50f; 
    float[] newHeight = new float[size];
    float[] velocity = new float[size];
    GameObject[] vertex = new GameObject[size];
	
	public void SplashAtPoint(Vector3 p){
		
	}
	
	void Init(){ //create initial water mass
		waveVerts = new Vector3[size];
		
		for(int i = 0; i<size; i++){
			if(i < size){
				waveVerts[i] = new Vector3 (i - size/2f,transform.position.y,transform.position.z);
				totalVerts[i] = waveVerts[i];
			}
			else{
				wave_depthVerts[i-size] = new Vector3 (
					waveVerts[i-size].x, waveVerts[i-size].y - waterDepth, waveVerts[i-size].z);
				totalVerts[i] = wave_depthVerts[i-size];
			}
		}
		
		Mesh mesh = new Mesh();
		myMesh = mesh;
		(GetComponent<MeshFilter>() as MeshFilter).mesh = mesh;
		mesh.vertices = waveVerts;
		mesh.uv = waveUVs;
		mesh.triangles = waveTris;
		waveMesh = mesh;
	}
	
	void UpdateWaves(){
		//waveMesh.MarkDynamic();
		// Water tension is simulated by a simple linear convolution over the height field.
        for(int i=1; i<size-1; i++)
        {
            int j=i-1;
            int k=i+1;
            newHeight[i] = (waveVerts[i].y + waveVerts[j].y + waveVerts[k].y) / 3.0f;
        }
        // Velocity and height are updated... 
        for(int i=0; i<size; i++)
        {
            // update velocity and height
            velocity[i] = (velocity[i] + (newHeight[i] - waveVerts[i].y)) * velocityDamping;
            float timeFactor = Time.deltaTime * timeScale;
            
			if (timeFactor > 1f)	{ timeFactor = 1f;}
            
			newHeight[i] += velocity[i] * timeFactor;

            // update the vertex position
            Vector3 newPosition = new Vector3(
                waveVerts[i].x, 
                newHeight[i],
                waveVerts[i].z);
			Vector3 new_wave_depthVerts = new Vector3(
				newPosition.x,
				newPosition.y - waterDepth,
				newPosition.z
				);
			
            waveVerts[i] 		= newPosition;
			wave_depthVerts[i]	= new_wave_depthVerts;
        }
		
		for(int v = 1, t = 1; v < waveVerts.Length; v++, t += 3){
			waveTris[t] = v;
			waveTris[t + 1] = v + 1;
		}
		
		waveMesh.Clear();
		waveMesh.vertices = waveVerts;
		waveMesh.triangles = waveTris;
		myMesh = waveMesh;
	}
	
	
    void Start () 
    {
		Init();
    }
	
    void Update () 
    {
		UpdateWaves();
    }
	
	void OnDrawGizmos(){
		for (int i = 0; i < size*2; i++){ 	
			if(i < size)
				Gizmos.color = Color.cyan;
			else
				Gizmos.color = Color.red;
			
			Gizmos.DrawCube(totalVerts[i], new Vector3(0.3f,0.3f,0.3f));
		}
	}
}

And here’s another script I found floating on the forums (I’m using this as a base):

using UnityEngine;
using System.Collections;


public class Wave : MonoBehaviour 
{
	
    static int size = 200; // Number of vertices
	
    static float velocityDamping = 0.999999f; // Proprotional velocity damping, must be less than or equal to 1.
    static float timeScale = 50f; 
    float[] newHeight = new float[size];
    float[] velocity = new float[size];
    GameObject[] vertex = new GameObject[size];

    void Start () 
    {
        // we'll use spheres to represent each vertex for demonstration purposes
        for(int i=0; i<size; i++)
        {
            vertex[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            vertex[i].transform.position = new Vector3(i - size/2, 0, 0);
        }
    }
	
    void Update () 
    {
        // Water tension is simulated by a simple linear convolution over the height field.
        for(int i=1; i<size-1; i++)
        {
            int j=i-1;
            int k=i+1;
            newHeight[i] = (vertex[i].transform.position.y + vertex[j].transform.position.y + vertex[k].transform.position.y) / 3.0f;
        }
        // Velocity and height are updated... 
        for(int i=0; i<size; i++)
        {
            // update velocity and height
            velocity[i] = (velocity[i] + (newHeight[i] - vertex[i].transform.position.y)) * velocityDamping;
            float timeFactor = Time.deltaTime * timeScale;
            if (timeFactor > 1f) timeFactor = 1f;
            newHeight[i] += velocity[i] * timeFactor;

            // update the vertex position
            Vector3 newPosition = new Vector3(
                vertex[i].transform.position.x, 
                newHeight[i],
                vertex[i].transform.position.z);
            vertex[i].transform.position = newPosition;
        }
    }
}

Bump’d. C’mon, somebody’s got to know how it’s done :slight_smile:

1 Like

Bumped for great justice.

1 Like

If you are generating them in a smart order, you should know how many tris you need, and their indices should be easily sequenced in this way:

		for (int i = 0; i < tris.Length / 6; i++) {
			tris[i * 6 + 0] = i * 2;
			tris[i * 6 + 1] = i * 2 + 1;
			tris[i * 6 + 2] = i * 2 + 2;

			tris[i * 6 + 3] = i * 2 + 2;
			tris[i * 6 + 4] = i * 2 + 1;
			tris[i * 6 + 5] = i * 2 + 3;
		}
1 Like

That’s the thing; I really don’t know if I’m generating them in the correct order. What’s the usual way something like this is done?

What I currently do:

  1. Create a row of 200 verts (0-199 indexed)
  2. Create another row of 200 verts under the initial row (200-399 index)

This ends up looking like this:

[0,1,2,3,4,..........................................,198,199 // end row

//Space between verts

200,201,202,.....................................,398,399] //end row

What I’d like is just to form a simple triange strip using this array. Am I going about it wrong?

Really appreciate all the help, it’s my first foray into procedural jazz :slight_smile:

It depends what you’re doing, but generally you make them in some pattern where you know the order you need to stitch your triangles together. It helps a lot if you think about the triangles from the start so that the initial order you lay your verts down in makes them easy to stitch.

If you draw your ordering out on paper and then figure out the required indices for the first few triangles it should be pretty easy for you to figure out logic to stitch them together from there, though. It looks like you’re thinking in numbers. You need to think visually, and then convert it back to numbers when you understand the pattern.

Well, I reordered my verts to work with the code above, and got it to make ~a~ mesh, but I don’t think it’s generating all of the proper tris:

//Init verts
//////......///////
for(int i = 0; i<size*2; i++){
			Vector3 vert = Vector3.zero;
			
			if(i % 2 == 0){
				vert = new Vector3(transform.position.x + (i/2), transform.position.y, transform.position.z );
				wave_depthVerts[depthIndex]=vert;
				depthIndex++;
			}else if(i % 2 != 0){
				vert = new Vector3(wave_depthVerts[depthIndex-1].x, transform.position.y+waterDepth, transform.position.z );
				waveVerts[waveIndex] = vert;
				waveIndex++;
			}
			totalVerts[i] = vert; 
		}
////....///
//Generate Triangles
		for(int t = 0; t < waveTris.Length/6; t ++){
			
			waveTris[t*6+0] = t * 2;
			waveTris[t*6+1] = t * 2 + 1;
			waveTris[t*6+2] = t * 2 + 2;
			
			waveTris[t*6+3] = t * 2 + 2;
			waveTris[t*6+4] = t * 2 + 1;
			waveTris[t*6+5] = t * 2 + 3;
		}
/////.......///

EDIT: PASTED WRONG CODE BEFORE! Fixed now.

Why have you chagned the tiangle loop from steps of 6 to steps of 3, with 6 steps in it?
Except for that, should be fine.
though this:
if(i % 2 == 0){
}else if(i % 2 != 0){

the second test is redundant

Whoops! The loop was a holdover from a different test; fixed that now. For some reason,the else block wasn’t executing without the 2nd test, so that’s why that’s there :face_with_spiral_eyes:

The above code results in the tri strip I wanted (which is nice), but I get this weird one-off vert/tri artifact, and I’ve no idea why. Here’s a pic:

Thanks again, really learning a lot here!

thanks for the link. Im really busy with work projects, but when i get some time, ill see if i can get it working too. If that happens, I’ll let you know how to make this happen if you haven’t figured it out by then,

Is the length of the tris array correct? should be (verts length - 2) * 3

@hpjohn, made the change to the tris array and get a proper number of tris now; thanks for that! The first 2 tris still are jutted out like the picture above. Any ideas why that would happen??

I would suggest reducing the number of verts to something like 10, and debug.Log’ing all the values to see where the mistake is happening.
The tri indices should read something like 0,1,2,2,1,3,4,5,6,6,5,7,8,9,10,10,9,11… and i wouldnt expect anything odd in this list.
If i had to guess, I’d say one of the values in “wave_depthVerts” is not what you expect it to be

For some reason, the mesh isn’t updating at all! I’m trying to move the waveVerts in Update(), but nothing happens. Here’s the function (called in Update() ):

//WIP- If its messy it's because I forgot to comment ^-^
void UpdateWaves(){
		// Water tension is simulated by a simple linear convolution over the height field.
        for(int i=1; i<size-1; i++)
        {
            int j=i-1;
            int k=i+1;
            newHeight[i] = (waveVerts[i].y + waveVerts[j].y + waveVerts[k].y) / 3.0f;
        }
		
        // Velocity and height are updated... 
        for(int i=1; i<size-1; i++)
        {
			debugIndex = i;
            // update velocity and height
            velocity[i] = (velocity[i] + (newHeight[i] - waveVerts[i].y)) * velocityDamping;
            float timeFactor = Time.deltaTime * timeScale;
            
			if (timeFactor > 1f) timeFactor = 1f;
            	newHeight[i] += velocity[i] * timeFactor;

            // update the vertex position
            Vector3 newPosition = new Vector3(
                waveVerts[i].x, 
                newHeight[i],
                waveVerts[i].z);	

            waveVerts[i] = newPosition;
        }
		
		//Merge wave verts back to total vert array
		int appendIndex = 1;
		for(int i = 0; i < size; i++ ){
			totalVerts[appendIndex] = waveVerts[i];
			i+=2;
		}		
		
		for(int t = 0; t < waveTris.Length/6; t++){
			
			waveTris[t*6+0] = t * 2;
			waveTris[t*6+1] = t * 2 + 1;
			waveTris[t*6+2] = t * 2 + 2;
			
			waveTris[t*6+3] = t * 2 + 2;
			waveTris[t*6+4] = t * 2 + 1;
			waveTris[t*6+5] = t * 2 + 3;
		}
		
		myMesh=(GetComponent<MeshFilter>()).mesh;
		myMesh.Clear ();
		myMesh.vertices = totalVerts;
		myMesh.triangles = waveTris;
		(GetComponent<MeshFilter>()).mesh = myMesh;
	}

Upon Debug.Log’in the tri indices, they all seem to just be in sequential order, ie [0,1,2,3,4…]

I’m so lost right now…

Bumped.

UPDATE: After adding in some Gizmos to visualize the vertex positions, I found that the first waveVert is positioned on top of the last one!
No idea why that is though;

1203770--48438--$genGlitch.png

…and here’s my initial positioning code for the verts:

int waveIndex	= 0;
		int depthIndex	= 0;
		for(int i = 0; i<size*2; i++){
			Vector3 vert = Vector3.zero;
			
			if(i % 2 == 0){
				vert = new Vector3(transform.position.x + (i/2), transform.position.y, transform.position.z );
				wave_depthVerts[depthIndex]=vert;
				depthIndex++;
			}else if(i % 2 != 0){
				vert = new Vector3(transform.position.x + ((i-1)/2), transform.position.y+waterDepth, transform.position.z );
				waveVerts[waveIndex] = vert;
				waveIndex++;
			}
			totalVerts[i] = vert;
		}
		
		int appendIndex = 1;
		for(int i = 0; i < size; i++ ){
			totalVerts[appendIndex] = waveVerts[i];
			i+=2;
		}

Still have no clue why the verts aren’t updating continuously: using method #3 from this page: Unity - Scripting API: Mesh

MAJOR UPDATE Figured it out, will post final solution here and on the wiki :smile:

Good idea on the gizmos, congrats on figuring it out.