TubeRenderer

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
Line 1: Line 1:
 
Created by StarManta
 
Created by StarManta
  
TubeRenderer creates a cylindrical tube in the same way that a LineRenderer creates a flat line. It has compatibility functions too so you can simply drop it onto your object and easily change our existing code to use tubes.
+
TubeRenderer creates a cylindrical tube much like a LineRenderer creates a flat line. It's great for ropes and the like.
  
You don't need the compatibility functions though; they're actually quite limiting. TubeRenderer supports arbitrary numbers of widths (instead of just start and end) and colors (though colors have not yet been implemented), and the points, colors, and diameters are all publicly accessible arrays.
+
You can use SetPoints with and array of Vector3's, or access the array of vertices manually.
  
 
<javascript>
 
<javascript>
var points : Vector3[] = [Vector3(0,0,0)];
+
/*
var diameters : float[] = [1.0];
+
TubeRenderer.js
var colors : Color[] = [Color.black];
+
 
var simulateInWorldSpace : boolean = false;
+
This script is created by Ray Nothnagel of Last Bastion Games. It is
 +
free for use and available on the Unify Wiki.
 +
 
 +
For other components I've created, see:
 +
http://lastbastiongames.com/middleware/
 +
 
 +
(C) 2008 Last Bastion Games
 +
*/
 +
 
 +
 
 +
class TubeVertex {
 +
var point : Vector3 = Vector3.zero;
 +
var radius : float = 1.0;
 +
var color : Color = Color.white;
 +
 +
function TubeVertex(pt : Vector3, r : float, c : Color) {
 +
point=pt;
 +
radius=r;
 +
color=c;
 +
}
 +
}
 +
 
 +
var vertices : TubeVertex[];
 
var material : Material;
 
var material : Material;
private var prevPoints : Vector3[];
+
 
 
var crossSegments : int = 3;
 
var crossSegments : int = 3;
private var crossPoints : Vector3[]; //cache the cross segment positions
+
private var crossPoints : Vector3[];
private var lastCrossSegments : int; //determines if the cache needs to be recalculated
+
private var lastCrossSegments : int;
 +
var flatAtDistance : float=-1;
  
 +
private var lastCameraPosition1 : Vector3;
 +
private var lastCameraPosition2 : Vector3;
 +
var movePixelsForRebuild = 6;
 +
var maxRebuildTime = 0.1;
 +
private var lastRebuildTime = 0.00;
 +
 +
function Reset() {
 +
vertices = [TubeVertex(Vector3.zero, 1.0, Color.white), TubeVertex(Vector3(1,0,0), 1.0, Color.white)];
 +
}
 
