修改水
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17503ab71a29b454ab068ea80d5f203c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,155 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
#if (SRP_UNIVERSAL)
|
||||
using UnityEngine.Rendering.Universal;
|
||||
#endif
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class ComputeFoamRenderSystem : ObiFoamRenderSystem
|
||||
{
|
||||
|
||||
private ComputeShader foamShader;
|
||||
private int sortKernel;
|
||||
private int clearMeshKernel;
|
||||
private int buildMeshKernel;
|
||||
|
||||
protected Material thickness_Material;
|
||||
protected Material color_Material;
|
||||
protected LocalKeyword shader2DFeature;
|
||||
|
||||
public ComputeFoamRenderSystem(ObiSolver solver) : base (solver)
|
||||
{
|
||||
foamShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/FluidFoam"));
|
||||
sortKernel = foamShader.FindKernel("Sort");
|
||||
clearMeshKernel = foamShader.FindKernel("ClearMesh");
|
||||
buildMeshKernel = foamShader.FindKernel("BuildMesh");
|
||||
|
||||
#if (SRP_UNIVERSAL)
|
||||
if (GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset)
|
||||
renderBatch = new ProceduralRenderBatch<DiffuseParticleVertex>(0, Resources.Load<Material>("ObiMaterials/URP/Fluid/FoamParticlesURP"), new RenderBatchParams(true));
|
||||
else
|
||||
#endif
|
||||
renderBatch = new ProceduralRenderBatch<DiffuseParticleVertex>(0, Resources.Load<Material>("ObiMaterials/Fluid/FoamParticles"), new RenderBatchParams(true));
|
||||
|
||||
renderBatch.vertexCount = (int)m_Solver.maxFoamParticles * 4;
|
||||
renderBatch.triangleCount = (int)m_Solver.maxFoamParticles * 2;
|
||||
renderBatch.Initialize(layout, true);
|
||||
}
|
||||
|
||||
private void ReallocateParticleBuffers()
|
||||
{
|
||||
// in case the amount of particles allocated does not match
|
||||
// the amount requested by the solver, reallocate
|
||||
if (m_Solver.foamPositions.count * 4 != renderBatch.vertexCount)
|
||||
{
|
||||
renderBatch.Dispose();
|
||||
renderBatch.vertexCount = m_Solver.foamPositions.count * 4;
|
||||
renderBatch.triangleCount = m_Solver.foamPositions.count * 2;
|
||||
renderBatch.Initialize(layout, true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
using (m_SetupRenderMarker.Auto())
|
||||
{
|
||||
for (int i = 0; i < renderers.Count; ++i)
|
||||
{
|
||||
renderers[i].actor.solverIndices.AsComputeBuffer<int>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Step()
|
||||
{
|
||||
// update solver indices, since particles may have died while updating the emitter.
|
||||
for (int i = 0; i < renderers.Count; ++i)
|
||||
{
|
||||
renderers[i].actor.solverIndices.Upload();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
var solver = m_Solver.implementation as ComputeSolverImpl;
|
||||
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
ReallocateParticleBuffers();
|
||||
|
||||
if (solver.activeParticlesBuffer == null || solver.abstraction.foamPositions.computeBuffer == null)
|
||||
return;
|
||||
|
||||
foreach (Camera camera in cameras)
|
||||
{
|
||||
if (camera == null)
|
||||
continue;
|
||||
|
||||
// sort by distance to camera:
|
||||
foamShader.SetVector("sortAxis", solver.abstraction.transform.InverseTransformDirection(camera.transform.forward));
|
||||
foamShader.SetBuffer(sortKernel, "outputPositions", solver.abstraction.foamPositions.computeBuffer);
|
||||
foamShader.SetBuffer(sortKernel, "outputVelocities", solver.abstraction.foamVelocities.computeBuffer);
|
||||
foamShader.SetBuffer(sortKernel, "outputColors", solver.abstraction.foamColors.computeBuffer);
|
||||
foamShader.SetBuffer(sortKernel, "outputAttributes", solver.abstraction.foamAttributes.computeBuffer);
|
||||
foamShader.SetBuffer(sortKernel, "dispatch", solver.abstraction.foamCount.computeBuffer);
|
||||
|
||||
int numPairs = ObiUtils.CeilToPowerOfTwo(m_Solver.foamPositions.count) / 2;
|
||||
int numStages = (int)Mathf.Log(numPairs * 2, 2);
|
||||
int groups = ComputeMath.ThreadGroupCount(numPairs, 128);
|
||||
|
||||
for (int stageIndex = 0; stageIndex < numStages; stageIndex++)
|
||||
{
|
||||
for (int stepIndex = 0; stepIndex < stageIndex + 1; stepIndex++)
|
||||
{
|
||||
int groupWidth = 1 << (stageIndex - stepIndex);
|
||||
int groupHeight = 2 * groupWidth - 1;
|
||||
foamShader.SetInt("groupWidth", groupWidth);
|
||||
foamShader.SetInt("groupHeight", groupHeight);
|
||||
foamShader.SetInt("stepIndex", stepIndex);
|
||||
foamShader.Dispatch(sortKernel, groups, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// build mesh:
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(m_Solver.foamPositions.count, 128);
|
||||
foamShader.SetInt("maxFoamParticles", m_Solver.foamPositions.count);
|
||||
foamShader.SetBuffer(clearMeshKernel, "indices", renderBatch.gpuIndexBuffer);
|
||||
foamShader.Dispatch(clearMeshKernel, threadGroups, 1, 1);
|
||||
|
||||
foamShader.SetBuffer(buildMeshKernel, "inputPositions", solver.abstraction.foamPositions.computeBuffer);
|
||||
foamShader.SetBuffer(buildMeshKernel, "inputVelocities", solver.abstraction.foamVelocities.computeBuffer);
|
||||
foamShader.SetBuffer(buildMeshKernel, "inputColors", solver.abstraction.foamColors.computeBuffer);
|
||||
foamShader.SetBuffer(buildMeshKernel, "inputAttributes", solver.abstraction.foamAttributes.computeBuffer);
|
||||
|
||||
foamShader.SetBuffer(buildMeshKernel, "vertices", renderBatch.gpuVertexBuffer);
|
||||
foamShader.SetBuffer(buildMeshKernel, "indices", renderBatch.gpuIndexBuffer);
|
||||
foamShader.SetBuffer(buildMeshKernel, "dispatch", solver.abstraction.foamCount.computeBuffer);
|
||||
|
||||
foamShader.DispatchIndirect(buildMeshKernel, solver.abstraction.foamCount.computeBuffer);
|
||||
|
||||
matProps.SetFloat("_FadeDepth", 0);
|
||||
matProps.SetFloat("_VelocityStretching", m_Solver.maxFoamVelocityStretch);
|
||||
matProps.SetFloat("_RadiusScale", m_Solver.foamRadiusScale);
|
||||
matProps.SetFloat("_FadeIn", m_Solver.foamFade.x);
|
||||
matProps.SetFloat("_FadeOut", m_Solver.foamFade.y);
|
||||
matProps.SetFloat("_ScatterDensity", m_Solver.foamVolumeDensity);
|
||||
matProps.SetFloat("_AmbientDensity", m_Solver.foamAmbientDensity);
|
||||
matProps.SetColor("_ScatterColor", m_Solver.foamScatterColor);
|
||||
matProps.SetColor("_AmbientColor", m_Solver.foamAmbientColor);
|
||||
|
||||
var rp = renderBatch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
rp.camera = camera;
|
||||
rp.matProps = matProps;
|
||||
rp.shadowCastingMode = ShadowCastingMode.Off;
|
||||
|
||||
Graphics.RenderMesh(rp, renderBatch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79b1bf3bc315944669288e5529915a5f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,104 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
using Unity.Profiling;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ComputeInstancedParticleRenderSystem : ObiInstancedParticleRenderSystem
|
||||
{
|
||||
|
||||
private ComputeShader instanceShader;
|
||||
private int updateKernel;
|
||||
private uint[] args = new uint[5] { 0, 0, 0, 0, 0 };
|
||||
|
||||
public ComputeInstancedParticleRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
instanceShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/InstancedParticleRendering"));
|
||||
updateKernel = instanceShader.FindKernel("UpdateParticleInstances");
|
||||
}
|
||||
|
||||
protected override void CloseBatches()
|
||||
{
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(true);
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
activeParticles.AsComputeBuffer<int>();
|
||||
rendererData.AsComputeBuffer<ParticleRendererData>();
|
||||
rendererIndex.AsComputeBuffer<int>();
|
||||
|
||||
instanceTransforms.AsComputeBuffer<Matrix4x4>();
|
||||
invInstanceTransforms.AsComputeBuffer<Matrix4x4>();
|
||||
instanceColors.AsComputeBuffer<Vector4>();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
|
||||
var computeSolver = m_Solver.implementation as ComputeSolverImpl;
|
||||
|
||||
if (computeSolver.renderablePositionsBuffer != null && computeSolver.renderablePositionsBuffer.count > 0 && activeParticles.count > 0)
|
||||
{
|
||||
instanceShader.SetBuffer(updateKernel, "activeParticles", activeParticles.computeBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "rendererData", rendererData.computeBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "rendererIndex", rendererIndex.computeBuffer);
|
||||
|
||||
instanceShader.SetBuffer(updateKernel, "renderablePositions", computeSolver.renderablePositionsBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "renderableOrientations", computeSolver.renderableOrientationsBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "renderableRadii", computeSolver.renderableRadiiBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "colors", computeSolver.colorsBuffer);
|
||||
|
||||
instanceShader.SetBuffer(updateKernel, "instanceTransforms", instanceTransforms.computeBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "invInstanceTransforms", invInstanceTransforms.computeBuffer);
|
||||
instanceShader.SetBuffer(updateKernel, "instanceColors", instanceColors.computeBuffer);
|
||||
|
||||
instanceShader.SetMatrix("solverToWorld", m_Solver.transform.localToWorldMatrix);
|
||||
|
||||
instanceShader.SetInt("particleCount", activeParticles.count);
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(activeParticles.count, 128);
|
||||
|
||||
instanceShader.Dispatch(updateKernel, threadGroups, 1, 1);
|
||||
|
||||
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
|
||||
mpb.SetBuffer("_InstanceTransforms", instanceTransforms.computeBuffer);
|
||||
mpb.SetBuffer("_InvInstanceTransforms", invInstanceTransforms.computeBuffer);
|
||||
mpb.SetBuffer("_Colors", instanceColors.computeBuffer);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
if (batch.mesh == null)
|
||||
continue;
|
||||
|
||||
args[0] = (uint)batch.mesh.GetIndexCount(0);
|
||||
args[1] = (uint)batch.instanceCount;
|
||||
args[2] = (uint)batch.mesh.GetIndexStart(0);
|
||||
args[3] = (uint)batch.mesh.GetBaseVertex(0);
|
||||
args[4] = (uint)batch.firstInstance;
|
||||
batch.argsBuffer.SetData(args);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.material = batch.material;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
rp.matProps = mpb;
|
||||
|
||||
Graphics.RenderMeshIndirect(rp, batch.mesh, batch.argsBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8b509404001c45aba2b5d70bed9ad1f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,71 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class ComputeParticleRenderSystem : ObiParticleRenderSystem
|
||||
{
|
||||
public ComputeShader meshComputeShader;
|
||||
private int buildMeshKernel;
|
||||
|
||||
public ComputeParticleRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
meshComputeShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/ParticleMeshBuilding"));
|
||||
buildMeshKernel = meshComputeShader.FindKernel("BuildMesh");
|
||||
}
|
||||
|
||||
protected override void CloseBatches()
|
||||
{
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(layout, true);
|
||||
|
||||
activeParticles.AsComputeBuffer<int>();
|
||||
rendererIndex.AsComputeBuffer<int>();
|
||||
rendererData.AsComputeBuffer<ParticleRendererData>();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
var solver = m_Solver.implementation as ComputeSolverImpl;
|
||||
|
||||
if (solver.renderablePositionsBuffer != null &&
|
||||
activeParticles.computeBuffer != null &&
|
||||
solver.renderablePositionsBuffer.count > 0)
|
||||
{
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "particleIndices", activeParticles.computeBuffer);
|
||||
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "positions", solver.renderablePositionsBuffer);
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "orientations", solver.renderableOrientationsBuffer);
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "radii", solver.renderableRadiiBuffer);
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "colors", solver.colorsBuffer);
|
||||
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "rendererIndices", rendererIndex.computeBuffer);
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "rendererData", rendererData.computeBuffer);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(batch.vertexCount / 4, 128);
|
||||
|
||||
meshComputeShader.SetInt("firstParticle", batch.firstParticle);
|
||||
meshComputeShader.SetInt("particleCount", batch.vertexCount / 4);
|
||||
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "vertices", batch.gpuVertexBuffer);
|
||||
meshComputeShader.SetBuffer(buildMeshKernel, "indices", batch.gpuIndexBuffer);
|
||||
|
||||
meshComputeShader.Dispatch(buildMeshKernel, threadGroups, 1, 1);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a636d056cf9924c4b9d569058fa42d31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,10 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c226d9f8a58648e789dbd116881847d
|
||||
labels:
|
||||
- ObiRope
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,107 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
using Unity.Profiling;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ComputeChainRopeRenderSystem : ObiChainRopeRenderSystem
|
||||
{
|
||||
|
||||
private ComputeShader ropeShader;
|
||||
private int updateKernel;
|
||||
private uint[] args = new uint[5] { 0, 0, 0, 0, 0 };
|
||||
|
||||
public ComputeChainRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
ropeShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/RopeChainRendering"));
|
||||
updateKernel = ropeShader.FindKernel("UpdateChainMesh");
|
||||
}
|
||||
|
||||
protected override void CloseBatches()
|
||||
{
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(true);
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
rendererData.AsComputeBuffer<ChainRendererData>();
|
||||
chunkData.AsComputeBuffer<ChunkData>();
|
||||
modifiers.SafeAsComputeBuffer<ObiRopeChainRenderer.LinkModifier>();
|
||||
elements.AsComputeBuffer<Vector2Int>();
|
||||
|
||||
instanceTransforms.AsComputeBuffer<Matrix4x4>();
|
||||
invInstanceTransforms.AsComputeBuffer<Matrix4x4>();
|
||||
instanceColors.AsComputeBuffer<Vector4>();
|
||||
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
|
||||
var computeSolver = m_Solver.implementation as ComputeSolverImpl;
|
||||
|
||||
if (computeSolver.renderablePositionsBuffer != null && computeSolver.renderablePositionsBuffer.count > 0 && elements.count > 0)
|
||||
{
|
||||
ropeShader.SetBuffer(updateKernel, "rendererData", rendererData.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "chunksData", chunkData.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "modifiers", modifiers.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "elements", elements.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "renderablePositions", computeSolver.renderablePositionsBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "renderableOrientations", computeSolver.renderableOrientationsBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "principalRadii", computeSolver.renderableRadiiBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "colors", computeSolver.colorsBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "instanceTransforms", instanceTransforms.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "invInstanceTransforms", invInstanceTransforms.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "instanceColors", instanceColors.computeBuffer);
|
||||
|
||||
ropeShader.SetMatrix("solverToWorld", m_Solver.transform.localToWorldMatrix);
|
||||
|
||||
ropeShader.SetInt("chunkCount", chunkData.count);
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(chunkData.count, 32);
|
||||
|
||||
ropeShader.Dispatch(updateKernel, threadGroups, 1, 1);
|
||||
|
||||
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
|
||||
mpb.SetBuffer("_InstanceTransforms", instanceTransforms.computeBuffer);
|
||||
mpb.SetBuffer("_InvInstanceTransforms", invInstanceTransforms.computeBuffer);
|
||||
mpb.SetBuffer("_Colors", instanceColors.computeBuffer);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
if (batch.mesh == null)
|
||||
continue;
|
||||
|
||||
args[0] = (uint)batch.mesh.GetIndexCount(0);
|
||||
args[1] = (uint)batch.instanceCount;
|
||||
args[2] = (uint)batch.mesh.GetIndexStart(0);
|
||||
args[3] = (uint)batch.mesh.GetBaseVertex(0);
|
||||
args[4] = (uint)batch.firstInstance;
|
||||
batch.argsBuffer.SetData(args);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.material = batch.material;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
rp.matProps = mpb;
|
||||
|
||||
Graphics.RenderMeshIndirect(rp, batch.mesh, batch.argsBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe4c45599ea584be2a1b122fbe7d0ec6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,101 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ComputeExtrudedRopeRenderSystem : ObiExtrudedRopeRenderSystem
|
||||
{
|
||||
|
||||
private ComputeShader ropeShader;
|
||||
private int updateKernel;
|
||||
|
||||
public ComputeExtrudedRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
ropeShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/RopeExtrudedRendering"));
|
||||
updateKernel = ropeShader.FindKernel("UpdateRopeMesh");
|
||||
}
|
||||
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(layout, true);
|
||||
|
||||
sectionData.AsComputeBuffer<Vector2>();
|
||||
sectionOffsets.AsComputeBuffer<int>();
|
||||
sectionIndices.AsComputeBuffer<int>();
|
||||
|
||||
vertexOffsets.AsComputeBuffer<int>();
|
||||
triangleOffsets.AsComputeBuffer<int>();
|
||||
triangleCounts.AsComputeBuffer<int>();
|
||||
|
||||
pathSmootherIndices.AsComputeBuffer<int>();
|
||||
rendererData.AsComputeBuffer<BurstExtrudedMeshData>();
|
||||
|
||||
pathSmootherSystem.chunkOffsets.AsComputeBuffer<int>();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
if (pathSmootherSystem == null)
|
||||
return;
|
||||
|
||||
// Single array: Cannot merge into a single vertices array, otherwise we would need to bring back to CPU for passing indices to each mesh.
|
||||
// Individual meshes: Cannot do each renderer independently (like we do with cloth) since each rope is done sequentially, would not parallelize at all.
|
||||
// Batches: 1 mesh per batch: best approach, but 1) bounds must be calculated per or solver, so we can only cull entire solver. Culling happens on the CPU, cannot bring back bounds from the CPU.
|
||||
// Cloth and Softbodies are rendered manually, particles are too. So Ropes could too.
|
||||
|
||||
// In Burst, we need merge all cloth mesh data into array for parallel processing, without using one schedule() per mesh.
|
||||
// So instead of writing slices of mesh data back to their original meshes, let's create one mesh per batch and draw it ourselves.
|
||||
// Basically the same as with ropes.
|
||||
|
||||
if (pathSmootherSystem.chunkOffsets != null && pathSmootherSystem.chunkOffsets.count > 0)
|
||||
{
|
||||
ropeShader.SetBuffer(updateKernel, "pathSmootherIndices", pathSmootherIndices.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "chunkOffsets", pathSmootherSystem.chunkOffsets.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "frames", pathSmootherSystem.smoothFrames.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "frameOffsets", pathSmootherSystem.smoothFrameOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "frameCounts", pathSmootherSystem.smoothFrameCounts.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "sectionData", sectionData.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "sectionOffsets", sectionOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "sectionIndices", sectionIndices.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "vertexOffsets", vertexOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "triangleOffsets", triangleOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "triangleCounts", triangleCounts.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "extrudedData", rendererData.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "pathData", pathSmootherSystem.pathData.computeBuffer);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(batch.rendererCount, 128);
|
||||
|
||||
ropeShader.SetInt("firstRenderer", batch.firstRenderer);
|
||||
ropeShader.SetInt("rendererCount", batch.rendererCount);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "vertices", batch.gpuVertexBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "tris", batch.gpuIndexBuffer);
|
||||
|
||||
ropeShader.Dispatch(updateKernel, threadGroups, 1, 1);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8977537c032b46c680d6b11b587e949
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,103 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
using Unity.Profiling;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ComputeLineRopeRenderSystem : ObiLineRopeRenderSystem
|
||||
{
|
||||
|
||||
private ComputeShader ropeShader;
|
||||
private int updateKernel;
|
||||
|
||||
public ComputeLineRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
ropeShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/RopeLineRendering"));
|
||||
updateKernel = ropeShader.FindKernel("UpdateLineMesh");
|
||||
}
|
||||
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(layout, true);
|
||||
|
||||
vertexOffsets.AsComputeBuffer<int>();
|
||||
triangleOffsets.AsComputeBuffer<int>();
|
||||
triangleCounts.AsComputeBuffer<int>();
|
||||
|
||||
pathSmootherIndices.AsComputeBuffer<int>();
|
||||
rendererData.AsComputeBuffer<BurstLineMeshData>();
|
||||
|
||||
pathSmootherSystem.chunkOffsets.AsComputeBuffer<int>();
|
||||
|
||||
}
|
||||
|
||||
public override void Render() { }
|
||||
|
||||
public override void RenderFromCamera(Camera camera)
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
if (pathSmootherSystem == null)
|
||||
return;
|
||||
|
||||
// Single array: Cannot merge into a single vertices array, otherwise we would need to bring back to CPU for passing indices to each mesh.
|
||||
// Individual meshes: Cannot do each renderer independently (like we do with cloth) since each rope is done sequentially, would not parallelize at all.
|
||||
// Batches: 1 mesh per batch: best approach, but 1) bounds must be calculated per or solver, so we can only cull entire solver. Culling happens on the CPU, cannot bring back bounds from the CPU.
|
||||
// Cloth and Softbodies are rendered manually, particles are too. So Ropes could too.
|
||||
|
||||
// In Burst, we need merge all cloth mesh data into array for parallel processing, without using one schedule() per mesh.
|
||||
// So instead of writing slices of mesh data back to their original meshes, let's create one mesh per batch and draw it ourselves.
|
||||
// Basically the same as with ropes.
|
||||
|
||||
if (pathSmootherSystem.chunkOffsets != null && pathSmootherSystem.chunkOffsets.count > 0)
|
||||
{
|
||||
ropeShader.SetBuffer(updateKernel, "pathSmootherIndices", pathSmootherIndices.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "chunkOffsets", pathSmootherSystem.chunkOffsets.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "frames", pathSmootherSystem.smoothFrames.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "frameOffsets", pathSmootherSystem.smoothFrameOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "frameCounts", pathSmootherSystem.smoothFrameCounts.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "vertexOffsets", vertexOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "triangleOffsets", triangleOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "triangleCounts", triangleCounts.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "rendererData", rendererData.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "pathData", pathSmootherSystem.pathData.computeBuffer);
|
||||
|
||||
ropeShader.SetVector("localSpaceCamera", m_Solver.transform.InverseTransformPoint(camera.transform.position));
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(batch.rendererCount, 128);
|
||||
|
||||
ropeShader.SetInt("firstRenderer", batch.firstRenderer);
|
||||
ropeShader.SetInt("rendererCount", batch.rendererCount);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "vertices", batch.gpuVertexBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "tris", batch.gpuIndexBuffer);
|
||||
|
||||
ropeShader.Dispatch(updateKernel, threadGroups, 1, 1);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
rp.camera = camera;
|
||||
|
||||
Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1de4576d2ba2b4966af730ac7a09e224
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,108 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class ComputeMeshRopeRenderSystem : ObiMeshRopeRenderSystem
|
||||
{
|
||||
private ComputeShader ropeShader;
|
||||
private int updateKernel;
|
||||
|
||||
public ComputeMeshRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
ropeShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/RopeMeshRendering"));
|
||||
updateKernel = ropeShader.FindKernel("UpdateRopeMesh");
|
||||
}
|
||||
|
||||
protected override void CloseBatches()
|
||||
{
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(sortedRenderers, meshData, meshIndices, layout, true);
|
||||
|
||||
meshData.PrepareForCompute();
|
||||
meshIndices.AsComputeBuffer<int>();
|
||||
|
||||
sortedIndices.AsComputeBuffer<int>();
|
||||
sortedOffsets.AsComputeBuffer<int>();
|
||||
|
||||
vertexOffsets.AsComputeBuffer<int>();
|
||||
|
||||
pathSmootherIndices.AsComputeBuffer<int>();
|
||||
rendererData.AsComputeBuffer<BurstMeshData>();
|
||||
|
||||
pathSmootherSystem.chunkOffsets.AsComputeBuffer<int>();
|
||||
|
||||
base.CloseBatches();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
if (pathSmootherSystem == null)
|
||||
return;
|
||||
|
||||
// Single array: Cannot merge into a single vertices array, otherwise we would need to bring back to CPU for passing indices to each mesh.
|
||||
// Individual meshes: Cannot do each renderer independently (like we do with cloth) since each rope is done sequentially, would not parallelize at all.
|
||||
// Batches: 1 mesh per batch: best approach, but 1) bounds must be calculated per or solver, so we can only cull entire solver. Culling happens on the CPU, cannot bring back bounds from the CPU.
|
||||
// Cloth and Softbodies are rendered manually, particles are too. So Ropes could too.
|
||||
|
||||
// In Burst, we need merge all cloth mesh data into array for parallel processing, without using one schedule() per mesh.
|
||||
// So instead of writing slices of mesh data back to their original meshes, let's create one mesh per batch and draw it ourselves.
|
||||
// Basically the same as with ropes.
|
||||
|
||||
if (pathSmootherSystem.chunkOffsets != null && pathSmootherSystem.chunkOffsets.count > 0)
|
||||
{
|
||||
ropeShader.SetBuffer(updateKernel, "chunkOffsets", pathSmootherSystem.chunkOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "pathSmootherIndices", pathSmootherIndices.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "frames", pathSmootherSystem.smoothFrames.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "frameOffsets", pathSmootherSystem.smoothFrameOffsets.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "frameCounts", pathSmootherSystem.smoothFrameCounts.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "vertexOffsets", vertexOffsets.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "meshIndices", meshIndices.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "meshData", meshData.meshData.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "rendererData", rendererData.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "pathData", pathSmootherSystem.pathData.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "sortedIndices", sortedIndices.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "sortedOffsets", sortedOffsets.computeBuffer);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "positions", meshData.restPositions.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "normals", meshData.restNormals.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "tangents", meshData.restTangents.computeBuffer);
|
||||
ropeShader.SetBuffer(updateKernel, "colors", meshData.restColors.computeBuffer);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(batch.rendererCount, 16);
|
||||
|
||||
ropeShader.SetInt("firstRenderer", batch.firstRenderer);
|
||||
ropeShader.SetInt("rendererCount", batch.rendererCount);
|
||||
|
||||
ropeShader.SetBuffer(updateKernel, "vertices", batch.gpuVertexBuffer);
|
||||
|
||||
ropeShader.Dispatch(updateKernel, threadGroups, 1, 1);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
for (int m = 0; m < batch.materials.Length; ++m)
|
||||
{
|
||||
rp.material = batch.materials[m];
|
||||
Graphics.RenderMesh(rp, batch.mesh, m, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f880620ed267d4cb4a701183bcadfe15
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,94 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class ComputePathSmootherRenderSystem : ObiPathSmootherRenderSystem
|
||||
{
|
||||
|
||||
private ComputeShader pathShader;
|
||||
private int parallelTransportKernel;
|
||||
private int decimateKernel;
|
||||
private int smoothKernel;
|
||||
|
||||
public ComputePathSmootherRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
pathShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/PathSmoothing"));
|
||||
parallelTransportKernel = pathShader.FindKernel("ParallelTransport");
|
||||
decimateKernel = pathShader.FindKernel("Decimate");
|
||||
smoothKernel = pathShader.FindKernel("ChaikinSmooth");
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
particleIndices.AsComputeBuffer<int>();
|
||||
rawFrameOffsets.AsComputeBuffer<int>();
|
||||
pathData.AsComputeBuffer<BurstPathSmootherData>();
|
||||
rawFrames.AsComputeBuffer<ObiPathFrame>();
|
||||
decimatedFrameCounts.AsComputeBuffer<int>();
|
||||
|
||||
smoothFrames.AsComputeBuffer<ObiPathFrame>();
|
||||
smoothFrameOffsets.AsComputeBuffer<int>();
|
||||
smoothFrameCounts.AsComputeBuffer<int>();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
//base.Render();
|
||||
|
||||
var computeSolver = m_Solver.implementation as ComputeSolverImpl;
|
||||
|
||||
if (computeSolver.renderablePositionsBuffer != null && computeSolver.renderablePositionsBuffer.count > 0)
|
||||
{
|
||||
// wait for gpu data to be transferred:
|
||||
pathData.WaitForReadback();
|
||||
smoothFrames.WaitForReadback();
|
||||
|
||||
// update rest lenghts and upload to gpu:
|
||||
base.Render();
|
||||
pathData.Upload();
|
||||
|
||||
int threadGroups = ComputeMath.ThreadGroupCount(rawFrameOffsets.count, 128);
|
||||
pathShader.SetInt("chunkCount", rawFrameOffsets.count);
|
||||
|
||||
pathShader.SetBuffer(parallelTransportKernel, "frameOffsets", rawFrameOffsets.computeBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "particleIndices", particleIndices.computeBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "renderablePositions", computeSolver.renderablePositionsBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "renderableOrientations", computeSolver.renderableOrientationsBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "principalRadii", computeSolver.principalRadiiBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "colors", computeSolver.colorsBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "pathData", pathData.computeBuffer);
|
||||
pathShader.SetBuffer(parallelTransportKernel, "pathFrames", rawFrames.computeBuffer);
|
||||
|
||||
pathShader.Dispatch(parallelTransportKernel, threadGroups, 1, 1);
|
||||
|
||||
pathShader.SetBuffer(decimateKernel, "pathFrames", rawFrames.computeBuffer);
|
||||
pathShader.SetBuffer(decimateKernel, "frameOffsets", rawFrameOffsets.computeBuffer);
|
||||
pathShader.SetBuffer(decimateKernel, "decimatedFrameCounts", decimatedFrameCounts.computeBuffer);
|
||||
pathShader.SetBuffer(decimateKernel, "pathData", pathData.computeBuffer);
|
||||
|
||||
pathShader.Dispatch(decimateKernel, threadGroups, 1, 1);
|
||||
|
||||
pathShader.SetBuffer(smoothKernel, "pathFrames", rawFrames.computeBuffer);
|
||||
pathShader.SetBuffer(smoothKernel, "frameOffsets", rawFrameOffsets.computeBuffer);
|
||||
pathShader.SetBuffer(smoothKernel, "decimatedFrameCounts", decimatedFrameCounts.computeBuffer);
|
||||
pathShader.SetBuffer(smoothKernel, "smoothFrames", smoothFrames.computeBuffer);
|
||||
pathShader.SetBuffer(smoothKernel, "smoothFrameOffsets", smoothFrameOffsets.computeBuffer);
|
||||
pathShader.SetBuffer(smoothKernel, "smoothFrameCounts", smoothFrameCounts.computeBuffer);
|
||||
pathShader.SetBuffer(smoothKernel, "pathData", pathData.computeBuffer);
|
||||
|
||||
pathShader.Dispatch(smoothKernel, threadGroups, 1, 1);
|
||||
|
||||
pathData.Readback();
|
||||
smoothFrames.Readback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ed459657fb054e7b8e0c806e8e5016e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user