forked from BilalY/Rasagar
1224 lines
60 KiB
C#
1224 lines
60 KiB
C#
using System;
|
|
using UnityEngine.Rendering;
|
|
using System.Collections.Generic;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
using UnityEngine.Experimental.Rendering;
|
|
|
|
namespace UnityEngine.VFX.SDF
|
|
{
|
|
/// <summary>
|
|
/// This class allows to bake Signed Distance Fields from Meshes, and holds the necessary data to perform this operation.
|
|
/// </summary>
|
|
public class MeshToSDFBaker : IDisposable
|
|
{
|
|
private RenderTexture[] m_RayMaps, m_SignMaps;
|
|
private RenderTexture[] m_RenderTextureViews;
|
|
private GraphicsBuffer m_CounterBuffer, m_AccumCounterBuffer, m_TrianglesInVoxels, m_TrianglesUV;
|
|
private GraphicsBuffer
|
|
m_TmpBuffer,
|
|
m_AccumSumBlocks,
|
|
m_SumBlocksBuffer,
|
|
m_InSumBlocksBuffer,
|
|
m_SumBlocksAdditional;
|
|
|
|
private GraphicsBuffer
|
|
m_IndicesBuffer,
|
|
m_VerticesBuffer,
|
|
m_VerticesOutBuffer,
|
|
m_CoordFlipBuffer,
|
|
m_AabbBuffer;
|
|
|
|
private int m_VertexBufferOffset;
|
|
private int m_ThreadGroupSize = 512;
|
|
private int m_SignPassesCount;
|
|
private float m_InOutThreshold;
|
|
private Material[] m_Material;
|
|
private Matrix4x4[] m_WorldToClip, m_ProjMat, m_ViewMat;
|
|
private int m_nStepsJFA;
|
|
private Kernels m_Kernels;
|
|
private Mesh m_Mesh;
|
|
private RenderTexture m_textureVoxel, m_textureVoxelBis, m_DistanceTexture;
|
|
private GraphicsBuffer m_bufferVoxel;
|
|
private ComputeShader m_computeShader;
|
|
private int m_maxResolution;
|
|
private float m_MaxExtent;
|
|
private float m_SdfOffset;
|
|
private int nTriangles;
|
|
private Vector3 m_SizeBox, m_Center;
|
|
private CommandBuffer m_Cmd;
|
|
private bool m_OwnsCommandBuffer = true;
|
|
private bool m_IsDisposed = false;
|
|
private int[] m_Dimensions = new int[3];
|
|
private int[] m_OffsetRayMap = new int[3];
|
|
private float[] m_MinBoundsExtended = new float[3];
|
|
private float[] m_MaxBoundsExtended = new float[3];
|
|
|
|
private int m_RayMapUseCounter = 0;
|
|
|
|
internal static uint kMaxRecommandedGridSize = 1 << 24;
|
|
internal static uint kMaxAbsoluteGridSize = 1 << 27;
|
|
|
|
//TODO: Use PLATFORM_UAVS_SEPARATE_TO_RTS (or equivalent) when it will be available
|
|
#if (UNITY_PS4 || UNITY_PS5) && (!UNITY_EDITOR)
|
|
private static int kNbActualRT = 1;
|
|
#else
|
|
private static int kNbActualRT = 0;
|
|
#endif
|
|
|
|
internal VFXRuntimeResources m_RuntimeResources;
|
|
|
|
/// <summary>
|
|
/// Returns the texture containing the baked Signed Distance Field
|
|
/// </summary>
|
|
public RenderTexture SdfTexture => m_DistanceTexture;
|
|
|
|
private static Mesh InitMeshFromList(List<Mesh> meshes, List<Matrix4x4> transforms)
|
|
{
|
|
int nMeshes = meshes.Count;
|
|
if (nMeshes != transforms.Count)
|
|
throw new ArgumentException("The number of meshes must be the same as the number of transforms");
|
|
List<CombineInstance> combine = new List<CombineInstance>();
|
|
for (var i = 0; i < nMeshes; i++)
|
|
{
|
|
Mesh mesh = meshes[i];
|
|
for (int j = 0; j < mesh.subMeshCount; j++)
|
|
{
|
|
CombineInstance comb = new CombineInstance();
|
|
comb.mesh = meshes[i];
|
|
comb.subMeshIndex = j;
|
|
comb.transform = transforms[i];
|
|
combine.Add(comb);
|
|
}
|
|
}
|
|
|
|
Mesh outMesh = new Mesh();
|
|
outMesh.indexFormat = IndexFormat.UInt32;
|
|
outMesh.CombineMeshes(combine.ToArray());
|
|
return outMesh;
|
|
}
|
|
|
|
private void InitCommandBuffer()
|
|
{
|
|
if (m_Cmd == null)
|
|
{
|
|
m_Cmd = new CommandBuffer
|
|
{
|
|
name = "SDFBakingCommand"
|
|
};
|
|
}
|
|
}
|
|
|
|
private int GetTotalVoxelCount()
|
|
{
|
|
return m_Dimensions[0] * m_Dimensions[1] * m_Dimensions[2];
|
|
}
|
|
|
|
private void InitSizeBox()
|
|
{
|
|
m_MaxExtent = Mathf.Max(m_SizeBox.x, Mathf.Max(m_SizeBox.y, m_SizeBox.z));
|
|
float voxelSize = 0;
|
|
if (m_MaxExtent == m_SizeBox.x)
|
|
{
|
|
m_Dimensions[0] = Mathf.Max(Mathf.RoundToInt(m_maxResolution * m_SizeBox.x / m_MaxExtent), 1);
|
|
m_Dimensions[1] = Mathf.Max(Mathf.CeilToInt(m_maxResolution * m_SizeBox.y / m_MaxExtent), 1);
|
|
m_Dimensions[2] = Mathf.Max(Mathf.CeilToInt(m_maxResolution * m_SizeBox.z / m_MaxExtent), 1);
|
|
voxelSize = m_MaxExtent / m_Dimensions[0];
|
|
}
|
|
else if (m_MaxExtent == m_SizeBox.y)
|
|
{
|
|
m_Dimensions[1] = Mathf.Max(Mathf.RoundToInt(m_maxResolution * m_SizeBox.y / m_MaxExtent), 1);
|
|
m_Dimensions[0] = Mathf.Max(Mathf.CeilToInt(m_maxResolution * m_SizeBox.x / m_MaxExtent), 1);
|
|
m_Dimensions[2] = Mathf.Max(Mathf.CeilToInt(m_maxResolution * m_SizeBox.z / m_MaxExtent), 1);
|
|
voxelSize = m_MaxExtent / m_Dimensions[1];
|
|
}
|
|
else if (m_MaxExtent == m_SizeBox.z)
|
|
{
|
|
m_Dimensions[2] = Mathf.Max(Mathf.RoundToInt(m_maxResolution * m_SizeBox.z / m_MaxExtent), 1);
|
|
m_Dimensions[1] = Mathf.Max(Mathf.CeilToInt(m_maxResolution * m_SizeBox.y / m_MaxExtent), 1);
|
|
m_Dimensions[0] = Mathf.Max(Mathf.CeilToInt(m_maxResolution * m_SizeBox.x / m_MaxExtent), 1);
|
|
voxelSize = m_MaxExtent / m_Dimensions[2];
|
|
}
|
|
|
|
if (GetTotalVoxelCount() > kMaxAbsoluteGridSize)
|
|
{
|
|
throw new ArgumentException(
|
|
$"The size of the voxel grid is too big (>2^{Mathf.Log(kMaxAbsoluteGridSize, 2)}), reduce the resolution, or provide a thinner bounding box.");
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
m_SizeBox[i] = m_Dimensions[i] * voxelSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the dimensions of the baked texture.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A Vector3Int containing the height, width and depth of the texture.
|
|
/// </returns>
|
|
public Vector3Int GetGridSize()
|
|
{
|
|
return new Vector3Int(m_Dimensions[0], m_Dimensions[1], m_Dimensions[2]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the size of the baking box used.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A Vector3 containing the size of the box along the three directions of space
|
|
/// </returns>
|
|
public Vector3 GetActualBoxSize()
|
|
{
|
|
return m_SizeBox;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor of the class MeshToSDFBaker.
|
|
/// </summary>
|
|
/// <param name="sizeBox">The desired size of the baking box.</param>
|
|
/// <param name="center">The center of the baking box.</param>
|
|
/// <param name="maxRes">The resolution along the largest dimension.</param>
|
|
/// <param name="mesh">The Mesh to be baked into an SDF.</param>
|
|
/// <param name="signPassesCount">The number of refinement passes on the sign of the SDF. This should stay below 20.</param>
|
|
/// <param name="threshold">The threshold controlling which voxels will be considered inside or outside of the surface.</param>
|
|
/// <param name="sdfOffset">The Offset to add to the SDF. It can be used to make the SDF more bulky or skinny.</param>
|
|
/// <param name="cmd">The CommandBuffer on which the baking process will be added.</param>
|
|
public MeshToSDFBaker(Vector3 sizeBox,
|
|
Vector3 center,
|
|
int maxRes,
|
|
Mesh mesh,
|
|
int signPassesCount = 1,
|
|
float threshold = 0.5f,
|
|
float sdfOffset = 0.0f,
|
|
CommandBuffer cmd = null)
|
|
{
|
|
LoadRuntimeResources();
|
|
m_Mesh = mesh;
|
|
if (cmd != null)
|
|
{
|
|
m_Cmd = cmd;
|
|
m_OwnsCommandBuffer = false;
|
|
}
|
|
SetParameters(sizeBox, center, maxRes, signPassesCount, threshold, sdfOffset);
|
|
Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor of the class MeshToSDFBaker.
|
|
/// </summary>
|
|
/// <param name="sizeBox">The desired size of the baking box</param>
|
|
/// <param name="center">The center of the baking box.</param>
|
|
/// <param name="maxRes">The resolution along the largest dimension.</param>
|
|
/// <param name="meshes">The list of meshes to be baked into an SDF.</param>
|
|
/// <param name="transforms">The list of transforms of the meshes.</param>
|
|
/// <param name="signPassesCount">The number of refinement passes on the sign of the SDF. This should stay below 20.</param>
|
|
/// <param name="threshold">The threshold controlling which voxels will be considered inside or outside of the surface.</param>
|
|
/// <param name="sdfOffset">The Offset to add to the SDF. It can be used to make the SDF more bulky or skinny.</param>
|
|
/// <param name="cmd">The CommandBuffer on which the baking process will be added.</param>
|
|
public MeshToSDFBaker(Vector3 sizeBox,
|
|
Vector3 center,
|
|
int maxRes,
|
|
List<Mesh> meshes,
|
|
List<Matrix4x4> transforms,
|
|
int signPassesCount = 1,
|
|
float threshold = 0.5f,
|
|
float sdfOffset = 0.0f,
|
|
CommandBuffer cmd = null) :
|
|
this(sizeBox, center, maxRes, InitMeshFromList(meshes, transforms), signPassesCount, threshold, sdfOffset, cmd)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// This finalizer should never be called. Dispose() should be called explicitly when an MeshToSDFBaker instance is finished being used.
|
|
/// </summary>
|
|
~MeshToSDFBaker()
|
|
{
|
|
if (!m_IsDisposed)
|
|
{
|
|
Debug.LogWarning("Dispose() should be called explicitly when an MeshToSDFBaker instance is finished being used.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reinitialize the baker with the new mesh and provided parameters.
|
|
/// </summary>
|
|
/// <param name="sizeBox">The desired size of the baking box.</param>
|
|
/// <param name="center">The center of the baking box.</param>
|
|
/// <param name="maxRes">The resolution along the largest dimension.</param>
|
|
/// <param name="mesh">The Mesh to be baked into an SDF.</param>
|
|
/// <param name="signPassesCount">The number of refinement passes on the sign of the SDF. This should stay below 20.</param>
|
|
/// <param name="threshold">The threshold controlling which voxels will be considered inside or outside of the surface.</param>
|
|
/// <param name="sdfOffset">The Offset to add to the SDF. It can be used to make the SDF more bulky or skinny.</param>
|
|
public void Reinit(Vector3 sizeBox,
|
|
Vector3 center,
|
|
int maxRes,
|
|
Mesh mesh,
|
|
int signPassesCount = 1,
|
|
float threshold = 0.5f,
|
|
float sdfOffset = 0.0f)
|
|
{
|
|
m_Mesh = mesh;
|
|
SetParameters(sizeBox, center, maxRes, signPassesCount, threshold, sdfOffset);
|
|
Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reinitialize the baker with the new lists of meshes and transforms, and provided parameters.
|
|
/// </summary>
|
|
/// <param name="sizeBox">The desired size of the baking box</param>
|
|
/// <param name="center">The center of the baking box.</param>
|
|
/// <param name="maxRes">The resolution along the largest dimension.</param>
|
|
/// <param name="meshes">The list of meshes to be baked into an SDF.</param>
|
|
/// <param name="transforms">The list of transforms of the meshes.</param>
|
|
/// <param name="signPassesCount">The number of refinement passes on the sign of the SDF. This should stay below 20.</param>
|
|
/// <param name="threshold">The threshold controlling which voxels will be considered inside or outside of the surface.</param>
|
|
/// <param name="sdfOffset">The Offset to add to the SDF. It can be used to make the SDF more bulky or skinny.</param>
|
|
public void Reinit(Vector3 sizeBox,
|
|
Vector3 center,
|
|
int maxRes,
|
|
List<Mesh> meshes,
|
|
List<Matrix4x4> transforms,
|
|
int signPassesCount = 1,
|
|
float threshold = 0.5f,
|
|
float sdfOffset = 0.0f)
|
|
{
|
|
Reinit(sizeBox, center, maxRes, InitMeshFromList(meshes, transforms), signPassesCount, threshold, sdfOffset);
|
|
}
|
|
|
|
private void SetParameters(Vector3 sizeBox, Vector3 center, int maxRes, int signPassesCount, float threshold, float sdfOffset)
|
|
{
|
|
if (m_SignPassesCount >= 20)
|
|
{
|
|
throw new ArgumentException("The signPassCount argument should be smaller than 20.");
|
|
}
|
|
m_SignPassesCount = signPassesCount;
|
|
m_InOutThreshold = threshold;
|
|
m_SdfOffset = sdfOffset;
|
|
m_Center = center;
|
|
m_SizeBox = sizeBox;
|
|
m_maxResolution = maxRes;
|
|
}
|
|
private void LoadRuntimeResources()
|
|
{
|
|
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3)
|
|
{
|
|
Debug.LogWarning("MeshToSDFBaker compute shaders are not supported on OpenGLES3");
|
|
}
|
|
|
|
m_RuntimeResources = VFXRuntimeResources.runtimeResources;
|
|
if (m_RuntimeResources == null)
|
|
{
|
|
throw new InvalidOperationException("VFX Runtime Resources could not be loaded.");
|
|
}
|
|
}
|
|
|
|
void InitTextures()
|
|
{
|
|
RenderTextureDescriptor rtDesc4Channels = new RenderTextureDescriptor
|
|
{
|
|
graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat,
|
|
dimension = TextureDimension.Tex3D,
|
|
enableRandomWrite = true,
|
|
width = m_Dimensions[0],
|
|
height = m_Dimensions[1],
|
|
volumeDepth = m_Dimensions[2],
|
|
msaaSamples = 1,
|
|
};
|
|
RenderTextureDescriptor rtDesc1Channel = new RenderTextureDescriptor
|
|
{
|
|
graphicsFormat = GraphicsFormat.R16_SFloat,
|
|
dimension = TextureDimension.Tex3D,
|
|
enableRandomWrite = true,
|
|
width = m_Dimensions[0],
|
|
height = m_Dimensions[1],
|
|
volumeDepth = m_Dimensions[2],
|
|
msaaSamples = 1,
|
|
};
|
|
|
|
RenderTextureDescriptor rtDescSignMap = new RenderTextureDescriptor
|
|
{
|
|
graphicsFormat = GraphicsFormat.R32_SFloat,
|
|
dimension = TextureDimension.Tex3D,
|
|
enableRandomWrite = true,
|
|
width = m_Dimensions[0],
|
|
height = m_Dimensions[1],
|
|
volumeDepth = m_Dimensions[2],
|
|
msaaSamples = 1,
|
|
};
|
|
|
|
CreateRenderTextureIfNeeded(ref m_textureVoxel, rtDesc4Channels);
|
|
CreateRenderTextureIfNeeded(ref m_textureVoxelBis, rtDesc4Channels);
|
|
|
|
if(m_RayMaps == null)
|
|
m_RayMaps = new RenderTexture[2];
|
|
if(m_SignMaps == null)
|
|
m_SignMaps = new RenderTexture[2];
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
CreateRenderTextureIfNeeded(ref m_RayMaps[i], rtDesc4Channels);
|
|
CreateRenderTextureIfNeeded(ref m_SignMaps[i], rtDescSignMap);
|
|
}
|
|
|
|
CreateRenderTextureIfNeeded(ref m_DistanceTexture, rtDesc1Channel);
|
|
CreateGraphicsBufferIfNeeded(ref m_bufferVoxel, GetTotalVoxelCount(), 4 * sizeof(float));
|
|
InitPrefixSumBuffers();
|
|
}
|
|
|
|
void Init()
|
|
{
|
|
m_Mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
|
|
m_Mesh.indexBufferTarget |= GraphicsBuffer.Target.Raw;
|
|
|
|
InitSizeBox();
|
|
InitCommandBuffer();
|
|
|
|
m_ThreadGroupSize = 512; //TODO call the proper system function
|
|
|
|
m_computeShader = m_RuntimeResources.sdfRayMapCS;
|
|
|
|
if (m_computeShader == null)
|
|
{
|
|
throw new InvalidOperationException("VFX Runtime Resources could not be loaded correctly.");
|
|
}
|
|
if (m_Kernels == null)
|
|
m_Kernels = new Kernels(m_computeShader);
|
|
InitTextures();
|
|
|
|
RenderTextureDescriptor rtDesc = new RenderTextureDescriptor();
|
|
rtDesc.width = m_Dimensions[0];
|
|
rtDesc.height = m_Dimensions[1];
|
|
rtDesc.graphicsFormat = GraphicsFormat.R8G8B8A8_SRGB;
|
|
rtDesc.volumeDepth = 1;
|
|
rtDesc.msaaSamples = 1;
|
|
rtDesc.dimension = TextureDimension.Tex2D;
|
|
if (m_RenderTextureViews == null)
|
|
m_RenderTextureViews = new RenderTexture[3];
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
rtDesc.width = m_Dimensions[0];
|
|
rtDesc.height = m_Dimensions[1];
|
|
CreateRenderTextureIfNeeded(ref m_RenderTextureViews[i], rtDesc);
|
|
break;
|
|
case 1:
|
|
rtDesc.width = m_Dimensions[2];
|
|
rtDesc.height = m_Dimensions[0];
|
|
CreateRenderTextureIfNeeded(ref m_RenderTextureViews[i], rtDesc);
|
|
break;
|
|
case 2:
|
|
rtDesc.width = m_Dimensions[1];
|
|
rtDesc.height = m_Dimensions[2];
|
|
CreateRenderTextureIfNeeded(ref m_RenderTextureViews[i], rtDesc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_Material == null || m_Material[0] == null || m_Material[1] == null || m_Material[2] == null)
|
|
{
|
|
m_Material = new Material[3];
|
|
Shader rayMapShader = m_RuntimeResources.sdfRayMapShader;
|
|
if (rayMapShader == null)
|
|
{
|
|
throw new InvalidOperationException("VFX Runtime Resources could not be loaded correctly.");
|
|
}
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
m_Material[i] = new Material(rayMapShader);
|
|
}
|
|
}
|
|
|
|
if (m_WorldToClip == null)
|
|
{
|
|
m_WorldToClip = new Matrix4x4[3];
|
|
}
|
|
if (m_ProjMat == null)
|
|
{
|
|
m_ProjMat = new Matrix4x4[3];
|
|
}
|
|
if (m_ViewMat == null)
|
|
{
|
|
m_ViewMat = new Matrix4x4[3];
|
|
}
|
|
UpdateCameras();
|
|
}
|
|
|
|
void UpdateCameras()
|
|
{
|
|
Vector3 pos = m_Center + Vector3.back * (m_SizeBox.z * 0.5f + 1f);
|
|
Quaternion rot = Quaternion.identity;
|
|
float near = 1.0f;
|
|
float far = near + m_SizeBox.z;
|
|
m_WorldToClip[0] = ComputeOrthographicWorldToClip(pos, rot, m_SizeBox.x, m_SizeBox.y, near, far, out m_ProjMat[0], out m_ViewMat[0]);
|
|
|
|
pos = m_Center + Vector3.down * (m_SizeBox.y * 0.5f + 1f);
|
|
rot = Quaternion.Euler(-90, -90, 0);
|
|
far = near + m_SizeBox.y;
|
|
m_WorldToClip[1] = ComputeOrthographicWorldToClip(pos, rot, m_SizeBox.z, m_SizeBox.x, near, far, out m_ProjMat[1], out m_ViewMat[1]);
|
|
|
|
pos = m_Center + Vector3.left * (m_SizeBox.x * 0.5f + 1f);
|
|
rot = Quaternion.Euler(0, 90, 90);
|
|
far = near + m_SizeBox.x;
|
|
m_WorldToClip[2] = ComputeOrthographicWorldToClip(pos, rot, m_SizeBox.y, m_SizeBox.z, near, far, out m_ProjMat[2], out m_ViewMat[2]);
|
|
}
|
|
|
|
Matrix4x4 ComputeOrthographicWorldToClip(Vector3 pos, Quaternion rot, float width, float height, float near, float far, out Matrix4x4 proj, out Matrix4x4 view)
|
|
{
|
|
proj = Matrix4x4.Ortho(-width / 2, width / 2, -height / 2, height / 2, near, far);
|
|
proj = GL.GetGPUProjectionMatrix(proj, false);
|
|
view = Matrix4x4.TRS(pos, rot, new Vector3(1, 1, -1)).inverse;
|
|
return proj * view;
|
|
}
|
|
|
|
int iDivUp(int a, int b)
|
|
{
|
|
return (a % b != 0) ? (a / b + 1) : (a / b);
|
|
}
|
|
|
|
Vector2Int GetThreadGroupsCount(int nbThreads, int threadCountPerGroup)
|
|
{
|
|
Vector2Int r = Vector2Int.zero;
|
|
int nbGroupNeeded = (nbThreads + threadCountPerGroup - 1) / threadCountPerGroup;
|
|
r.y = 1 + (nbGroupNeeded / 0xffff); //0xffff is maximal number of group of DX11 : D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION
|
|
r.x = nbGroupNeeded / r.y;
|
|
return r;
|
|
}
|
|
|
|
void PrefixSumCount()
|
|
{
|
|
int nVoxels = GetTotalVoxelCount();
|
|
|
|
m_Cmd.BeginSample("BakeSDF.PrefixSum");
|
|
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.numElem, nVoxels);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.inBucketSum, ShaderProperties.inputBuffer, m_CounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.inBucketSum, ShaderProperties.resultBuffer, m_TmpBuffer);
|
|
Vector2Int dispatchSize = GetThreadGroupsCount(nVoxels, m_ThreadGroupSize);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.dispatchWidth, dispatchSize.x);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.inBucketSum,
|
|
dispatchSize.x, dispatchSize.y, 1);
|
|
|
|
|
|
int nBlocks = iDivUp(nVoxels, m_ThreadGroupSize);
|
|
if (nBlocks > m_ThreadGroupSize) //If the number of cells is bigger than m_ThreadGroupSize^2, (512^2, 64^3), apply prefix sum recursively
|
|
{
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.toBlockSumBuffer, ShaderProperties.inputCounter, m_CounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.toBlockSumBuffer, ShaderProperties.inputBuffer, m_TmpBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.toBlockSumBuffer, ShaderProperties.resultBuffer, m_SumBlocksBuffer);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.toBlockSumBuffer,
|
|
Mathf.CeilToInt((float)nVoxels / (m_ThreadGroupSize * m_ThreadGroupSize)), 1, 1);
|
|
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.numElem, nBlocks);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.inBucketSum, ShaderProperties.inputBuffer, m_SumBlocksBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.inBucketSum, ShaderProperties.resultBuffer, m_InSumBlocksBuffer);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.inBucketSum,
|
|
Mathf.CeilToInt((float)nVoxels / (m_ThreadGroupSize * m_ThreadGroupSize)), 1, 1);
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.blockSums, ShaderProperties.inputCounter, m_SumBlocksBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.blockSums, ShaderProperties.inputBuffer, m_InSumBlocksBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.blockSums, ShaderProperties.resultBuffer, m_SumBlocksAdditional);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.blockSums,
|
|
Mathf.CeilToInt((float)nVoxels / (m_ThreadGroupSize * m_ThreadGroupSize * m_ThreadGroupSize)), 1, 1);
|
|
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.exclusive, 0);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.inputBuffer, m_InSumBlocksBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.auxBuffer, m_SumBlocksAdditional);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.inputCounter, m_SumBlocksBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.resultBuffer, m_AccumSumBlocks);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.finalSum,
|
|
Mathf.CeilToInt((float)nVoxels / (m_ThreadGroupSize * m_ThreadGroupSize)), 1, 1);
|
|
}
|
|
else
|
|
{
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.blockSums, ShaderProperties.inputCounter, m_CounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.blockSums, ShaderProperties.inputBuffer, m_TmpBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.blockSums, ShaderProperties.resultBuffer, m_AccumSumBlocks);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.blockSums,
|
|
Mathf.CeilToInt((float)nVoxels / (m_ThreadGroupSize * m_ThreadGroupSize)), 1, 1);
|
|
}
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.numElem, nVoxels);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.exclusive, 0);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.inputBuffer, m_TmpBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.auxBuffer, m_AccumSumBlocks);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.inputCounter, m_CounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.finalSum, ShaderProperties.resultBuffer, m_AccumCounterBuffer);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.finalSum,
|
|
dispatchSize.x, dispatchSize.y, 1);
|
|
m_Cmd.EndSample("BakeSDF.PrefixSum");
|
|
}
|
|
|
|
void SurfaceClosing()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.SurfaceClosing");
|
|
if (m_SignPassesCount == 0)
|
|
{
|
|
m_InOutThreshold *= 6.0f;
|
|
}
|
|
m_Cmd.SetComputeFloatParam(m_computeShader, ShaderProperties.threshold, m_InOutThreshold);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.surfaceClosing, ShaderProperties.signMap, GetSignMapPrincipal(m_SignPassesCount));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.surfaceClosing, ShaderProperties.voxelsTexture, GetTextureVoxelPrincipal(0));
|
|
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.surfaceClosing, iDivUp(m_Dimensions[0], 4), iDivUp(m_Dimensions[1], 4), iDivUp(m_Dimensions[2], 4));
|
|
m_Cmd.EndSample("BakeSDF.SurfaceClosing");
|
|
}
|
|
|
|
RenderTexture GetTextureVoxelPrincipal(int step)
|
|
{
|
|
if (step % 2 == 0)
|
|
{
|
|
return m_textureVoxel;
|
|
}
|
|
else
|
|
{
|
|
return m_textureVoxelBis;
|
|
}
|
|
}
|
|
|
|
RenderTexture GetTextureVoxelBis(int step)
|
|
{
|
|
if (step % 2 == 0)
|
|
{
|
|
return m_textureVoxelBis;
|
|
}
|
|
else
|
|
{
|
|
return m_textureVoxel;
|
|
}
|
|
}
|
|
|
|
void JFA()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.JFA");
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.toTextureNormalized, ShaderProperties.voxelsBuffer, m_bufferVoxel);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.toTextureNormalized, ShaderProperties.voxelsTexture, GetTextureVoxelPrincipal(0));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.toTextureNormalized, Mathf.CeilToInt(m_Dimensions[0] / 4.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 4.0f), Mathf.CeilToInt(m_Dimensions[2] / 4.0f));
|
|
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.jfa, ShaderProperties.voxelsTexture, GetTextureVoxelPrincipal(0), 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.jfa, ShaderProperties.voxelsTmpTexture, GetTextureVoxelBis(0), 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.copyTextures, ShaderProperties.voxelsTexture, GetTextureVoxelPrincipal(0), 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.copyTextures, ShaderProperties.voxelsTmpTexture, GetTextureVoxelBis(0), 0);
|
|
|
|
// 1+JFA
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.offset, 1);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.jfa, Mathf.CeilToInt(m_Dimensions[0] / 4.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 4.0f), Mathf.CeilToInt(m_Dimensions[2] / 4.0f));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.copyTextures, Mathf.CeilToInt(m_Dimensions[0] / 4.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 4.0f), Mathf.CeilToInt(m_Dimensions[2] / 4.0f));
|
|
|
|
m_nStepsJFA = Mathf.CeilToInt(Mathf.Log(m_maxResolution, 2));
|
|
for (int level = 1; level <= m_nStepsJFA; level++)
|
|
{
|
|
int offset = Mathf.FloorToInt(Mathf.Pow(2, m_nStepsJFA - level) + 0.5f);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.offset, offset);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.jfa, ShaderProperties.voxelsTexture, GetTextureVoxelPrincipal(level), 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.jfa, ShaderProperties.voxelsTmpTexture, GetTextureVoxelBis(level), 0);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.jfa, Mathf.CeilToInt(m_Dimensions[0] / 4.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 4.0f), Mathf.CeilToInt(m_Dimensions[2] / 4.0f));
|
|
}
|
|
m_Cmd.EndSample("BakeSDF.JFA");
|
|
}
|
|
|
|
void GenerateRayMap()
|
|
{
|
|
m_RayMapUseCounter = 0;
|
|
m_Cmd.BeginSample("BakeSDF.Raymap");
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.generateRayMapLocal, ShaderProperties.accumCounter, m_AccumCounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.generateRayMapLocal, ShaderProperties.triangleIDs, m_TrianglesInVoxels);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.generateRayMapLocal, ShaderProperties.trianglesUV, m_TrianglesUV);
|
|
|
|
m_Cmd.BeginSample("BakeSDF.LocalRaymap");
|
|
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
m_OffsetRayMap[0] = i & 1;
|
|
m_OffsetRayMap[1] = (i & 2) >> 1;
|
|
m_OffsetRayMap[2] = (i & 4) >> 2;
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.generateRayMapLocal, ShaderProperties.rayMap, GetRayMapPrincipal(m_RayMapUseCounter));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.generateRayMapLocal, ShaderProperties.rayMapTmp, GetRayMapBis(m_RayMapUseCounter));
|
|
m_Cmd.SetComputeIntParams(m_computeShader, ShaderProperties.offsetRayMap, m_OffsetRayMap);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.generateRayMapLocal,
|
|
Mathf.CeilToInt(m_Dimensions[0] / (2.0f * 4.0f)),
|
|
Mathf.CeilToInt(m_Dimensions[1] / (2.0f * 4.0f)),
|
|
Mathf.CeilToInt(m_Dimensions[2] / (2.0f * 4.0f)));
|
|
m_RayMapUseCounter++;
|
|
}
|
|
|
|
m_Cmd.EndSample("BakeSDF.LocalRaymap");
|
|
|
|
m_Cmd.BeginSample("BakeSDF.GlobalRaymap");
|
|
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.rayMapScanX, ShaderProperties.rayMap, GetRayMapPrincipal(m_RayMapUseCounter));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.rayMapScanX, ShaderProperties.rayMapTmp, GetRayMapBis(m_RayMapUseCounter));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.rayMapScanX,
|
|
1,
|
|
Mathf.CeilToInt(m_Dimensions[1] / 8.0f),
|
|
Mathf.CeilToInt(m_Dimensions[2] / 8.0f));
|
|
m_RayMapUseCounter++;
|
|
|
|
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.rayMapScanY, ShaderProperties.rayMap, GetRayMapPrincipal(m_RayMapUseCounter));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.rayMapScanY, ShaderProperties.rayMapTmp, GetRayMapBis(m_RayMapUseCounter));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.rayMapScanY,
|
|
Mathf.CeilToInt(m_Dimensions[0] / 8.0f),
|
|
1,
|
|
Mathf.CeilToInt(m_Dimensions[2] / 8.0f));
|
|
m_RayMapUseCounter++;
|
|
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.rayMapScanZ, ShaderProperties.rayMap, GetRayMapPrincipal(m_RayMapUseCounter));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.rayMapScanZ, ShaderProperties.rayMapTmp, GetRayMapBis(m_RayMapUseCounter));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.rayMapScanZ,
|
|
Mathf.CeilToInt(m_Dimensions[0] / 8.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 8.0f),
|
|
1);
|
|
m_Cmd.EndSample("BakeSDF.GlobalRaymap");
|
|
|
|
m_Cmd.EndSample("BakeSDF.Raymap");
|
|
}
|
|
|
|
RenderTexture GetRayMapPrincipal(int step) { return m_RayMaps[step % 2]; }
|
|
RenderTexture GetRayMapBis(int step) { return m_RayMaps[(step+1) % 2]; }
|
|
RenderTexture GetSignMapPrincipal(int step) { return m_SignMaps[step % 2]; }
|
|
RenderTexture GetSignMapBis(int step) { return m_SignMaps[(step+1) % 2]; }
|
|
|
|
void SignPass()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.SignPass");
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.signPass6Rays, ShaderProperties.rayMap, GetRayMapPrincipal(m_RayMapUseCounter));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.signPass6Rays, ShaderProperties.signMap, GetSignMapPrincipal(0));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.signPass6Rays, Mathf.CeilToInt(m_Dimensions[0] / 4.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 4.0f), Mathf.CeilToInt(m_Dimensions[2] / 4.0f));
|
|
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.signPassNeighbors, ShaderProperties.rayMap, GetRayMapPrincipal(m_RayMapUseCounter));
|
|
int neighboursCount = 8;
|
|
float normalizeFactor = 6.0f;
|
|
m_Cmd.SetComputeFloatParam(m_computeShader, ShaderProperties.normalizeFactor, normalizeFactor);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.numNeighbours, neighboursCount);
|
|
|
|
int signPasses = m_SignPassesCount;
|
|
for (int i = 1; i <= signPasses; i++)
|
|
{
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.passId, i);
|
|
m_Cmd.SetComputeFloatParam(m_computeShader, ShaderProperties.normalizeFactor, normalizeFactor);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.signPassNeighbors, ShaderProperties.signMap, GetSignMapPrincipal(i));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.signPassNeighbors, ShaderProperties.signMapTmp, GetSignMapBis(i));
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.needNormalize, (i == signPasses) ? 1 : 0);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.signPassNeighbors, Mathf.CeilToInt(m_Dimensions[0] / 4.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 4.0f), Mathf.CeilToInt(m_Dimensions[2] / 4.0f));
|
|
normalizeFactor = normalizeFactor + neighboursCount * 6 * normalizeFactor;
|
|
}
|
|
|
|
m_Cmd.EndSample("BakeSDF.SignPass");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs the baking operation. After this function is called, the resulting SDF is accessible via the property MeshToSDFBaker.SdfTexture.
|
|
/// </summary>
|
|
public void BakeSDF()
|
|
{
|
|
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3)
|
|
{
|
|
throw new NotSupportedException("MeshToSDFBaker compute shaders are not supported on OpenGLES3");
|
|
}
|
|
m_Cmd.BeginSample("BakeSDF");
|
|
UpdateCameras();
|
|
m_Cmd.SetComputeIntParams(m_computeShader, ShaderProperties.size, m_Dimensions);
|
|
CreateGraphicsBufferIfNeeded(ref m_bufferVoxel, GetTotalVoxelCount(), 4 * sizeof(float));
|
|
|
|
InitPrefixSumBuffers();
|
|
|
|
InitMeshBuffers();
|
|
|
|
// upper bound of length of triangle list
|
|
int upperBoundCount = (int)Mathf.Pow(m_maxResolution, 2) * (int)Mathf.Pow(nTriangles, 0.5f);
|
|
upperBoundCount = (int)Mathf.Max(nTriangles * 30L, upperBoundCount);
|
|
upperBoundCount = Mathf.Min(1536 * 1 << 18, upperBoundCount);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.upperBoundCount, upperBoundCount);
|
|
ClearRenderTexturesAndBuffers();
|
|
|
|
InitGeometryBuffers(upperBoundCount);
|
|
|
|
BuildGeometry();
|
|
|
|
FirstDraw();
|
|
|
|
PrefixSumCount();
|
|
|
|
SecondDraw();
|
|
|
|
GenerateRayMap();
|
|
|
|
SignPass();
|
|
|
|
SurfaceClosing();
|
|
|
|
JFA();
|
|
|
|
|
|
PerformDistanceTransformWinding();
|
|
|
|
m_Cmd.EndSample("BakeSDF");
|
|
|
|
if (m_OwnsCommandBuffer)
|
|
{
|
|
m_Cmd.ClearRandomWriteTargets();
|
|
Graphics.ExecuteCommandBuffer(m_Cmd);
|
|
m_Cmd.Clear();
|
|
}
|
|
}
|
|
|
|
private void InitMeshBuffers()
|
|
{
|
|
|
|
if (m_Mesh.GetVertexAttributeFormat(VertexAttribute.Position) != VertexAttributeFormat.Float32)
|
|
{
|
|
throw new ArgumentException(
|
|
"The SDF Baker only supports the VertexAttributeFormat Float32 for the Position attribute.");
|
|
}
|
|
int positionStream = m_Mesh.GetVertexAttributeStream(VertexAttribute.Position);
|
|
m_VertexBufferOffset = m_Mesh.GetVertexAttributeOffset(VertexAttribute.Position);
|
|
m_VerticesBuffer?.Dispose();
|
|
m_IndicesBuffer?.Dispose();
|
|
m_VerticesBuffer = m_Mesh.GetVertexBuffer(positionStream);
|
|
m_IndicesBuffer = m_Mesh.GetIndexBuffer();
|
|
|
|
nTriangles = 0;
|
|
for (int i = 0; i < m_Mesh.subMeshCount; i++)
|
|
nTriangles += m_Mesh.GetSubMesh(i).indexCount;
|
|
|
|
nTriangles /= 3;
|
|
}
|
|
|
|
private void FirstDraw()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.FirstDraw");
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
m_Material[i].SetInt(ShaderProperties.dimX, m_Dimensions[0]);
|
|
m_Material[i].SetInt(ShaderProperties.dimY, m_Dimensions[1]);
|
|
m_Material[i].SetInt(ShaderProperties.dimZ, m_Dimensions[2]);
|
|
m_Material[i].SetInt(ShaderProperties.currentAxis, i);
|
|
m_Material[i].SetBuffer(ShaderProperties.verticesBuffer, m_VerticesOutBuffer);
|
|
m_Material[i].SetBuffer(ShaderProperties.coordFlipBuffer, m_CoordFlipBuffer);
|
|
}
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
m_Cmd.ClearRandomWriteTargets();
|
|
m_Cmd.SetRenderTarget(m_RenderTextureViews[i]);
|
|
m_Cmd.ClearRenderTarget(true, true, Color.black, 1.0f);
|
|
m_Cmd.SetRandomWriteTarget(4 + kNbActualRT, m_AabbBuffer, false);
|
|
m_Cmd.SetRandomWriteTarget(1 + kNbActualRT, m_bufferVoxel, false);
|
|
m_Cmd.SetRandomWriteTarget(2 + kNbActualRT, m_CounterBuffer, false);
|
|
m_Cmd.SetViewProjectionMatrices(m_ViewMat[i], m_ProjMat[i]);
|
|
m_Cmd.DrawProcedural(Matrix4x4.identity, m_Material[i], 0, MeshTopology.Triangles, nTriangles * 3);
|
|
}
|
|
m_Cmd.ClearRandomWriteTargets();
|
|
|
|
m_Cmd.EndSample("BakeSDF.FirstDraw");
|
|
}
|
|
|
|
private void SecondDraw()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.SecondDraw");
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
m_Cmd.ClearRandomWriteTargets();
|
|
m_Cmd.SetRenderTarget(m_RenderTextureViews[i]);
|
|
m_Cmd.ClearRenderTarget(true, true, Color.black, 1.0f);
|
|
m_Cmd.SetRandomWriteTarget(4 + kNbActualRT, m_AabbBuffer, false);
|
|
m_Cmd.SetRandomWriteTarget(3 + kNbActualRT, m_TrianglesInVoxels, false);
|
|
m_Cmd.SetRandomWriteTarget(2 + kNbActualRT, m_AccumCounterBuffer, false);
|
|
m_Cmd.SetViewProjectionMatrices(m_ViewMat[i], m_ProjMat[i]);
|
|
m_Cmd.DrawProcedural(Matrix4x4.identity, m_Material[i], 1, MeshTopology.Triangles, nTriangles * 3);
|
|
}
|
|
m_Cmd.ClearRandomWriteTargets();
|
|
m_Cmd.EndSample("BakeSDF.SecondDraw");
|
|
}
|
|
|
|
private void BuildGeometry()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.FakeGeometryShader");
|
|
|
|
Vector3 minBoundsExtented = m_Center - m_SizeBox * 0.5f;
|
|
Vector3 maxBoundsExtented = m_Center + m_SizeBox * 0.5f;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
m_MinBoundsExtended[i] = minBoundsExtented[i];
|
|
m_MaxBoundsExtended[i] = maxBoundsExtented[i];
|
|
}
|
|
|
|
m_Cmd.SetComputeFloatParams(m_computeShader, ShaderProperties.minBoundsExtended, m_MinBoundsExtended);
|
|
m_Cmd.SetComputeFloatParams(m_computeShader, ShaderProperties.maxBoundsExtended, m_MaxBoundsExtended);
|
|
|
|
m_Cmd.SetComputeFloatParam(m_computeShader, ShaderProperties.maxExtent, m_MaxExtent);
|
|
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.nTriangles, nTriangles);
|
|
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.vertexPositionOffset, m_VertexBufferOffset);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.vertexStride, m_VerticesBuffer.stride);
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.indexStride, m_IndicesBuffer.stride);
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.chooseDirectionTriangleOnly, ShaderProperties.indicesBuffer, m_IndicesBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.chooseDirectionTriangleOnly, ShaderProperties.verticesBuffer, m_VerticesBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.chooseDirectionTriangleOnly, ShaderProperties.coordFlipBuffer, m_CoordFlipBuffer);
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.conservativeRasterization, ShaderProperties.indicesBuffer, m_IndicesBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.conservativeRasterization, ShaderProperties.verticesBuffer, m_VerticesBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.conservativeRasterization, ShaderProperties.verticesOutBuffer, m_VerticesOutBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.conservativeRasterization, ShaderProperties.coordFlipBuffer, m_CoordFlipBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.conservativeRasterization, ShaderProperties.aabbBuffer, m_AabbBuffer);
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.generateTrianglesUV, ShaderProperties.rw_trianglesUV, m_TrianglesUV);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.generateTrianglesUV, ShaderProperties.indicesBuffer, m_IndicesBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.generateTrianglesUV, ShaderProperties.verticesBuffer, m_VerticesBuffer);
|
|
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.generateTrianglesUV, Mathf.CeilToInt(nTriangles / 64.0f), 1, 1);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.chooseDirectionTriangleOnly, Mathf.CeilToInt(nTriangles / 64.0f), 1, 1);
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
m_Cmd.SetComputeIntParam(m_computeShader, ShaderProperties.currentAxis, i);
|
|
m_Cmd.SetComputeMatrixParam(m_computeShader, ShaderProperties.worldToClip, m_WorldToClip[i]);
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.conservativeRasterization, Mathf.CeilToInt(nTriangles / 64.0f), 1, 1);
|
|
}
|
|
|
|
m_Cmd.EndSample("BakeSDF.FakeGeometryShader");
|
|
}
|
|
|
|
private void InitGeometryBuffers(int upperBoundCount)
|
|
{
|
|
CreateGraphicsBufferIfNeeded(ref m_VerticesOutBuffer, 3 * nTriangles, 4 * sizeof(float));
|
|
CreateGraphicsBufferIfNeeded(ref m_CoordFlipBuffer, nTriangles, sizeof(int));
|
|
CreateGraphicsBufferIfNeeded(ref m_AabbBuffer, nTriangles, 4 * sizeof(float));
|
|
CreateGraphicsBufferIfNeeded(ref m_TrianglesInVoxels, upperBoundCount, sizeof(uint));
|
|
CreateGraphicsBufferIfNeeded(ref m_TrianglesUV, nTriangles, 9 * sizeof(float));
|
|
}
|
|
|
|
private void InitPrefixSumBuffers()
|
|
{
|
|
CreateGraphicsBufferIfNeeded(ref m_CounterBuffer, GetTotalVoxelCount(),
|
|
sizeof(int));
|
|
CreateGraphicsBufferIfNeeded(ref m_AccumCounterBuffer, GetTotalVoxelCount(),
|
|
sizeof(int));
|
|
CreateGraphicsBufferIfNeeded(ref m_AccumSumBlocks,
|
|
Mathf.CeilToInt((float)GetTotalVoxelCount() / m_ThreadGroupSize), sizeof(int));
|
|
|
|
CreateGraphicsBufferIfNeeded(ref m_SumBlocksBuffer,
|
|
Mathf.CeilToInt((float)GetTotalVoxelCount() / m_ThreadGroupSize), sizeof(int));
|
|
CreateGraphicsBufferIfNeeded(ref m_InSumBlocksBuffer,
|
|
Mathf.CeilToInt((float)GetTotalVoxelCount() / m_ThreadGroupSize), sizeof(int));
|
|
CreateGraphicsBufferIfNeeded(ref m_TmpBuffer, GetTotalVoxelCount(), sizeof(int));
|
|
CreateGraphicsBufferIfNeeded(ref m_SumBlocksAdditional,
|
|
Mathf.CeilToInt((float)GetTotalVoxelCount() / (m_ThreadGroupSize * m_ThreadGroupSize)),
|
|
sizeof(int));
|
|
}
|
|
|
|
private void ClearRenderTexturesAndBuffers()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.ClearTexturesAndBuffers");
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.voxelsTexture, m_textureVoxel, 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.voxelsTmpTexture, m_textureVoxelBis, 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.rayMap, m_RayMaps[0], 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.rw_rayMapTmp, m_RayMaps[1], 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.signMap, m_SignMaps[0], 0);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.signMapTmp, m_SignMaps[1]);
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.voxelsBuffer, m_bufferVoxel);
|
|
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.counter, m_CounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.clearTexturesAndBuffers, ShaderProperties.accumCounter, m_AccumCounterBuffer);
|
|
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.clearTexturesAndBuffers, Mathf.CeilToInt(m_Dimensions[0] / 8.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 8.0f), Mathf.CeilToInt(m_Dimensions[2] / 8.0f));
|
|
m_Cmd.EndSample("BakeSDF.ClearTexturesAndBuffers");
|
|
}
|
|
|
|
private void PerformDistanceTransformWinding()
|
|
{
|
|
m_Cmd.BeginSample("BakeSDF.DistanceTransform");
|
|
m_Cmd.SetComputeFloatParam(m_computeShader, ShaderProperties.threshold, m_InOutThreshold);
|
|
m_Cmd.SetComputeFloatParam(m_computeShader, ShaderProperties.sdfOffset, m_SdfOffset);
|
|
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.distanceTransform, ShaderProperties.voxelsTexture, GetTextureVoxelPrincipal(m_nStepsJFA + 1));
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.distanceTransform, ShaderProperties.distanceTexture, m_DistanceTexture);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.distanceTransform, ShaderProperties.accumCounter, m_AccumCounterBuffer);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.distanceTransform, ShaderProperties.triangleIDs, m_TrianglesInVoxels);
|
|
m_Cmd.SetComputeBufferParam(m_computeShader, m_Kernels.distanceTransform, ShaderProperties.trianglesUV, m_TrianglesUV);
|
|
m_Cmd.SetComputeTextureParam(m_computeShader, m_Kernels.distanceTransform, ShaderProperties.signMap, GetSignMapPrincipal(m_SignPassesCount));
|
|
m_Cmd.DispatchCompute(m_computeShader, m_Kernels.distanceTransform, Mathf.CeilToInt(m_Dimensions[0] / 8.0f),
|
|
Mathf.CeilToInt(m_Dimensions[1] / 8.0f), Mathf.CeilToInt(m_Dimensions[2] / 8.0f));
|
|
|
|
m_Cmd.EndSample("BakeSDF.DistanceTransform");
|
|
}
|
|
|
|
private void ReleaseBuffersAndTextures()
|
|
{
|
|
//Release textures.
|
|
ReleaseRenderTexture(ref m_textureVoxel);
|
|
ReleaseRenderTexture(ref m_textureVoxelBis);
|
|
ReleaseRenderTexture(ref m_DistanceTexture);
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
ReleaseRenderTexture(ref m_RenderTextureViews[i]);
|
|
if(Application.isPlaying)
|
|
Object.Destroy(m_Material[i]);
|
|
else
|
|
Object.DestroyImmediate(m_Material[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
ReleaseRenderTexture(ref m_SignMaps[i]);
|
|
ReleaseRenderTexture(ref m_RayMaps[i]);
|
|
}
|
|
|
|
//Release buffers.
|
|
ReleaseGraphicsBuffer(ref m_bufferVoxel);
|
|
ReleaseGraphicsBuffer(ref m_TrianglesUV);
|
|
ReleaseGraphicsBuffer(ref m_TrianglesInVoxels);
|
|
ReleaseGraphicsBuffer(ref m_IndicesBuffer);
|
|
ReleaseGraphicsBuffer(ref m_VerticesBuffer);
|
|
ReleaseGraphicsBuffer(ref m_VerticesOutBuffer);
|
|
ReleaseGraphicsBuffer(ref m_CoordFlipBuffer);
|
|
ReleaseGraphicsBuffer(ref m_AabbBuffer);
|
|
ReleaseGraphicsBuffer(ref m_TmpBuffer);
|
|
ReleaseGraphicsBuffer(ref m_AccumSumBlocks);
|
|
ReleaseGraphicsBuffer(ref m_SumBlocksBuffer);
|
|
ReleaseGraphicsBuffer(ref m_InSumBlocksBuffer);
|
|
ReleaseGraphicsBuffer(ref m_SumBlocksAdditional);
|
|
ReleaseGraphicsBuffer(ref m_CounterBuffer);
|
|
ReleaseGraphicsBuffer(ref m_AccumCounterBuffer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Release all the buffers and textures created by the object. This must be called you are finished using the object.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
ReleaseBuffersAndTextures();
|
|
GC.SuppressFinalize(this);
|
|
m_IsDisposed = true;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private string m_DefaultPath = "Assets/AllTests/VFXTests/SDFTests/";
|
|
private void SaveWithComputeBuffer(RenderTexture tex, string assetName = "", bool oneChannel = true)
|
|
{
|
|
ComputeBuffer tmpBufferVoxel = new ComputeBuffer(GetTotalVoxelCount(), 4 * sizeof(float));
|
|
|
|
int kernelIdCopy = m_computeShader.FindKernel("CopyToBuffer");
|
|
m_computeShader.SetBuffer(kernelIdCopy, "voxelsBuffer", tmpBufferVoxel);
|
|
m_computeShader.SetTexture(kernelIdCopy, "voxels", tex, 0);
|
|
m_computeShader.Dispatch(kernelIdCopy, Mathf.CeilToInt(m_Dimensions[0] / 8.0f), Mathf.CeilToInt(m_Dimensions[1] / 8.0f), Mathf.CeilToInt(m_Dimensions[2] / 8.0f));
|
|
Texture3D outTexture = new Texture3D(m_Dimensions[0], m_Dimensions[1], m_Dimensions[2], oneChannel ? TextureFormat.RHalf : TextureFormat.RGBAHalf, false);
|
|
outTexture.filterMode = FilterMode.Bilinear;
|
|
outTexture.wrapMode = TextureWrapMode.Clamp;
|
|
Color[] voxelArray = outTexture.GetPixels(0);
|
|
tmpBufferVoxel.GetData(voxelArray);
|
|
outTexture.SetPixels(voxelArray, 0);
|
|
outTexture.Apply();
|
|
string path = "";
|
|
if (assetName == "")
|
|
{
|
|
path = EditorUtility.SaveFilePanelInProject("Save the SDF as", "SDF", "asset", "");
|
|
}
|
|
else
|
|
{
|
|
path = m_DefaultPath + assetName + ".asset";
|
|
}
|
|
|
|
if (path != "")
|
|
{
|
|
AssetDatabase.DeleteAsset(path);
|
|
AssetDatabase.CreateAsset(outTexture, path);
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
|
}
|
|
|
|
tmpBufferVoxel.Release();
|
|
}
|
|
|
|
#endif
|
|
|
|
private void CreateGraphicsBufferIfNeeded(ref GraphicsBuffer gb, int length, int stride)
|
|
{
|
|
if (gb != null && gb.count == length && gb.stride == stride)
|
|
return;
|
|
|
|
ReleaseGraphicsBuffer(ref gb);
|
|
gb = new GraphicsBuffer(GraphicsBuffer.Target.Structured, length, stride);
|
|
m_IsDisposed = false;
|
|
}
|
|
|
|
private void ReleaseGraphicsBuffer(ref GraphicsBuffer gb)
|
|
{
|
|
if (gb != null)
|
|
gb.Release();
|
|
gb = null;
|
|
}
|
|
|
|
private void CreateRenderTextureIfNeeded(ref RenderTexture rt, RenderTextureDescriptor rtDesc)
|
|
{
|
|
if (rt != null
|
|
&& rt.width == rtDesc.width
|
|
&& rt.height == rtDesc.height
|
|
&& rt.volumeDepth == rtDesc.volumeDepth
|
|
&& rt.graphicsFormat == rtDesc.graphicsFormat)
|
|
{
|
|
return;
|
|
}
|
|
ReleaseRenderTexture(ref rt);
|
|
rt = new RenderTexture(rtDesc);
|
|
rt.hideFlags = HideFlags.DontSave;
|
|
rt.Create();
|
|
m_IsDisposed = false;
|
|
}
|
|
|
|
private void ReleaseRenderTexture(ref RenderTexture rt)
|
|
{
|
|
if (rt != null)
|
|
{
|
|
rt.Release();
|
|
if(Application.isPlaying)
|
|
Object.Destroy(rt);
|
|
else
|
|
Object.DestroyImmediate(rt);
|
|
}
|
|
rt = null;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
internal void SaveToAsset(string assetName = "")
|
|
{
|
|
SaveWithComputeBuffer(m_DistanceTexture);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
static class ShaderProperties
|
|
{
|
|
internal static int indicesBuffer = Shader.PropertyToID("indices");
|
|
internal static int verticesBuffer = Shader.PropertyToID("vertices");
|
|
internal static int vertexPositionOffset = Shader.PropertyToID("vertexPositionOffset");
|
|
internal static int vertexStride = Shader.PropertyToID("vertexStride");
|
|
internal static int indexStride = Shader.PropertyToID("indexStride");
|
|
|
|
internal static int coordFlipBuffer = Shader.PropertyToID("coordFlip");
|
|
internal static int verticesOutBuffer = Shader.PropertyToID("verticesOut");
|
|
internal static int aabbBuffer = Shader.PropertyToID("aabb");
|
|
internal static int worldToClip = Shader.PropertyToID("worldToClip");
|
|
internal static int currentAxis = Shader.PropertyToID("currentAxis");
|
|
internal static int voxelsBuffer = Shader.PropertyToID("voxelsBuffer");
|
|
internal static int rw_trianglesUV = Shader.PropertyToID("rw_trianglesUV");
|
|
internal static int trianglesUV = Shader.PropertyToID("trianglesUV");
|
|
internal static int voxelsTexture = Shader.PropertyToID("voxels");
|
|
internal static int voxelsTmpTexture = Shader.PropertyToID("voxelsTmp");
|
|
internal static int rayMap = Shader.PropertyToID("rayMap");
|
|
internal static int rayMapTmp = Shader.PropertyToID("rayMapTmp");
|
|
internal static int rw_rayMapTmp = Shader.PropertyToID("rw_rayMapTmp");
|
|
internal static int nTriangles = Shader.PropertyToID("nTriangles");
|
|
internal static int minBoundsExtended = Shader.PropertyToID("minBoundsExtended");
|
|
internal static int maxBoundsExtended = Shader.PropertyToID("maxBoundsExtended");
|
|
internal static int maxExtent = Shader.PropertyToID("maxExtent");
|
|
internal static int upperBoundCount = Shader.PropertyToID("upperBoundCount");
|
|
internal static int counter = Shader.PropertyToID("counter");
|
|
|
|
internal static int dimX = Shader.PropertyToID("dimX");
|
|
internal static int dimY = Shader.PropertyToID("dimY");
|
|
internal static int dimZ = Shader.PropertyToID("dimZ");
|
|
internal static int size = Shader.PropertyToID("size");
|
|
|
|
//Prefix sum
|
|
internal static int inputBuffer = Shader.PropertyToID("Input");
|
|
internal static int inputCounter = Shader.PropertyToID("inputCounter");
|
|
internal static int auxBuffer = Shader.PropertyToID("auxBuffer");
|
|
internal static int resultBuffer = Shader.PropertyToID("Result");
|
|
internal static int numElem = Shader.PropertyToID("numElem");
|
|
internal static int exclusive = Shader.PropertyToID("exclusive");
|
|
internal static int dispatchWidth = Shader.PropertyToID("dispatchWidth");
|
|
|
|
|
|
//Copy kernels
|
|
internal static int src = Shader.PropertyToID("src");
|
|
internal static int dest = Shader.PropertyToID("dest");
|
|
|
|
//Sign map
|
|
internal static int signMap = Shader.PropertyToID("signMap");
|
|
internal static int threshold = Shader.PropertyToID("threshold");
|
|
internal static int signMapTmp = Shader.PropertyToID("signMapTmp");
|
|
internal static int normalizeFactor = Shader.PropertyToID("normalizeFactor");
|
|
internal static int numNeighbours = Shader.PropertyToID("numNeighbours");
|
|
internal static int passId = Shader.PropertyToID("passId");
|
|
internal static int needNormalize = Shader.PropertyToID("needNormalize");
|
|
|
|
//JFA
|
|
internal static int offset = Shader.PropertyToID("offset");
|
|
|
|
//Ray Map
|
|
internal static int offsetRayMap = Shader.PropertyToID("offsetRayMap");
|
|
internal static int triangleIDs = Shader.PropertyToID("triangleIDs");
|
|
internal static int accumCounter = Shader.PropertyToID("accumCounter");
|
|
|
|
//Distance
|
|
internal static int distanceTexture = Shader.PropertyToID("distanceTexture");
|
|
internal static int sdfOffset = Shader.PropertyToID("sdfOffset");
|
|
}
|
|
|
|
internal class Kernels
|
|
{
|
|
internal int inBucketSum = -1;
|
|
internal int blockSums = -1;
|
|
internal int finalSum = -1;
|
|
internal int toTextureNormalized = -1;
|
|
internal int copyTextures = -1;
|
|
internal int jfa = -1;
|
|
internal int distanceTransform = -1;
|
|
internal int copyBuffers = -1;
|
|
internal int generateRayMapLocal = -1;
|
|
internal int rayMapScanX = -1;
|
|
internal int rayMapScanY = -1;
|
|
internal int rayMapScanZ = -1;
|
|
internal int signPass6Rays = -1;
|
|
internal int signPassNeighbors = -1;
|
|
internal int toBlockSumBuffer = -1;
|
|
internal int clearTexturesAndBuffers = -1;
|
|
internal int copyToBuffer = -1;
|
|
internal int generateTrianglesUV = -1;
|
|
internal int conservativeRasterization = -1;
|
|
internal int chooseDirectionTriangleOnly = -1;
|
|
internal int surfaceClosing = -1;
|
|
internal Kernels(ComputeShader computeShader)
|
|
{
|
|
inBucketSum = computeShader.FindKernel("InBucketSum");
|
|
blockSums = computeShader.FindKernel("BlockSums");
|
|
finalSum = computeShader.FindKernel("FinalSum");
|
|
toTextureNormalized = computeShader.FindKernel("ToTextureNormalized");
|
|
copyTextures = computeShader.FindKernel("CopyTextures");
|
|
jfa = computeShader.FindKernel("JFA");
|
|
distanceTransform = computeShader.FindKernel("DistanceTransform");
|
|
copyBuffers = computeShader.FindKernel("CopyBuffers");
|
|
generateRayMapLocal = computeShader.FindKernel("GenerateRayMapLocal");
|
|
rayMapScanX = computeShader.FindKernel("RayMapScanX");
|
|
rayMapScanY = computeShader.FindKernel("RayMapScanY");
|
|
rayMapScanZ = computeShader.FindKernel("RayMapScanZ");
|
|
signPass6Rays = computeShader.FindKernel("SignPass6Rays");
|
|
signPassNeighbors = computeShader.FindKernel("SignPassNeighbors");
|
|
toBlockSumBuffer = computeShader.FindKernel("ToBlockSumBuffer");
|
|
clearTexturesAndBuffers = computeShader.FindKernel("ClearTexturesAndBuffers");
|
|
copyToBuffer = computeShader.FindKernel("CopyToBuffer");
|
|
generateTrianglesUV = computeShader.FindKernel("GenerateTrianglesUV");
|
|
conservativeRasterization = computeShader.FindKernel("ConservativeRasterization");
|
|
chooseDirectionTriangleOnly = computeShader.FindKernel("ChooseDirectionTriangleOnly");
|
|
surfaceClosing = computeShader.FindKernel("SurfaceClosing");
|
|
}
|
|
}
|
|
}
|
|
}
|