function Start() {
 
function Start() {
 
gameObject.AddComponent(MeshFilter);
 
gameObject.AddComponent(MeshFilter);
 
var mr : MeshRenderer = gameObject.AddComponent(MeshRenderer);
 
var mr : MeshRenderer = gameObject.AddComponent(MeshRenderer);
 
mr.material = material;
 
mr.material = material;
prevPoints = new Vector3[0];
 
 
}
 
}
  
 
function LateUpdate () {
 
function LateUpdate () {
if (!points || points.length <= 1) {
+
if (!vertices || vertices.length <= 1) {
 
renderer.enabled=false;
 
renderer.enabled=false;
 
return;
 
return;
Line 31: Line 62:
 
 
 
//rebuild the mesh?
 
//rebuild the mesh?
 +
var re : boolean=false;
 +
var distFromMainCam : float;
 +
if(vertices.length > 1)
 +
{
 +
cur1 = Camera.main.WorldToScreenPoint(vertices[0].point);
 +
distFromMainCam = lastCameraPosition1.z;
 +
lastCameraPosition1.z = 0;
 +
cur2 = Camera.main.WorldToScreenPoint(vertices[vertices.length - 1].point);
 +
lastCameraPosition2.z = 0;
  
+
distance = (lastCameraPosition1 - cur1).magnitude;
var rebuildMesh : boolean = false;
+
distance += (lastCameraPosition2 - cur2).magnitude;
if (prevPoints.length != points.length) {
+
 
rebuildMesh=true;
+
if(distance > movePixelsForRebuild || Time.time - lastRebuildTime > maxRebuildTime)
}
+
{
else {
+
re = true;
for (p=0;p<points.length;p++) {
+
lastCameraPosition1 = cur1;
if (points[p] != prevPoints[p]) {
+
lastCameraPosition2 = cur2;
rebuildMesh = true; break;
+
}
+
 
}
 
}
 
}
 
}
  
if (rebuildMesh) {
+
if (re) {
prevPoints = new Vector3[points.length];
+
for (p=0;p<points.length;p++) {
+
prevPoints[p] = points[p];
+
}
+
 
+
 
//draw tube
 
//draw tube
 
 
Line 62: Line 95:
 
}
 
}
 
 
var vertices : Vector3[] = new Vector3[points.length*crossSegments];
+
var meshVertices : Vector3[] = new Vector3[vertices.length*crossSegments];
var uvs : Vector2[] = new Vector2[points.length*crossSegments];
+
var uvs : Vector2[] = new Vector2[vertices.length*crossSegments];
var tris : int[] = new int[points.length*crossSegments*6];
+
var colors : Color[] = new Color[vertices.length*crossSegments];
 +
var tris : int[] = new int[vertices.length*crossSegments*6];
 
var lastVertices : int[] = new int[crossSegments];
 
var lastVertices : int[] = new int[crossSegments];
 
var theseVertices : int[] = new int[crossSegments];
 
var theseVertices : int[] = new int[crossSegments];
 
var rotation : Quaternion;
 
var rotation : Quaternion;
 
 
var thisPoint : Vector3;
+
for (p=0;p<vertices.length;p++) {
var lastPoint : Vector3;
+
if (p<vertices.length-1) rotation = Quaternion.FromToRotation(Vector3.forward, vertices[p+1].point-vertices[p].point);
var nextPoint : Vector3;
+
+
for (p=0;p<points.length;p++) {
+
lastPoint = thisPoint;
+
thisPoint = nextPoint;
+
if (p<points.length-1) {
+
if (simulateInWorldSpace) nextPoint = transform.InverseTransformPoint(points[p+1]);
+
else nextPoint = points[p+1];
+
}
+
+
if (p==0)
+
rotation = Quaternion.FromToRotation(Vector3.forward, nextPoint-thisPoint);
+
else if (p<points.length-1)
+
rotation = Quaternion.FromToRotation(Vector3.forward, nextPoint-thisPoint + thisPoint-lastPoint);
+
else
+
rotation = Quaternion.FromToRotation(Vector3.forward, thisPoint-lastPoint);
+
var thisDiameter : float=GetDiameter(p);
+
 
 
 
for (c=0;c<crossSegments;c++) {
 
for (c=0;c<crossSegments;c++) {
if (thisDiameter == 0.0) vertices[p*crossSegments+c] = thisPoint;
+
var vertexIndex : int = p*crossSegments+c;
vertices[p*crossSegments+c] = thisPoint + rotation * crossPoints[c] * thisDiameter;
+
meshVertices[vertexIndex] = vertices[p].point + rotation * crossPoints[c] * vertices[p].radius;
// print(c+" - vertex index "+(p*crossSegments+c) + " is " + vertices[p*crossSegments+c]);
+
uvs[vertexIndex] = Vector2((0.0+c)/crossSegments,(0.0+p)/vertices.length);
uvs[p*crossSegments+c] = Vector2((0.0+c)/crossSegments,(0.0+p)/points.length);
+
colors[vertexIndex] = vertices[p].color;
 +
 +
// print(c+" - vertex index "+(p*crossSegments+c) + " is " + meshVertices[p*crossSegments+c]);
 
lastVertices[c]=theseVertices[c];
 
lastVertices[c]=theseVertices[c];
 
theseVertices[c] = p*crossSegments+c;
 
theseVertices[c] = p*crossSegments+c;
Line 113: Line 132:
 
 
 
var mesh : Mesh = new Mesh();
 
var mesh : Mesh = new Mesh();
mesh.vertices = vertices;
+
mesh.vertices = meshVertices;
 
mesh.triangles = tris;
 
mesh.triangles = tris;
 
mesh.RecalculateNormals();
 
mesh.RecalculateNormals();
mesh.RecalculateBounds();
 
 
mesh.uv = uvs;
 
mesh.uv = uvs;
 
GetComponent(MeshFilter).mesh = mesh;
 
GetComponent(MeshFilter).mesh = mesh;
 
 
}
 
}
 
}
 
}
  
//gets the diameter, interpolated
+
//sets all the points to points of a Vector3 array, as well as capping the ends.
function GetDiameter(index : int) : float {
+
function SetPoints(points : Vector3[], radius : float, col : Color) {
if (diameters.length == 0) return 1.0;
+
if (points.length < 2) return;
else if (diameters.length == 1) return diameters[0];
+
vertices = new TubeVertex[points.length+2];
var normalizedIndex : float = (0.0+index)/points.length;
+
var diameterIndex : float = normalizedIndex * diameters.length;
+
var v0offset : Vector3 = (points[0]-points[1])*0.01;
var baseDiameterIndex : int = diameterIndex;
+
vertices[0] = TubeVertex(v0offset+points[0], 0.0, col);
if (baseDiameterIndex == diameterIndex || baseDiameterIndex >= diameters.length-1) { //it's right on an index, so no need to interpolate
+
var v1offset : Vector3 = (points[points.length-1] - points[points.length-2])*0.01;
return diameters[baseDiameterIndex];
+
vertices[vertices.length-1] = TubeVertex(v1offset+points[points.length-1], 0.0, col);
 +
 +
for (p=0;p<points.length;p++) {
 +
vertices[p+1] = TubeVertex(points[p], radius, col);
 
}
 
}
return Mathf.Lerp(diameters[baseDiameterIndex], diameters[baseDiameterIndex+1], diameterIndex-baseDiameterIndex);
 
}
 
 
 
//LineRenderer compatibility functions
 
function SetVertexCount(count : int) {
 
points = new Vector3[count];
 
}
 
 
function SetPoint(index : int, point : Vector3) {
 
points[index] = point;
 
}
 
 
function SetColors(start : Color, end : Color) {
 
colors = [start, end];
 
}
 
 
function SetWidth(start : float, end : float) {
 
diameters = [start, end];
 
 
}</javascript>
 
}</javascript>

Revision as of 17:36, 15 November 2008

Created by StarManta

TubeRenderer creates a cylindrical tube much like a LineRenderer creates a flat line. It's great for ropes and the like.

You can use SetPoints with and array of Vector3's, or access the array of vertices manually.

<javascript> /* TubeRenderer.js

This script is created by Ray Nothnagel of Last Bastion Games. It is free for use and available on the Unify Wiki.

For other components I've created, see: http://lastbastiongames.com/middleware/

(C) 2008 Last Bastion Games

  • /


class TubeVertex { var point : Vector3 = Vector3.zero; var radius : float = 1.0; var color : Color = Color.white;

function TubeVertex(pt : Vector3, r : float, c : Color) { point=pt; radius=r; color=c; } }

var vertices : TubeVertex[]; var material : Material;

var crossSegments : int = 3; private var crossPoints : Vector3[]; private var lastCrossSegments : int; var flatAtDistance : float=-1;

private var lastCameraPosition1 : Vector3; private var lastCameraPosition2 : Vector3; var movePixelsForRebuild = 6; var maxRebuildTime = 0.1; private var lastRebuildTime = 0.00;

function Reset() { vertices = [TubeVertex(Vector3.zero, 1.0, Color.white), TubeVertex(Vector3(1,0,0), 1.0, Color.white)]; } function Start() { gameObject.AddComponent(MeshFilter); var mr : MeshRenderer = gameObject.AddComponent(MeshRenderer); mr.material = material; }

function LateUpdate () { if (!vertices || vertices.length <= 1) { renderer.enabled=false; return; } renderer.enabled=true;

//rebuild the mesh? var re : boolean=false; var distFromMainCam : float; if(vertices.length > 1) { cur1 = Camera.main.WorldToScreenPoint(vertices[0].point); distFromMainCam = lastCameraPosition1.z; lastCameraPosition1.z = 0; cur2 = Camera.main.WorldToScreenPoint(vertices[vertices.length - 1].point); lastCameraPosition2.z = 0;

distance = (lastCameraPosition1 - cur1).magnitude; distance += (lastCameraPosition2 - cur2).magnitude;

if(distance > movePixelsForRebuild || Time.time - lastRebuildTime > maxRebuildTime) { re = true; lastCameraPosition1 = cur1; lastCameraPosition2 = cur2; } }

if (re) { //draw tube

if (crossSegments != lastCrossSegments) { crossPoints = new Vector3[crossSegments]; var theta : float = 2.0*Mathf.PI/crossSegments; for (c=0;c<crossSegments;c++) { crossPoints[c] = Vector3(Mathf.Cos(theta*c), Mathf.Sin(theta*c), 0); } lastCrossSegments = crossSegments; }

var meshVertices : Vector3[] = new Vector3[vertices.length*crossSegments]; var uvs : Vector2[] = new Vector2[vertices.length*crossSegments]; var colors : Color[] = new Color[vertices.length*crossSegments]; var tris : int[] = new int[vertices.length*crossSegments*6]; var lastVertices : int[] = new int[crossSegments]; var theseVertices : int[] = new int[crossSegments]; var rotation : Quaternion;

for (p=0;p<vertices.length;p++) { if (p<vertices.length-1) rotation = Quaternion.FromToRotation(Vector3.forward, vertices[p+1].point-vertices[p].point);

for (c=0;c<crossSegments;c++) { var vertexIndex : int = p*crossSegments+c; meshVertices[vertexIndex] = vertices[p].point + rotation * crossPoints[c] * vertices[p].radius; uvs[vertexIndex] = Vector2((0.0+c)/crossSegments,(0.0+p)/vertices.length); colors[vertexIndex] = vertices[p].color;

// print(c+" - vertex index "+(p*crossSegments+c) + " is " + meshVertices[p*crossSegments+c]); lastVertices[c]=theseVertices[c]; theseVertices[c] = p*crossSegments+c; } //make triangles if (p>0) { for (c=0;c<crossSegments;c++) { var start : int= (p*crossSegments+c)*6; tris[start] = lastVertices[c]; tris[start+1] = lastVertices[(c+1)%crossSegments]; tris[start+2] = theseVertices[c]; tris[start+3] = tris[start+2]; tris[start+4] = tris[start+1]; tris[start+5] = theseVertices[(c+1)%crossSegments]; // print("Triangle: indexes("+tris[start]+", "+tris[start+1]+", "+tris[start+2]+"), ("+tris[start+3]+", "+tris[start+4]+", "+tris[start+5]+")"); } } }

var mesh : Mesh = new Mesh(); mesh.vertices = meshVertices; mesh.triangles = tris; mesh.RecalculateNormals(); mesh.uv = uvs; GetComponent(MeshFilter).mesh = mesh; } }

//sets all the points to points of a Vector3 array, as well as capping the ends. function SetPoints(points : Vector3[], radius : float, col : Color) { if (points.length < 2) return; vertices = new TubeVertex[points.length+2];

var v0offset : Vector3 = (points[0]-points[1])*0.01; vertices[0] = TubeVertex(v0offset+points[0], 0.0, col); var v1offset : Vector3 = (points[points.length-1] - points[points.length-2])*0.01; vertices[vertices.length-1] = TubeVertex(v1offset+points[points.length-1], 0.0, col);

for (p=0;p<points.length;p++) { vertices[p+1] = TubeVertex(points[p], radius, col); } }</javascript>

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox