修改水
This commit is contained in:
@@ -1,368 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct DynamicBatchVertex
|
||||
{
|
||||
public Vector3 pos;
|
||||
public Vector3 normal;
|
||||
public Vector4 tangent;
|
||||
public Vector4 color;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct StaticBatchVertex
|
||||
{
|
||||
public Vector2 uv;
|
||||
public Vector2 uv2;
|
||||
public Vector2 uv3;
|
||||
public Vector2 uv4;
|
||||
}
|
||||
|
||||
public class DynamicRenderBatch<T> : IRenderBatch where T : IMeshDataProvider, IActorRenderer
|
||||
{
|
||||
private VertexAttributeDescriptor[] vertexLayout;
|
||||
|
||||
private RenderBatchParams renderBatchParams;
|
||||
public RenderParams renderParams { get; private set; }
|
||||
|
||||
public Material[] materials;
|
||||
public Mesh mesh;
|
||||
|
||||
public int firstRenderer;
|
||||
public int rendererCount;
|
||||
|
||||
public ObiNativeList<int> vertexToRenderer; // for each vertex in the batch, index of its renderer
|
||||
public ObiNativeList<int> particleToRenderer; // for each particle in the batch, index of its renderer
|
||||
|
||||
public ObiNativeList<int> particleIndices; // solver indices for all renderers in the batch
|
||||
|
||||
public ObiNativeList<DynamicBatchVertex> dynamicVertexData;
|
||||
public ObiNativeList<StaticBatchVertex> staticVertexData;
|
||||
public ObiNativeList<int> triangles;
|
||||
|
||||
public GraphicsBuffer gpuVertexBuffer;
|
||||
|
||||
public int vertexCount;
|
||||
public int triangleCount => triangles.count / 3;
|
||||
public int particleCount => particleIndices.count;
|
||||
|
||||
public DynamicRenderBatch(int rendererIndex, int vertexCount, Material[] materials, RenderBatchParams param)
|
||||
{
|
||||
this.renderBatchParams = param;
|
||||
this.materials = materials;
|
||||
this.vertexCount = vertexCount;
|
||||
|
||||
this.firstRenderer = rendererIndex;
|
||||
this.rendererCount = 1;
|
||||
}
|
||||
|
||||
public void Initialize(List<T> renderers,
|
||||
MeshDataBatch meshData,
|
||||
ObiNativeList<int> meshIndices,
|
||||
VertexAttributeDescriptor[] layout,
|
||||
bool gpu = false)
|
||||
{
|
||||
renderParams = renderBatchParams.ToRenderParams();
|
||||
vertexLayout = layout;
|
||||
|
||||
mesh = new Mesh();
|
||||
|
||||
vertexToRenderer = new ObiNativeList<int>();
|
||||
particleToRenderer = new ObiNativeList<int>();
|
||||
particleIndices = new ObiNativeList<int>();
|
||||
|
||||
dynamicVertexData = new ObiNativeList<DynamicBatchVertex>();
|
||||
staticVertexData = new ObiNativeList<StaticBatchVertex>();
|
||||
triangles = new ObiNativeList<int>();
|
||||
|
||||
// there will be exactly one submesh per material in the output batch.
|
||||
// so we iterate trough materials, and for each one, build a submesh by merging the
|
||||
// renderer's submeshes. If a renderer has less submeshes than materials, reuse the last one.
|
||||
|
||||
SubMeshDescriptor[] descriptors = new SubMeshDescriptor[materials.Length];
|
||||
|
||||
for (int m = 0; m < materials.Length; ++m)
|
||||
{
|
||||
int vertexOffset = 0;
|
||||
var desc = new SubMeshDescriptor();
|
||||
desc.indexStart = triangles.count;
|
||||
|
||||
for (int i = firstRenderer; i < firstRenderer + rendererCount; ++i)
|
||||
{
|
||||
var renderer = renderers[i];
|
||||
int meshIndex = meshIndices[i];
|
||||
int submeshIndex = Mathf.Min(m, renderer.sourceMesh.subMeshCount - 1);
|
||||
var submeshInfo = renderer.sourceMesh.GetSubMesh(submeshIndex);
|
||||
|
||||
var meshTriangles = meshData.GetTriangles(meshIndex);
|
||||
for (int k = 0; k < renderer.meshInstances; ++k)
|
||||
{
|
||||
// append submesh triangles:
|
||||
for (int t = submeshInfo.indexStart; t < submeshInfo.indexStart + submeshInfo.indexCount; ++t)
|
||||
triangles.Add(vertexOffset + meshTriangles[t]);
|
||||
|
||||
vertexOffset += meshData.GetVertexCount(meshIndex);
|
||||
}
|
||||
}
|
||||
|
||||
desc.indexCount = triangles.count - desc.indexStart;
|
||||
descriptors[m] = desc;
|
||||
}
|
||||
|
||||
// vertices:
|
||||
for (int i = firstRenderer; i < firstRenderer + rendererCount; ++i)
|
||||
{
|
||||
var renderer = renderers[i];
|
||||
int meshIndex = meshIndices[i];
|
||||
|
||||
int vCount = meshData.GetVertexCount(meshIndex);
|
||||
|
||||
for (int k = 0; k < renderer.meshInstances; ++k)
|
||||
{
|
||||
vertexToRenderer.AddReplicate(i, vCount);
|
||||
particleToRenderer.AddReplicate(i, renderer.actor.solverIndices.count);
|
||||
particleIndices.AddRange(renderer.actor.solverIndices);
|
||||
|
||||
var verts = meshData.GetVertices(meshIndex);
|
||||
var norms = meshData.GetNormals(meshIndex);
|
||||
var tan = meshData.GetTangents(meshIndex);
|
||||
var col = meshData.GetColors(meshIndex);
|
||||
|
||||
var uv = meshData.GetUV(meshIndex);
|
||||
var uv2 = meshData.GetUV2(meshIndex);
|
||||
var uv3 = meshData.GetUV3(meshIndex);
|
||||
var uv4 = meshData.GetUV4(meshIndex);
|
||||
|
||||
for (int j = 0; j < vCount; ++j)
|
||||
{
|
||||
dynamicVertexData.Add(new DynamicBatchVertex
|
||||
{
|
||||
pos = verts[j],
|
||||
normal = norms[j],
|
||||
tangent = tan[j],
|
||||
color = j < col.Length ? (Vector4)col[j] : Vector4.one
|
||||
});
|
||||
|
||||
staticVertexData.Add(new StaticBatchVertex
|
||||
{
|
||||
uv = j < uv.Length ? uv[j] : Vector2.zero,
|
||||
uv2 = j < uv2.Length ? uv2[j] : Vector2.zero,
|
||||
uv3 = j < uv3.Length ? uv3[j] : Vector2.zero,
|
||||
uv4 = j < uv4.Length ? uv4[j] : Vector2.zero,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup combined mesh:
|
||||
mesh.SetVertexBufferParams(vertexCount, layout);
|
||||
mesh.SetIndexBufferParams(triangles.count, IndexFormat.UInt32);
|
||||
|
||||
mesh.SetVertexBufferData(dynamicVertexData.AsNativeArray<DynamicBatchVertex>(), 0, 0, dynamicVertexData.count, 0, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
mesh.SetVertexBufferData(staticVertexData.AsNativeArray<StaticBatchVertex>(), 0, 0, staticVertexData.count, 1, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
mesh.SetIndexBufferData(triangles.AsNativeArray<int>(), 0, 0, triangles.count, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
// set submeshes:
|
||||
mesh.subMeshCount = materials.Length;
|
||||
for (int m = 0; m < materials.Length; ++m)
|
||||
mesh.SetSubMesh(m, descriptors[m], MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
if (gpu)
|
||||
{
|
||||
dynamicVertexData.Dispose();
|
||||
|
||||
mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
|
||||
|
||||
// meshes with no vertices will have no vertex buffer, and Unity will throw an exception.
|
||||
try
|
||||
{
|
||||
if (mesh.vertexCount > 0)
|
||||
{
|
||||
gpuVertexBuffer ??= mesh.GetVertexBuffer(0);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
|
||||
particleIndices.AsComputeBuffer<int>();
|
||||
vertexToRenderer.AsComputeBuffer<int>();
|
||||
particleToRenderer.AsComputeBuffer<int>();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (vertexToRenderer != null)
|
||||
vertexToRenderer.Dispose();
|
||||
if (particleToRenderer != null)
|
||||
particleToRenderer.Dispose();
|
||||
|
||||
if (particleIndices != null)
|
||||
particleIndices.Dispose();
|
||||
|
||||
if (dynamicVertexData != null)
|
||||
dynamicVertexData.Dispose();
|
||||
if (staticVertexData != null)
|
||||
staticVertexData.Dispose();
|
||||
if (triangles != null)
|
||||
triangles.Dispose();
|
||||
|
||||
gpuVertexBuffer?.Dispose();
|
||||
gpuVertexBuffer = null;
|
||||
|
||||
GameObject.DestroyImmediate(mesh);
|
||||
}
|
||||
|
||||
public bool TryMergeWith(IRenderBatch other)
|
||||
{
|
||||
var pbatch = other as DynamicRenderBatch<T>;
|
||||
if (pbatch != null)
|
||||
{
|
||||
if (CompareTo(pbatch) == 0 &&
|
||||
vertexCount + pbatch.vertexCount < Constants.maxVertsPerMesh)
|
||||
{
|
||||
rendererCount += pbatch.rendererCount;
|
||||
vertexCount += pbatch.vertexCount;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int CompareMaterialLists(Material[] a, Material[] b)
|
||||
{
|
||||
int l = Mathf.Min(a.Length, b.Length);
|
||||
for (int i = 0; i < l; ++i)
|
||||
{
|
||||
if (a[i] == null && b[i] == null)
|
||||
return 0;
|
||||
|
||||
if (a[i] == null) return -1;
|
||||
if (b[i] == null) return 1;
|
||||
|
||||
int compare = a[i].GetInstanceID().CompareTo(b[i].GetInstanceID());
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
}
|
||||
return a.Length.CompareTo(b.Length);
|
||||
}
|
||||
|
||||
public int CompareTo(IRenderBatch other)
|
||||
{
|
||||
var pbatch = other as DynamicRenderBatch<T>;
|
||||
int result = CompareMaterialLists(materials, pbatch.materials);
|
||||
if (result == 0)
|
||||
return renderBatchParams.CompareTo(pbatch.renderBatchParams);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void BakeMesh(List<T> renderers,
|
||||
T renderer,
|
||||
ref Mesh bakedMesh, bool transformToActorLocalSpace = false)
|
||||
{
|
||||
// if the dynamic data is not available (such as when the batch is intended for GPU use), read it back:
|
||||
bool gpu = !dynamicVertexData.isCreated || dynamicVertexData == null;
|
||||
if (gpu)
|
||||
{
|
||||
dynamicVertexData = new ObiNativeList<DynamicBatchVertex>();
|
||||
dynamicVertexData.ResizeUninitialized(this.vertexCount);
|
||||
var nativeArray = dynamicVertexData.AsNativeArray<DynamicBatchVertex>();
|
||||
AsyncGPUReadback.RequestIntoNativeArray(ref nativeArray, gpuVertexBuffer, this.vertexCount * dynamicVertexData.stride, 0).WaitForCompletion();
|
||||
}
|
||||
|
||||
bakedMesh.Clear();
|
||||
|
||||
int vOffset = 0;
|
||||
int tOffset = 0;
|
||||
|
||||
for (int i = firstRenderer; i < firstRenderer + rendererCount; ++i)
|
||||
{
|
||||
// Count vertices of all instances:
|
||||
int vCount = 0;
|
||||
for (int k = 0; k < renderers[i].meshInstances; ++k)
|
||||
vCount += renderers[i].sourceMesh.vertexCount;
|
||||
|
||||
// Count triangles of all submeshes/instances:
|
||||
int tCount = 0;
|
||||
for (int m = 0; m < materials.Length; ++m)
|
||||
{
|
||||
int submeshIndex = Mathf.Min(m, renderers[i].sourceMesh.subMeshCount - 1);
|
||||
var submeshInfo = renderers[i].sourceMesh.GetSubMesh(submeshIndex);
|
||||
tCount += submeshInfo.indexCount * (int)renderers[i].meshInstances;
|
||||
}
|
||||
|
||||
// if this is the renderer we're interested in, populate the mesh:
|
||||
if (renderers[i].Equals(renderer))
|
||||
{
|
||||
bakedMesh.SetVertexBufferParams(vCount, vertexLayout);
|
||||
bakedMesh.SetVertexBufferData(dynamicVertexData.AsNativeArray<DynamicBatchVertex>(), vOffset, 0, vCount, 0, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
bakedMesh.SetVertexBufferData(staticVertexData.AsNativeArray<StaticBatchVertex>(), vOffset, 0, vCount, 1, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
// transform vertices from solver space to actor space:
|
||||
if (transformToActorLocalSpace)
|
||||
{
|
||||
var solver2Actor = renderer.actor.actorSolverToLocalMatrix;
|
||||
var verts = bakedMesh.vertices;
|
||||
for (int v = 0; v < verts.Length; ++v)
|
||||
verts[v] = solver2Actor.MultiplyPoint3x4(verts[v]);
|
||||
bakedMesh.vertices = verts;
|
||||
}
|
||||
|
||||
ObiNativeList<int> indices = new ObiNativeList<int>(tCount);
|
||||
|
||||
// calculate submeshes (one submesh per material):
|
||||
SubMeshDescriptor[] descriptors = new SubMeshDescriptor[materials.Length];
|
||||
for (int m = 0; m < materials.Length; ++m)
|
||||
{
|
||||
int vertexOffset = 0;
|
||||
var desc = new SubMeshDescriptor();
|
||||
desc.indexStart = indices.count;
|
||||
|
||||
int submeshIndex = Mathf.Min(m, renderer.sourceMesh.subMeshCount - 1);
|
||||
var submeshInfo = renderer.sourceMesh.GetSubMesh(submeshIndex);
|
||||
|
||||
for (int k = 0; k < renderer.meshInstances; ++k)
|
||||
{
|
||||
// append submesh triangles:
|
||||
var meshTriangles = renderer.sourceMesh.triangles;
|
||||
for (int t = submeshInfo.indexStart; t < submeshInfo.indexStart + submeshInfo.indexCount; ++t)
|
||||
indices.Add(vertexOffset + meshTriangles[t]);
|
||||
|
||||
vertexOffset += renderer.sourceMesh.vertexCount;
|
||||
}
|
||||
|
||||
desc.indexCount = indices.count - desc.indexStart;
|
||||
descriptors[m] = desc;
|
||||
}
|
||||
|
||||
bakedMesh.SetIndexBufferParams(tCount, IndexFormat.UInt32);
|
||||
bakedMesh.SetIndexBufferData(indices.AsNativeArray<int>(), 0, 0, tCount, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
bakedMesh.subMeshCount = materials.Length;
|
||||
for (int m = 0; m < materials.Length; ++m)
|
||||
bakedMesh.SetSubMesh(m, descriptors[m], MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
bakedMesh.RecalculateBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
vOffset += vCount;
|
||||
tOffset += tCount;
|
||||
}
|
||||
|
||||
if (gpu)
|
||||
{
|
||||
dynamicVertexData.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bee4cda10f5944149b6f8c90a947c49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public interface IRenderBatch : IComparable<IRenderBatch>
|
||||
{
|
||||
bool TryMergeWith(IRenderBatch other);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct RenderBatchParams
|
||||
{
|
||||
[HideInInspector] public int layer;
|
||||
public LightProbeUsage lightProbeUsage;
|
||||
public ReflectionProbeUsage reflectionProbeUsage;
|
||||
public ShadowCastingMode shadowCastingMode;
|
||||
public bool receiveShadows;
|
||||
public MotionVectorGenerationMode motionVectors;
|
||||
public uint renderingLayerMask;
|
||||
|
||||
public RenderBatchParams(bool receiveShadow)
|
||||
{
|
||||
layer = 0;
|
||||
lightProbeUsage = LightProbeUsage.BlendProbes;
|
||||
reflectionProbeUsage = ReflectionProbeUsage.BlendProbes;
|
||||
shadowCastingMode = ShadowCastingMode.On;
|
||||
receiveShadows = receiveShadow;
|
||||
motionVectors = MotionVectorGenerationMode.Camera;
|
||||
renderingLayerMask = 0xffffffff;
|
||||
}
|
||||
|
||||
public RenderBatchParams(Renderer renderer)
|
||||
{
|
||||
this.layer = renderer.gameObject.layer;
|
||||
this.lightProbeUsage = renderer.lightProbeUsage;
|
||||
this.reflectionProbeUsage = renderer.reflectionProbeUsage;
|
||||
this.shadowCastingMode = renderer.shadowCastingMode;
|
||||
this.receiveShadows = renderer.receiveShadows;
|
||||
this.motionVectors = renderer.motionVectorGenerationMode;
|
||||
this.renderingLayerMask = renderer.renderingLayerMask;
|
||||
}
|
||||
|
||||
public int CompareTo(RenderBatchParams param)
|
||||
{
|
||||
int cmp = layer.CompareTo(param.layer);
|
||||
if (cmp == 0) cmp = renderingLayerMask.CompareTo(param.renderingLayerMask);
|
||||
if (cmp == 0) cmp = lightProbeUsage.CompareTo(param.lightProbeUsage);
|
||||
if (cmp == 0) cmp = reflectionProbeUsage.CompareTo(param.reflectionProbeUsage);
|
||||
if (cmp == 0) cmp = shadowCastingMode.CompareTo(param.shadowCastingMode);
|
||||
if (cmp == 0) cmp = receiveShadows.CompareTo(param.receiveShadows);
|
||||
if (cmp == 0) cmp = motionVectors.CompareTo(param.motionVectors);
|
||||
|
||||
return cmp;
|
||||
}
|
||||
|
||||
public RenderParams ToRenderParams()
|
||||
{
|
||||
var renderParams = new RenderParams();
|
||||
|
||||
// URP and HDRP don't work without this line.
|
||||
renderParams.renderingLayerMask = GraphicsSettings.defaultRenderingLayerMask;
|
||||
|
||||
renderParams.lightProbeUsage = lightProbeUsage;
|
||||
renderParams.reflectionProbeUsage = reflectionProbeUsage;
|
||||
renderParams.shadowCastingMode = shadowCastingMode;
|
||||
renderParams.receiveShadows = receiveShadows;
|
||||
renderParams.motionVectorMode = motionVectors;
|
||||
renderParams.renderingLayerMask = renderingLayerMask;
|
||||
renderParams.layer = layer;
|
||||
return renderParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a827293101844d32bed440c32d08c83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,141 +0,0 @@
|
||||
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();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74d879a363c7040229e215fe6c48a581
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,186 +0,0 @@
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Unity.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class ProceduralRenderBatch<T> : IRenderBatch where T : struct
|
||||
{
|
||||
private RenderBatchParams renderBatchParams;
|
||||
public RenderParams renderParams { get; private set; }
|
||||
|
||||
public Material material;
|
||||
public Mesh mesh;
|
||||
|
||||
public int firstRenderer;
|
||||
public int rendererCount;
|
||||
|
||||
public int firstParticle;
|
||||
|
||||
public NativeArray<T> vertices;
|
||||
public NativeArray<int> triangles;
|
||||
|
||||
public GraphicsBuffer gpuVertexBuffer;
|
||||
public GraphicsBuffer gpuIndexBuffer;
|
||||
|
||||
public int vertexCount;
|
||||
public int triangleCount;
|
||||
|
||||
public ProceduralRenderBatch(int rendererIndex, Material material, RenderBatchParams param)
|
||||
{
|
||||
this.renderBatchParams = param;
|
||||
|
||||
this.material = material;
|
||||
this.firstRenderer = rendererIndex;
|
||||
this.firstParticle = 0;
|
||||
this.rendererCount = 1;
|
||||
this.vertexCount = 0;
|
||||
this.triangleCount = 0;
|
||||
}
|
||||
|
||||
public void Initialize(VertexAttributeDescriptor[] layout, bool gpu = false)
|
||||
{
|
||||
var rp = renderBatchParams.ToRenderParams();
|
||||
rp.material = material;
|
||||
renderParams = rp;
|
||||
|
||||
mesh = new Mesh();
|
||||
|
||||
mesh.SetVertexBufferParams(vertexCount, layout);
|
||||
mesh.SetIndexBufferParams(triangleCount * 3, IndexFormat.UInt32);
|
||||
|
||||
vertices = new NativeArray<T>(vertexCount, Allocator.Persistent);
|
||||
mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length, 0, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
triangles = new NativeArray<int>(triangleCount * 3, Allocator.Persistent);
|
||||
mesh.SetIndexBufferData(triangles, 0, 0, triangles.Length, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
mesh.subMeshCount = 1;
|
||||
SubMeshDescriptor subMeshDescriptor = new SubMeshDescriptor();
|
||||
subMeshDescriptor.indexCount = triangleCount * 3;
|
||||
mesh.SetSubMesh(0, subMeshDescriptor, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
if (gpu)
|
||||
{
|
||||
vertices.Dispose();
|
||||
triangles.Dispose();
|
||||
|
||||
mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
|
||||
mesh.indexBufferTarget |= GraphicsBuffer.Target.Raw;
|
||||
|
||||
// particles with no vertices will have no vertex buffer, and Unity will throw an exception.
|
||||
if (mesh.vertexCount > 0)
|
||||
{
|
||||
gpuVertexBuffer ??= mesh.GetVertexBuffer(0);
|
||||
gpuIndexBuffer ??= mesh.GetIndexBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
gpuVertexBuffer?.Dispose();
|
||||
gpuIndexBuffer?.Dispose();
|
||||
|
||||
gpuVertexBuffer = null;
|
||||
gpuIndexBuffer = null;
|
||||
|
||||
if (vertices.IsCreated)
|
||||
vertices.Dispose();
|
||||
if (triangles.IsCreated)
|
||||
triangles.Dispose();
|
||||
|
||||
GameObject.DestroyImmediate(mesh);
|
||||
}
|
||||
|
||||
public bool TryMergeWith(IRenderBatch other)
|
||||
{
|
||||
var pbatch = other as ProceduralRenderBatch<T>;
|
||||
if (pbatch != null)
|
||||
{
|
||||
if (CompareTo(pbatch) == 0 &&
|
||||
vertexCount + pbatch.vertexCount < Constants.maxVertsPerMesh)
|
||||
{
|
||||
rendererCount += pbatch.rendererCount;
|
||||
triangleCount += pbatch.triangleCount;
|
||||
vertexCount += pbatch.vertexCount;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int CompareTo(IRenderBatch other)
|
||||
{
|
||||
var pbatch = other as ProceduralRenderBatch<T>;
|
||||
int idA = material != null ? material.GetInstanceID() : 0;
|
||||
int idB = (pbatch != null && pbatch.material != null) ? pbatch.material.GetInstanceID() : 0;
|
||||
|
||||
int result = idA.CompareTo(idB);
|
||||
if (result == 0)
|
||||
return renderBatchParams.CompareTo(pbatch.renderBatchParams);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void BakeMesh(int vertexOffset, int vertexCount, int triangleOffset, int triangleCount,
|
||||
Matrix4x4 transform,
|
||||
ref Mesh bakedMesh, bool transformVertices = false)
|
||||
{
|
||||
|
||||
// if the data is not available in the CPU (such as when the batch is intended for GPU use), read it back:
|
||||
bool gpu = !vertices.IsCreated;
|
||||
if (gpu)
|
||||
{
|
||||
vertices = new NativeArray<T>(this.vertexCount, Allocator.Persistent);
|
||||
triangles = new NativeArray<int>(this.triangleCount * 3, Allocator.Persistent);
|
||||
AsyncGPUReadback.RequestIntoNativeArray(ref vertices, gpuVertexBuffer, this.vertexCount * UnsafeUtility.SizeOf<T>(), 0).WaitForCompletion();
|
||||
AsyncGPUReadback.RequestIntoNativeArray(ref triangles, gpuIndexBuffer, this.triangleCount * 3 * 4, 0).WaitForCompletion();
|
||||
}
|
||||
|
||||
bakedMesh.Clear();
|
||||
|
||||
bakedMesh.SetVertexBufferParams(vertexCount, mesh.GetVertexAttributes());
|
||||
bakedMesh.SetVertexBufferData(vertices, vertexOffset, 0, vertexCount, 0, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
// transform vertices from solver space to actor space:
|
||||
if (transformVertices)
|
||||
{
|
||||
var solver2Actor = transform;
|
||||
var verts = bakedMesh.vertices;
|
||||
for (int v = 0; v < verts.Length; ++v)
|
||||
verts[v] = solver2Actor.MultiplyPoint3x4(verts[v]);
|
||||
bakedMesh.vertices = verts;
|
||||
}
|
||||
|
||||
ObiNativeList<int> indices = new ObiNativeList<int>(triangleCount * 3);
|
||||
|
||||
// offset indices:
|
||||
for (int i = 0; i < triangleCount * 3; ++i)
|
||||
{
|
||||
int index = triangles[triangleOffset * 3 + i] - vertexOffset;
|
||||
|
||||
// clamp indices to zero, since decimated ropes have unused triangles
|
||||
// that reference vertex 0. Subtracting the vertex offset from these results in a negative index.
|
||||
indices.Add(Mathf.Max(0,index));
|
||||
}
|
||||
|
||||
bakedMesh.SetIndexBufferParams(triangleCount * 3, IndexFormat.UInt32);
|
||||
bakedMesh.SetIndexBufferData(indices.AsNativeArray<int>(), 0, 0, triangleCount * 3, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
bakedMesh.subMeshCount = 1;
|
||||
SubMeshDescriptor subMeshDescriptor = new SubMeshDescriptor();
|
||||
subMeshDescriptor.indexCount = triangleCount * 3; // mesh triangle count.
|
||||
bakedMesh.SetSubMesh(0, subMeshDescriptor, MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
if (gpu)
|
||||
{
|
||||
if (vertices.IsCreated)
|
||||
vertices.Dispose();
|
||||
if (triangles.IsCreated)
|
||||
triangles.Dispose();
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ded06625ac9f94b1fa77fd845bb28ec9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user