|
|
- //====================================================================================
- //
- // Purpose: To generate a bezier curve between at least 4 points in space and draw
- // a number of spheres across the generated curve
- //
- // This script is heavily based on the tutorial at:
- // http://catlikecoding.com/unity/tutorials/curves-and-splines/
- //
- //====================================================================================
- namespace VRTK
- {
- using UnityEngine;
-
- public static class Bezier
- {
-
- public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, float t)
- {
- t = Mathf.Clamp01(t);
- float oneMinusT = 1f - t;
- return
- oneMinusT * oneMinusT * p0 +
- 2f * oneMinusT * t * p1 +
- t * t * p2;
- }
-
- public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t)
- {
- return
- 2f * (1f - t) * (p1 - p0) +
- 2f * t * (p2 - p1);
- }
-
- public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
- {
- t = Mathf.Clamp01(t);
- float OneMinusT = 1f - t;
- return
- OneMinusT * OneMinusT * OneMinusT * p0 +
- 3f * OneMinusT * OneMinusT * t * p1 +
- 3f * OneMinusT * t * t * p2 +
- t * t * t * p3;
- }
-
- public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
- {
- t = Mathf.Clamp01(t);
- float oneMinusT = 1f - t;
- return
- 3f * oneMinusT * oneMinusT * (p1 - p0) +
- 6f * oneMinusT * t * (p2 - p1) +
- 3f * t * t * (p3 - p2);
- }
- }
-
- public class VRTK_CurveGenerator : MonoBehaviour
- {
- public enum BezierControlPointMode
- {
- Free,
- Aligned,
- Mirrored
- }
-
- protected Vector3[] points;
- protected GameObject[] items;
- protected BezierControlPointMode[] modes;
- protected bool loop;
- protected int frequency;
- protected bool customTracer;
- protected bool rescalePointerTracer;
- protected GameObject tracerLineRenderer;
- protected LineRenderer customLineRenderer;
- protected bool lineRendererAndItem;
-
- public virtual void Create(int setFrequency, float radius, GameObject tracer, bool rescaleTracer = false)
- {
- float circleSize = radius / 8;
-
- frequency = setFrequency;
- customLineRenderer = (tracer != null ? tracer.GetComponent<LineRenderer>() : null);
- lineRendererAndItem = (customLineRenderer != null && tracer.GetComponentInChildren<MeshFilter>());
- if (customLineRenderer != null)
- {
- tracerLineRenderer = Instantiate(tracer);
- tracerLineRenderer.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, name, "LineRenderer");
- for (int i = 0; i < tracerLineRenderer.transform.childCount; i++)
- {
- Destroy(tracerLineRenderer.transform.GetChild(i).gameObject);
- }
- customLineRenderer = tracerLineRenderer.GetComponent<LineRenderer>();
- #if UNITY_5_5
- customLineRenderer.numPositions = frequency;
- #elif UNITY_5_6_OR_NEWER
- customLineRenderer.positionCount = frequency;
- #else
- customLineRenderer.SetVertexCount(frequency);
- #endif
- }
-
- if (customLineRenderer == null || lineRendererAndItem)
- {
- items = new GameObject[frequency];
- for (int f = 0; f < items.Length; f++)
- {
- customTracer = true;
- items[f] = (tracer != null ? Instantiate(tracer) : CreateSphere());
- items[f].transform.SetParent(transform);
- items[f].layer = LayerMask.NameToLayer("Ignore Raycast");
- items[f].transform.localScale = new Vector3(circleSize, circleSize, circleSize);
- if (customLineRenderer != null)
- {
- Destroy(items[f].GetComponent<LineRenderer>());
- }
- }
- }
-
- rescalePointerTracer = rescaleTracer;
- }
-
- public virtual void SetPoints(Vector3[] controlPoints, Material material, Color color)
- {
- PointsInit(controlPoints);
- SetObjects(material, color);
- }
-
- public virtual Vector3[] GetPoints(Vector3[] controlPoints)
- {
- PointsInit(controlPoints);
-
- Vector3[] calculatedPoints = new Vector3[frequency];
- float stepSize = frequency * 1;
- if (Loop || stepSize == 1)
- {
- stepSize = VRTK_SharedMethods.DividerToMultiplier(stepSize);
- }
- else
- {
- stepSize = VRTK_SharedMethods.DividerToMultiplier((stepSize - 1));
- }
-
- for (int f = 0; f < frequency; f++)
- {
- calculatedPoints[f] = GetPoint(f * stepSize);
- }
- return calculatedPoints;
- }
-
- public virtual void TogglePoints(bool state)
- {
- gameObject.SetActive(state);
- if (tracerLineRenderer != null)
- {
- tracerLineRenderer.SetActive(state);
- }
- }
-
- protected virtual void OnDisable()
- {
- if (tracerLineRenderer != null)
- {
- tracerLineRenderer.SetActive(false);
- }
- }
-
- protected virtual void PointsInit(Vector3[] controlPoints)
- {
- points = controlPoints;
- modes = new BezierControlPointMode[]
- {
- BezierControlPointMode.Free,
- BezierControlPointMode.Free
- };
- }
-
- protected virtual GameObject CreateSphere()
- {
- customTracer = false;
- GameObject item = GameObject.CreatePrimitive(PrimitiveType.Sphere);
- item.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, "Sphere");
- Destroy(item.GetComponent<SphereCollider>());
- item.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- item.GetComponent<MeshRenderer>().receiveShadows = false;
-
- return item;
- }
-
- protected virtual bool Loop
- {
- get
- {
- return loop;
- }
- set
- {
- loop = value;
- if (value == true)
- {
- modes[modes.Length - 1] = modes[0];
- SetControlPoint(0, points[0]);
- }
- }
- }
-
- protected virtual int ControlPointCount
- {
- get
- {
- return points.Length;
- }
- }
-
- protected virtual Vector3 GetControlPoint(int index)
- {
- return points[index];
- }
-
- protected virtual void SetControlPoint(int index, Vector3 point)
- {
- if (index % 3 == 0)
- {
- Vector3 delta = point - points[index];
- if (loop)
- {
- if (index == 0)
- {
- points[1] += delta;
- points[points.Length - 2] += delta;
- points[points.Length - 1] = point;
- }
- else if (index == points.Length - 1)
- {
- points[0] = point;
- points[1] += delta;
- points[index - 1] += delta;
- }
- else
- {
- points[index - 1] += delta;
- points[index + 1] += delta;
- }
- }
- else
- {
- if (index > 0)
- {
- points[index - 1] += delta;
- }
- if (index + 1 < points.Length)
- {
- points[index + 1] += delta;
- }
- }
- }
- points[index] = point;
- EnforceMode(index);
- }
-
- protected virtual void EnforceMode(int index)
- {
- int modeIndex = (index + 1) / 3;
- BezierControlPointMode mode = modes[modeIndex];
- if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Length - 1))
- {
- return;
- }
-
- int middleIndex = modeIndex * 3;
- int fixedIndex, enforcedIndex;
- if (index <= middleIndex)
- {
- fixedIndex = middleIndex - 1;
- if (fixedIndex < 0)
- {
- fixedIndex = points.Length - 2;
- }
- enforcedIndex = middleIndex + 1;
- if (enforcedIndex >= points.Length)
- {
- enforcedIndex = 1;
- }
- }
- else
- {
- fixedIndex = middleIndex + 1;
- if (fixedIndex >= points.Length)
- {
- fixedIndex = 1;
- }
- enforcedIndex = middleIndex - 1;
- if (enforcedIndex < 0)
- {
- enforcedIndex = points.Length - 2;
- }
- }
-
- Vector3 middle = points[middleIndex];
- Vector3 enforcedTangent = middle - points[fixedIndex];
- if (mode == BezierControlPointMode.Aligned)
- {
- enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, points[enforcedIndex]);
- }
- points[enforcedIndex] = middle + enforcedTangent;
- }
-
- protected virtual int CurveCount
- {
- get
- {
- return (points.Length - 1) / 3;
- }
- }
-
- protected virtual Vector3 GetPoint(float t)
- {
- int i;
- if (t >= 1f)
- {
- t = 1f;
- i = points.Length - 4;
- }
- else
- {
- t = Mathf.Clamp01(t) * CurveCount;
- i = (int)t;
- t -= i;
- i *= 3;
- }
- return transform.TransformPoint(Bezier.GetPoint(points[i], points[i + 1], points[i + 2], points[i + 3], t));
- }
-
- protected virtual void SetObjects(Material material, Color color)
- {
- float stepSize = frequency * 1;
- if (Loop || stepSize == 1)
- {
- stepSize = VRTK_SharedMethods.DividerToMultiplier(stepSize);
- }
- else
- {
- stepSize = VRTK_SharedMethods.DividerToMultiplier((stepSize - 1));
- }
-
- SetPointData(material, color, stepSize);
- }
-
- protected virtual void SetPointData(Material material, Color color, float stepSize)
- {
- for (int f = 0; f < frequency; f++)
- {
- Vector3 position = GetPoint(f * stepSize);
-
- if (customLineRenderer != null)
- {
- customLineRenderer.SetPosition(f, position);
- SetMaterial(customLineRenderer.sharedMaterial, color);
- }
-
- if (customLineRenderer == null || lineRendererAndItem)
- {
- SetItemPosition(f, position, material, color, stepSize);
- }
- }
- }
-
- protected virtual void SetItemPosition(int currentIndex, Vector3 setPosition, Material material, Color color, float stepSize)
- {
- if (customTracer && (currentIndex == (frequency - 1)))
- {
- items[currentIndex].SetActive(false);
- return;
- }
- SetItemMaterial(items[currentIndex], material, color);
- items[currentIndex].transform.position = setPosition;
-
- Vector3 nextPosition = GetPoint((currentIndex + 1) * stepSize);
- Vector3 offset = nextPosition - setPosition;
- Vector3 lookPosition = offset.normalized;
- if (lookPosition != Vector3.zero)
- {
- items[currentIndex].transform.rotation = Quaternion.LookRotation(lookPosition);
-
- // rescale the custom tracer according to the length of the beam
- if (rescalePointerTracer)
- {
- Vector3 scl = items[currentIndex].transform.localScale;
- scl.z = offset.magnitude / 2f; // (assuming a center-based scaling)
- items[currentIndex].transform.localScale = scl;
- }
- }
- }
-
- protected virtual void SetItemMaterial(GameObject item, Material material, Color color)
- {
- Renderer[] itemRenderers = item.GetComponentsInChildren<Renderer>();
- for (int i = 0; i < itemRenderers.Length; i++)
- {
- if (material != null)
- {
- itemRenderers[i].material = material;
- }
- SetMaterial(itemRenderers[i].material, color);
- }
- }
-
- protected virtual void SetMaterial(Material material, Color color)
- {
- if (material != null)
- {
- material.EnableKeyword("_EMISSION");
-
- if (material.HasProperty("_Color"))
- {
- material.color = color;
- }
-
- if (material.HasProperty("_EmissionColor"))
- {
- material.SetColor("_EmissionColor", VRTK_SharedMethods.ColorDarken(color, 50));
- }
- }
- }
- }
- }
|