重新导入obi
This commit is contained in:
171
Assets/Obi/Scripts/RopeAndRod/Rendering/ObiRopeChainRenderer.cs
Normal file
171
Assets/Obi/Scripts/RopeAndRod/Rendering/ObiRopeChainRenderer.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[AddComponentMenu("Physics/Obi/Obi Rope Chain Renderer", 885)]
|
||||
[ExecuteInEditMode]
|
||||
public class ObiRopeChainRenderer : MonoBehaviour
|
||||
{
|
||||
static ProfilerMarker m_UpdateChainRopeRendererChunksPerfMarker = new ProfilerMarker("UpdateChainRopeRenderer");
|
||||
|
||||
[HideInInspector] [SerializeField] public List<GameObject> linkInstances = new List<GameObject>();
|
||||
|
||||
[SerializeProperty("RandomizeLinks")]
|
||||
[SerializeField] private bool randomizeLinks = false;
|
||||
|
||||
public Vector3 linkScale = Vector3.one; /**< Scale of chain links.*/
|
||||
public List<GameObject> linkPrefabs = new List<GameObject>();
|
||||
|
||||
[Range(0, 1)]
|
||||
public float twistAnchor = 0; /**< Normalized position of twisting origin along rope.*/
|
||||
|
||||
public float sectionTwist = 0; /**< Amount of twist applied to each section, in degrees.*/
|
||||
|
||||
ObiPathFrame frame = new ObiPathFrame();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
ClearChainLinkInstances();
|
||||
}
|
||||
|
||||
public bool RandomizeLinks
|
||||
{
|
||||
get { return randomizeLinks; }
|
||||
set
|
||||
{
|
||||
if (value != randomizeLinks)
|
||||
{
|
||||
randomizeLinks = value;
|
||||
CreateChainLinkInstances(GetComponent<ObiRopeBase>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
GetComponent<ObiRopeBase>().OnInterpolate += UpdateRenderer;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
GetComponent<ObiRopeBase>().OnInterpolate -= UpdateRenderer;
|
||||
ClearChainLinkInstances();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys all chain link instances. Used when the chain must be re-created from scratch, and when the actor is disabled/destroyed.
|
||||
*/
|
||||
public void ClearChainLinkInstances()
|
||||
{
|
||||
|
||||
if (linkInstances == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < linkInstances.Count; ++i)
|
||||
{
|
||||
if (linkInstances[i] != null)
|
||||
GameObject.DestroyImmediate(linkInstances[i]);
|
||||
}
|
||||
linkInstances.Clear();
|
||||
}
|
||||
|
||||
public void CreateChainLinkInstances(ObiRopeBase rope)
|
||||
{
|
||||
|
||||
ClearChainLinkInstances();
|
||||
|
||||
if (linkPrefabs.Count > 0)
|
||||
{
|
||||
|
||||
for (int i = 0; i < rope.particleCount; ++i)
|
||||
{
|
||||
|
||||
int index = randomizeLinks ? UnityEngine.Random.Range(0, linkPrefabs.Count) : i % linkPrefabs.Count;
|
||||
|
||||
GameObject linkInstance = null;
|
||||
|
||||
if (linkPrefabs[index] != null)
|
||||
{
|
||||
linkInstance = GameObject.Instantiate(linkPrefabs[index]);
|
||||
linkInstance.transform.SetParent(rope.transform, false);
|
||||
linkInstance.hideFlags = HideFlags.HideAndDontSave;
|
||||
linkInstance.SetActive(false);
|
||||
}
|
||||
|
||||
linkInstances.Add(linkInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateRenderer(ObiActor actor)
|
||||
{
|
||||
using (m_UpdateChainRopeRendererChunksPerfMarker.Auto())
|
||||
{
|
||||
var rope = actor as ObiRopeBase;
|
||||
|
||||
// In case there are no link prefabs to instantiate:
|
||||
if (linkPrefabs.Count == 0)
|
||||
return;
|
||||
|
||||
// Regenerate instances if needed:
|
||||
if (linkInstances == null || linkInstances.Count < rope.particleCount)
|
||||
{
|
||||
CreateChainLinkInstances(rope);
|
||||
}
|
||||
|
||||
var blueprint = rope.sourceBlueprint;
|
||||
int elementCount = rope.elements.Count;
|
||||
|
||||
float twist = -sectionTwist * elementCount * twistAnchor;
|
||||
|
||||
//we will define and transport a reference frame along the curve using parallel transport method:
|
||||
frame.Reset();
|
||||
frame.SetTwist(twist);
|
||||
|
||||
int lastParticle = -1;
|
||||
|
||||
for (int i = 0; i < elementCount; ++i)
|
||||
{
|
||||
ObiStructuralElement elm = rope.elements[i];
|
||||
|
||||
Vector3 pos = rope.GetParticlePosition(elm.particle1);
|
||||
Vector3 nextPos = rope.GetParticlePosition(elm.particle2);
|
||||
Vector3 linkVector = nextPos - pos;
|
||||
Vector3 tangent = linkVector.normalized;
|
||||
|
||||
if (rope.sourceBlueprint.usesOrientedParticles)
|
||||
{
|
||||
frame.Transport(nextPos, tangent, rope.GetParticleOrientation(elm.particle1) * Vector3.up, twist);
|
||||
twist += sectionTwist;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.Transport(nextPos, tangent, sectionTwist);
|
||||
}
|
||||
|
||||
if (linkInstances[i] != null)
|
||||
{
|
||||
linkInstances[i].SetActive(true);
|
||||
Transform linkTransform = linkInstances[i].transform;
|
||||
linkTransform.position = pos + linkVector * 0.5f;
|
||||
linkTransform.localScale = rope.GetParticleMaxRadius(elm.particle1) * 2 * linkScale;
|
||||
linkTransform.rotation = Quaternion.LookRotation(tangent, frame.normal);
|
||||
}
|
||||
|
||||
lastParticle = elm.particle2;
|
||||
|
||||
}
|
||||
|
||||
for (int i = elementCount; i < linkInstances.Count; ++i)
|
||||
{
|
||||
if (linkInstances[i] != null)
|
||||
linkInstances[i].SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09ac962c0743c400aa230ebf871b6156
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 1289c40ad0e7c4fb3bd738f8a3f3e068, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[AddComponentMenu("Physics/Obi/Obi Rope Extruded Renderer", 883)]
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(ObiPathSmoother))]
|
||||
public class ObiRopeExtrudedRenderer : MonoBehaviour
|
||||
{
|
||||
static ProfilerMarker m_UpdateExtrudedRopeRendererChunksPerfMarker = new ProfilerMarker("UpdateExtrudedRopeRenderer");
|
||||
|
||||
private List<Vector3> vertices = new List<Vector3>();
|
||||
private List<Vector3> normals = new List<Vector3>();
|
||||
private List<Vector4> tangents = new List<Vector4>();
|
||||
private List<Vector2> uvs = new List<Vector2>();
|
||||
private List<Color> vertColors = new List<Color>();
|
||||
private List<int> tris = new List<int>();
|
||||
|
||||
ObiPathSmoother smoother; // Each renderer should have its own smoother. The renderer then has a method to get position and orientation at a point.
|
||||
|
||||
[HideInInspector] [NonSerialized] public Mesh extrudedMesh;
|
||||
|
||||
[Range(0, 1)]
|
||||
public float uvAnchor = 0; /**< Normalized position of texture coordinate origin along rope.*/
|
||||
|
||||
public Vector2 uvScale = Vector2.one; /**< Scaling of uvs along rope.*/
|
||||
|
||||
public bool normalizeV = true;
|
||||
|
||||
public ObiRopeSection section = null; /**< Section asset to be extruded along the rope.*/
|
||||
|
||||
public float thicknessScale = 0.8f; /**< Scales section thickness.*/
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
smoother = GetComponent<ObiPathSmoother>();
|
||||
smoother.OnCurveGenerated += UpdateRenderer;
|
||||
CreateMeshIfNeeded();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
smoother.OnCurveGenerated -= UpdateRenderer;
|
||||
GameObject.DestroyImmediate(extrudedMesh);
|
||||
}
|
||||
|
||||
private void CreateMeshIfNeeded()
|
||||
{
|
||||
if (extrudedMesh == null)
|
||||
{
|
||||
extrudedMesh = new Mesh();
|
||||
extrudedMesh.name = "extrudedMesh";
|
||||
extrudedMesh.MarkDynamic();
|
||||
GetComponent<MeshFilter>().mesh = extrudedMesh;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateRenderer(ObiActor actor)
|
||||
{
|
||||
using (m_UpdateExtrudedRopeRendererChunksPerfMarker.Auto())
|
||||
{
|
||||
if (section == null)
|
||||
return;
|
||||
|
||||
var rope = actor as ObiRopeBase;
|
||||
|
||||
CreateMeshIfNeeded();
|
||||
ClearMeshData();
|
||||
|
||||
int sectionIndex = 0;
|
||||
int sectionSegments = section.Segments;
|
||||
int verticesPerSection = sectionSegments + 1; // the last vertex in each section must be duplicated, due to uv wraparound.
|
||||
float vCoord = -uvScale.y * rope.restLength * uvAnchor; // v texture coordinate.
|
||||
float actualToRestLengthRatio = smoother.SmoothLength / rope.restLength;
|
||||
|
||||
Vector3 vertex = Vector3.zero, normal = Vector3.zero;
|
||||
Vector4 texTangent = Vector4.zero;
|
||||
Vector2 uv = Vector2.zero;
|
||||
|
||||
for (int c = 0; c < smoother.smoothChunks.Count; ++c)
|
||||
{
|
||||
ObiList<ObiPathFrame> curve = smoother.smoothChunks[c];
|
||||
|
||||
for (int i = 0; i < curve.Count; ++i)
|
||||
{
|
||||
// Calculate previous and next curve indices:
|
||||
int prevIndex = Mathf.Max(i - 1, 0);
|
||||
|
||||
// advance v texcoord:
|
||||
vCoord += uvScale.y * (Vector3.Distance(curve.Data[i].position, curve.Data[prevIndex].position) /
|
||||
(normalizeV ? smoother.SmoothLength : actualToRestLengthRatio));
|
||||
|
||||
// calculate section thickness and scale the basis vectors by it:
|
||||
float sectionThickness = curve.Data[i].thickness * thicknessScale;
|
||||
|
||||
// Loop around each segment:
|
||||
int nextSectionIndex = sectionIndex + 1;
|
||||
for (int j = 0; j <= sectionSegments; ++j)
|
||||
{
|
||||
// make just one copy of the section vertex:
|
||||
Vector2 sectionVertex = section.vertices[j];
|
||||
|
||||
// calculate normal using section vertex, curve normal and binormal:
|
||||
normal.x = (sectionVertex.x * curve.Data[i].normal.x + sectionVertex.y * curve.Data[i].binormal.x) * sectionThickness;
|
||||
normal.y = (sectionVertex.x * curve.Data[i].normal.y + sectionVertex.y * curve.Data[i].binormal.y) * sectionThickness;
|
||||
normal.z = (sectionVertex.x * curve.Data[i].normal.z + sectionVertex.y * curve.Data[i].binormal.z) * sectionThickness;
|
||||
|
||||
// offset curve position by normal:
|
||||
vertex.x = curve.Data[i].position.x + normal.x;
|
||||
vertex.y = curve.Data[i].position.y + normal.y;
|
||||
vertex.z = curve.Data[i].position.z + normal.z;
|
||||
|
||||
// cross(normal, curve tangent)
|
||||
texTangent.x = normal.y * curve.Data[i].tangent.z - normal.z * curve.Data[i].tangent.y;
|
||||
texTangent.y = normal.z * curve.Data[i].tangent.x - normal.x * curve.Data[i].tangent.z;
|
||||
texTangent.z = normal.x * curve.Data[i].tangent.y - normal.y * curve.Data[i].tangent.x;
|
||||
texTangent.w = -1;
|
||||
|
||||
uv.x = (j / (float)sectionSegments) * uvScale.x;
|
||||
uv.y = vCoord;
|
||||
|
||||
vertices.Add(vertex);
|
||||
normals.Add(normal);
|
||||
tangents.Add(texTangent);
|
||||
vertColors.Add(curve.Data[i].color);
|
||||
uvs.Add(uv);
|
||||
|
||||
if (j < sectionSegments && i < curve.Count - 1)
|
||||
{
|
||||
tris.Add(sectionIndex * verticesPerSection + j);
|
||||
tris.Add(nextSectionIndex * verticesPerSection + j);
|
||||
tris.Add(sectionIndex * verticesPerSection + (j + 1));
|
||||
|
||||
tris.Add(sectionIndex * verticesPerSection + (j + 1));
|
||||
tris.Add(nextSectionIndex * verticesPerSection + j);
|
||||
tris.Add(nextSectionIndex * verticesPerSection + (j + 1));
|
||||
}
|
||||
}
|
||||
sectionIndex++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CommitMeshData();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearMeshData()
|
||||
{
|
||||
extrudedMesh.Clear();
|
||||
vertices.Clear();
|
||||
normals.Clear();
|
||||
tangents.Clear();
|
||||
uvs.Clear();
|
||||
vertColors.Clear();
|
||||
tris.Clear();
|
||||
}
|
||||
|
||||
private void CommitMeshData()
|
||||
{
|
||||
extrudedMesh.SetVertices(vertices);
|
||||
extrudedMesh.SetNormals(normals);
|
||||
extrudedMesh.SetTangents(tangents);
|
||||
extrudedMesh.SetColors(vertColors);
|
||||
extrudedMesh.SetUVs(0, uvs);
|
||||
extrudedMesh.SetTriangles(tris, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4747da60837c44f9ba4b4a86879bcc8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- extrudedMesh: {instanceID: 0}
|
||||
- section: {fileID: 11400000, guid: a0bc36a59515f413e90e10895929c938, type: 2}
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: a552ed0e1c0fd47c38eeff6d60b5b115, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
199
Assets/Obi/Scripts/RopeAndRod/Rendering/ObiRopeLineRenderer.cs
Normal file
199
Assets/Obi/Scripts/RopeAndRod/Rendering/ObiRopeLineRenderer.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[AddComponentMenu("Physics/Obi/Obi Rope Line Renderer", 884)]
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(ObiPathSmoother))]
|
||||
public class ObiRopeLineRenderer : MonoBehaviour
|
||||
{
|
||||
static ProfilerMarker m_UpdateLineRopeRendererChunksPerfMarker = new ProfilerMarker("UpdateLineRopeRenderer");
|
||||
|
||||
private List<Vector3> vertices = new List<Vector3>();
|
||||
private List<Vector3> normals = new List<Vector3>();
|
||||
private List<Vector4> tangents = new List<Vector4>();
|
||||
private List<Vector2> uvs = new List<Vector2>();
|
||||
private List<Color> vertColors = new List<Color>();
|
||||
private List<int> tris = new List<int>();
|
||||
|
||||
ObiRopeBase rope;
|
||||
ObiPathSmoother smoother;
|
||||
|
||||
#if (UNITY_2019_1_OR_NEWER)
|
||||
System.Action<ScriptableRenderContext, Camera> renderCallback;
|
||||
#endif
|
||||
|
||||
[HideInInspector] [NonSerialized] public Mesh lineMesh;
|
||||
|
||||
[Range(0, 1)]
|
||||
public float uvAnchor = 0; /**< Normalized position of texture coordinate origin along rope.*/
|
||||
|
||||
public Vector2 uvScale = Vector2.one; /**< Scaling of uvs along rope.*/
|
||||
|
||||
public bool normalizeV = true;
|
||||
|
||||
public float thicknessScale = 0.8f; /**< Scales section thickness.*/
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
|
||||
CreateMeshIfNeeded();
|
||||
|
||||
#if (UNITY_2019_1_OR_NEWER)
|
||||
renderCallback = new System.Action<ScriptableRenderContext, Camera>((cntxt, cam) => { UpdateRenderer(cam); });
|
||||
RenderPipelineManager.beginCameraRendering += renderCallback;
|
||||
#endif
|
||||
Camera.onPreCull += UpdateRenderer;
|
||||
|
||||
rope = GetComponent<ObiRopeBase>();
|
||||
smoother = GetComponent<ObiPathSmoother>();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
|
||||
#if (UNITY_2019_1_OR_NEWER)
|
||||
RenderPipelineManager.beginCameraRendering -= renderCallback;
|
||||
#endif
|
||||
Camera.onPreCull -= UpdateRenderer;
|
||||
|
||||
GameObject.DestroyImmediate(lineMesh);
|
||||
}
|
||||
|
||||
private void CreateMeshIfNeeded()
|
||||
{
|
||||
if (lineMesh == null)
|
||||
{
|
||||
lineMesh = new Mesh();
|
||||
lineMesh.name = "extrudedMesh";
|
||||
lineMesh.MarkDynamic();
|
||||
GetComponent<MeshFilter>().mesh = lineMesh;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateRenderer(Camera camera)
|
||||
{
|
||||
using (m_UpdateLineRopeRendererChunksPerfMarker.Auto())
|
||||
{
|
||||
|
||||
if (camera == null || !rope.gameObject.activeInHierarchy)
|
||||
return;
|
||||
|
||||
CreateMeshIfNeeded();
|
||||
ClearMeshData();
|
||||
|
||||
float actualToRestLengthRatio = smoother.SmoothLength / rope.restLength;
|
||||
|
||||
float vCoord = -uvScale.y * rope.restLength * uvAnchor; // v texture coordinate.
|
||||
int sectionIndex = 0;
|
||||
|
||||
Vector3 localSpaceCamera = rope.transform.InverseTransformPoint(camera.transform.position);
|
||||
Vector3 vertex = Vector3.zero, normal = Vector3.zero;
|
||||
Vector4 bitangent = Vector4.zero;
|
||||
Vector2 uv = Vector2.zero;
|
||||
|
||||
for (int c = 0; c < smoother.smoothChunks.Count; ++c)
|
||||
{
|
||||
|
||||
ObiList<ObiPathFrame> curve = smoother.smoothChunks[c];
|
||||
|
||||
for (int i = 0; i < curve.Count; ++i)
|
||||
{
|
||||
|
||||
// Calculate previous and next curve indices:
|
||||
int prevIndex = Mathf.Max(i - 1, 0);
|
||||
|
||||
// advance v texcoord:
|
||||
vCoord += uvScale.y * (Vector3.Distance(curve.Data[i].position, curve.Data[prevIndex].position) /
|
||||
(normalizeV ? smoother.SmoothLength : actualToRestLengthRatio));
|
||||
|
||||
// calculate section thickness (either constant, or particle radius based):
|
||||
float sectionThickness = curve.Data[i].thickness * thicknessScale;
|
||||
|
||||
|
||||
normal.x = curve.Data[i].position.x - localSpaceCamera.x;
|
||||
normal.y = curve.Data[i].position.y - localSpaceCamera.y;
|
||||
normal.z = curve.Data[i].position.z - localSpaceCamera.z;
|
||||
normal.Normalize();
|
||||
|
||||
bitangent.x = -(normal.y * curve.Data[i].tangent.z - normal.z * curve.Data[i].tangent.y);
|
||||
bitangent.y = -(normal.z * curve.Data[i].tangent.x - normal.x * curve.Data[i].tangent.z);
|
||||
bitangent.z = -(normal.x * curve.Data[i].tangent.y - normal.y * curve.Data[i].tangent.x);
|
||||
bitangent.w = 0;
|
||||
bitangent.Normalize();
|
||||
|
||||
vertex.x = curve.Data[i].position.x - bitangent.x * sectionThickness;
|
||||
vertex.y = curve.Data[i].position.y - bitangent.y * sectionThickness;
|
||||
vertex.z = curve.Data[i].position.z - bitangent.z * sectionThickness;
|
||||
vertices.Add(vertex);
|
||||
|
||||
vertex.x = curve.Data[i].position.x + bitangent.x * sectionThickness;
|
||||
vertex.y = curve.Data[i].position.y + bitangent.y * sectionThickness;
|
||||
vertex.z = curve.Data[i].position.z + bitangent.z * sectionThickness;
|
||||
vertices.Add(vertex);
|
||||
|
||||
normals.Add(-normal);
|
||||
normals.Add(-normal);
|
||||
|
||||
bitangent.w = 1;
|
||||
tangents.Add(bitangent);
|
||||
tangents.Add(bitangent);
|
||||
|
||||
vertColors.Add(curve.Data[i].color);
|
||||
vertColors.Add(curve.Data[i].color);
|
||||
|
||||
uv.x = 0; uv.y = vCoord;
|
||||
uvs.Add(uv);
|
||||
uv.x = 1;
|
||||
uvs.Add(uv);
|
||||
|
||||
if (i < curve.Count - 1)
|
||||
{
|
||||
tris.Add(sectionIndex * 2);
|
||||
tris.Add((sectionIndex + 1) * 2);
|
||||
tris.Add(sectionIndex * 2 + 1);
|
||||
|
||||
tris.Add(sectionIndex * 2 + 1);
|
||||
tris.Add((sectionIndex + 1) * 2);
|
||||
tris.Add((sectionIndex + 1) * 2 + 1);
|
||||
}
|
||||
|
||||
sectionIndex++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CommitMeshData();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearMeshData()
|
||||
{
|
||||
lineMesh.Clear();
|
||||
vertices.Clear();
|
||||
normals.Clear();
|
||||
tangents.Clear();
|
||||
uvs.Clear();
|
||||
vertColors.Clear();
|
||||
tris.Clear();
|
||||
}
|
||||
|
||||
private void CommitMeshData()
|
||||
{
|
||||
lineMesh.SetVertices(vertices);
|
||||
lineMesh.SetNormals(normals);
|
||||
lineMesh.SetTangents(tangents);
|
||||
lineMesh.SetColors(vertColors);
|
||||
lineMesh.SetUVs(0, uvs);
|
||||
lineMesh.SetTriangles(tris, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18f853588397d4a80a561203ed92fc8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 905a18c273af443d6bc588b59ebd56f6, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
260
Assets/Obi/Scripts/RopeAndRod/Rendering/ObiRopeMeshRenderer.cs
Normal file
260
Assets/Obi/Scripts/RopeAndRod/Rendering/ObiRopeMeshRenderer.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[AddComponentMenu("Physics/Obi/Obi Rope Mesh Renderer", 886)]
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(ObiPathSmoother))]
|
||||
public class ObiRopeMeshRenderer : MonoBehaviour
|
||||
{
|
||||
static ProfilerMarker m_UpdateMeshRopeRendererChunksPerfMarker = new ProfilerMarker("UpdateMeshRopeRenderer");
|
||||
|
||||
[SerializeProperty("SourceMesh")]
|
||||
[SerializeField] private Mesh mesh;
|
||||
|
||||
[SerializeProperty("SweepAxis")]
|
||||
[SerializeField] private ObiPathFrame.Axis axis;
|
||||
|
||||
public float volumeScaling = 0;
|
||||
public bool stretchWithRope = true;
|
||||
public bool spanEntireLength = true;
|
||||
|
||||
[SerializeProperty("Instances")]
|
||||
[SerializeField] private int instances = 1;
|
||||
|
||||
[SerializeProperty("InstanceSpacing")]
|
||||
[SerializeField] private float instanceSpacing = 1;
|
||||
|
||||
public float offset = 0;
|
||||
public Vector3 scale = Vector3.one;
|
||||
|
||||
[HideInInspector] [SerializeField] private float meshSizeAlongAxis = 1;
|
||||
|
||||
private Vector3[] inputVertices;
|
||||
private Vector3[] inputNormals;
|
||||
private Vector4[] inputTangents;
|
||||
|
||||
private Vector3[] vertices;
|
||||
private Vector3[] normals;
|
||||
private Vector4[] tangents;
|
||||
|
||||
private int[] orderedVertices = new int[0];
|
||||
|
||||
private ObiPathSmoother smoother;
|
||||
|
||||
public Mesh SourceMesh
|
||||
{
|
||||
set { mesh = value; PreprocessInputMesh(); }
|
||||
get { return mesh; }
|
||||
}
|
||||
|
||||
public ObiPathFrame.Axis SweepAxis
|
||||
{
|
||||
set { axis = value; PreprocessInputMesh(); }
|
||||
get { return axis; }
|
||||
}
|
||||
|
||||
public int Instances
|
||||
{
|
||||
set { instances = value; PreprocessInputMesh(); }
|
||||
get { return instances; }
|
||||
}
|
||||
|
||||
public float InstanceSpacing
|
||||
{
|
||||
set { instanceSpacing = value; PreprocessInputMesh(); }
|
||||
get { return instanceSpacing; }
|
||||
}
|
||||
|
||||
[HideInInspector] [NonSerialized] public Mesh deformedMesh;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
smoother = GetComponent<ObiPathSmoother>();
|
||||
smoother.OnCurveGenerated += UpdateRenderer;
|
||||
PreprocessInputMesh();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
smoother.OnCurveGenerated -= UpdateRenderer;
|
||||
GameObject.DestroyImmediate(deformedMesh);
|
||||
}
|
||||
|
||||
private void PreprocessInputMesh()
|
||||
{
|
||||
|
||||
if (deformedMesh == null)
|
||||
{
|
||||
deformedMesh = new Mesh();
|
||||
deformedMesh.name = "deformedMesh";
|
||||
deformedMesh.MarkDynamic();
|
||||
GetComponent<MeshFilter>().mesh = deformedMesh;
|
||||
}
|
||||
|
||||
deformedMesh.Clear();
|
||||
|
||||
if (mesh == null)
|
||||
{
|
||||
orderedVertices = new int[0];
|
||||
return;
|
||||
}
|
||||
|
||||
// Clamp instance count to a positive value.
|
||||
instances = Mathf.Max(0, instances);
|
||||
|
||||
// combine all mesh instances into a single mesh:
|
||||
Mesh combinedMesh = new Mesh();
|
||||
CombineInstance[] meshInstances = new CombineInstance[instances];
|
||||
Vector3 pos = Vector3.zero;
|
||||
|
||||
// initial offset for the combined mesh is half the size of its bounding box in the swept axis:
|
||||
pos[(int)axis] = mesh.bounds.extents[(int)axis];
|
||||
|
||||
for (int i = 0; i < instances; ++i)
|
||||
{
|
||||
meshInstances[i].mesh = mesh;
|
||||
meshInstances[i].transform = Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one);
|
||||
pos[(int)axis] = mesh.bounds.extents[(int)axis] + (i + 1) * mesh.bounds.size[(int)axis] * instanceSpacing;
|
||||
}
|
||||
combinedMesh.CombineMeshes(meshInstances, true, true);
|
||||
|
||||
// get combined mesh data:
|
||||
inputVertices = combinedMesh.vertices;
|
||||
inputNormals = combinedMesh.normals;
|
||||
inputTangents = combinedMesh.tangents;
|
||||
|
||||
// sort vertices along curve axis:
|
||||
float[] keys = new float[inputVertices.Length];
|
||||
orderedVertices = new int[inputVertices.Length];
|
||||
|
||||
for (int i = 0; i < keys.Length; ++i)
|
||||
{
|
||||
keys[i] = inputVertices[i][(int)axis];
|
||||
orderedVertices[i] = i;
|
||||
}
|
||||
|
||||
Array.Sort(keys, orderedVertices);
|
||||
|
||||
// Copy the combined mesh data to deform it:
|
||||
deformedMesh.vertices = combinedMesh.vertices;
|
||||
deformedMesh.normals = combinedMesh.normals;
|
||||
deformedMesh.tangents = combinedMesh.tangents;
|
||||
deformedMesh.uv = combinedMesh.uv;
|
||||
deformedMesh.uv2 = combinedMesh.uv2;
|
||||
deformedMesh.uv3 = combinedMesh.uv3;
|
||||
deformedMesh.uv4 = combinedMesh.uv4;
|
||||
deformedMesh.colors = combinedMesh.colors;
|
||||
deformedMesh.triangles = combinedMesh.triangles;
|
||||
|
||||
vertices = deformedMesh.vertices;
|
||||
normals = deformedMesh.normals;
|
||||
tangents = deformedMesh.tangents;
|
||||
|
||||
// Calculate scale along swept axis so that the mesh spans the entire lenght of the rope if required.
|
||||
meshSizeAlongAxis = combinedMesh.bounds.size[(int)axis];
|
||||
|
||||
// destroy combined mesh:
|
||||
GameObject.DestroyImmediate(combinedMesh);
|
||||
|
||||
}
|
||||
|
||||
public void UpdateRenderer(ObiActor actor)
|
||||
{
|
||||
using (m_UpdateMeshRopeRendererChunksPerfMarker.Auto())
|
||||
{
|
||||
|
||||
if (mesh == null)
|
||||
return;
|
||||
|
||||
if (smoother.smoothChunks.Count == 0)
|
||||
return;
|
||||
|
||||
ObiList<ObiPathFrame> curve = smoother.smoothChunks[0];
|
||||
|
||||
if (curve.Count < 2)
|
||||
return;
|
||||
|
||||
var rope = actor as ObiRopeBase;
|
||||
|
||||
float actualToRestLengthRatio = stretchWithRope ? smoother.SmoothLength / rope.restLength : 1;
|
||||
|
||||
// squashing factor, makes mesh thinner when stretched and thicker when compresssed.
|
||||
float squashing = Mathf.Clamp(1 + volumeScaling * (1 / Mathf.Max(actualToRestLengthRatio, 0.01f) - 1), 0.01f, 2);
|
||||
|
||||
// Calculate scale along swept axis so that the mesh spans the entire lenght of the rope if required.
|
||||
Vector3 actualScale = scale;
|
||||
if (spanEntireLength)
|
||||
actualScale[(int)axis] = rope.restLength / meshSizeAlongAxis;
|
||||
|
||||
float previousVertexValue = 0;
|
||||
float meshLength = 0;
|
||||
int index = 0;
|
||||
int nextIndex = 1;
|
||||
int prevIndex = 0;
|
||||
float sectionMagnitude = Vector3.Distance(curve[index].position, curve[nextIndex].position);
|
||||
|
||||
// basis matrix for deforming the mesh:
|
||||
Matrix4x4 basis = curve[0].ToMatrix(axis);
|
||||
|
||||
for (int i = 0; i < orderedVertices.Length; ++i)
|
||||
{
|
||||
|
||||
int vIndex = orderedVertices[i];
|
||||
float vertexValue = inputVertices[vIndex][(int)axis] * actualScale[(int)axis] + offset;
|
||||
|
||||
// Calculate how much we've advanced in the sort axis since the last vertex:
|
||||
meshLength += (vertexValue - previousVertexValue) * actualToRestLengthRatio;
|
||||
previousVertexValue = vertexValue;
|
||||
|
||||
// If we have advanced to the next section of the curve:
|
||||
while (meshLength > sectionMagnitude && sectionMagnitude > Mathf.Epsilon)
|
||||
{
|
||||
|
||||
meshLength -= sectionMagnitude;
|
||||
index = Mathf.Min(index + 1, curve.Count - 1);
|
||||
|
||||
// Calculate previous and next curve indices:
|
||||
nextIndex = Mathf.Min(index + 1, curve.Count - 1);
|
||||
prevIndex = Mathf.Max(index - 1, 0);
|
||||
|
||||
// Calculate current tangent as the vector between previous and next curve points:
|
||||
sectionMagnitude = Vector3.Distance(curve[index].position, curve[nextIndex].position);
|
||||
|
||||
// Update basis matrix:
|
||||
basis = curve[index].ToMatrix(axis);
|
||||
|
||||
}
|
||||
|
||||
float sectionThickness = curve[index].thickness;
|
||||
|
||||
// calculate deformed vertex position:
|
||||
Vector3 offsetFromCurve = Vector3.Scale(inputVertices[vIndex], actualScale * sectionThickness * squashing);
|
||||
offsetFromCurve[(int)axis] = meshLength;
|
||||
|
||||
vertices[vIndex] = curve[index].position + basis.MultiplyVector(offsetFromCurve);
|
||||
normals[vIndex] = basis.MultiplyVector(inputNormals[vIndex]);
|
||||
tangents[vIndex] = basis * inputTangents[vIndex]; // avoids expensive implicit conversion from Vector4 to Vector3.
|
||||
tangents[vIndex].w = inputTangents[vIndex].w;
|
||||
}
|
||||
|
||||
CommitMeshData();
|
||||
}
|
||||
}
|
||||
|
||||
private void CommitMeshData()
|
||||
{
|
||||
deformedMesh.vertices = vertices;
|
||||
deformedMesh.normals = normals;
|
||||
deformedMesh.tangents = tangents;
|
||||
deformedMesh.RecalculateBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ec7e70e3318044b69e11352b1f2136b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: c5afdc6c291b44a68be8bf66702358a5, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user