217 lines
7.6 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|