Created
January 13, 2018 17:45
-
-
Save Madgvox/d7192152c5411842003b3dcfc3f76d54 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections.Generic; | |
using System; | |
[ExecuteInEditMode] | |
[RequireComponent( typeof( MeshFilter ), typeof( MeshRenderer ) )] | |
public class StrandRenderer : MonoBehaviour { | |
public StrandRenderer child; | |
[HideInInspector] | |
public MeshFilter filter; | |
[HideInInspector] | |
public MeshRenderer renderer; | |
public Vector3[] points; | |
public float width; | |
public float marginWidth; | |
public bool overrideEndDirections; | |
public Vector3 entryDirection; | |
public Vector3 exitDirection; | |
public Gradient colorGradient; | |
public Color startColor { | |
get { | |
return colorGradient.Evaluate( 0 ); | |
} | |
set { | |
var keys = colorGradient.colorKeys; | |
keys[ 0 ].color = value; | |
colorGradient.colorKeys = keys; | |
} | |
} | |
public Color endColor { | |
get { | |
return colorGradient.Evaluate( 1 ); | |
} | |
set { | |
var keys = colorGradient.colorKeys; | |
keys[ keys.Length - 1 ].color = value; | |
colorGradient.colorKeys = keys; | |
} | |
} | |
public int sortingOrder { | |
get { | |
return renderer.sortingOrder; | |
} | |
set { | |
renderer.sortingOrder = value; | |
} | |
} | |
public int sortingLayerID { | |
get { | |
return renderer.sortingLayerID; | |
} | |
set { | |
renderer.sortingLayerID = value; | |
} | |
} | |
public string sortingLayerName { | |
get { | |
return renderer.sortingLayerName; | |
} | |
set { | |
renderer.sortingLayerName = value; | |
} | |
} | |
[SerializeField] | |
[HideInInspector] | |
bool isChild; | |
int[] triangles; | |
Vector3[] vertices; | |
Vector2[] uv; | |
Color[] colors; | |
Mesh mesh; | |
void Awake () { | |
mesh = new Mesh(); | |
mesh.name = "StrandRenderer-Mesh"; | |
if( filter != null ) filter.mesh = mesh; | |
UpdateLine(); | |
if( child != null ) { | |
child.isChild = true; | |
} | |
} | |
public void UpdateLine () { | |
if( isChild ) return; | |
if( mesh == null ) return; | |
var pointCount = points.Length; | |
var hasChild = child != null && child.width > 0; | |
if( pointCount < 2 || Mathf.Approximately( width, 0 ) ) { | |
return; | |
} | |
var vertCount = pointCount * 2; | |
if( vertices == null || vertCount != vertices.Length ) { | |
vertices = new Vector3[ vertCount ]; | |
triangles = new int[ ( vertCount - 2 ) * 3 ]; | |
uv = new Vector2[ vertCount ]; | |
colors = new Color[ vertCount ]; | |
if( hasChild ) { | |
child.vertices = new Vector3[ vertCount ]; | |
child.triangles = new int[ ( vertCount - 2 ) * 3 ]; | |
child.uv = new Vector2[ vertCount ]; | |
child.colors = new Color[ vertCount ]; | |
} | |
} | |
var ratio = hasChild ? child.width / width : 0; | |
var vertIndex = 0; | |
var triangleIndex = 0; | |
var sqrLength = 0f; | |
Vector3 prevTanDir = Vector3.zero; | |
for( int i = 0; i < pointCount; i++ ) { | |
var pt = points[ i ]; | |
var hasNextPoint = i < pointCount - 1; | |
var hasPrevPoint = i > 0; | |
var nextPoint = hasNextPoint ? points[ i + 1 ] : Vector3.zero; | |
var prevPoint = hasPrevPoint ? points[ i - 1 ] : Vector3.zero; | |
Vector3 tangentDir; | |
if( !hasPrevPoint ) { | |
if( overrideEndDirections ) { | |
tangentDir = entryDirection.normalized; | |
} else { | |
tangentDir = ( nextPoint - pt ).normalized; | |
} | |
prevTanDir = tangentDir; | |
} else if( !hasNextPoint ) { | |
if( overrideEndDirections ) { | |
tangentDir = exitDirection.normalized; | |
} else { | |
tangentDir = ( pt - prevPoint ).normalized; | |
} | |
prevTanDir = tangentDir; | |
} else { | |
var nextTanDir = ( nextPoint - pt ).normalized; | |
tangentDir = ( prevTanDir + nextTanDir ).normalized; | |
} | |
var angle = Vector3.Angle( tangentDir, prevTanDir ) * Mathf.Deg2Rad; | |
var w = ( 1 / Mathf.Cos( angle ) ) * width * 0.5f; | |
var left = Vector3.Cross( tangentDir, Vector3.back ).normalized; | |
var right = Vector3.Cross( tangentDir, Vector3.forward ).normalized; | |
vertices[ vertIndex ] = pt + left * w; | |
vertices[ vertIndex + 1 ] = pt + right * w; | |
if( hasChild ) { | |
child.vertices[ vertIndex ] = pt + left * ( w * ratio ); | |
child.vertices[ vertIndex + 1 ] = pt + right * ( w * ratio ); | |
} | |
if( hasNextPoint ) { | |
triangles[ triangleIndex ] = vertIndex; | |
triangles[ triangleIndex + 1 ] = vertIndex + 3; | |
triangles[ triangleIndex + 2 ] = vertIndex + 1; | |
triangles[ triangleIndex + 3 ] = vertIndex + 2; | |
triangles[ triangleIndex + 4 ] = vertIndex + 3; | |
triangles[ triangleIndex + 5 ] = vertIndex; | |
if( hasChild ) { | |
child.triangles[ triangleIndex ] = vertIndex; | |
child.triangles[ triangleIndex + 1 ] = vertIndex + 3; | |
child.triangles[ triangleIndex + 2 ] = vertIndex + 1; | |
child.triangles[ triangleIndex + 3 ] = vertIndex + 2; | |
child.triangles[ triangleIndex + 4 ] = vertIndex + 3; | |
child.triangles[ triangleIndex + 5 ] = vertIndex; | |
} | |
sqrLength += ( nextPoint - pt ).sqrMagnitude; | |
} | |
vertIndex += 2; | |
triangleIndex += 6; | |
prevTanDir = tangentDir; | |
} | |
vertIndex = 0; | |
var len = 0f; | |
for( int i = 0; i < pointCount; i++ ) { | |
var pt = points[ i ]; | |
// set color/uv p based on distance traveled | |
var p = len / sqrLength; | |
var left = new Vector2( p, 1 ); | |
var right = new Vector2( p, 0 ); | |
uv[ vertIndex ] = left; | |
uv[ vertIndex + 1 ] = right; | |
var color = colorGradient.Evaluate( p ); | |
colors[ vertIndex ] = color; | |
colors[ vertIndex + 1 ] = color; | |
if( hasChild ) { | |
var childColor = child.colorGradient.Evaluate( p ); | |
child.uv[ vertIndex ] = left; | |
child.uv[ vertIndex + 1 ] = right; | |
child.colors[ vertIndex ] = childColor; | |
child.colors[ vertIndex + 1 ] = childColor; | |
} | |
if( i < pointCount - 1 ) { | |
len += ( points[ i + 1 ] - pt ).sqrMagnitude; | |
} | |
vertIndex += 2; | |
} | |
UpdateMesh(); | |
if( hasChild ) { | |
child.UpdateMesh(); | |
} | |
} | |
void UpdateMesh () { | |
mesh.Clear(); | |
mesh.vertices = vertices; | |
mesh.triangles = triangles; | |
mesh.colors = colors; | |
mesh.uv = uv; | |
} | |
void OnValidate () { | |
if( child != null ) child.isChild = true; | |
UpdateLine(); | |
} | |
void Reset () { | |
filter = GetComponent<MeshFilter>(); | |
renderer = GetComponent<MeshRenderer>(); | |
if( mesh == null ) mesh = new Mesh(); | |
if( filter != null ) filter.mesh = mesh; | |
isChild = false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment