_xiaofang/xiaofang/Assets/Obi/Scripts/RopeAndRod/Rendering/ObiChainRopeRenderSystem.cs
杨号敬 bcc74f0465 add
2024-12-18 02:18:45 +08:00

217 lines
7.6 KiB
C#

using System.Runtime.InteropServices;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using Unity.Profiling;
namespace Obi
{
[StructLayout(LayoutKind.Sequential)]
public struct ChainRendererData
{
public int modifierOffset;
public float twistAnchor;
public float twist;
public uint usesOrientedParticles;
public Vector4 scale;
public ChainRendererData(int modifierOffset, float twistAnchor, float twist, Vector3 scale, bool usesOrientedParticles)
{
this.modifierOffset = modifierOffset;
this.twistAnchor = twistAnchor;
this.twist = twist;
this.usesOrientedParticles = (uint)(usesOrientedParticles ? 1 : 0);
this.scale = scale;
}
}
public abstract class ObiChainRopeRenderSystem : RenderSystem<ObiRopeChainRenderer>
{
public Oni.RenderingSystemType typeEnum { get => Oni.RenderingSystemType.ChainRope; }
public RendererSet<ObiRopeChainRenderer> renderers { get; } = new RendererSet<ObiRopeChainRenderer>();
// specify vertex count and layout
protected VertexAttributeDescriptor[] layout =
{
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.Tangent, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2),
};
static protected ProfilerMarker m_SetupRenderMarker = new ProfilerMarker("SetupChainRopeRendering");
static protected ProfilerMarker m_RenderMarker = new ProfilerMarker("ChainRopeRendering");
protected ObiSolver m_Solver;
protected List<InstancedRenderBatch> batchList = new List<InstancedRenderBatch>();
protected ObiNativeList<ChainRendererData> rendererData;
protected ObiNativeList<ChunkData> chunkData;
protected ObiNativeList<ObiRopeChainRenderer.LinkModifier> modifiers;
protected ObiNativeList<Vector2Int> elements;
protected ObiNativeList<Matrix4x4> instanceTransforms;
protected ObiNativeList<Matrix4x4> invInstanceTransforms;
protected ObiNativeList<Vector4> instanceColors;
public ObiChainRopeRenderSystem(ObiSolver solver)
{
m_Solver = solver;
}
public virtual void Dispose()
{
CleanupBatches();
DestroyLists();
}
private void DestroyLists()
{
if (instanceTransforms != null)
instanceTransforms.Dispose();
if (invInstanceTransforms != null)
invInstanceTransforms.Dispose();
if (instanceColors != null)
instanceColors.Dispose();
if (elements != null)
elements.Dispose();
if (chunkData != null)
chunkData.Dispose();
if (rendererData != null)
rendererData.Dispose();
if (modifiers != null)
modifiers.Dispose();
}
private void CreateListsIfNecessary()
{
DestroyLists();
instanceTransforms = new ObiNativeList<Matrix4x4>();
invInstanceTransforms = new ObiNativeList<Matrix4x4>();
instanceColors = new ObiNativeList<Vector4>();
elements = new ObiNativeList<Vector2Int>();
chunkData = new ObiNativeList<ChunkData>();
rendererData = new ObiNativeList<ChainRendererData>();
modifiers = new ObiNativeList<ObiRopeChainRenderer.LinkModifier>();
}
private void CleanupBatches()
{
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Dispose();
batchList.Clear();
}
private void GenerateBatches()
{
instanceTransforms.Clear();
invInstanceTransforms.Clear();
instanceColors.Clear();
elements.Clear();
rendererData.Clear();
chunkData.Clear();
modifiers.Clear();
// generate batches:
for (int i = 0; i < renderers.Count; ++i)
{
var renderer = renderers[i];
if (renderer.linkMesh != null && renderer.linkMaterial != null)
{
renderer.renderParameters.layer = renderer.gameObject.layer;
batchList.Add(new InstancedRenderBatch(i, renderer.linkMesh, renderer.linkMaterial, renderer.renderParameters));
}
}
// sort batches:
batchList.Sort();
// append elements:
for (int i = 0; i < batchList.Count; ++i)
{
var renderer = renderers[batchList[i].firstRenderer];
var rope = renderer.actor as ObiRopeBase;
modifiers.AddRange(renderer.linkModifiers);
rendererData.Add(new ChainRendererData(modifiers.count, renderer.twistAnchor, renderer.linkTwist, renderer.linkScale, rope.usesOrientedParticles));
batchList[i].firstInstance = elements.count;
batchList[i].instanceCount = rope.elements.Count;
// iterate trough elements, finding discontinuities as we go:
for (int e = 0; e < rope.elements.Count; ++e)
{
elements.Add(new Vector2Int(rope.elements[e].particle1, rope.elements[e].particle2));
// At discontinuities, start a new chunk.
if (e < rope.elements.Count - 1 && rope.elements[e].particle2 != rope.elements[e + 1].particle1)
{
chunkData.Add(new ChunkData(rendererData.count - 1, elements.count));
}
}
chunkData.Add(new ChunkData(rendererData.count - 1, elements.count));
}
instanceTransforms.ResizeUninitialized(elements.count);
invInstanceTransforms.ResizeUninitialized(elements.count);
instanceColors.ResizeUninitialized(elements.count);
}
protected virtual void CloseBatches()
{
// Initialize each batch:
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Initialize();
}
public virtual void Setup()
{
using (m_SetupRenderMarker.Auto())
{
CreateListsIfNecessary();
CleanupBatches();
GenerateBatches();
ObiUtils.MergeBatches(batchList);
CloseBatches();
}
}
public abstract void Render();
public void Step()
{
}
public void BakeMesh(ObiRopeChainRenderer renderer, ref Mesh mesh, bool transformToActorLocalSpace = false)
{
int index = renderers.IndexOf(renderer);
for (int i = 0; i < batchList.Count; ++i)
{
var batch = batchList[i];
if (index >= batch.firstRenderer && index < batch.firstRenderer + batch.rendererCount)
{
batch.BakeMesh(renderers, renderer, chunkData, instanceTransforms,
renderer.actor.actorSolverToLocalMatrix, ref mesh, transformToActorLocalSpace);
return;
}
}
}
}
}