修改水
This commit is contained in:
@@ -1,85 +1,259 @@
|
||||
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, ObiActorRenderer<ObiRopeMeshRenderer>, IMeshDataProvider
|
||||
public class ObiRopeMeshRenderer : MonoBehaviour
|
||||
{
|
||||
public Renderer sourceRenderer { get; protected set; }
|
||||
public ObiActor actor { get; private set; }
|
||||
public uint meshInstances { get {return instances;} }
|
||||
static ProfilerMarker m_UpdateMeshRopeRendererChunksPerfMarker = new ProfilerMarker("UpdateMeshRopeRenderer");
|
||||
|
||||
[field: SerializeField]
|
||||
public Mesh sourceMesh { get; set; }
|
||||
[SerializeProperty("SourceMesh")]
|
||||
[SerializeField] private Mesh mesh;
|
||||
|
||||
[field: SerializeField]
|
||||
public Material[] materials { get; set; }
|
||||
|
||||
public virtual int vertexCount { get { return sourceMesh ? sourceMesh.vertexCount : 0; } }
|
||||
public virtual int triangleCount { get { return sourceMesh ? sourceMesh.triangles.Length / 3 : 0; } }
|
||||
|
||||
public RenderBatchParams renderParameters = new RenderBatchParams(true);
|
||||
|
||||
public ObiPathFrame.Axis axis;
|
||||
[SerializeProperty("SweepAxis")]
|
||||
[SerializeField] private ObiPathFrame.Axis axis;
|
||||
|
||||
public float volumeScaling = 0;
|
||||
public bool stretchWithRope = true;
|
||||
public bool spanEntireLength = true;
|
||||
|
||||
public uint instances = 1;
|
||||
public float instanceSpacing = 0;
|
||||
[SerializeProperty("Instances")]
|
||||
[SerializeField] private int instances = 1;
|
||||
|
||||
[SerializeProperty("InstanceSpacing")]
|
||||
[SerializeField] private float instanceSpacing = 1;
|
||||
|
||||
public float offset = 0;
|
||||
public Vector3 scale = Vector3.one;
|
||||
|
||||
public void Awake()
|
||||
[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
|
||||
{
|
||||
actor = GetComponent<ObiActor>();
|
||||
sourceRenderer = GetComponent<MeshRenderer>();
|
||||
set { mesh = value; PreprocessInputMesh(); }
|
||||
get { return mesh; }
|
||||
}
|
||||
|
||||
public void OnEnable()
|
||||
public ObiPathFrame.Axis SweepAxis
|
||||
{
|
||||
((ObiActorRenderer<ObiRopeMeshRenderer>)this).EnableRenderer();
|
||||
set { axis = value; PreprocessInputMesh(); }
|
||||
get { return axis; }
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
public int Instances
|
||||
{
|
||||
((ObiActorRenderer<ObiRopeMeshRenderer>)this).DisableRenderer();
|
||||
set { instances = value; PreprocessInputMesh(); }
|
||||
get { return instances; }
|
||||
}
|
||||
|
||||
public void OnValidate()
|
||||
public float InstanceSpacing
|
||||
{
|
||||
((ObiActorRenderer<ObiRopeMeshRenderer>)this).SetRendererDirty(Oni.RenderingSystemType.MeshRope);
|
||||
set { instanceSpacing = value; PreprocessInputMesh(); }
|
||||
get { return instanceSpacing; }
|
||||
}
|
||||
|
||||
RenderSystem<ObiRopeMeshRenderer> ObiRenderer<ObiRopeMeshRenderer>.CreateRenderSystem(ObiSolver solver)
|
||||
[HideInInspector] [NonSerialized] public Mesh deformedMesh;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
switch (solver.backendType)
|
||||
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 (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
case ObiSolver.BackendType.Burst: return new BurstMeshRopeRenderSystem(solver);
|
||||
#endif
|
||||
case ObiSolver.BackendType.Compute:
|
||||
default:
|
||||
if (mesh == null)
|
||||
return;
|
||||
|
||||
if (SystemInfo.supportsComputeShaders)
|
||||
return new ComputeMeshRopeRenderSystem(solver);
|
||||
return null;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void GetVertices(List<Vector3> vertices) { sourceMesh.GetVertices(vertices); }
|
||||
public virtual void GetNormals(List<Vector3> normals) { sourceMesh.GetNormals(normals); }
|
||||
public virtual void GetTangents(List<Vector4> tangents) { sourceMesh.GetTangents(tangents); }
|
||||
public virtual void GetColors(List<Color> colors) { sourceMesh.GetColors(colors); }
|
||||
public virtual void GetUVs(int channel, List<Vector2> uvs) { sourceMesh.GetUVs(channel, uvs); }
|
||||
|
||||
public virtual void GetTriangles(List<int> triangles) { triangles.Clear(); triangles.AddRange(sourceMesh.triangles); }
|
||||
private void CommitMeshData()
|
||||
{
|
||||
deformedMesh.vertices = vertices;
|
||||
deformedMesh.normals = normals;
|
||||
deformedMesh.tangents = tangents;
|
||||
deformedMesh.RecalculateBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user