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

142 lines
4.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
namespace Obi
{
[StructLayout(LayoutKind.Sequential)]
public struct ChunkData
{
public int rendererIndex;
public int offset; // index of the first element for each chunk.
public ChunkData(int rendererIndex, int offset)
{
this.rendererIndex = rendererIndex;
this.offset = offset;
}
}
public class InstancedRenderBatch : IRenderBatch
{
private RenderBatchParams renderBatchParams;
public RenderParams renderParams { get; private set; }
public Mesh mesh;
public Material material;
public int firstRenderer;
public int rendererCount;
public int firstInstance;
public int instanceCount;
public GraphicsBuffer argsBuffer;
public InstancedRenderBatch(int rendererIndex, Mesh mesh, Material material, RenderBatchParams renderBatchParams)
{
this.renderBatchParams = renderBatchParams;
this.firstRenderer = rendererIndex;
this.rendererCount = 1;
this.mesh = mesh;
this.material = material;
this.firstInstance = 0;
this.instanceCount = 0;
}
public void Initialize(bool gpu = false)
{
renderParams = renderBatchParams.ToRenderParams();
if (gpu)
argsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 1, 5 * sizeof(uint));
}
public void Dispose()
{
argsBuffer?.Dispose();
argsBuffer = null;
}
public bool TryMergeWith(IRenderBatch other)
{
var ibatch = other as InstancedRenderBatch;
if (ibatch != null)
{
if (CompareTo(ibatch) == 0 &&
instanceCount + ibatch.instanceCount < Constants.maxInstancesPerBatch)
{
rendererCount += ibatch.rendererCount;
instanceCount += ibatch.instanceCount;
return true;
}
}
return false;
}
public int CompareTo(IRenderBatch other)
{
var ibatch = other as InstancedRenderBatch;
int idA = material != null ? material.GetInstanceID() : 0;
int idB = (ibatch != null && ibatch.material != null) ? ibatch.material.GetInstanceID() : 0;
int compareMat = idA.CompareTo(idB);
if (compareMat == 0)
{
idA = mesh != null ? mesh.GetInstanceID() : 0;
idB = (ibatch != null && ibatch.mesh != null) ? ibatch.mesh.GetInstanceID() : 0;
compareMat = idA.CompareTo(idB);
if (compareMat == 0)
return renderBatchParams.CompareTo(ibatch.renderBatchParams);
}
return compareMat;
}
public void BakeMesh<T>(RendererSet<T> renderers, T renderer, ObiNativeList<ChunkData> chunkData,
ObiNativeList<Matrix4x4> instanceTransforms,
Matrix4x4 transform,
ref Mesh bakedMesh, bool transformVertices = false) where T:ObiRenderer<T>
{
// if the data is not available in the CPU (such as when the batch is intended for GPU use), read it back:
bool gpu = argsBuffer != null && argsBuffer.IsValid();
if (gpu)
{
instanceTransforms.Readback(false);
}
List<CombineInstance> combineInstances = new List<CombineInstance>();
bakedMesh.Clear();
for (int i = 0; i < chunkData.count; ++i)
{
// if this chunk's renderer is the renderer we are interested in,
// append its instances to the mesh.
if (renderers[chunkData[i].rendererIndex].Equals(renderer))
{
int firstIndex = i > 0 ? chunkData[i - 1].offset : 0;
int elementCount = chunkData[i].offset - firstIndex;
for (int m = 0; m < elementCount; ++m)
{
combineInstances.Add(new CombineInstance
{
mesh = mesh,
transform = transformVertices ? transform * instanceTransforms[firstIndex + m] : instanceTransforms[firstIndex + m]
});
}
}
}
bakedMesh.CombineMeshes(combineInstances.ToArray(), true, true, false);
bakedMesh.RecalculateBounds();
}
}
}