Skip to content

Instantly share code, notes, and snippets.

@onedayitwillmake
Last active August 29, 2015 13:57
Show Gist options
  • Save onedayitwillmake/9532364 to your computer and use it in GitHub Desktop.
Save onedayitwillmake/9532364 to your computer and use it in GitHub Desktop.
/// Creating a dynamic 3D ribbon which moves towards a changing position each frame
/// Author Mario Gonzalez
using UnityEngine;
using System.Collections;
using System.Text;
public class RibbonMeshNotSharedVertices {
private Mesh mesh;
// Mesh Components
private Vector3[] vertices;
private Vector3[] normals;
private Vector2[] uvs;
private int[] triangles;
// Mesh properties
private float width;
private int len;
private int _index = 0;
// Bookkeeping
private Vector3 v0; // Store last two vertices
private Vector3 v1;
private Vector3 n0; // Store last two normals
private Vector3 n1;
private bool firstCall = true;
private Vector3 unitLeft;
private Vector3 unitRight;
private bool useFlippedNormals;
public Transform _quadTransform;
public RibbonMeshNotSharedVertices( GameObject aContainer, int aLength, float aWidth, bool shouldUseFlippedNormals ) {
// Set properties of the ribbon
len = aLength;
width = aWidth;
useFlippedNormals = shouldUseFlippedNormals;
// Create arrays for each of our properties
vertices = new Vector3[ len * 4 ];
triangles = new int[ len * 6 ];
normals = new Vector3[ len * 4];
uvs = new Vector2[ len * 4];
mesh = new Mesh();
aContainer.GetComponent<MeshFilter>().mesh = mesh;
_quadTransform = new GameObject().transform;
_quadTransform.parent = aContainer.GetComponent<Transform>();
unitLeft = new Vector3( width*0.5f, 0, width*0.5f );
unitRight = new Vector3( -width*0.5f, 0, width*0.5f );
}
private float angle = 1f;
public void CreateQuad( Vector3 target, float aWidth, float lookAtSpeed, float chaseSpeed ) {
if( aWidth != width ) {
width = aWidth;
unitLeft = new Vector3( width*0.5f, 0, width*0.5f );
unitRight = new Vector3( -width*0.5f, 0, width*0.5f );
}
// Move towards target
Vector3 newPosition = Vector3.Lerp(_quadTransform.position, target , Time.deltaTime * chaseSpeed);
Vector3 relativePosition = _quadTransform.position - newPosition;
// Ignore if position change is insignificant
float sqrLen = relativePosition.sqrMagnitude;
float min = 0.0001f;
if( sqrLen < min*min ) return;
//Smooth lookat - target
Quaternion rotation = Quaternion.LookRotation(relativePosition, Vector3.up );
_quadTransform.rotation = Quaternion.Slerp(_quadTransform.rotation, rotation, Time.deltaTime * lookAtSpeed ) ;
_quadTransform.transform.position = newPosition;
// Slight extra rotation just to make it appear more 'ribbon like' as it moves
angle += 1f;
//_quadTransform.RotateAround( Vector3.up, angle );
// Rotate the unitLeft and unitRight positions
Vector3 toTheLeft = _quadTransform.rotation * unitLeft;
Vector3 toTheRight = _quadTransform.rotation * unitRight;
//////////////////////////
// SET THE INDICES //
//////////////////////////
// Wrap the if past the length
if( _index >= len ) { // Wrap
_index = 0;
}
int _v_index = _index * 4; // Vertex array index - 4 points per quad, so increment by 4
int _t_index = _index * 6; // Triangle array index - Three points per triangle, so incriment by two triangles
//////////////////////////
// CREATE FOUR VERTICES //
//////////////////////////
// For the first call, create v0 and v1 explicitely
// For proceeding calls, set the first two verts of this quad to the last two of the prev quad
if( firstCall ) {
vertices[ _v_index + 0] = _quadTransform.TransformPoint( toTheLeft );
vertices[ _v_index + 1] = _quadTransform.TransformPoint( toTheRight );
} else {
vertices[ _v_index + 0] = v0;
vertices[ _v_index + 1] = v1;
}
// If using flipped normals - wind the triangles in reverse order
if( useFlippedNormals ) {
v0 = vertices[ _v_index + 2] = _quadTransform.TransformPoint( toTheLeft );
v1 = vertices[ _v_index + 3] = _quadTransform.TransformPoint( toTheRight );
} else {
v0 = vertices[ _v_index + 2] = _quadTransform.TransformPoint( toTheRight );
v1 = vertices[ _v_index + 3] = _quadTransform.TransformPoint( toTheLeft );
}
// Create the normals all pointing outward
if( firstCall ) {
normals[ _v_index + 0 ] = Vector3.Cross( vertices[_v_index + 1] - vertices[_v_index + 0], vertices[_v_index + 2] - vertices[_v_index + 0]).normalized;
normals[ _v_index + 1 ] = Vector3.Cross( vertices[_v_index + 1] - vertices[_v_index + 0], vertices[_v_index + 2] - vertices[_v_index + 0]).normalized;
} else { // The normals for the second triangles are shared from the previous
normals[ _v_index + 0 ] = n0;
normals[ _v_index + 1 ] = n1;
}
n0 = normals[ _v_index + 2 ] = Vector3.Cross( vertices[_v_index + 2] - vertices[_v_index + 1], vertices[_v_index + 3] - vertices[_v_index + 1]).normalized;
n1 = normals[ _v_index + 3 ] = Vector3.Cross( vertices[_v_index + 2] - vertices[_v_index + 1], vertices[_v_index + 3] - vertices[_v_index + 1]).normalized;
// Create UV's at each corner
uvs[ _v_index + 0] = new Vector2(0, 1);
uvs[ _v_index + 1] = new Vector2(1, 1);
uvs[ _v_index + 2] = new Vector2(0, 0);
uvs[ _v_index + 3] = new Vector2(1, 0);
// Create two triangles pointing using the vertices array index positions
// 0
triangles[ _t_index + 0] = _v_index + 0;
triangles[ _t_index + 1] = _v_index + 2;
triangles[ _t_index + 2] = _v_index + 1;
// 1
triangles[ _t_index + 3] = _v_index + 2;
triangles[ _t_index + 4] = _v_index + 3;
triangles[ _t_index + 5] = _v_index + 1;
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.uv = uvs;
// mesh.RecalculateNormals();
_index += 1;
firstCall = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment