修改水

This commit is contained in:
2026-01-01 22:00:33 +08:00
parent 040a222bd6
commit 9ceffccd39
1800 changed files with 103929 additions and 139495 deletions

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 13ef5aa25fc194dda8d453b36a50e5d0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,316 +0,0 @@
using UnityEngine;
using Unity.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Obi
{
public interface IMeshDataProvider
{
Mesh sourceMesh { get; }
uint meshInstances { get; }
int vertexCount { get; }
int triangleCount { get; }
void GetVertices(List<Vector3> vertices);
void GetNormals(List<Vector3> normals);
void GetTangents(List<Vector4> tangents);
void GetColors(List<Color> colors);
void GetUVs(int channel, List<Vector2> uvs);
void GetTriangles(List<int> triangles);
}
public class MeshDataBatch
{
public struct MeshData
{
public int firstVertex;
public int vertexCount;
public int firstTriangle;
public int triangleCount;
}
private Dictionary<Mesh, int> meshToIndex;
// per mesh data:
public ObiNativeList<MeshData> meshData;
public ObiNativeList<Vector3> restPositions;
public ObiNativeList<Vector3> restNormals;
public ObiNativeList<Vector4> restTangents;
public ObiNativeList<Color> restColors;
public ObiNativeList<Vector2> uv;
public ObiNativeList<Vector2> uv2;
public ObiNativeList<Vector2> uv3;
public ObiNativeList<Vector2> uv4;
public ObiNativeList<int> triangles;
private List<Vector3> tempVertices;
private List<Vector3> tempNormals;
private List<Vector4> tempTangents;
private List<Color> tempColors;
private List<Vector2> tempUV;
private List<Vector2> tempUV2;
private List<Vector2> tempUV3;
private List<Vector2> tempUV4;
private List<int> tempTriangles;
public int Count { get { return meshData.count; } }
public MeshDataBatch()
{
meshToIndex = new Dictionary<Mesh, int>();
meshData = new ObiNativeList<MeshData>();
InitializeTempData();
InitializeDynamicData();
InitializeStaticData();
}
public void InitializeTempData()
{
tempVertices = new List<Vector3>();
tempNormals = new List<Vector3>();
tempTangents = new List<Vector4>();
tempColors = new List<Color>();
tempUV = new List<Vector2>();
tempUV2 = new List<Vector2>();
tempUV3 = new List<Vector2>();
tempUV4 = new List<Vector2>();
tempTriangles = new List<int>();
}
public void InitializeDynamicData()
{
if (restPositions == null)
restPositions = new ObiNativeList<Vector3>();
if (restNormals == null)
restNormals = new ObiNativeList<Vector3>();
if (restTangents == null)
restTangents = new ObiNativeList<Vector4>();
if (restColors == null)
restColors = new ObiNativeList<Color>();
}
public void InitializeStaticData()
{
if (uv == null)
uv = new ObiNativeList<Vector2>();
if (uv2 == null)
uv2 = new ObiNativeList<Vector2>();
if (uv3 == null)
uv3 = new ObiNativeList<Vector2>();
if (uv4 == null)
uv4 = new ObiNativeList<Vector2>();
if (triangles == null)
triangles = new ObiNativeList<int>();
}
public void Dispose()
{
if (meshData != null) meshData.Dispose();
DisposeOfTempData();
DisposeOfDynamicData();
DisposeOfStaticData();
}
public void DisposeOfTempData()
{
tempVertices = null;
tempNormals = null;
tempTangents = null;
tempColors = null;
tempUV = null;
tempUV2 = null;
tempUV3 = null;
tempUV4 = null;
tempTriangles = null;
}
public void DisposeOfDynamicData()
{
if (restPositions != null) restPositions.Dispose(); restPositions = null;
if (restNormals != null) restNormals.Dispose(); restNormals = null;
if (restTangents != null) restTangents.Dispose(); restTangents = null;
if (restColors != null) restColors.Dispose(); restColors = null;
}
public void DisposeOfStaticData()
{
if (uv != null) uv.Dispose(); uv = null;
if (uv2 != null) uv2.Dispose(); uv2 = null;
if (uv3 != null) uv3.Dispose(); uv3 = null;
if (uv4 != null) uv4.Dispose(); uv4 = null;
if (triangles != null) triangles.Dispose(); triangles = null;
}
public void Clear()
{
if (meshToIndex != null) meshToIndex.Clear();
if (meshData != null) meshData.Clear();
if (restPositions != null) restPositions.Clear();
if (restNormals != null) restNormals.Clear();
if (restTangents != null) restTangents.Clear();
if (restColors != null) restColors.Clear();
if (uv != null) uv.Clear();
if (uv2 != null) uv2.Clear();
if (uv3 != null) uv3.Clear();
if (uv4 != null) uv4.Clear();
if (triangles != null) triangles.Clear();
}
public int AddMesh(IMeshDataProvider meshProvider)
{
if (!meshToIndex.TryGetValue(meshProvider.sourceMesh, out int index))
{
index = meshData.count;
meshToIndex[meshProvider.sourceMesh] = index;
meshProvider.GetVertices(tempVertices);
meshProvider.GetNormals(tempNormals);
meshProvider.GetTangents(tempTangents);
meshProvider.GetColors(tempColors);
meshProvider.GetUVs(0, tempUV);
meshProvider.GetUVs(1, tempUV2);
meshProvider.GetUVs(2, tempUV3);
meshProvider.GetUVs(3, tempUV4);
meshProvider.GetTriangles(tempTriangles);
if (tempTangents.Count == 0)
tempTangents.AddRange(Enumerable.Repeat(Vector4.zero, tempVertices.Count));
if (tempColors.Count == 0)
tempColors.AddRange(Enumerable.Repeat(Color.white, tempVertices.Count));
if (tempUV.Count == 0)
tempUV.AddRange(Enumerable.Repeat(Vector2.zero, tempVertices.Count));
if (tempUV2.Count == 0)
tempUV2.AddRange(Enumerable.Repeat(Vector2.zero, tempVertices.Count));
if (tempUV3.Count == 0)
tempUV3.AddRange(Enumerable.Repeat(Vector2.zero, tempVertices.Count));
if (tempUV4.Count == 0)
tempUV4.AddRange(Enumerable.Repeat(Vector2.zero, tempVertices.Count));
meshData.Add(new MeshData
{
firstVertex = restPositions.count,
vertexCount = tempVertices.Count,
firstTriangle = triangles.count,
triangleCount = tempTriangles.Count
});
restPositions.AddRange(tempVertices);
restNormals.AddRange(tempNormals);
restTangents.AddRange(tempTangents);
restColors.AddRange(tempColors);
uv.AddRange(tempUV);
uv2.AddRange(tempUV2);
uv3.AddRange(tempUV3);
uv4.AddRange(tempUV4);
triangles.AddRange(tempTriangles);
}
return index;
}
public void PrepareForCompute()
{
meshData.AsComputeBuffer<MeshData>();
restPositions.AsComputeBuffer<Vector3>();
restNormals.AsComputeBuffer<Vector3>();
restTangents.AsComputeBuffer<Vector4>();
restColors.AsComputeBuffer<Color>();
}
public int GetVertexCount(int meshIndex)
{
return meshData[meshIndex].vertexCount;
}
public int GetTriangleCount(int meshIndex)
{
return meshData[meshIndex].triangleCount;
}
public NativeSlice<Vector3> GetVertices(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return restPositions.AsNativeArray<Vector3>().Slice(start,count);
}
public NativeSlice<Vector3> GetNormals(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return restNormals.AsNativeArray<Vector3>().Slice(start, count);
}
public NativeSlice<Vector4> GetTangents(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return restTangents.AsNativeArray<Vector4>().Slice(start, count);
}
public NativeSlice<Color> GetColors(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return restColors.AsNativeArray<Color>().Slice(start, count);
}
public NativeSlice<Vector2> GetUV(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return uv.AsNativeArray<Vector2>().Slice(start, count);
}
public NativeSlice<Vector2> GetUV2(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return uv2.AsNativeArray<Vector2>().Slice(start, count);
}
public NativeSlice<Vector2> GetUV3(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return uv3.AsNativeArray<Vector2>().Slice(start, count);
}
public NativeSlice<Vector2> GetUV4(int meshIndex)
{
int start = meshData[meshIndex].firstVertex;
int count = meshData[meshIndex].vertexCount;
return uv4.AsNativeArray<Vector2>().Slice(start, count);
}
public NativeSlice<int> GetTriangles(int meshIndex)
{
int start = meshData[meshIndex].firstTriangle;
int count = meshData[meshIndex].triangleCount;
return triangles.AsNativeArray<int>().Slice(start, count);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 51631a4146e8e4501adcbe8ff6f039c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,117 +0,0 @@
using UnityEngine;
namespace Obi
{
public class SkeletonDataBatch
{
public struct SkeletonData
{
public int firstBone;
public int boneCount;
}
// per skinMap data:
public ObiNativeList<SkeletonData> skeletonData;
public ObiNativeList<Matrix4x4> world2Solver;
// bone data:
public ObiNativeList<Vector3> bonePositions;
public ObiNativeList<Quaternion> boneRotations;
public ObiNativeList<Vector3> boneScales;
public int Count { get { return skeletonData.count; } }
public SkeletonDataBatch()
{
skeletonData = new ObiNativeList<SkeletonData>();
world2Solver = new ObiNativeList<Matrix4x4>();
bonePositions = new ObiNativeList<Vector3>();
boneRotations = new ObiNativeList<Quaternion>();
boneScales = new ObiNativeList<Vector3>();
}
public void Dispose()
{
skeletonData.Dispose();
world2Solver.Dispose();
bonePositions.Dispose();
boneRotations.Dispose();
boneScales.Dispose();
}
public void Clear()
{
skeletonData.Clear();
world2Solver.Clear();
bonePositions.Clear();
boneRotations.Clear();
boneScales.Clear();
}
public int AddSkeleton(Transform[] bones, Matrix4x4 worldToSolver)
{
var data = new SkeletonData
{
firstBone = bonePositions.count,
};
foreach (var bone in bones)
{
if (bone != null)
{
bonePositions.Add(bone.position);
boneRotations.Add(bone.rotation);
boneScales.Add(bone.localScale);
}
}
data.boneCount = bonePositions.count;
skeletonData.Add(data);
world2Solver.Add(worldToSolver);
return skeletonData.count - 1;
}
public void PrepareForCompute()
{
skeletonData.SafeAsComputeBuffer<SkeletonData>();
world2Solver.SafeAsComputeBuffer<Matrix4x4>();
bonePositions.SafeAsComputeBuffer<Vector3>();
boneRotations.SafeAsComputeBuffer<Quaternion>();
boneScales.SafeAsComputeBuffer<Vector3>();
}
public void SetBoneTransform(int index, int boneIndex, Transform transform)
{
if (transform != null)
{
var i = skeletonData[index].firstBone + boneIndex;
bonePositions[i] = transform.position;
boneScales[i] = transform.lossyScale;
boneRotations[i] = transform.rotation;
}
}
public void UpdateBoneTransformsCompute()
{
bonePositions.Upload();
boneScales.Upload();
boneRotations.Upload();
}
public Matrix4x4 GetWorldToSolverTransform(int index)
{
return world2Solver[index];
}
public void SetWorldToSolverTransform(int index, Matrix4x4 trfm)
{
world2Solver[index] = trfm;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6b609b47dfb88424c9ae3e32c64bfaeb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,10 +0,0 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace Obi
{
public interface ISurfaceChunkUser
{
uint usedChunkCount { get; }
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5e544f8db79af4a6a91df85c5df0dee7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,48 +0,0 @@
namespace Obi
{
public interface IActorRenderer
{
public ObiActor actor
{
get;
}
}
public interface ObiActorRenderer<T> : IActorRenderer, ObiRenderer<T> where T : ObiActorRenderer<T>
{
public void EnableRenderer()
{
actor.OnBlueprintLoaded += ObiActorRenderer_OnBlueprintLoaded;
actor.OnBlueprintUnloaded += ObiActorRenderer_OnBlueprintUnloaded;
if (actor.isLoaded)
RegisterRenderer(actor.solver);
}
public void DisableRenderer()
{
if (actor.isLoaded)
UnregisterRenderer(actor.solver);
actor.OnBlueprintLoaded -= ObiActorRenderer_OnBlueprintLoaded;
actor.OnBlueprintUnloaded -= ObiActorRenderer_OnBlueprintUnloaded;
}
public void SetRendererDirty(Oni.RenderingSystemType type)
{
if (actor != null)
actor.SetRenderingDirty(type);
}
private void ObiActorRenderer_OnBlueprintLoaded(ObiActor act, ObiActorBlueprint blueprint)
{
RegisterRenderer(act.solver);
}
protected void ObiActorRenderer_OnBlueprintUnloaded(ObiActor act, ObiActorBlueprint blueprint)
{
UnregisterRenderer(act.solver);
}
}
}

View File

@@ -37,7 +37,7 @@ namespace Obi
public void OnEnable()
{
material = GameObject.Instantiate(Resources.Load<Material>("ObiMaterials/DistanceFields/DistanceFieldRendering"));
material = GameObject.Instantiate(Resources.Load<Material>("ObiMaterials/DistanceFieldRendering"));
material.hideFlags = HideFlags.HideAndDontSave;
}

View File

@@ -1,96 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.Rendering;
namespace Obi
{
[StructLayout(LayoutKind.Sequential)]
public struct DiffuseParticleVertex
{
public Vector4 pos;
public Vector3 offset;
public Vector4 color;
public Vector4 velocity;
public Vector4 attributes;
}
public class ObiFoamRenderSystem : RenderSystem<ObiFoamGenerator>
{
public Oni.RenderingSystemType typeEnum { get => Oni.RenderingSystemType.FoamParticles; }
public RendererSet<ObiFoamGenerator> renderers { get; } = new RendererSet<ObiFoamGenerator>();
public bool isSetup => true;
protected VertexAttributeDescriptor[] layout =
{
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 4), // velocity
new VertexAttributeDescriptor(VertexAttribute.TexCoord1, VertexAttributeFormat.Float32, 4), // attributes
};
static protected ProfilerMarker m_SetupRenderMarker = new ProfilerMarker("SetupSurfaceMeshing");
static protected ProfilerMarker m_RenderMarker = new ProfilerMarker("SurfaceMeshing");
protected HashSet<Camera> cameras = new HashSet<Camera>();
protected MaterialPropertyBlock matProps;
protected ObiSolver m_Solver;
public ProceduralRenderBatch<DiffuseParticleVertex> renderBatch;
#if (UNITY_2019_1_OR_NEWER)
System.Action<ScriptableRenderContext, Camera> renderCallback;
#endif
// must be done before fluid meshing.
public uint tier
{
get { return 0; }
}
public ObiFoamRenderSystem(ObiSolver solver)
{
m_Solver = solver;
matProps = new MaterialPropertyBlock();
#if (UNITY_2019_1_OR_NEWER)
renderCallback = new System.Action<ScriptableRenderContext, Camera>((cntxt, cam) => { RenderFromCamera(cam); });
RenderPipelineManager.beginCameraRendering += renderCallback;
#endif
Camera.onPreCull += RenderFromCamera;
}
public virtual void Dispose()
{
#if (UNITY_2019_1_OR_NEWER)
RenderPipelineManager.beginCameraRendering -= renderCallback;
#endif
Camera.onPreCull -= RenderFromCamera;
renderBatch.Dispose();
cameras.Clear();
}
public void RenderFromCamera(Camera camera)
{
cameras.Add(camera);
}
public virtual void Setup()
{
}
public virtual void Step()
{
}
public virtual void Render()
{
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 96d883432ef854a8598e264c73232bdc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,151 +0,0 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Rendering;
using Unity.Collections;
using Unity.Profiling;
using System.Runtime.InteropServices;
namespace Obi
{
public abstract class ObiInstancedParticleRenderSystem : RenderSystem<ObiInstancedParticleRenderer>
{
public Oni.RenderingSystemType typeEnum { get => Oni.RenderingSystemType.InstancedParticles; }
public RendererSet<ObiInstancedParticleRenderer> renderers { get; } = new RendererSet<ObiInstancedParticleRenderer>();
public bool isSetup => activeParticles != null;
static protected ProfilerMarker m_SetupRenderMarker = new ProfilerMarker("SetupParticleRendering");
static protected ProfilerMarker m_RenderMarker = new ProfilerMarker("ParticleRendering");
protected ObiSolver m_Solver;
protected List<InstancedRenderBatch> batchList = new List<InstancedRenderBatch>();
protected ObiNativeList<int> activeParticles;
protected ObiNativeList<int> rendererIndex;
protected ObiNativeList<ParticleRendererData> rendererData;
protected ObiNativeList<Matrix4x4> instanceTransforms;
protected ObiNativeList<Matrix4x4> invInstanceTransforms;
protected ObiNativeList<Vector4> instanceColors;
public ObiInstancedParticleRenderSystem(ObiSolver solver)
{
m_Solver = solver;
activeParticles = new ObiNativeList<int>();
rendererIndex = new ObiNativeList<int>();
rendererData = new ObiNativeList<ParticleRendererData>();
instanceTransforms = new ObiNativeList<Matrix4x4>();
invInstanceTransforms = new ObiNativeList<Matrix4x4>();
instanceColors = new ObiNativeList<Vector4>();
}
public virtual void Dispose()
{
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Dispose();
batchList.Clear();
if (activeParticles != null)
activeParticles.Dispose();
if (rendererData != null)
rendererData.Dispose();
if (rendererIndex != null)
rendererIndex.Dispose();
if (instanceTransforms != null)
instanceTransforms.Dispose();
if (invInstanceTransforms != null)
invInstanceTransforms.Dispose();
if (instanceColors != null)
instanceColors.Dispose();
}
protected virtual void Clear()
{
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Dispose();
batchList.Clear();
activeParticles.Clear();
rendererData.Clear();
rendererIndex.Clear();
instanceTransforms.Clear();
invInstanceTransforms.Clear();
instanceColors.Clear();
}
protected virtual void CreateBatches()
{
// generate batches:
for (int i = 0; i < renderers.Count; ++i)
{
renderers[i].renderParameters.layer = renderers[i].gameObject.layer;
// Create multiple batches of at most maxInstancesPerBatch particles each:
int instanceCount = 0;
while (instanceCount < renderers[i].actor.particleCount)
{
var batch = new InstancedRenderBatch(i, renderers[i].mesh, renderers[i].material, renderers[i].renderParameters);
batch.firstInstance = instanceCount;
batch.instanceCount = Mathf.Min(renderers[i].actor.particleCount - instanceCount, Constants.maxInstancesPerBatch);
instanceCount += batch.instanceCount;
batchList.Add(batch);
}
}
// sort batches:
batchList.Sort();
for (int i = 0; i < batchList.Count; ++i)
{
var batch = batchList[i];
var renderer = renderers[batch.firstRenderer];
int particlesSoFar = activeParticles.count;
// add active particles here, respecting batch order:
activeParticles.AddRange(renderer.actor.solverIndices, batch.firstInstance, batch.instanceCount);
rendererIndex.AddReplicate(i, batch.instanceCount);
rendererData.Add(new ParticleRendererData(renderer.instanceColor, renderer.instanceScale));
batch.firstInstance = particlesSoFar;
}
instanceTransforms.ResizeUninitialized(activeParticles.count);
invInstanceTransforms.ResizeUninitialized(activeParticles.count);
instanceColors.ResizeUninitialized(activeParticles.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())
{
Clear();
CreateBatches();
ObiUtils.MergeBatches(batchList);
CloseBatches();
}
}
public virtual void Step()
{
}
public virtual void Render()
{
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fd33018010abc46be9ac6cc091142ccf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -11,51 +11,80 @@ namespace Obi
[AddComponentMenu("Physics/Obi/Obi Instanced Particle Renderer", 1001)]
[ExecuteInEditMode]
[RequireComponent(typeof(ObiActor))]
public class ObiInstancedParticleRenderer : MonoBehaviour, ObiActorRenderer<ObiInstancedParticleRenderer>
public class ObiInstancedParticleRenderer : MonoBehaviour
{
static ProfilerMarker m_DrawParticlesPerfMarker = new ProfilerMarker("DrawParticles");
public bool render = true;
public Mesh mesh;
public Material material;
public RenderBatchParams renderParameters = new RenderBatchParams(true);
public Color instanceColor = Color.white;
public float instanceScale = 1;
public Vector3 instanceScale = Vector3.one;
public ObiActor actor { get; private set; }
private List<Matrix4x4> matrices = new List<Matrix4x4>();
private List<Vector4> colors = new List<Vector4>();
private MaterialPropertyBlock mpb;
void Awake()
{
actor = GetComponent<ObiActor>();
}
int meshesPerBatch = 0;
int batchCount;
public void OnEnable()
{
((ObiActorRenderer<ObiInstancedParticleRenderer>)this).EnableRenderer();
GetComponent<ObiActor>().OnInterpolate += DrawParticles;
}
public void OnDisable()
{
((ObiActorRenderer<ObiInstancedParticleRenderer>)this).DisableRenderer();
GetComponent<ObiActor>().OnInterpolate -= DrawParticles;
}
public void OnValidate()
void DrawParticles(ObiActor actor)
{
((ObiActorRenderer<ObiInstancedParticleRenderer>)this).SetRendererDirty(Oni.RenderingSystemType.InstancedParticles);
}
RenderSystem<ObiInstancedParticleRenderer> ObiRenderer<ObiInstancedParticleRenderer>.CreateRenderSystem(ObiSolver solver)
{
switch (solver.backendType)
using (m_DrawParticlesPerfMarker.Auto())
{
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
case ObiSolver.BackendType.Burst: return new BurstInstancedParticleRenderSystem(solver);
#endif
case ObiSolver.BackendType.Compute:
default:
if (mesh == null || material == null || !render || !isActiveAndEnabled || !actor.isActiveAndEnabled || actor.solver == null)
{
return;
}
if (SystemInfo.supportsComputeShaders)
return new ComputeInstancedParticleRenderSystem(solver);
return null;
ObiSolver solver = actor.solver;
// figure out the size of our instance batches:
meshesPerBatch = Constants.maxInstancesPerBatch;
batchCount = actor.particleCount / meshesPerBatch + 1;
meshesPerBatch = Mathf.Min(meshesPerBatch, actor.particleCount);
Vector4 basis1 = new Vector4(1, 0, 0, 0);
Vector4 basis2 = new Vector4(0, 1, 0, 0);
Vector4 basis3 = new Vector4(0, 0, 1, 0);
//Convert particle data to mesh instances:
for (int i = 0; i < batchCount; i++)
{
matrices.Clear();
colors.Clear();
mpb = new MaterialPropertyBlock();
int limit = Mathf.Min((i + 1) * meshesPerBatch, actor.activeParticleCount);
for (int j = i * meshesPerBatch; j < limit; ++j)
{
int solverIndex = actor.solverIndices[j];
actor.GetParticleAnisotropy(solverIndex, ref basis1, ref basis2, ref basis3);
matrices.Add(Matrix4x4.TRS(actor.GetParticlePosition(solverIndex),
actor.GetParticleOrientation(solverIndex),
Vector3.Scale(new Vector3(basis1[3], basis2[3], basis3[3]), instanceScale)));
colors.Add(actor.GetParticleColor(solverIndex));
}
if (colors.Count > 0)
mpb.SetVectorArray("_Color", colors);
// Send the meshes to be drawn:
Graphics.DrawMeshInstanced(mesh, 0, material, matrices, mpb);
}
}
}
}

View File

@@ -1,145 +0,0 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Rendering;
using Unity.Profiling;
using System.Runtime.InteropServices;
namespace Obi
{
[StructLayout(LayoutKind.Sequential)]
public struct ParticleVertex
{
public Vector4 pos;
public Vector3 offset;
public Vector4 color;
public Vector4 b1;
public Vector4 b2;
public Vector4 b3;
}
public abstract class ObiParticleRenderSystem : RenderSystem<ObiParticleRenderer>
{
public Oni.RenderingSystemType typeEnum { get => Oni.RenderingSystemType.Particles; }
public RendererSet<ObiParticleRenderer> renderers { get; } = new RendererSet<ObiParticleRenderer>();
public bool isSetup => activeParticles != null;
protected VertexAttributeDescriptor[] layout =
{
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.TexCoord1, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.TexCoord2, VertexAttributeFormat.Float32, 4)
};
static protected ProfilerMarker m_SetupRenderMarker = new ProfilerMarker("SetupParticleRendering");
static protected ProfilerMarker m_RenderMarker = new ProfilerMarker("ParticleRendering");
protected ObiSolver m_Solver;
protected List<ProceduralRenderBatch<ParticleVertex>> batchList = new List<ProceduralRenderBatch<ParticleVertex>>();
protected ObiNativeList<int> activeParticles;
protected ObiNativeList<int> rendererIndex;
protected ObiNativeList<ParticleRendererData> rendererData;
public ObiParticleRenderSystem(ObiSolver solver)
{
m_Solver = solver;
activeParticles = new ObiNativeList<int>();
rendererIndex = new ObiNativeList<int>();
rendererData = new ObiNativeList<ParticleRendererData>();
}
public virtual void Dispose()
{
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Dispose();
batchList.Clear();
if (activeParticles != null)
activeParticles.Dispose();
if (rendererData != null)
rendererData.Dispose();
if (rendererIndex != null)
rendererIndex.Dispose();
}
protected virtual void Clear()
{
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Dispose();
batchList.Clear();
activeParticles.Clear();
rendererData.Clear();
rendererIndex.Clear();
}
protected virtual void CreateBatches()
{
// generate batches:
for (int i = 0; i < renderers.Count; ++i)
{
renderers[i].renderParameters.layer = renderers[i].gameObject.layer;
batchList.Add(new ProceduralRenderBatch<ParticleVertex>(i, renderers[i].material, renderers[i].renderParameters));
}
// sort batches:
batchList.Sort();
int particleCount = 0;
for (int i = 0; i < batchList.Count; ++i)
{
var batch = batchList[i];
var renderer = renderers[batch.firstRenderer];
int actorParticleCount = renderer.actor.particleCount;
batch.vertexCount += actorParticleCount * 4;
batch.triangleCount += actorParticleCount * 2;
batch.firstParticle = particleCount;
particleCount += actorParticleCount;
// add particles here, respecting batch order:
activeParticles.AddRange(renderer.actor.solverIndices, actorParticleCount);
rendererData.Add(new ParticleRendererData(renderer.particleColor, renderer.radiusScale));
rendererIndex.AddReplicate(i, actorParticleCount);
}
}
protected virtual void CloseBatches()
{
// Initialize each batch:
for (int i = 0; i < batchList.Count; ++i)
batchList[i].Initialize(layout);
}
public virtual void Setup()
{
using (m_SetupRenderMarker.Auto())
{
Clear();
CreateBatches();
ObiUtils.MergeBatches(batchList);
CloseBatches();
}
}
public virtual void Step()
{
}
public virtual void Render()
{
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5e36441d408a548d29fbc80dfa4fffc1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,78 +1,110 @@
using UnityEngine;
using Unity.Profiling;
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
namespace Obi
{
public interface IParticleRenderer
{
public ObiActor actor { get; }
public Color particleColor { get; }
public float radiusScale { get; }
}
public struct ParticleRendererData
{
public Color color;
public float radiusScale;
public ParticleRendererData(Color color, float radiusScale)
{
this.color = color;
this.radiusScale = radiusScale;
}
}
[AddComponentMenu("Physics/Obi/Obi Particle Renderer", 1000)]
[ExecuteInEditMode]
[RequireComponent(typeof(ObiActor))]
public class ObiParticleRenderer : MonoBehaviour, IParticleRenderer, ObiActorRenderer<ObiParticleRenderer>
public class ObiParticleRenderer : MonoBehaviour
{
public Material material;
public RenderBatchParams renderParameters = new RenderBatchParams(true);
static ProfilerMarker m_DrawParticlesPerfMarker = new ProfilerMarker("DrawParticles");
[field: SerializeField]
public Color particleColor { get; set; } = Color.white;
public bool render = true;
public Shader shader;
public Color particleColor = Color.white;
public float radiusScale = 1;
private ParticleImpostorRendering m_Impostors;
[field: SerializeField]
public float radiusScale { get; set; } = 1;
public ObiActor actor { get; private set; }
public void Awake()
public IEnumerable<Mesh> ParticleMeshes
{
actor = GetComponent<ObiActor>();
get { return impostors.Meshes; }
}
public ParticleImpostorRendering impostors
{
get {
if (m_Impostors == null)
m_Impostors = new ParticleImpostorRendering();
return m_Impostors;
}
}
public Material ParticleMaterial { get; private set; }
public void OnEnable()
{
((ObiActorRenderer<ObiParticleRenderer>)this).EnableRenderer();
GetComponent<ObiActor>().OnInterpolate += DrawParticles;
}
public void OnDisable()
{
((ObiActorRenderer<ObiParticleRenderer>)this).DisableRenderer();
GetComponent<ObiActor>().OnInterpolate -= DrawParticles;
if (m_Impostors != null)
m_Impostors.ClearMeshes();
DestroyImmediate(ParticleMaterial);
}
public void OnValidate()
void CreateMaterialIfNeeded()
{
((ObiActorRenderer<ObiParticleRenderer>)this).SetRendererDirty(Oni.RenderingSystemType.Particles);
}
RenderSystem<ObiParticleRenderer> ObiRenderer<ObiParticleRenderer>.CreateRenderSystem(ObiSolver solver)
{
switch (solver.backendType)
if (shader != null)
{
if (!shader.isSupported)
Debug.LogWarning("Particle rendering shader not suported.");
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
case ObiSolver.BackendType.Burst: return new BurstParticleRenderSystem(solver);
#endif
case ObiSolver.BackendType.Compute:
default:
if (SystemInfo.supportsComputeShaders)
return new ComputeParticleRenderSystem(solver);
return null;
if (ParticleMaterial == null || ParticleMaterial.shader != shader)
{
DestroyImmediate(ParticleMaterial);
ParticleMaterial = new Material(shader);
ParticleMaterial.hideFlags = HideFlags.HideAndDontSave;
}
}
}
void DrawParticles(ObiActor actor)
{
using (m_DrawParticlesPerfMarker.Auto())
{
if (!isActiveAndEnabled || !actor.isActiveAndEnabled || actor.solver == null)
{
impostors.ClearMeshes();
return;
}
CreateMaterialIfNeeded();
impostors.UpdateMeshes(actor);
DrawParticles();
}
}
private void DrawParticles()
{
if (ParticleMaterial != null)
{
ParticleMaterial.SetFloat("_RadiusScale", radiusScale);
ParticleMaterial.SetColor("_Color", particleColor);
// Send the meshes to be drawn:
if (render)
{
var meshes = ParticleMeshes;
foreach (Mesh mesh in meshes)
Graphics.DrawMesh(mesh, Matrix4x4.identity, ParticleMaterial, gameObject.layer);
}
}
}
}
}

View File

@@ -1,10 +1,11 @@
fileFormatVersion: 2
guid: c8b45ebbf86be4df6b0e6cd933812af2
timeCreated: 1521054123
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- material: {fileID: 2100000, guid: fb88690dea2394644849cde5abd037f9, type: 2}
- shader: {fileID: 4800000, guid: 801733041f66b49e1b3c2101471db877, type: 3}
executionOrder: 0
icon: {fileID: 2800000, guid: f424a87c9f03240c2870a664731ac9aa, type: 3}
userData:

View File

@@ -1,65 +0,0 @@
using UnityEngine;
namespace Obi
{
public interface ObiRenderer<T> where T : ObiRenderer<T>
{
protected RenderSystem<T> CreateRenderSystem(ObiSolver solver);
public bool ValidateRenderer() { return true; }
public void CleanupRenderer() { }
protected bool UnregisterRenderer(ObiSolver solver)
{
CleanupRenderer();
// try to get a render system from the solver:
var system = solver.GetRenderSystem<T>();
// if there's an existing render system for this kind of renderer,
// unregister from it.
if (system != null && system.RemoveRenderer((T)this))
{
// if the render system is empty, destroy it:
if (system.isEmpty)
{
solver.UnregisterRenderSystem(system);
system.Dispose();
}
solver.dirtyRendering |= (int)system.typeEnum;
return true;
}
return false;
}
protected bool RegisterRenderer(ObiSolver solver)
{
if (ValidateRenderer())
{
// try to get a render system from the solver:
var system = solver.GetRenderSystem<T>();
// if no appropiate system has been created yet, create it:
if (system == null)
{
system = CreateRenderSystem(solver) as RenderSystem<T>;
solver.RegisterRenderSystem(system);
}
// register in the renderer:
if (system != null)
{
if (system.AddRenderer((T)this))
{
solver.dirtyRendering |= (int)system.typeEnum;
return true;
}
}
}
return false;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7d4f237ec9acf4df0a30d5a0139e0f36
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 7f9c5efc94e964016b39c7778b3af164
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5bee4cda10f5944149b6f8c90a947c49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4a827293101844d32bed440c32d08c83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 74d879a363c7040229e215fe6c48a581
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: ded06625ac9f94b1fa77fd845bb28ec9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace Obi{
public class ShadowmapExposer : MonoBehaviour
{
Light unityLight;
CommandBuffer afterShadow = null;
public ObiParticleRenderer[] particleRenderers;
public void Awake(){
unityLight = GetComponent<Light>();
}
public void OnEnable(){
Cleanup();
afterShadow = new CommandBuffer();
afterShadow.name = "FluidShadows";
unityLight.AddCommandBuffer (LightEvent.AfterShadowMapPass, afterShadow);
}
public void OnDisable(){
Cleanup();
}
private void Cleanup(){
if (afterShadow != null){
unityLight.RemoveCommandBuffer (LightEvent.AfterShadowMapPass,afterShadow);
afterShadow = null;
}
}
public void SetupFluidShadowsCommandBuffer()
{
afterShadow.Clear();
if (particleRenderers == null)
return;
foreach(ObiParticleRenderer renderer in particleRenderers){
if (renderer != null){
foreach(Mesh mesh in renderer.ParticleMeshes)
afterShadow.DrawMesh(mesh,Matrix4x4.identity,renderer.ParticleMaterial,0,1);
}
}
afterShadow.SetGlobalTexture ("_MyShadowMap", new RenderTargetIdentifier(BuiltinRenderTextureType.CurrentActive));
}
// Use this for initialization
void Update()
{
bool act = gameObject.activeInHierarchy && enabled;
if (!act || particleRenderers == null || particleRenderers.Length == 0)
{
Cleanup();
return;
}
if (afterShadow != null)
{
SetupFluidShadowsCommandBuffer();
}
}
}
}

View File

@@ -1,7 +1,8 @@
fileFormatVersion: 2
guid: 8f86d1462578d497182bb58c20b89d42
guid: dbf7247281ef14860853fa0ee2cb4829
timeCreated: 1463174681
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0