更新obi到7.1
This commit is contained in:
8
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/Common.meta
vendored
Normal file
8
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/Common.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3595afed529f346669fbe538323cd7d2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/Common/BuildParticleMeshDataJob.cs
vendored
Normal file
62
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/Common/BuildParticleMeshDataJob.cs
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[BurstCompile]
|
||||
struct BuildParticleMeshDataJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> particleIndices;
|
||||
[ReadOnly] public NativeArray<int> rendererIndices;
|
||||
[ReadOnly] public NativeArray<ParticleRendererData> rendererData;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
[ReadOnly] public NativeArray<quaternion> renderableOrientations;
|
||||
[ReadOnly] public NativeArray<float4> renderableRadii;
|
||||
[ReadOnly] public NativeArray<float4> colors;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<ParticleVertex> vertices;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> indices;
|
||||
|
||||
[ReadOnly] public int firstParticle;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int p = particleIndices[firstParticle + i];
|
||||
int r = rendererIndices[firstParticle + i];
|
||||
|
||||
ParticleVertex v = new ParticleVertex();
|
||||
|
||||
v.pos = new float4(renderablePositions[p].xyz, 1);
|
||||
v.color = colors[p] * (Vector4)rendererData[r].color;
|
||||
v.b1 = new float4(math.mul(renderableOrientations[p], new float3(1, 0, 0)), renderableRadii[p][0] * renderableRadii[p][3] * rendererData[r].radiusScale);
|
||||
v.b2 = new float4(math.mul(renderableOrientations[p], new float3(0, 1, 0)), renderableRadii[p][1] * renderableRadii[p][3] * rendererData[r].radiusScale);
|
||||
v.b3 = new float4(math.mul(renderableOrientations[p], new float3(0, 0, 1)), renderableRadii[p][2] * renderableRadii[p][3] * rendererData[r].radiusScale);
|
||||
|
||||
v.offset = new float3(1, 1, 0);
|
||||
vertices[i * 4] = v;
|
||||
|
||||
v.offset = new float3(-1, 1, 0);
|
||||
vertices[i * 4 + 1] = v;
|
||||
|
||||
v.offset = new float3(-1, -1, 0);
|
||||
vertices[i * 4 + 2] = v;
|
||||
|
||||
v.offset = new float3(1, -1, 0);
|
||||
vertices[i * 4 + 3] = v;
|
||||
|
||||
indices[i * 6] = (i * 4 + 2);
|
||||
indices[i * 6 + 1] = (i * 4 + 1);
|
||||
indices[i * 6 + 2] = (i * 4);
|
||||
|
||||
indices[i * 6 + 3] = (i * 4 + 3);
|
||||
indices[i * 6 + 4] = (i * 4 + 2);
|
||||
indices[i * 6 + 5] = (i * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cacb4a3597ee245a6b40358728c300e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
247
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/Common/BurstFoamRenderSystem.cs
vendored
Normal file
247
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/Common/BurstFoamRenderSystem.cs
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if (SRP_UNIVERSAL)
|
||||
using UnityEngine.Rendering.Universal;
|
||||
#endif
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class BurstFoamRenderSystem : ObiFoamRenderSystem
|
||||
{
|
||||
protected NativeArray<float2> sortHandles;
|
||||
|
||||
protected struct SortHandleComparer : IComparer<float2>
|
||||
{
|
||||
public int Compare(float2 a, float2 b)
|
||||
{
|
||||
return b.y.CompareTo(a.y);
|
||||
}
|
||||
}
|
||||
|
||||
protected SortHandleComparer comparer = new SortHandleComparer();
|
||||
|
||||
public BurstFoamRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
#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));
|
||||
ReallocateRenderBatch();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
if (sortHandles.IsCreated)
|
||||
sortHandles.Dispose();
|
||||
}
|
||||
|
||||
private void ReallocateRenderBatch()
|
||||
{
|
||||
// in case the amount of particles allocated does not match
|
||||
// the amount requested by the solver, reallocate
|
||||
if (!sortHandles.IsCreated || 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);
|
||||
|
||||
if (sortHandles.IsCreated)
|
||||
sortHandles.Dispose();
|
||||
sortHandles = new NativeArray<float2>(m_Solver.foamPositions.count, Allocator.Persistent);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Step()
|
||||
{
|
||||
}
|
||||
|
||||
public override unsafe void Render()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
var solver = m_Solver.implementation as BurstSolverImpl;
|
||||
|
||||
ReallocateRenderBatch();
|
||||
|
||||
foreach (Camera camera in cameras)
|
||||
{
|
||||
if (camera == null)
|
||||
continue;
|
||||
|
||||
JobHandle inputDeps = new JobHandle();
|
||||
var sortJob = sortHandles.Slice(0, m_Solver.foamCount[3]).SortJob(comparer);
|
||||
|
||||
//Clear all triangle indices to zero:
|
||||
UnsafeUtility.MemClear(
|
||||
NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(renderBatch.triangles),
|
||||
UnsafeUtility.SizeOf<int>() * renderBatch.triangles.Length);
|
||||
|
||||
var projectJob = new ProjectOnSortAxisJob
|
||||
{
|
||||
inputPositions = solver.abstraction.foamPositions.AsNativeArray<float4>(),
|
||||
sortHandles = sortHandles,
|
||||
sortAxis = solver.abstraction.transform.InverseTransformDirection(camera.transform.forward)
|
||||
};
|
||||
|
||||
inputDeps = projectJob.Schedule(m_Solver.foamCount[3], 256, inputDeps);
|
||||
|
||||
inputDeps = sortJob.Schedule(inputDeps);
|
||||
|
||||
var sortParticlesJob = new SortParticles
|
||||
{
|
||||
sortHandles = sortHandles,
|
||||
inputPositions = solver.abstraction.foamPositions.AsNativeArray<float4>(),
|
||||
inputVelocities = solver.abstraction.foamVelocities.AsNativeArray<float4>(),
|
||||
inputColors = solver.abstraction.foamColors.AsNativeArray<float4>(),
|
||||
inputAttributes = solver.abstraction.foamAttributes.AsNativeArray<float4>(),
|
||||
|
||||
outputPositions = solver.auxPositions,
|
||||
outputVelocities = solver.auxVelocities,
|
||||
outputColors = solver.auxColors,
|
||||
outputAttributes = solver.auxAttributes
|
||||
};
|
||||
|
||||
inputDeps = sortParticlesJob.Schedule(m_Solver.foamCount[3], 256, inputDeps);
|
||||
|
||||
var meshJob = new BuildFoamMeshDataJob
|
||||
{
|
||||
inputPositions = solver.auxPositions,
|
||||
inputVelocities = solver.auxVelocities,
|
||||
inputColors = solver.auxColors,
|
||||
inputAttributes = solver.auxAttributes,
|
||||
|
||||
vertices = renderBatch.vertices,
|
||||
indices = renderBatch.triangles,
|
||||
};
|
||||
|
||||
inputDeps = meshJob.Schedule(m_Solver.foamCount[3], 128, inputDeps);
|
||||
|
||||
inputDeps.Complete();
|
||||
|
||||
renderBatch.mesh.SetVertexBufferData(renderBatch.vertices, 0, 0, renderBatch.vertexCount, 0, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds | MeshUpdateFlags.DontNotifyMeshUsers);
|
||||
renderBatch.mesh.SetIndexBufferData(renderBatch.triangles, 0, 0, renderBatch.triangleCount * 3, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
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;
|
||||
|
||||
Graphics.RenderMesh(rp, renderBatch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[BurstCompile]
|
||||
unsafe struct ProjectOnSortAxisJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> inputPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float2> sortHandles;
|
||||
|
||||
public float3 sortAxis;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
sortHandles[i] = new float2(i, math.dot(inputPositions[i].xyz, sortAxis));
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
unsafe struct SortParticles : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float2> sortHandles;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> inputPositions;
|
||||
[ReadOnly] public NativeArray<float4> inputVelocities;
|
||||
[ReadOnly] public NativeArray<float4> inputColors;
|
||||
[ReadOnly] public NativeArray<float4> inputAttributes;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> outputPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> outputVelocities;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> outputColors;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> outputAttributes;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int o = (int)sortHandles[i].x;
|
||||
outputPositions[i] = inputPositions[o];
|
||||
outputVelocities[i] = inputVelocities[o];
|
||||
outputColors[i] = inputColors[o];
|
||||
outputAttributes[i] = inputAttributes[o];
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct BuildFoamMeshDataJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> inputPositions;
|
||||
[ReadOnly] public NativeArray<float4> inputVelocities;
|
||||
[ReadOnly] public NativeArray<float4> inputColors;
|
||||
[ReadOnly] public NativeArray<float4> inputAttributes;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<DiffuseParticleVertex> vertices;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> indices;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
DiffuseParticleVertex v = new DiffuseParticleVertex();
|
||||
|
||||
v.pos = new float4(inputPositions[i].xyz, 1);
|
||||
v.color = inputColors[i];
|
||||
v.velocity = inputVelocities[i];
|
||||
v.attributes = inputAttributes[i];
|
||||
|
||||
v.offset = new float3(1, 1, 0);
|
||||
vertices[i * 4] = v;
|
||||
|
||||
v.offset = new float3(-1, 1, 0);
|
||||
vertices[i * 4 + 1] = v;
|
||||
|
||||
v.offset = new float3(-1, -1, 0);
|
||||
vertices[i * 4 + 2] = v;
|
||||
|
||||
v.offset = new float3(1, -1, 0);
|
||||
vertices[i * 4 + 3] = v;
|
||||
|
||||
indices[i * 6] = (i * 4 + 2);
|
||||
indices[i * 6 + 1] = (i * 4 + 1);
|
||||
indices[i * 6 + 2] = (i * 4);
|
||||
|
||||
indices[i * 6 + 3] = (i * 4 + 3);
|
||||
indices[i * 6 + 4] = (i * 4 + 2);
|
||||
indices[i * 6 + 5] = (i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 555e1cc2122984a93afc0f6f31fa173b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class BurstInstancedParticleRenderSystem : ObiInstancedParticleRenderSystem
|
||||
{
|
||||
|
||||
public BurstInstancedParticleRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
var instanceTransformsJob = new InstancedParticleTransforms
|
||||
{
|
||||
activeParticles = activeParticles.AsNativeArray<int>(),
|
||||
rendererData = rendererData.AsNativeArray<ParticleRendererData>(),
|
||||
rendererIndex = rendererIndex.AsNativeArray<int>(),
|
||||
instanceTransforms = instanceTransforms.AsNativeArray<float4x4>(),
|
||||
instanceColors = instanceColors.AsNativeArray<float4>(),
|
||||
|
||||
renderablePositions = m_Solver.renderablePositions.AsNativeArray<float4>(),
|
||||
renderableOrientations = m_Solver.renderableOrientations.AsNativeArray<quaternion>(),
|
||||
renderableRadii = m_Solver.renderableRadii.AsNativeArray<float4>(),
|
||||
colors = m_Solver.colors.AsNativeArray<float4>(),
|
||||
solverToWorld = m_Solver.transform.localToWorldMatrix
|
||||
};
|
||||
|
||||
instanceTransformsJob.Schedule(activeParticles.count, 32).Complete();
|
||||
|
||||
var mpb = new MaterialPropertyBlock();
|
||||
|
||||
//Draw instances:
|
||||
for (int i = 0; i < batchList.Count; i++)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
if (batch.instanceCount > 0)
|
||||
{
|
||||
// workaround for RenderMeshInstanced bug
|
||||
// (https://forum.unity.com/threads/gpu-instanced-custom-properties-dont-take-unity_baseinstanceid-into-account.1520602/)
|
||||
// also, no NativeArray<> overload :(
|
||||
mpb.SetVectorArray("_Colors", instanceColors.AsNativeArray<Vector4>().Slice(batch.firstInstance, batch.instanceCount).ToArray());
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.material = batch.material;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
rp.matProps = mpb;
|
||||
|
||||
// TODO: use generic overload to pass matrix + instance color.
|
||||
Graphics.RenderMeshInstanced(rp, batch.mesh, 0, instanceTransforms.AsNativeArray<Matrix4x4>(), batch.instanceCount, batch.firstInstance);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct InstancedParticleTransforms : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
[ReadOnly] public NativeArray<ParticleRendererData> rendererData;
|
||||
[ReadOnly] public NativeArray<int> rendererIndex;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
[ReadOnly] public NativeArray<quaternion> renderableOrientations;
|
||||
[ReadOnly] public NativeArray<float4> renderableRadii;
|
||||
[ReadOnly] public NativeArray<float4> colors;
|
||||
[ReadOnly] public float4x4 solverToWorld;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4x4> instanceTransforms;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> instanceColors;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int p = activeParticles[i];
|
||||
|
||||
Matrix4x4 tfrm = float4x4.TRS(renderablePositions[p].xyz,
|
||||
renderableOrientations[p],
|
||||
renderableRadii[p].xyz * renderableRadii[p][3] * rendererData[rendererIndex[i]].radiusScale);
|
||||
|
||||
instanceTransforms[i] = math.mul(solverToWorld, tfrm);
|
||||
|
||||
instanceColors[i] = colors[p] * (Vector4)rendererData[rendererIndex[i]].color;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3896a2253db543bcaa92126d83a7ba0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstParticleRenderSystem : ObiParticleRenderSystem
|
||||
{
|
||||
public BurstParticleRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
m_Solver = solver;
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
var buildArraysJob = new BuildParticleMeshDataJob
|
||||
{
|
||||
particleIndices = activeParticles.AsNativeArray<int>(),
|
||||
rendererIndices = rendererIndex.AsNativeArray<int>(),
|
||||
rendererData = rendererData.AsNativeArray<ParticleRendererData>(),
|
||||
|
||||
renderablePositions = m_Solver.renderablePositions.AsNativeArray<float4>(),
|
||||
renderableOrientations = m_Solver.renderableOrientations.AsNativeArray<quaternion>(),
|
||||
renderableRadii = m_Solver.renderableRadii.AsNativeArray<float4>(),
|
||||
colors = m_Solver.colors.AsNativeArray<float4>(),
|
||||
|
||||
vertices = batch.vertices,
|
||||
indices = batch.triangles,
|
||||
|
||||
firstParticle = batch.firstParticle,
|
||||
};
|
||||
|
||||
buildArraysJob.Schedule(batch.vertexCount / 4, 32).Complete();
|
||||
|
||||
batch.mesh.SetVertexBufferData(batch.vertices, 0, 0, batch.vertexCount, 0, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds | MeshUpdateFlags.DontNotifyMeshUsers);
|
||||
batch.mesh.SetIndexBufferData(batch.triangles, 0, 0, batch.triangleCount * 3, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1d1ddc20ab7148e3ac806e3559ba2b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod.meta
vendored
Normal file
10
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod.meta
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68fb3be53914247609d4e6da4f249e52
|
||||
labels:
|
||||
- ObiRope
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,139 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
|
||||
public class BurstChainRopeRenderSystem : ObiChainRopeRenderSystem
|
||||
{
|
||||
protected Matrix4x4[] transformsArray = new Matrix4x4[1023];
|
||||
|
||||
public BurstChainRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
// generate raw frames using parallel transport
|
||||
var instanceTransformsJob = new InstanceTransforms()
|
||||
{
|
||||
rendererData = rendererData.AsNativeArray<ChainRendererData>(),
|
||||
chunkData = chunkData.AsNativeArray<ChunkData>(),
|
||||
modifiers = modifiers.AsNativeArray<ObiRopeChainRenderer.LinkModifier>(),
|
||||
elements = elements.AsNativeArray<int2>(),
|
||||
|
||||
instanceTransforms = instanceTransforms.AsNativeArray<float4x4>(),
|
||||
instanceColors = instanceColors.AsNativeArray<float4>(),
|
||||
|
||||
renderablePositions = m_Solver.renderablePositions.AsNativeArray<float4>(),
|
||||
renderableOrientations = m_Solver.renderableOrientations.AsNativeArray<quaternion>(),
|
||||
principalRadii = m_Solver.principalRadii.AsNativeArray<float4>(),
|
||||
colors = m_Solver.colors.AsNativeArray<float4>(),
|
||||
solverToWorld = m_Solver.transform.localToWorldMatrix,
|
||||
};
|
||||
|
||||
instanceTransformsJob.Schedule(chunkData.count, 8).Complete();
|
||||
|
||||
//Draw instances:
|
||||
for (int i = 0; i < batchList.Count; i++)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.material = batch.material;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
Graphics.RenderMeshInstanced(rp, batch.mesh, 0, instanceTransforms.AsNativeArray<Matrix4x4>(), batch.instanceCount, batch.firstInstance);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct InstanceTransforms : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<ChainRendererData> rendererData;
|
||||
[ReadOnly] public NativeArray<ChunkData> chunkData;
|
||||
[ReadOnly] public NativeArray<ObiRopeChainRenderer.LinkModifier> modifiers;
|
||||
[ReadOnly] public NativeArray<int2> elements;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
[ReadOnly] public NativeArray<quaternion> renderableOrientations;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<float4> colors;
|
||||
[ReadOnly] public float4x4 solverToWorld;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4x4> instanceTransforms;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> instanceColors;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int firstIndex = i > 0 ? chunkData[i - 1].offset : 0;
|
||||
int elementCount = chunkData[i].offset - firstIndex;
|
||||
|
||||
var rendererIndex = chunkData[i].rendererIndex;
|
||||
var renderer = rendererData[rendererIndex];
|
||||
|
||||
float3 rendScale = ((float4)renderer.scale).xyz;
|
||||
|
||||
int firstModifier = rendererIndex > 0 ? rendererData[rendererIndex - 1].modifierOffset : 0;
|
||||
int modifierCount = renderer.modifierOffset - firstModifier;
|
||||
|
||||
var modifier = new ObiRopeChainRenderer.LinkModifier();
|
||||
modifier.Clear();
|
||||
|
||||
BurstPathFrame frame = new BurstPathFrame();
|
||||
frame.Reset();
|
||||
|
||||
float twist = -renderer.twist * elementCount * renderer.twistAnchor;
|
||||
frame.SetTwist(twist);
|
||||
|
||||
// parallel transport:
|
||||
for (int m = 0; m < elementCount; ++m)
|
||||
{
|
||||
if (modifierCount > 0)
|
||||
modifier = modifiers[firstModifier + m % modifierCount];
|
||||
|
||||
int index = firstIndex + m;
|
||||
float4 pos = renderablePositions[elements[index].x];
|
||||
float4 nextPos = renderablePositions[elements[index].y];
|
||||
float4 vector = nextPos - pos;
|
||||
float3 tangent = math.normalizesafe(vector.xyz);
|
||||
|
||||
if (renderer.usesOrientedParticles == 1)
|
||||
{
|
||||
frame.Transport(nextPos.xyz, tangent, math.rotate(renderableOrientations[elements[index].x], new float3(0, 1, 0)), twist);
|
||||
twist += renderer.twist;
|
||||
}
|
||||
else
|
||||
frame.Transport(nextPos.xyz, tangent, renderer.twist);
|
||||
|
||||
var rotation = quaternion.LookRotationSafe(frame.tangent, frame.normal);
|
||||
var position = (pos + vector * 0.5f).xyz + math.mul(rotation, modifier.translation);
|
||||
var scale = principalRadii[elements[index].x].x * 2 * rendScale * modifier.scale;
|
||||
|
||||
rotation = math.mul(rotation, quaternion.Euler(math.radians(modifier.rotation)));
|
||||
|
||||
instanceTransforms[index] = math.mul(solverToWorld,float4x4.TRS(position,rotation,scale));
|
||||
instanceColors[index] = (colors[elements[index].x] + colors[elements[index].y]) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c63ccd17bfc14b40a403c1c9a0be2c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,215 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstExtrudedRopeRenderSystem : ObiExtrudedRopeRenderSystem
|
||||
{
|
||||
public BurstExtrudedRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(layout, false);
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
if (pathSmootherSystem == null)
|
||||
return;
|
||||
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
var handles = new NativeArray<JobHandle>(batchList.Count, Allocator.Temp);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
var meshJob = new BuildExtrudedMesh
|
||||
{
|
||||
pathSmootherIndices = pathSmootherIndices.AsNativeArray<int>(),
|
||||
chunkOffsets = pathSmootherSystem.chunkOffsets.AsNativeArray<int>(),
|
||||
|
||||
frames = pathSmootherSystem.smoothFrames.AsNativeArray<BurstPathFrame>(),
|
||||
frameOffsets = pathSmootherSystem.smoothFrameOffsets.AsNativeArray<int>(),
|
||||
frameCounts = pathSmootherSystem.smoothFrameCounts.AsNativeArray<int>(),
|
||||
|
||||
sectionData = sectionData.AsNativeArray<float2>(),
|
||||
sectionOffsets = sectionOffsets.AsNativeArray<int>(),
|
||||
sectionIndices = sectionIndices.AsNativeArray<int>(),
|
||||
|
||||
vertexOffsets = vertexOffsets.AsNativeArray<int>(),
|
||||
triangleOffsets = triangleOffsets.AsNativeArray<int>(),
|
||||
triangleCounts = triangleCounts.AsNativeArray<int>(),
|
||||
|
||||
pathData = pathSmootherSystem.pathData.AsNativeArray<BurstPathSmootherData>(),
|
||||
rendererData = rendererData.AsNativeArray<BurstExtrudedMeshData>(),
|
||||
|
||||
vertices = batch.vertices,
|
||||
tris = batch.triangles,
|
||||
|
||||
firstRenderer = batch.firstRenderer
|
||||
};
|
||||
handles[i] = meshJob.Schedule(batch.rendererCount, 1);
|
||||
}
|
||||
|
||||
JobHandle.CombineDependencies(handles).Complete();
|
||||
handles.Dispose();
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
batch.mesh.SetVertexBufferData(batch.vertices, 0, 0, batch.vertexCount, 0, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds);
|
||||
batch.mesh.SetIndexBufferData(batch.triangles, 0, 0, batch.triangleCount * 3, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct BuildExtrudedMesh : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> pathSmootherIndices;
|
||||
[ReadOnly] public NativeArray<int> chunkOffsets;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstPathFrame> frames;
|
||||
[ReadOnly] public NativeArray<int> frameOffsets;
|
||||
[ReadOnly] public NativeArray<int> frameCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<float2> sectionData;
|
||||
[ReadOnly] public NativeArray<int> sectionOffsets;
|
||||
[ReadOnly] public NativeArray<int> sectionIndices;
|
||||
|
||||
[ReadOnly] public NativeArray<int> vertexOffsets;
|
||||
[ReadOnly] public NativeArray<int> triangleOffsets;
|
||||
[ReadOnly] public NativeArray<int> triangleCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstExtrudedMeshData> rendererData;
|
||||
[ReadOnly] public NativeArray<BurstPathSmootherData> pathData;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<ProceduralRopeVertex> vertices;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> tris;
|
||||
|
||||
[ReadOnly] public int firstRenderer;
|
||||
|
||||
public void Execute(int u)
|
||||
{
|
||||
int k = firstRenderer + u;
|
||||
int s = pathSmootherIndices[k];
|
||||
|
||||
float3 vertex = float3.zero;
|
||||
float3 normal = float3.zero;
|
||||
float4 texTangent = float4.zero;
|
||||
|
||||
int tri = 0;
|
||||
int sectionIndex = 0;
|
||||
int sectionStart = sectionOffsets[sectionIndices[k]];
|
||||
int sectionSegments = (sectionOffsets[sectionIndices[k] + 1] - sectionStart) - 1;
|
||||
int verticesPerSection = sectionSegments + 1; // the last vertex in each section must be duplicated, due to uv wraparound.
|
||||
|
||||
float smoothLength = 0;
|
||||
for (int i = chunkOffsets[s]; i < chunkOffsets[s + 1]; ++i)
|
||||
smoothLength += pathData[i].smoothLength;
|
||||
|
||||
float vCoord = -rendererData[k].uvScale.y * pathData[chunkOffsets[s]].restLength * rendererData[k].uvAnchor;
|
||||
float actualToRestLengthRatio = smoothLength / pathData[chunkOffsets[s]].restLength;
|
||||
|
||||
int firstVertex = vertexOffsets[k];
|
||||
int firstTriangle = triangleOffsets[k];
|
||||
|
||||
// clear out triangle indices for this rope:
|
||||
for (int i = firstTriangle; i < firstTriangle + triangleCounts[k]; ++i)
|
||||
{
|
||||
int offset = i * 3;
|
||||
tris[offset] = 0;
|
||||
tris[offset+1] = 0;
|
||||
tris[offset+2] = 0;
|
||||
}
|
||||
|
||||
// for each chunk in the rope:
|
||||
for (int i = chunkOffsets[s]; i < chunkOffsets[s + 1]; ++i)
|
||||
{
|
||||
int firstFrame = frameOffsets[i];
|
||||
int frameCount = frameCounts[i];
|
||||
|
||||
for (int f = 0; f < frameCount; ++f)
|
||||
{
|
||||
// Calculate previous and next curve indices:
|
||||
int prevIndex = firstFrame + math.max(f - 1, 0);
|
||||
int index = firstFrame + f;
|
||||
|
||||
// advance v texcoord:
|
||||
vCoord += rendererData[k].uvScale.y * (math.distance(frames[index].position, frames[prevIndex].position) /
|
||||
(rendererData[k].normalizeV == 1 ? smoothLength : actualToRestLengthRatio));
|
||||
|
||||
// calculate section thickness and scale the basis vectors by it:
|
||||
float sectionThickness = frames[index].thickness * rendererData[k].thicknessScale;
|
||||
|
||||
// Loop around each segment:
|
||||
int nextSectionIndex = sectionIndex + 1;
|
||||
for (int j = 0; j <= sectionSegments; ++j)
|
||||
{
|
||||
// make just one copy of the section vertex:
|
||||
float2 sectionVertex = sectionData[sectionStart + j];
|
||||
|
||||
// calculate normal using section vertex, curve normal and binormal:
|
||||
normal.x = (sectionVertex.x * frames[index].normal.x + sectionVertex.y * frames[index].binormal.x) * sectionThickness;
|
||||
normal.y = (sectionVertex.x * frames[index].normal.y + sectionVertex.y * frames[index].binormal.y) * sectionThickness;
|
||||
normal.z = (sectionVertex.x * frames[index].normal.z + sectionVertex.y * frames[index].binormal.z) * sectionThickness;
|
||||
|
||||
// offset curve position by normal:
|
||||
vertex.x = frames[index].position.x + normal.x;
|
||||
vertex.y = frames[index].position.y + normal.y;
|
||||
vertex.z = frames[index].position.z + normal.z;
|
||||
|
||||
// cross(normal, curve tangent)
|
||||
texTangent.xyz = math.cross(normal, frames[index].tangent);
|
||||
texTangent.w = -1;
|
||||
|
||||
vertices[firstVertex + sectionIndex * verticesPerSection + j] = new ProceduralRopeVertex
|
||||
{
|
||||
pos = vertex,
|
||||
normal = normal,
|
||||
tangent = texTangent,
|
||||
color = frames[index].color,
|
||||
uv = new float2(j / (float)sectionSegments * rendererData[k].uvScale.x, vCoord)
|
||||
};
|
||||
|
||||
if (j < sectionSegments && f < frameCount - 1)
|
||||
{
|
||||
int offset = firstTriangle * 3;
|
||||
tris[offset + tri++] = (firstVertex + sectionIndex * verticesPerSection + j);
|
||||
tris[offset + tri++] = (firstVertex + nextSectionIndex * verticesPerSection + j);
|
||||
tris[offset + tri++] = (firstVertex + sectionIndex * verticesPerSection + (j + 1));
|
||||
|
||||
tris[offset + tri++] = (firstVertex + sectionIndex * verticesPerSection + (j + 1));
|
||||
tris[offset + tri++] = (firstVertex + nextSectionIndex * verticesPerSection + j);
|
||||
tris[offset + tri++] = (firstVertex + nextSectionIndex * verticesPerSection + (j + 1));
|
||||
}
|
||||
}
|
||||
sectionIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10b89fddf68724bc9ad3305774d86ee1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,215 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstLineRopeRenderSystem : ObiLineRopeRenderSystem
|
||||
{
|
||||
public BurstLineRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
|
||||
// Initialize each batch:
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(layout, false);
|
||||
}
|
||||
|
||||
public override void Render(){}
|
||||
|
||||
public override void RenderFromCamera(Camera camera)
|
||||
{
|
||||
if (pathSmootherSystem == null)
|
||||
return;
|
||||
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
var handles = new NativeArray<JobHandle>(batchList.Count, Allocator.Temp);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
var meshJob = new BuildLineMesh
|
||||
{
|
||||
pathSmootherIndices = pathSmootherIndices.AsNativeArray<int>(),
|
||||
chunkOffsets = pathSmootherSystem.chunkOffsets.AsNativeArray<int>(),
|
||||
|
||||
frames = pathSmootherSystem.smoothFrames.AsNativeArray<BurstPathFrame>(),
|
||||
frameOffsets = pathSmootherSystem.smoothFrameOffsets.AsNativeArray<int>(),
|
||||
frameCounts = pathSmootherSystem.smoothFrameCounts.AsNativeArray<int>(),
|
||||
|
||||
vertexOffsets = vertexOffsets.AsNativeArray<int>(),
|
||||
triangleOffsets = triangleOffsets.AsNativeArray<int>(),
|
||||
triangleCounts = triangleCounts.AsNativeArray<int>(),
|
||||
|
||||
pathData = pathSmootherSystem.pathData.AsNativeArray<BurstPathSmootherData>(),
|
||||
rendererData = rendererData.AsNativeArray<BurstLineMeshData>(),
|
||||
|
||||
vertices = batch.vertices,
|
||||
tris = batch.triangles,
|
||||
|
||||
firstRenderer = batch.firstRenderer,
|
||||
localSpaceCamera = m_Solver.transform.InverseTransformPoint(camera.transform.position)
|
||||
};
|
||||
handles[i] = meshJob.Schedule(batch.rendererCount, 1);
|
||||
}
|
||||
|
||||
JobHandle.CombineDependencies(handles).Complete();
|
||||
handles.Dispose();
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
batch.mesh.SetVertexBufferData(batch.vertices, 0, 0, batch.vertexCount, 0, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds);
|
||||
batch.mesh.SetIndexBufferData(batch.triangles, 0, 0, batch.triangleCount * 3, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds);
|
||||
|
||||
var rp = batch.renderParams;
|
||||
rp.worldBounds = m_Solver.bounds;
|
||||
|
||||
Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct BuildLineMesh : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> pathSmootherIndices;
|
||||
[ReadOnly] public NativeArray<int> chunkOffsets;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstPathFrame> frames;
|
||||
[ReadOnly] public NativeArray<int> frameOffsets;
|
||||
[ReadOnly] public NativeArray<int> frameCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<int> vertexOffsets;
|
||||
[ReadOnly] public NativeArray<int> triangleOffsets;
|
||||
[ReadOnly] public NativeArray<int> triangleCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstLineMeshData> rendererData;
|
||||
[ReadOnly] public NativeArray<BurstPathSmootherData> pathData;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<ProceduralRopeVertex> vertices;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> tris;
|
||||
|
||||
[ReadOnly] public int firstRenderer;
|
||||
|
||||
[ReadOnly] public float3 localSpaceCamera;
|
||||
|
||||
public void Execute(int u)
|
||||
{
|
||||
int k = firstRenderer + u;
|
||||
int s = pathSmootherIndices[k];
|
||||
|
||||
float3 vertex = float3.zero;
|
||||
float3 normal = float3.zero;
|
||||
float4 bitangent = float4.zero;
|
||||
|
||||
int tri = 0;
|
||||
int sectionIndex = 0;
|
||||
int firstVertex = vertexOffsets[k];
|
||||
int firstTriangle = triangleOffsets[k];
|
||||
|
||||
float smoothLength = 0;
|
||||
for (int i = chunkOffsets[s]; i < chunkOffsets[s + 1]; ++i)
|
||||
smoothLength += pathData[i].smoothLength;
|
||||
|
||||
float vCoord = -rendererData[k].uvScale.y * pathData[chunkOffsets[s]].restLength * rendererData[k].uvAnchor;
|
||||
float actualToRestLengthRatio = smoothLength / pathData[chunkOffsets[s]].restLength;
|
||||
|
||||
// clear out triangle indices for this rope:
|
||||
for (int i = firstTriangle; i < firstTriangle + triangleCounts[k]; ++i)
|
||||
{
|
||||
int offset = i * 3;
|
||||
tris[offset] = 0;
|
||||
tris[offset+1] = 0;
|
||||
tris[offset+2] = 0;
|
||||
}
|
||||
|
||||
// for each chunk in the rope:
|
||||
for (int i = chunkOffsets[s]; i < chunkOffsets[s + 1]; ++i)
|
||||
{
|
||||
int firstFrame = frameOffsets[i];
|
||||
int frameCount = frameCounts[i];
|
||||
|
||||
for (int f = 0; f < frameCount; ++f)
|
||||
{
|
||||
// Calculate previous and next curve indices:
|
||||
int prevIndex = firstFrame + math.max(f - 1, 0);
|
||||
int index = firstFrame + f;
|
||||
|
||||
// advance v texcoord:
|
||||
vCoord += rendererData[k].uvScale.y * (math.distance(frames[index].position, frames[prevIndex].position) /
|
||||
(rendererData[k].normalizeV == 1 ? smoothLength : actualToRestLengthRatio));
|
||||
|
||||
// calculate section thickness and scale the basis vectors by it:
|
||||
float sectionThickness = frames[index].thickness * rendererData[k].thicknessScale;
|
||||
|
||||
normal.x = frames[index].position.x - localSpaceCamera.x;
|
||||
normal.y = frames[index].position.y - localSpaceCamera.y;
|
||||
normal.z = frames[index].position.z - localSpaceCamera.z;
|
||||
normal = math.normalize(normal);
|
||||
|
||||
bitangent.x = -(normal.y * frames[index].tangent.z - normal.z * frames[index].tangent.y);
|
||||
bitangent.y = -(normal.z * frames[index].tangent.x - normal.x * frames[index].tangent.z);
|
||||
bitangent.z = -(normal.x * frames[index].tangent.y - normal.y * frames[index].tangent.x);
|
||||
bitangent.xyz = math.normalize(bitangent.xyz);
|
||||
bitangent.w = 1;
|
||||
|
||||
vertex.x = frames[index].position.x - bitangent.x * sectionThickness;
|
||||
vertex.y = frames[index].position.y - bitangent.y * sectionThickness;
|
||||
vertex.z = frames[index].position.z - bitangent.z * sectionThickness;
|
||||
|
||||
vertices[firstVertex + sectionIndex * 2] = new ProceduralRopeVertex
|
||||
{
|
||||
pos = vertex,
|
||||
normal = -normal,
|
||||
tangent = bitangent,
|
||||
color = frames[index].color,
|
||||
uv = new float2(0, vCoord)
|
||||
};
|
||||
|
||||
vertex.x = frames[index].position.x + bitangent.x * sectionThickness;
|
||||
vertex.y = frames[index].position.y + bitangent.y * sectionThickness;
|
||||
vertex.z = frames[index].position.z + bitangent.z * sectionThickness;
|
||||
|
||||
vertices[firstVertex + sectionIndex * 2 + 1] = new ProceduralRopeVertex
|
||||
{
|
||||
pos = vertex,
|
||||
normal = -normal,
|
||||
tangent = bitangent,
|
||||
color = frames[index].color,
|
||||
uv = new float2(1, vCoord)
|
||||
};
|
||||
|
||||
if (f < frameCount - 1)
|
||||
{
|
||||
int offset = firstTriangle * 3;
|
||||
tris[offset + tri++] = firstVertex + sectionIndex * 2;
|
||||
tris[offset + tri++] = firstVertex + (sectionIndex + 1) * 2;
|
||||
tris[offset + tri++] = firstVertex + sectionIndex * 2 + 1;
|
||||
|
||||
tris[offset + tri++] = firstVertex + sectionIndex * 2 + 1;
|
||||
tris[offset + tri++] = firstVertex + (sectionIndex + 1) * 2;
|
||||
tris[offset + tri++] = firstVertex + (sectionIndex + 1) * 2 + 1;
|
||||
}
|
||||
|
||||
sectionIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f950cc46a13e4273856e2ec96c59eb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,272 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstMeshRopeRenderSystem : ObiMeshRopeRenderSystem
|
||||
{
|
||||
public BurstMeshRopeRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CloseBatches()
|
||||
{
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
batchList[i].Initialize(sortedRenderers, meshData, meshIndices, layout, false);
|
||||
|
||||
base.CloseBatches();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
if (pathSmootherSystem == null)
|
||||
return;
|
||||
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
var handles = new NativeArray<JobHandle>(batchList.Count, Allocator.Temp);
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
var meshJob = new BuildRopeMeshJob
|
||||
{
|
||||
chunkOffsets = pathSmootherSystem.chunkOffsets.AsNativeArray<int>(),
|
||||
pathSmootherIndices = pathSmootherIndices.AsNativeArray<int>(),
|
||||
|
||||
frames = pathSmootherSystem.smoothFrames.AsNativeArray<BurstPathFrame>(),
|
||||
frameOffsets = pathSmootherSystem.smoothFrameOffsets.AsNativeArray<int>(),
|
||||
frameCounts = pathSmootherSystem.smoothFrameCounts.AsNativeArray<int>(),
|
||||
|
||||
vertexOffsets = vertexOffsets.AsNativeArray<int>(),
|
||||
|
||||
meshIndices = meshIndices.AsNativeArray<int>(),
|
||||
meshData = meshData.meshData.AsNativeArray<MeshDataBatch.MeshData>(),
|
||||
|
||||
rendererData = rendererData.AsNativeArray<BurstMeshData>(),
|
||||
pathData = pathSmootherSystem.pathData.AsNativeArray<BurstPathSmootherData>(),
|
||||
|
||||
sortedIndices = sortedIndices.AsNativeArray<int>(),
|
||||
sortedOffsets = sortedOffsets.AsNativeArray<int>(),
|
||||
|
||||
positions = meshData.restPositions.AsNativeArray<float3>(),
|
||||
normals = meshData.restNormals.AsNativeArray<float3>(),
|
||||
tangents = meshData.restTangents.AsNativeArray<float4>(),
|
||||
colors = meshData.restColors.AsNativeArray<float4>(),
|
||||
|
||||
vertices = batch.dynamicVertexData.AsNativeArray<RopeMeshVertex>(),
|
||||
|
||||
firstRenderer = batch.firstRenderer
|
||||
|
||||
};
|
||||
handles[i] = meshJob.Schedule(batch.rendererCount, 1);
|
||||
}
|
||||
|
||||
JobHandle.CombineDependencies(handles).Complete();
|
||||
handles.Dispose();
|
||||
|
||||
for (int i = 0; i < batchList.Count; ++i)
|
||||
{
|
||||
var batch = batchList[i];
|
||||
|
||||
batch.mesh.SetVertexBufferData(batch.dynamicVertexData.AsNativeArray<DynamicBatchVertex>(), 0, 0, batch.vertexCount, 0, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds | MeshUpdateFlags.DontNotifyMeshUsers);
|
||||
|
||||
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);
|
||||
|
||||
// Unity bug: Graphics.RenderMesh consistently crashes when existing play mode (seems fixed in 2021.3.4f1)
|
||||
// https://issuetracker.unity3d.com/issues/the-editor-crashes-on-exit-when-using-graphics-dot-rendermesh
|
||||
//renderParams.material = batch.materials[m];
|
||||
//renderParams.camera = null;
|
||||
//Graphics.RenderMesh(renderParams, batch.mesh, m, m_Solver.transform.localToWorldMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct BuildRopeMeshJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> pathSmootherIndices;
|
||||
[ReadOnly] public NativeArray<int> chunkOffsets;
|
||||
[ReadOnly] public NativeArray<BurstPathFrame> frames;
|
||||
[ReadOnly] public NativeArray<int> frameOffsets;
|
||||
[ReadOnly] public NativeArray<int> frameCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<int> vertexOffsets;
|
||||
|
||||
[ReadOnly] public NativeArray<int> meshIndices;
|
||||
[ReadOnly] public NativeArray<MeshDataBatch.MeshData> meshData;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstMeshData> rendererData;
|
||||
[ReadOnly] public NativeArray<BurstPathSmootherData> pathData;
|
||||
|
||||
[ReadOnly] public NativeArray<int> sortedIndices;
|
||||
[ReadOnly] public NativeArray<int> sortedOffsets;
|
||||
|
||||
[ReadOnly] public NativeArray<float3> positions;
|
||||
[ReadOnly] public NativeArray<float3> normals;
|
||||
[ReadOnly] public NativeArray<float4> tangents;
|
||||
[ReadOnly] public NativeArray<float4> colors;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<RopeMeshVertex> vertices;
|
||||
|
||||
[ReadOnly] public int firstRenderer;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int rendererIndex = firstRenderer + i;
|
||||
int pathIndex = pathSmootherIndices[rendererIndex];
|
||||
var renderer = rendererData[rendererIndex];
|
||||
|
||||
// get mesh data:
|
||||
var mesh = meshData[meshIndices[rendererIndex]];
|
||||
var sortedOffset = sortedOffsets[rendererIndex];
|
||||
|
||||
// get index of first output vertex:
|
||||
int firstOutputVertex = vertexOffsets[rendererIndex];
|
||||
|
||||
// get index of first chunk, ignore others (no support for tearing):
|
||||
int chunkIndex = chunkOffsets[pathIndex];
|
||||
|
||||
// get first frame and frame count:
|
||||
int firstFrame = frameOffsets[chunkIndex];
|
||||
int lastFrame = firstFrame + frameCounts[chunkIndex] - 1;
|
||||
|
||||
// get mesh deform axis:
|
||||
int axis = (int)renderer.axis;
|
||||
|
||||
// initialize scale vector:
|
||||
float3 actualScale = (Vector3)renderer.scale;
|
||||
|
||||
// calculate stretch ratio:
|
||||
float stretchRatio = renderer.stretchWithRope == 1 ? pathData[chunkIndex].smoothLength / pathData[chunkIndex].restLength : 1;
|
||||
|
||||
// squashing factor, makes mesh thinner when stretched and thicker when compresssed.
|
||||
float squashing = math.clamp(1 + renderer.volumeScaling * (1 / math.max(stretchRatio, 0.01f) - 1), 0.01f, 2);
|
||||
|
||||
// calculate scale along swept axis so that the mesh spans the entire lenght of the rope if required.
|
||||
if (renderer.spanEntireLength == 1)
|
||||
{
|
||||
float totalMeshLength = renderer.meshSizeAlongAxis * renderer.instances;
|
||||
float totalSpacing = renderer.instanceSpacing * (renderer.instances - 1);
|
||||
actualScale[axis] = pathData[chunkIndex].restLength / (totalMeshLength + totalSpacing);
|
||||
}
|
||||
|
||||
// adjust axis lenght by stretch ratio:
|
||||
actualScale[axis] *= stretchRatio;
|
||||
|
||||
// init loop variables:
|
||||
float lengthAlongAxis = renderer.offset;
|
||||
int index = firstFrame;
|
||||
int nextIndex = firstFrame + 1;
|
||||
int prevIndex = firstFrame;
|
||||
float nextMagnitude = math.distance(frames[index].position, frames[nextIndex].position);
|
||||
float prevMagnitude = nextMagnitude;
|
||||
|
||||
for (int k = 0; k < renderer.instances; ++k)
|
||||
{
|
||||
for (int j = 0; j < mesh.vertexCount; ++j)
|
||||
{
|
||||
int currVIndex = mesh.firstVertex + sortedIndices[sortedOffset + j];
|
||||
int prevVIndex = mesh.firstVertex + sortedIndices[sortedOffset + math.max(0,j - 1)];
|
||||
|
||||
// calculate how much we've advanced in the sort axis since the last vertex:
|
||||
lengthAlongAxis += (positions[currVIndex][axis] - positions[prevVIndex][axis]) * actualScale[axis];
|
||||
|
||||
// check if we have moved to a new section of the curve:
|
||||
BurstPathFrame frame;
|
||||
if (lengthAlongAxis < 0)
|
||||
{
|
||||
while (-lengthAlongAxis > prevMagnitude && index > firstFrame)
|
||||
{
|
||||
lengthAlongAxis += prevMagnitude;
|
||||
index = math.max(index - 1, firstFrame);
|
||||
nextIndex = math.min(index + 1, lastFrame);
|
||||
prevIndex = math.max(index - 1, firstFrame);
|
||||
nextMagnitude = math.distance(frames[index].position, frames[nextIndex].position);
|
||||
prevMagnitude = math.distance(frames[index].position, frames[prevIndex].position);
|
||||
}
|
||||
|
||||
var offset = float3.zero;
|
||||
if (index == prevIndex)
|
||||
{
|
||||
offset = frames[index].position - frames[nextIndex].position;
|
||||
prevMagnitude = math.length(offset);
|
||||
}
|
||||
|
||||
frame = InterpolateFrames(frames[index], frames[prevIndex], offset, -lengthAlongAxis / prevMagnitude);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (lengthAlongAxis > nextMagnitude && index < lastFrame)
|
||||
{
|
||||
lengthAlongAxis -= nextMagnitude;
|
||||
index = math.min(index + 1, lastFrame);
|
||||
nextIndex = math.min(index + 1, lastFrame);
|
||||
prevIndex = math.max(index - 1, firstFrame);
|
||||
nextMagnitude = math.distance(frames[index].position, frames[nextIndex].position);
|
||||
prevMagnitude = math.distance(frames[index].position, frames[prevIndex].position);
|
||||
}
|
||||
|
||||
var offset = float3.zero;
|
||||
if (index == nextIndex)
|
||||
{
|
||||
offset = frames[index].position - frames[prevIndex].position;
|
||||
nextMagnitude = math.length(offset);
|
||||
}
|
||||
|
||||
frame = InterpolateFrames(frames[index], frames[nextIndex], offset, lengthAlongAxis / nextMagnitude);
|
||||
}
|
||||
|
||||
// update basis matrix:
|
||||
var basis = frame.ToMatrix(axis);
|
||||
|
||||
// calculate vertex offset from curve:
|
||||
float3 offsetFromCurve = positions[currVIndex] * actualScale * frame.thickness * squashing;
|
||||
offsetFromCurve[axis] = 0;
|
||||
|
||||
// write modified vertex data:
|
||||
vertices[firstOutputVertex + sortedIndices[sortedOffset + j]] = new RopeMeshVertex
|
||||
{
|
||||
pos = frame.position + math.mul(basis, offsetFromCurve),
|
||||
normal = math.mul(basis, normals[currVIndex]),
|
||||
tangent = new float4(math.mul(basis, tangents[currVIndex].xyz), tangents[currVIndex].w),
|
||||
color = colors[currVIndex] * frame.color,
|
||||
};
|
||||
}
|
||||
|
||||
firstOutputVertex += mesh.vertexCount;
|
||||
lengthAlongAxis += renderer.instanceSpacing * actualScale[axis];
|
||||
}
|
||||
}
|
||||
|
||||
BurstPathFrame InterpolateFrames(BurstPathFrame a, BurstPathFrame b, float3 bOffset, float t)
|
||||
{
|
||||
// this offset is used to displace a copy of the first and last frames of the path,
|
||||
// to ensure meshes extrude correctly prior to the first or past the last frame.
|
||||
b.position += bOffset;
|
||||
var interp = (1 - t) * a + t * b;
|
||||
|
||||
// (no need to renormalize tangent, since offsetFromCurve[axis] = 0)
|
||||
interp.normal = math.normalize(interp.normal);
|
||||
interp.binormal = math.normalize(interp.binormal);
|
||||
return interp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1578f081848d045dba76cd147f835e7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
170
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/BurstPathFrame.cs
vendored
Normal file
170
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/BurstPathFrame.cs
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BurstPathFrame
|
||||
{
|
||||
public enum Axis
|
||||
{
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2
|
||||
}
|
||||
|
||||
public float3 position;
|
||||
public float3 tangent;
|
||||
public float3 normal;
|
||||
public float3 binormal;
|
||||
public float4 color;
|
||||
public float thickness;
|
||||
|
||||
public BurstPathFrame(float3 position, float3 tangent, float3 normal, float3 binormal, float4 color, float thickness)
|
||||
{
|
||||
this.position = position;
|
||||
this.normal = normal;
|
||||
this.tangent = tangent;
|
||||
this.binormal = binormal;
|
||||
this.color = color;
|
||||
this.thickness = thickness;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
position = float3.zero;
|
||||
tangent = new float3(0, 0, 1);
|
||||
normal = new float3(0, 1, 0);
|
||||
binormal = new float3(1, 0, 0);
|
||||
color = new float4(1, 1, 1, 1);
|
||||
thickness = 0;
|
||||
}
|
||||
|
||||
public static BurstPathFrame operator +(BurstPathFrame c1, BurstPathFrame c2)
|
||||
{
|
||||
return new BurstPathFrame(c1.position + c2.position, c1.tangent + c2.tangent, c1.normal + c2.normal, c1.binormal + c2.binormal, c1.color + c2.color, c1.thickness + c2.thickness);
|
||||
}
|
||||
|
||||
public static BurstPathFrame operator *(float f, BurstPathFrame c)
|
||||
{
|
||||
return new BurstPathFrame(c.position * f, c.tangent * f, c.normal * f, c.binormal * f, c.color * f, c.thickness * f);
|
||||
}
|
||||
|
||||
public static void WeightedSum(float w1, float w2, float w3, in BurstPathFrame c1, in BurstPathFrame c2, in BurstPathFrame c3, ref BurstPathFrame sum)
|
||||
{
|
||||
sum.position.x = c1.position.x * w1 + c2.position.x * w2 + c3.position.x * w3;
|
||||
sum.position.y = c1.position.y * w1 + c2.position.y * w2 + c3.position.y * w3;
|
||||
sum.position.z = c1.position.z * w1 + c2.position.z * w2 + c3.position.z * w3;
|
||||
|
||||
sum.tangent.x = c1.tangent.x * w1 + c2.tangent.x * w2 + c3.tangent.x * w3;
|
||||
sum.tangent.y = c1.tangent.y * w1 + c2.tangent.y * w2 + c3.tangent.y * w3;
|
||||
sum.tangent.z = c1.tangent.z * w1 + c2.tangent.z * w2 + c3.tangent.z * w3;
|
||||
|
||||
sum.normal.x = c1.normal.x * w1 + c2.normal.x * w2 + c3.normal.x * w3;
|
||||
sum.normal.y = c1.normal.y * w1 + c2.normal.y * w2 + c3.normal.y * w3;
|
||||
sum.normal.z = c1.normal.z * w1 + c2.normal.z * w2 + c3.normal.z * w3;
|
||||
|
||||
sum.binormal.x = c1.binormal.x * w1 + c2.binormal.x * w2 + c3.binormal.x * w3;
|
||||
sum.binormal.y = c1.binormal.y * w1 + c2.binormal.y * w2 + c3.binormal.y * w3;
|
||||
sum.binormal.z = c1.binormal.z * w1 + c2.binormal.z * w2 + c3.binormal.z * w3;
|
||||
|
||||
sum.color.x = c1.color.x * w1 + c2.color.x * w2 + c3.color.x * w3;
|
||||
sum.color.y = c1.color.y * w1 + c2.color.y * w2 + c3.color.y * w3;
|
||||
sum.color.z = c1.color.z * w1 + c2.color.z * w2 + c3.color.z * w3;
|
||||
sum.color.w = c1.color.w * w1 + c2.color.w * w2 + c3.color.w * w3;
|
||||
|
||||
sum.thickness = c1.thickness * w1 + c2.thickness * w2 + c3.thickness * w3;
|
||||
}
|
||||
|
||||
public void SetTwist(float twist)
|
||||
{
|
||||
quaternion twistQ = quaternion.AxisAngle(tangent, math.radians(twist));
|
||||
normal = math.mul(twistQ, normal);
|
||||
binormal = math.mul(twistQ, binormal);
|
||||
}
|
||||
|
||||
public static quaternion FromToRotation(float3 aFrom, float3 aTo)
|
||||
{
|
||||
float3 axis = math.cross(aFrom, aTo);
|
||||
float angle = math.acos(math.clamp(math.dot(math.normalize(aFrom), math.normalize(aTo)), -1f, 1f));
|
||||
return quaternion.AxisAngle(math.normalize(axis), angle);
|
||||
}
|
||||
|
||||
public void SetTwistAndTangent(float twist, float3 tangent)
|
||||
{
|
||||
this.tangent = tangent;
|
||||
normal = math.normalize(new float3(tangent.y, tangent.x, 0));
|
||||
binormal = math.cross(normal, tangent);
|
||||
|
||||
quaternion twistQ = quaternion.AxisAngle(tangent, math.radians(twist));
|
||||
normal = math.mul(twistQ, normal);
|
||||
binormal = math.mul(twistQ, binormal);
|
||||
}
|
||||
|
||||
public void Transport(in BurstPathFrame frame, float twist)
|
||||
{
|
||||
// Calculate delta rotation:
|
||||
quaternion rotQ = Quaternion.FromToRotation(tangent, frame.tangent);
|
||||
quaternion twistQ = quaternion.AxisAngle(frame.tangent, math.radians(twist));
|
||||
quaternion finalQ = math.mul(twistQ, rotQ);
|
||||
|
||||
// Rotate previous frame axes to obtain the new ones:
|
||||
normal = math.mul(finalQ, normal);
|
||||
binormal = math.mul(finalQ, binormal);
|
||||
tangent = frame.tangent;
|
||||
position = frame.position;
|
||||
thickness = frame.thickness;
|
||||
color = frame.color;
|
||||
}
|
||||
|
||||
public void Transport(float3 newPosition, float3 newTangent, float twist)
|
||||
{
|
||||
// Calculate delta rotation:
|
||||
quaternion rotQ = Quaternion.FromToRotation(tangent, newTangent);
|
||||
quaternion twistQ = quaternion.AxisAngle(newTangent, math.radians(twist));
|
||||
quaternion finalQ = math.mul(twistQ, rotQ);
|
||||
|
||||
// Rotate previous frame axes to obtain the new ones:
|
||||
normal = math.mul(finalQ, normal);
|
||||
binormal = math.mul(finalQ, binormal);
|
||||
tangent = newTangent;
|
||||
position = newPosition;
|
||||
|
||||
}
|
||||
|
||||
// Transport, hinting the normal.
|
||||
public void Transport(float3 newPosition, float3 newTangent, float3 newNormal, float twist)
|
||||
{
|
||||
normal = math.mul(quaternion.AxisAngle(newTangent, math.radians(twist)), newNormal);
|
||||
tangent = newTangent;
|
||||
binormal = math.cross(normal, tangent);
|
||||
position = newPosition;
|
||||
}
|
||||
|
||||
public float3x3 ToMatrix(int mainAxis)
|
||||
{
|
||||
float3x3 basis = new float3x3();
|
||||
|
||||
int xo = (mainAxis) % 3;
|
||||
int yo = (mainAxis + 1) % 3;
|
||||
int zo = (mainAxis + 2) % 3;
|
||||
|
||||
basis[xo] = tangent;
|
||||
basis[yo] = binormal;
|
||||
basis[zo] = normal;
|
||||
|
||||
return basis;
|
||||
}
|
||||
|
||||
public void DebugDraw(float size)
|
||||
{
|
||||
Debug.DrawRay(position, binormal * size, Color.red);
|
||||
Debug.DrawRay(position, normal * size, Color.green);
|
||||
Debug.DrawRay(position, tangent * size, Color.blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
11
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/BurstPathFrame.cs.meta
vendored
Normal file
11
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/BurstPathFrame.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4827bd4bd4feb46bfbe458174871b8ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,63 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstPathSmootherRenderSystem : ObiPathSmootherRenderSystem
|
||||
{
|
||||
public BurstPathSmootherRenderSystem(ObiSolver solver) : base(solver)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
using (m_RenderMarker.Auto())
|
||||
{
|
||||
base.Render();
|
||||
|
||||
// generate raw frames using parallel transport
|
||||
var parallelTransportJob = new ParallelTransportJob
|
||||
{
|
||||
pathFrames = rawFrames.AsNativeArray<BurstPathFrame>(),
|
||||
frameOffsets = rawFrameOffsets.AsNativeArray<int>(),
|
||||
particleIndices = particleIndices.AsNativeArray<int>(),
|
||||
renderablePositions = m_Solver.renderablePositions.AsNativeArray<float4>(),
|
||||
renderableOrientations = m_Solver.renderableOrientations.AsNativeArray<quaternion>(),
|
||||
principalRadii = m_Solver.principalRadii.AsNativeArray<float4>(),
|
||||
colors = m_Solver.colors.AsNativeArray<float4>(),
|
||||
pathData = pathData.AsNativeArray<BurstPathSmootherData>()
|
||||
};
|
||||
|
||||
var handle = parallelTransportJob.Schedule(rawFrameOffsets.count, 4);
|
||||
|
||||
// throw away unneeded frames using decimation
|
||||
var decimationJob = new DecimateChunksJob
|
||||
{
|
||||
inputFrames = rawFrames.AsNativeArray<BurstPathFrame>(),
|
||||
inputFrameOffsets = rawFrameOffsets.AsNativeArray<int>(),
|
||||
outputFrameCounts = decimatedFrameCounts.AsNativeArray<int>(),
|
||||
pathData = pathData.AsNativeArray<BurstPathSmootherData>()
|
||||
};
|
||||
|
||||
handle = decimationJob.Schedule(rawFrameOffsets.count, 4, handle);
|
||||
|
||||
// smooth chunks:
|
||||
var chaikinJob = new ChaikinSmoothChunksJob()
|
||||
{
|
||||
inputFrames = rawFrames.AsNativeArray<BurstPathFrame>(),
|
||||
inputFrameOffsets = rawFrameOffsets.AsNativeArray<int>(),
|
||||
inputFrameCounts = decimatedFrameCounts.AsNativeArray<int>(),
|
||||
outputFrames = smoothFrames.AsNativeArray<BurstPathFrame>(),
|
||||
outputFrameOffsets = smoothFrameOffsets.AsNativeArray<int>(),
|
||||
outputFrameCounts = smoothFrameCounts.AsNativeArray<int>(),
|
||||
pathData = pathData.AsNativeArray<BurstPathSmootherData>()
|
||||
};
|
||||
|
||||
chaikinJob.Schedule(rawFrameOffsets.count, 4, handle).Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be61f37ff31ff43ebb9bc8a55bd3edc7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[BurstCompile]
|
||||
struct ChaikinSmoothChunksJob : IJobParallelFor
|
||||
{
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BurstPathFrame> inputFrames;
|
||||
[ReadOnly] public NativeArray<int> inputFrameOffsets;
|
||||
[ReadOnly] public NativeArray<int> inputFrameCounts;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BurstPathFrame> outputFrames;
|
||||
[ReadOnly] public NativeArray<int> outputFrameOffsets;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> outputFrameCounts;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BurstPathSmootherData> pathData;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int firstInputIndex = i > 0 ? inputFrameOffsets[i - 1] : 0;
|
||||
int inputFrameCount = inputFrameCounts[i];
|
||||
|
||||
int firstOutputIndex = outputFrameOffsets[i];
|
||||
|
||||
int k = (int)pathData[i].smoothing;
|
||||
|
||||
// No work to do. just copy the input to the output:
|
||||
if (k == 0)
|
||||
{
|
||||
outputFrameCounts[i] = inputFrameCount;
|
||||
for (int j = 0; j < inputFrameCount; ++j)
|
||||
outputFrames[firstOutputIndex + j] = inputFrames[firstInputIndex + j];
|
||||
}
|
||||
else
|
||||
{
|
||||
// precalculate some quantities:
|
||||
int pCount = (int)math.pow(2, k);
|
||||
int n0 = inputFrameCount - 1;
|
||||
float twoRaisedToMinusKPlus1 = math.pow(2, -(k + 1));
|
||||
float twoRaisedToMinusK = math.pow(2, -k);
|
||||
float twoRaisedToMinus2K = math.pow(2, -2 * k);
|
||||
float twoRaisedToMinus2KMinus1 = math.pow(2, -2 * k - 1);
|
||||
|
||||
outputFrameCounts[i] = (inputFrameCount - 2) * pCount + 2;
|
||||
|
||||
// calculate initial curve points:
|
||||
outputFrames[firstOutputIndex] = (0.5f + twoRaisedToMinusKPlus1) * inputFrames[firstInputIndex] + (0.5f - twoRaisedToMinusKPlus1) * inputFrames[firstInputIndex + 1];
|
||||
outputFrames[firstOutputIndex + pCount * n0 - pCount + 1] = (0.5f - twoRaisedToMinusKPlus1) * inputFrames[firstInputIndex + n0 - 1] + (0.5f + twoRaisedToMinusKPlus1) * inputFrames[firstInputIndex + n0];
|
||||
|
||||
// calculate internal points:
|
||||
for (int j = 1; j <= pCount; ++j)
|
||||
{
|
||||
// precalculate coefficients:
|
||||
float F = 0.5f - twoRaisedToMinusKPlus1 - (j - 1) * (twoRaisedToMinusK - j * twoRaisedToMinus2KMinus1);
|
||||
float G = 0.5f + twoRaisedToMinusKPlus1 + (j - 1) * (twoRaisedToMinusK - j * twoRaisedToMinus2K);
|
||||
float H = (j - 1) * j * twoRaisedToMinus2KMinus1;
|
||||
|
||||
for (int l = 1; l < n0; ++l)
|
||||
{
|
||||
BurstPathFrame.WeightedSum(F, G, H,
|
||||
in GetElementAsRef(inputFrames, firstInputIndex + l - 1),
|
||||
in GetElementAsRef(inputFrames, firstInputIndex + l),
|
||||
in GetElementAsRef(inputFrames, firstInputIndex + l + 1),
|
||||
ref GetElementAsRef(outputFrames, firstOutputIndex + (l - 1) * pCount + j));
|
||||
}
|
||||
}
|
||||
|
||||
// make first and last curve points coincide with original points:
|
||||
outputFrames[firstOutputIndex] = inputFrames[firstInputIndex];
|
||||
outputFrames[firstOutputIndex + outputFrameCounts[i] - 1] = inputFrames[firstInputIndex + inputFrameCount - 1];
|
||||
}
|
||||
|
||||
var data = pathData[i];
|
||||
data.smoothLength = 0;
|
||||
for (int j = firstOutputIndex + 1; j < firstOutputIndex + outputFrameCounts[i]; ++j)
|
||||
data.smoothLength += math.distance(outputFrames[j - 1].position, outputFrames[j].position);
|
||||
|
||||
pathData[i] = data;
|
||||
|
||||
}
|
||||
|
||||
private static unsafe ref T GetElementAsRef<T>(NativeArray<T> array, int index) where T : unmanaged
|
||||
{
|
||||
return ref UnsafeUtility.ArrayElementAsRef<T>(array.GetUnsafePtr(), index);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b479f3e1bd184363a9259c4d737b611
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
79
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/DecimateChunksJob.cs
vendored
Normal file
79
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/DecimateChunksJob.cs
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[BurstCompile]
|
||||
struct DecimateChunksJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> inputFrameOffsets;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BurstPathFrame> inputFrames;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> outputFrameCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstPathSmootherData> pathData;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
|
||||
int firstInputIndex = i > 0 ? inputFrameOffsets[i - 1] : 0;
|
||||
int inputFrameCount = inputFrameOffsets[i] - firstInputIndex;
|
||||
|
||||
// no decimation, no work to do, just return:
|
||||
if (pathData[i].decimation < 0.00001f || inputFrameCount < 3)
|
||||
{
|
||||
outputFrameCounts[i] = inputFrameCount;
|
||||
return;
|
||||
}
|
||||
|
||||
float scaledThreshold = pathData[i].decimation * pathData[i].decimation * 0.01f;
|
||||
|
||||
int start = 0;
|
||||
int end = inputFrameCount - 1;
|
||||
outputFrameCounts[i] = 0;
|
||||
|
||||
while (start < end)
|
||||
{
|
||||
// add starting point:
|
||||
inputFrames[firstInputIndex + outputFrameCounts[i]++] = inputFrames[firstInputIndex + start];
|
||||
|
||||
var newEnd = end;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int maxDistanceIndex = 0;
|
||||
float maxDistance = 0;
|
||||
|
||||
// find the point that's furthest away from the current segment:
|
||||
for (int k = start + 1; k < newEnd; k++)
|
||||
{
|
||||
var nearest = BurstMath.NearestPointOnEdge(inputFrames[firstInputIndex + start].position,
|
||||
inputFrames[firstInputIndex + newEnd].position,
|
||||
inputFrames[firstInputIndex + k].position, out _);
|
||||
float d = math.lengthsq(nearest - inputFrames[firstInputIndex + k].position);
|
||||
|
||||
if (d > maxDistance)
|
||||
{
|
||||
maxDistanceIndex = k;
|
||||
maxDistance = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxDistance <= scaledThreshold)
|
||||
break;
|
||||
|
||||
newEnd = maxDistanceIndex;
|
||||
}
|
||||
|
||||
start = newEnd;
|
||||
}
|
||||
|
||||
// add the last point:
|
||||
inputFrames[firstInputIndex + outputFrameCounts[i]++] = inputFrames[firstInputIndex + end];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e3177e6c6643442db096e939f5d7109
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
89
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/ParallelTransportJob.cs
vendored
Normal file
89
Assets/ThirdParty/Obi/Scripts/Common/Backends/Burst/Rendering/RopeAndRod/ParallelTransportJob.cs
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[BurstCompile]
|
||||
struct ParallelTransportJob : IJobParallelFor
|
||||
{
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BurstPathFrame> pathFrames;
|
||||
[ReadOnly] public NativeArray<int> frameOffsets;
|
||||
[ReadOnly] public NativeArray<int> particleIndices;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
[ReadOnly] public NativeArray<quaternion> renderableOrientations;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<float4> colors;
|
||||
[ReadOnly] public NativeArray<BurstPathSmootherData> pathData;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
BurstPathFrame nextFrame = new BurstPathFrame();
|
||||
BurstPathFrame currFrame = new BurstPathFrame();
|
||||
BurstPathFrame prevFrame = new BurstPathFrame();
|
||||
|
||||
nextFrame.Reset();
|
||||
currFrame.Reset();
|
||||
prevFrame.Reset();
|
||||
|
||||
int firstIndex = i > 0 ? frameOffsets[i - 1] : 0;
|
||||
int frameCount = frameOffsets[i] - firstIndex;
|
||||
|
||||
// initialize current and previous frame:
|
||||
PathFrameFromParticle(ref currFrame, particleIndices[firstIndex], pathData[i].usesOrientedParticles == 1, false);
|
||||
prevFrame = currFrame;
|
||||
|
||||
// parallel transport:
|
||||
for (int m = 1; m <= frameCount; ++m)
|
||||
{
|
||||
int index = firstIndex + math.min(m, frameCount - 1);
|
||||
int pIndex = particleIndices[index];
|
||||
|
||||
// generate curve frame from particle:
|
||||
PathFrameFromParticle(ref nextFrame, pIndex, pathData[i].usesOrientedParticles == 1);
|
||||
|
||||
if (pathData[i].usesOrientedParticles == 1)
|
||||
{
|
||||
// copy frame directly.
|
||||
prevFrame = currFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
// perform parallel transport, using forward / backward average to calculate tangent.
|
||||
// if the average is too small, reuse the previous frame tangent.
|
||||
currFrame.tangent = math.normalizesafe((currFrame.position - prevFrame.position) +
|
||||
(nextFrame.position - currFrame.position), prevFrame.tangent);
|
||||
prevFrame.Transport(currFrame, pathData[i].twist);
|
||||
}
|
||||
|
||||
// advance current frame:
|
||||
currFrame = nextFrame;
|
||||
pathFrames[firstIndex + m - 1] = prevFrame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void PathFrameFromParticle(ref BurstPathFrame frame, int particleIndex, bool useOrientedParticles, bool interpolateOrientation = false)
|
||||
{
|
||||
// Update current frame values from particles:
|
||||
frame.position = renderablePositions[particleIndex].xyz;
|
||||
frame.thickness = principalRadii[particleIndex][0];
|
||||
frame.color = colors[particleIndex];
|
||||
|
||||
// Use particle orientation if possible:
|
||||
if (useOrientedParticles)
|
||||
{
|
||||
quaternion current = renderableOrientations[particleIndex];
|
||||
quaternion previous = renderableOrientations[math.max(0, particleIndex - 1)];
|
||||
float4x4 average = (interpolateOrientation ? math.slerp(current, previous, 0.5f) : current).toMatrix();
|
||||
frame.normal = average.c1.xyz;
|
||||
frame.binormal = average.c0.xyz;
|
||||
frame.tangent = average.c2.xyz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c4018fb5d53646be9ef6c91f07c7eb6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user