You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4945 lines
219 KiB
C#
4945 lines
219 KiB
C#
/******************************************************************************/
|
|
/*
|
|
Project - MudBun
|
|
Publisher - Long Bunny Labs
|
|
http://LongBunnyLabs.com
|
|
Author - Ming-Lun "Allen" Chou
|
|
http://AllenChou.net
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.XR;
|
|
|
|
namespace MudBun
|
|
{
|
|
[ExecuteInEditMode]
|
|
public abstract class MudRendererBase : MonoBehaviour
|
|
{
|
|
#region Events
|
|
|
|
public virtual void InvokeOnMeshGenerated(Mesh mesh) { }
|
|
|
|
#endregion
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Enums & Structs
|
|
|
|
public enum HardwareModeEnum
|
|
{
|
|
[InspectorName("GPU")] Gpu,
|
|
// [InspectorName("CPU")] Cpu,
|
|
}
|
|
|
|
public enum RenderModeEnum
|
|
{
|
|
FlatMesh = 0,
|
|
SmoothMesh = 1,
|
|
CircleSplats = 2,
|
|
QuadSplats = 3,
|
|
Decal = 4,
|
|
/*
|
|
[HideInInspector] RayMarchedSurface = 5,
|
|
[HideInInspector] RayTracedVoxels = 6,
|
|
*/
|
|
}
|
|
|
|
public enum RenderMaterialModeEnum
|
|
{
|
|
Static,
|
|
Dynamic,
|
|
}
|
|
|
|
public enum RayTracedVoxelModeEnum
|
|
{
|
|
FlatCubes,
|
|
FacetedCubes,
|
|
FlatSpheres,
|
|
SmoothSpheres,
|
|
Custom = 100,
|
|
}
|
|
|
|
public enum RayTracedVoxelPaddingModeEnum
|
|
{
|
|
None,
|
|
ByDistance,
|
|
Full,
|
|
}
|
|
|
|
public enum RenderModeCategoryEnum
|
|
{
|
|
Unknown = -1,
|
|
Mesh,
|
|
Splats,
|
|
Decal,
|
|
/*
|
|
RayMarchedSurface,
|
|
RayTracedVoxels,
|
|
*/
|
|
}
|
|
|
|
public enum MeshingModeEnum
|
|
{
|
|
MarchingCubes,
|
|
DualQuads,
|
|
SurfaceNets,
|
|
DualContouring,
|
|
}
|
|
|
|
public enum ComputeModeEnum
|
|
{
|
|
Auto,
|
|
Manual,
|
|
ManualNoRender,
|
|
EveryFrame,
|
|
TimeSliced
|
|
}
|
|
|
|
public enum TimeSliceModeEnum
|
|
{
|
|
ByFramesAutoOffset,
|
|
ByFramesManualOffset,
|
|
ByPeriodAutoOffset,
|
|
ByPeriodManualOffset,
|
|
}
|
|
|
|
public struct Const
|
|
{
|
|
public struct KernelIndex
|
|
{
|
|
public int ClearVoxelHashTable;
|
|
public int ClearAutoSmoothVertDataTable;
|
|
public int ClearVoxelCache;
|
|
public int RegisterTopNodes;
|
|
public int UpdateBranchingIndirectDispatchArgs;
|
|
public int AllocateChildNodes;
|
|
public int UpdateVoxelIndirectDispatchArgs;
|
|
|
|
public int GenerateFlatMarchingCubesMesh;
|
|
public int GenerateSmoothMarchingCubesMesh;
|
|
public int GenerateMarchingCubesSplats;
|
|
public int GenerateFlatMarchingCubesMesh2d;
|
|
public int GenerateSmoothMarchingCubesMesh2d;
|
|
public int GenerateMarchingCubesSplats2d;
|
|
public int UpdateMarchingCubesAutoSmoothIndirectDispatchArgs;
|
|
public int MarchingCubesUpdateAutoSmooth;
|
|
public int MarchingCubesComputeAutoSmooth;
|
|
|
|
public int GenerateDualQuads;
|
|
public int GenerateDualQuads2d;
|
|
public int UpdateDualMeshingIndirectDispatchArgs;
|
|
public int DualMeshingFlatMeshNormal;
|
|
public int DualMeshingSmoothMeshNormal;
|
|
public int DualMeshingFlatMeshNormal2d;
|
|
public int DualMeshingSmoothMeshNormal2d;
|
|
public int DualMeshingUpdateAutoSmooth;
|
|
public int DualMeshingComputeAutoSmooth;
|
|
public int DualMeshingUpdateSmoothCornerIndirectDispatchArgs;
|
|
public int DualMeshingSmoothCorner;
|
|
public int UpdateDualMeshingSplatsIndirectArgs;
|
|
public int ConvertDualMeshingSplats;
|
|
|
|
public int SurfaceNetsMovePoint;
|
|
public int SurfaceNetsMovePoint2d;
|
|
|
|
public int DualContouringMovePoint;
|
|
public int DualContouringMovePoint2d;
|
|
|
|
public int UpdateRayTracedVoxelIndirectDispatchArgs;
|
|
public int ComputeRayTracedVoxelGenPoints;
|
|
public int ComputeRayTracedVoxelGenPointsWithNormals;
|
|
|
|
public int GenerateNoiseCache;
|
|
|
|
public int RigBones;
|
|
|
|
public int GenerateSdf;
|
|
}
|
|
public static KernelIndex Kernel;
|
|
|
|
public static int TriTable;
|
|
public static int VertTable;
|
|
public static int TriTable2d;
|
|
|
|
public static int Brushes;
|
|
public static int BrushMaterials;
|
|
public static int NumBrushes;
|
|
|
|
public static int SurfaceShift;
|
|
|
|
public static int RenderMode;
|
|
public static int MeshingMode;
|
|
public static int RayTracedVoxelMode;
|
|
public static int RayTracedVoxelSizeMultiplier;
|
|
public static int RayTracedVoxelSmoothCubeNormal;
|
|
public static int RayTracedVoxelRadius;
|
|
public static int RayTracedVoxelPaddingMode;
|
|
public static int RayTracedVoxelInternalPaddingDistance;
|
|
public static int RayTracedVoxelSizeFadeDistance;
|
|
|
|
public static int NormalDifferentiationStep;
|
|
public static int NormalQuantization;
|
|
public static int Normal2dFadeDist;
|
|
public static int Normal2dStrength;
|
|
public static int EnableAutoSmooth;
|
|
public static int AutoSmoothMaxAngle;
|
|
public static int AutoSmoothVertDataTable;
|
|
public static int AutoSmoothVertDataPoolSize;
|
|
public static int EnableSmoothCorner;
|
|
public static int SmoothCornerSubdivision;
|
|
public static int SmoothCornerNormalBlur;
|
|
public static int SmoothCornerFade;
|
|
public static int InvertNormals;
|
|
|
|
public static int SplatSize;
|
|
public static int SplatSizeJitter;
|
|
public static int SplatNormalShift;
|
|
public static int SplatNormalShiftJitter;
|
|
public static int SplatColorJitter;
|
|
public static int SplatPositionJitter;
|
|
public static int SplatRotationJitter;
|
|
public static int SplatOrientationJitter;
|
|
public static int SplatOriginalNormalBlend;
|
|
public static int SplatJitterNoisiness;
|
|
public static int SplatCameraFacing;
|
|
public static int SplatNormalsMatchCameraFacing;
|
|
public static int SplatShadowsMatchCameraFacing;
|
|
public static int SplatScreenSpaceFlattening;
|
|
//public static int SplatSmoothNormalBlend;
|
|
public static int SurfaceNetsDualQuadsBlend;
|
|
public static int SurfaceNetsBinarySearchIterations;
|
|
public static int SurfaceNetsGradientDescentIterations;
|
|
public static int SurfaceNetsGradientDescentFactor;
|
|
public static int DualContouringDualQuadsBlend;
|
|
public static int DualContouringRelaxation;
|
|
public static int DualContouringSolverIterations;
|
|
public static int DualContouringBinarySearchIterations;
|
|
public static int DualContouringGradientDescentIterations;
|
|
public static int DualContouringGradientDescentFactor;
|
|
|
|
public static int AabbTree;
|
|
public static int AabbRoot;
|
|
|
|
public static int Enable2dMode;
|
|
public static int ForceAllBrushes;
|
|
public static int NumAllocations; // general allocation counters
|
|
public static int NodeHashTable;
|
|
public static int NodeHashTableSize;
|
|
public static int NodePool;
|
|
public static int NodePoolSize;
|
|
public static int NumNodesAllocated;
|
|
public static int UseVoxelCache;
|
|
public static int VoxelCacheIdTable;
|
|
public static int VoxelCache;
|
|
public static int VoxelCacheSize;
|
|
public static int BrushMaskPool;
|
|
public static int BrushMaskPoolSize;
|
|
public static int IndirectDispatchArgs;
|
|
public static int CurrentNodeDepth;
|
|
public static int CurrentNodeBranchingFactor;
|
|
public static int CurrentNodeSize;
|
|
public static int VoxelSize;
|
|
public static int VoxelTreeBranchingFactorsCompressed;
|
|
public static int VoxelNodeSizes;
|
|
public static int MaxNodeDepth;
|
|
public static int ChunkVoxelDensity;
|
|
public static int GenPoints;
|
|
public static int MaxGenPoints;
|
|
public static int IndirectDrawArgs;
|
|
|
|
public static int MasterColor;
|
|
public static int MasterEmission;
|
|
public static int MasterMetallic;
|
|
public static int MasterSmoothness;
|
|
|
|
public static int ScaleSign;
|
|
public static int LocalToWorld;
|
|
public static int LocalToWorldIt;
|
|
public static int LocalToWorldScale;
|
|
public static int WorldToLocal;
|
|
public static int WorldToLocalIt;
|
|
|
|
public static int NoiseCache;
|
|
public static int NoiseCacheDimension;
|
|
public static int NoiseCacheDensity;
|
|
public static int NoiseCachePeriod;
|
|
|
|
public static int SdfOutput;
|
|
public static int SdfOutputSize;
|
|
public static int SdfCenter;
|
|
public static int SdfDimension;
|
|
|
|
public static int MaxRayMarchSteps;
|
|
public static int RayMarchHitDistance;
|
|
public static int RayMarchMaxRayDistance;
|
|
|
|
public static int MeshGenerationAutoRiggingAlgorithm;
|
|
|
|
/*
|
|
public static int NumLightMarchSteps;
|
|
public static int RayMarchStepSize;
|
|
public static int RayMarchVolumeDensity;
|
|
public static int RayMarchVolumeBorderFade;
|
|
public static int RayMarchLightPositionType;
|
|
public static int RayMarchLightDirection;
|
|
public static int RayMarchAbsorption;
|
|
public static int RayMarchDarknesThreshold;
|
|
public static int RayMarchTransmittanceCurve;
|
|
public static int RayMarchNoiseEdgeFade;
|
|
public static int RayMarchNoiseThreshold;
|
|
public static int RayMarchNoiseScrollSpeed;
|
|
public static int RayMarchNoiseBaseOctaveSize;
|
|
public static int RayMarchNoiseNumOctaves;
|
|
public static int RayMarchNoiseOctaveOffsetFactor;
|
|
*/
|
|
|
|
public static int IsMeshRenderMaterial;
|
|
public static int IsSplatRenderMaterial;
|
|
public static int MaterialNeedsSdfProperties;
|
|
public static int MaterialNeedsRayMarchingProperties;
|
|
}
|
|
|
|
#endregion // end: Enums & Structs
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Global Consts
|
|
|
|
public static readonly int ThreadGroupExtent = 4;
|
|
public static readonly int ThreadGroupSize = ThreadGroupExtent * ThreadGroupExtent * ThreadGroupExtent;
|
|
public static readonly int ClearThreadGroupSize = 256;
|
|
private static int[] s_aVoxelTreeBranchingFactor = new int[] { 8, 8, 4 };
|
|
public static int[] VoxelTreeBranchingFactors => s_aVoxelTreeBranchingFactor;
|
|
public static int VoxelTreeBranchingFactorsComrpessed = (int) Codec.Pack8888((uint)s_aVoxelTreeBranchingFactor[0], (uint)s_aVoxelTreeBranchingFactor[1], (uint)s_aVoxelTreeBranchingFactor[2], 0);
|
|
public static int VoxelNodeDepth => VoxelTreeBranchingFactors.Length;
|
|
private static int s_chunkVoxelDensity = -1;
|
|
public static int ChunkVoxelDensity
|
|
{
|
|
get
|
|
{
|
|
if (s_chunkVoxelDensity < 0)
|
|
s_chunkVoxelDensity = VoxelTreeBranchingFactors.Aggregate((x, y) => x * y);
|
|
return s_chunkVoxelDensity;
|
|
}
|
|
}
|
|
|
|
// maximum allowed number of brushes per renderer
|
|
// NOTE: MaxBrushes must be a multiple of 32 (8 * sizeof(int))
|
|
// (MaxBrushes / 32) must be less than or equal to kMaxBrushMaskInts in BrushMaskDefs.cginc
|
|
// MaxBrushes must *NOT* be larger than 2^kAabbTreeNodeStackSize in AabbTreeDefs.cginc
|
|
public static readonly int MaxBrushes = 1024;
|
|
public static int MaxBrushMaskInts => MaxBrushes / 32;
|
|
public static int MaxBrushGroupDepth = 6;
|
|
|
|
private static int[] s_noiseCacheDimensionInts = new int[] { 256, 128, 256 };
|
|
public static int[] NoiseCacheDimensionInts => s_noiseCacheDimensionInts;
|
|
private static float[] s_noiseCacheDimensionFloats;
|
|
public static float[] NoiseCacheDimensionFloats
|
|
{
|
|
get
|
|
{
|
|
if (s_noiseCacheDimensionFloats == null)
|
|
s_noiseCacheDimensionFloats = NoiseCacheDimensionInts.Select(x => (float)x).ToArray();
|
|
return s_noiseCacheDimensionFloats;
|
|
}
|
|
}
|
|
public static readonly float NoiseCacheDensity = 32.0f;
|
|
private static float[] s_noiseCachePeriod;
|
|
public static float[] NoiseCachePeriod
|
|
{
|
|
get
|
|
{
|
|
if (s_noiseCachePeriod == null)
|
|
s_noiseCachePeriod = NoiseCacheDimensionInts.Select(x => x / NoiseCacheDensity).ToArray();
|
|
return s_noiseCachePeriod;
|
|
}
|
|
}
|
|
|
|
public int VoxelToVertexFactor
|
|
{
|
|
get
|
|
{
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
case RenderModeEnum.SmoothMesh:
|
|
return 3;
|
|
|
|
case RenderModeEnum.CircleSplats:
|
|
return 2;
|
|
|
|
case RenderModeEnum.QuadSplats:
|
|
return 3;
|
|
}
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
#endregion // end: Global Consts
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Global Resources
|
|
|
|
private static bool s_globalResourcesValid = false;
|
|
|
|
protected static HashSet<MudRendererBase> s_renderers = new HashSet<MudRendererBase>();
|
|
protected static Dictionary<float, MudBrushBase> s_brushMap = new Dictionary<float, MudBrushBase>();
|
|
private static ComputeShader s_computeVoxelGen;
|
|
private static ComputeShader s_computeMarchingCubes;
|
|
private static ComputeShader s_computeDualMeshing;
|
|
private static ComputeShader s_computeSurfaceNets;
|
|
private static ComputeShader s_computeDualContouring;
|
|
private static ComputeShader s_computeRayTracedVoxels;
|
|
private static ComputeShader s_computeNoiseCache;
|
|
private static ComputeShader s_computeMeshLock;
|
|
private static ComputeShader s_computeSdfGen;
|
|
private static ComputeBuffer s_triTableBuffer;
|
|
private static ComputeBuffer s_vertTableBuffer;
|
|
private static ComputeBuffer s_triTable2dBuffer;
|
|
private static ComputeBuffer s_brushesBuffer;
|
|
private static ComputeBuffer s_brushMaterialBuffer;
|
|
private static ComputeBuffer s_aabbTreeBuffer;
|
|
private static ComputeBuffer s_dummyBuffer;
|
|
private static RenderTexture s_noiseCache;
|
|
public static RenderTexture NoiseCache => s_noiseCache;
|
|
/*
|
|
private static Texture s_noiseCache;
|
|
public static Texture NoiseCache
|
|
{
|
|
get
|
|
{
|
|
if (s_noiseCache != null)
|
|
return s_noiseCache;
|
|
|
|
s_noiseCache = ResourcesUtil.NoiseTexture;
|
|
return s_noiseCache;
|
|
}
|
|
}
|
|
*/
|
|
|
|
public static ResourcesUtil.RenderPipelineEnum RenderPipeline => ResourcesUtil.RenderPipeline;
|
|
|
|
public static int GlobalResourceGpuMemoryAllocated
|
|
{
|
|
get
|
|
{
|
|
int bytes = 0;
|
|
|
|
if (s_triTableBuffer != null)
|
|
bytes += s_triTableBuffer.stride * s_triTableBuffer.count;
|
|
|
|
if (s_vertTableBuffer != null)
|
|
bytes += s_vertTableBuffer.stride * s_vertTableBuffer.count;
|
|
|
|
if (s_triTable2dBuffer != null)
|
|
bytes += s_triTable2dBuffer.stride * s_triTable2dBuffer.count;
|
|
|
|
if (s_brushesBuffer != null)
|
|
bytes += s_brushesBuffer.stride * s_brushesBuffer.count;
|
|
|
|
if (s_brushMaterialBuffer != null)
|
|
bytes += s_brushMaterialBuffer.stride * s_brushMaterialBuffer.count;
|
|
|
|
if (s_aabbTreeBuffer != null)
|
|
bytes += s_aabbTreeBuffer.stride * s_aabbTreeBuffer.count;
|
|
|
|
if (s_noiseCache != null)
|
|
bytes += s_noiseCache.width * s_noiseCache.height * s_noiseCache.volumeDepth * sizeof(float);
|
|
|
|
if (s_dummyBuffer != null)
|
|
bytes += s_dummyBuffer.stride * s_dummyBuffer.count;
|
|
|
|
return bytes;
|
|
}
|
|
}
|
|
|
|
public static void ReloadAllShaders()
|
|
{
|
|
foreach (var renderer in s_renderers)
|
|
{
|
|
renderer.ReloadShaders();
|
|
}
|
|
}
|
|
|
|
#endregion // end: Global Resources
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Local Resources
|
|
|
|
private bool m_localResourcesValid = false;
|
|
|
|
protected NativeArray<SdfBrush> m_aSdfBrush;
|
|
protected NativeArray<SdfBrushMaterial> m_aSdfBrushMaterial;
|
|
protected Dictionary<int, int> m_sdfBrushMaterialIndexMap;
|
|
|
|
//[Header("Budgets")]
|
|
|
|
// base budgets
|
|
[Range(1, 2048)] public int MaxVoxelsK = 256;
|
|
[Range(16, 1024)] public int MaxChunks = 64;
|
|
private bool UseVoxelCache = false; // profiler says this doesn't really help with performance
|
|
|
|
// derived budgets
|
|
public int MaxVoxels => 1024 * MaxVoxelsK;
|
|
public int MaxVoxelNodes => 1024 * (MaxChunks + MaxVoxelsK);
|
|
public int MaxBrushMasks => 256 * MaxChunks;
|
|
public int MaxGenPoints => VoxelToVertexFactor * MaxVoxelNodes;
|
|
|
|
// only works in editor
|
|
public bool ShowGpuMemoryUsage = false;
|
|
public bool AutoAdjustBudgetsToHighWaterMarks = false;
|
|
[Range(0, 100)] public int AutoAdjustBudgetsToHighWaterMarksMarginPercent = 15;
|
|
private bool m_autoAdjustBudgetsToHighWaterMarks = false;
|
|
|
|
//[Header("Render")]
|
|
|
|
// local shader resources
|
|
[Range(0.1f, 100.0f)] public float VoxelDensity = 8.0f;
|
|
public float TopVoxelNodeSize
|
|
{
|
|
get
|
|
{
|
|
float size = ChunkVoxelDensity / VoxelDensity;
|
|
if (LockMeshIntermediateState != LockMeshIntermediateStateEnum.Idle)
|
|
size = ChunkVoxelDensity / MeshGenerationVoxelDensity;
|
|
return size * 1.0001f;
|
|
}
|
|
}
|
|
private float[] m_aNodeSize;
|
|
public float[] NodeSizes
|
|
{
|
|
get
|
|
{
|
|
if (m_aNodeSize == null || m_aNodeSize.Length != VoxelNodeDepth + 1)
|
|
m_aNodeSize = new float[VoxelNodeDepth + 1];
|
|
float nodeSize = TopVoxelNodeSize;
|
|
for (int depth = 0; depth < m_aNodeSize.Length; ++depth)
|
|
{
|
|
m_aNodeSize[depth] = nodeSize;
|
|
if (depth < VoxelNodeDepth)
|
|
nodeSize /= VoxelTreeBranchingFactors[depth];
|
|
}
|
|
return m_aNodeSize;
|
|
}
|
|
}
|
|
public Vector4 NodeSizesVector
|
|
{
|
|
get
|
|
{
|
|
var aNodeSize = NodeSizes;
|
|
int maxDepth = aNodeSize.Length;
|
|
|
|
Vector4 vec = Vector4.zero;
|
|
if (maxDepth > 0)
|
|
vec.x = aNodeSize[0];
|
|
if (maxDepth > 1)
|
|
vec.y = aNodeSize[1];
|
|
if (maxDepth > 2)
|
|
vec.z = aNodeSize[2];
|
|
if (maxDepth > 3)
|
|
vec.w = aNodeSize[3];
|
|
|
|
return vec;
|
|
}
|
|
}
|
|
|
|
public float VoxelSize
|
|
{
|
|
get
|
|
{
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Decal:
|
|
//case RenderModeCategoryEnum.RayMarchedSurface:
|
|
return 1e-5f;
|
|
}
|
|
return NodeSizes[VoxelNodeDepth];
|
|
}
|
|
}
|
|
|
|
private bool AllowSharedRWBuffers
|
|
{
|
|
get
|
|
{
|
|
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal) // Metal is weird
|
|
return false;
|
|
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Decal:
|
|
//case RenderModeCategoryEnum.RayMarchedSurface:
|
|
//case RenderModeCategoryEnum.RayTracedVoxels:
|
|
return false;
|
|
|
|
case RenderModeCategoryEnum.Splats:
|
|
/*
|
|
if (SplatSmoothNormalBlend > 0.0f)
|
|
return false;
|
|
*/
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private bool m_initialized = false;
|
|
|
|
private ComputeBuffer m_brushesBuffer;
|
|
private ComputeBuffer m_brushMaterialBuffer;
|
|
private ComputeBuffer m_aabbTreeBuffer;
|
|
private int m_aabbTreeBufferRoot;
|
|
private ComputeBuffer m_nodeHashTableBuffer;
|
|
protected ComputeBuffer m_nodePoolBuffer;
|
|
protected ComputeBuffer m_numNodesAllocatedBuffer;
|
|
private ComputeBuffer m_numAllocationsBuffer;
|
|
private ComputeBuffer m_voxelCacheIdTableBuffer;
|
|
private ComputeBuffer m_voxelCacheBuffer;
|
|
private ComputeBuffer m_brushMaskPoolBuffer;
|
|
private ComputeBuffer m_indirectDispatchArgsBuffer;
|
|
private ComputeBuffer m_autoSmoothVertDataTableBuffer;
|
|
protected ComputeBuffer m_genPointsBufferDefault;
|
|
protected ComputeBuffer m_indirectDrawArgsBufferDefault;
|
|
protected ComputeBuffer m_genPointsBufferOverride;
|
|
protected ComputeBuffer m_indirectDrawArgsBufferOverride;
|
|
protected ComputeBuffer m_genPointsBufferUsedForCompute;
|
|
protected ComputeBuffer m_indirectDrawArgsBufferUsedForCompute;
|
|
|
|
private NativeArray<int> m_indirectDrawArgsInitData;
|
|
private NativeArray<int> IndirectDrawArgsInitData
|
|
{
|
|
get
|
|
{
|
|
bool usingXr = false;
|
|
var aXrDisplaySubsystem = new List<XRDisplaySubsystem>();
|
|
SubsystemManager.GetInstances(aXrDisplaySubsystem);
|
|
foreach (var xrDisplay in aXrDisplaySubsystem)
|
|
{
|
|
if (xrDisplay.running)
|
|
{
|
|
usingXr = true;
|
|
break;
|
|
}
|
|
}
|
|
int numInstances = usingXr ? 2 : 1;
|
|
|
|
if (!m_indirectDrawArgsInitData.IsCreated)
|
|
{
|
|
m_indirectDrawArgsInitData = new NativeArray<int>(new int[] { 0, numInstances, 0, 0, 0, }, Allocator.Persistent);
|
|
}
|
|
|
|
m_indirectDrawArgsInitData[1] = numInstances;
|
|
|
|
return m_indirectDrawArgsInitData;
|
|
}
|
|
}
|
|
|
|
private static NativeArray<int> s_numAllocatoinsBufferInitData;
|
|
private static NativeArray<int> NumAllocatoinsBufferInitData
|
|
{
|
|
get
|
|
{
|
|
int desiredLength = VoxelTreeBranchingFactors.Length;
|
|
|
|
if (s_numAllocatoinsBufferInitData.IsCreated)
|
|
{
|
|
if (s_numAllocatoinsBufferInitData.Length == desiredLength)
|
|
return s_numAllocatoinsBufferInitData;
|
|
else
|
|
s_numAllocatoinsBufferInitData.Dispose();
|
|
}
|
|
|
|
s_numAllocatoinsBufferInitData = new NativeArray<int>(desiredLength, Allocator.Persistent, NativeArrayOptions.ClearMemory);
|
|
return s_numAllocatoinsBufferInitData;
|
|
}
|
|
}
|
|
|
|
private static NativeArray<int> s_unitIndirectDispatchArgsInitData;
|
|
private static NativeArray<int> UnitIndirectDispatchArgsInitData
|
|
{
|
|
get
|
|
{
|
|
if (s_unitIndirectDispatchArgsInitData.IsCreated)
|
|
return s_unitIndirectDispatchArgsInitData;
|
|
|
|
s_unitIndirectDispatchArgsInitData = new NativeArray<int>(new int[] { 1, 1, 1 }, Allocator.Persistent);
|
|
return s_unitIndirectDispatchArgsInitData;
|
|
}
|
|
}
|
|
|
|
private int[] m_numAllocationsBufferInitData;
|
|
|
|
private static readonly int NodeHashTableAllocationMultiplier = 2;
|
|
public int NodeHashTableSize
|
|
{
|
|
get
|
|
{
|
|
/*
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.RayTracedVoxels:
|
|
return MaxVoxels * NodeHashTableAllocationMultiplier;
|
|
}
|
|
*/
|
|
return MaxChunks * NodeHashTableAllocationMultiplier;
|
|
}
|
|
}
|
|
|
|
private static readonly int AutoSmoothVertDataAllocationMultiplier = 2;
|
|
public int AutoSmoothVertDataTableSize => MaxVoxels * AutoSmoothVertDataAllocationMultiplier;
|
|
|
|
public enum NumAllcationIndex
|
|
{
|
|
BrushMask,
|
|
VoxelCache,
|
|
VoxelHash,
|
|
AutoSmoothVertData,
|
|
}
|
|
|
|
private static bool s_warnedResourceAccessPerformanceImpact = false;
|
|
|
|
public long LocalResourceGpuMemoryAllocated
|
|
{
|
|
get
|
|
{
|
|
long bytes = 0;
|
|
|
|
if (!AllowSharedRWBuffers)
|
|
{
|
|
if (m_brushesBuffer != null)
|
|
bytes += m_brushesBuffer.stride * m_brushesBuffer.count;
|
|
|
|
if (m_brushMaterialBuffer != null)
|
|
bytes += m_brushMaterialBuffer.stride * m_brushMaterialBuffer.count;
|
|
|
|
if (m_aabbTreeBuffer != null)
|
|
bytes += m_aabbTreeBuffer.stride * m_aabbTreeBuffer.count;
|
|
}
|
|
|
|
if (m_nodePoolBuffer != null)
|
|
bytes += m_nodePoolBuffer.stride * ((long) m_nodePoolBuffer.count);
|
|
|
|
if (m_nodeHashTableBuffer != null)
|
|
bytes += m_nodeHashTableBuffer.stride * m_nodeHashTableBuffer.count;
|
|
|
|
if (m_numNodesAllocatedBuffer != null)
|
|
bytes += m_numNodesAllocatedBuffer.stride * m_numNodesAllocatedBuffer.count;
|
|
|
|
if (m_numAllocationsBuffer != null)
|
|
bytes += m_numAllocationsBuffer.stride * m_numAllocationsBuffer.count;
|
|
|
|
if (m_voxelCacheIdTableBuffer != null)
|
|
bytes += m_voxelCacheIdTableBuffer.stride * m_voxelCacheIdTableBuffer.count;
|
|
|
|
if (m_voxelCacheBuffer != null)
|
|
bytes += m_voxelCacheBuffer.stride * m_voxelCacheBuffer.count;
|
|
|
|
if (m_brushMaskPoolBuffer != null)
|
|
bytes += m_brushMaskPoolBuffer.stride * m_brushMaskPoolBuffer.count;
|
|
|
|
if (m_indirectDispatchArgsBuffer != null)
|
|
bytes += m_indirectDispatchArgsBuffer.stride * m_indirectDispatchArgsBuffer.count;
|
|
|
|
if (m_genPointsBufferDefault != null)
|
|
bytes += m_genPointsBufferDefault.stride * ((long)m_genPointsBufferDefault.count);
|
|
|
|
if (m_indirectDrawArgsBufferDefault != null)
|
|
bytes += m_indirectDrawArgsBufferDefault.stride * m_indirectDrawArgsBufferDefault.count;
|
|
|
|
if (m_autoSmoothVertDataTableBuffer != null)
|
|
bytes += m_autoSmoothVertDataTableBuffer.stride * m_autoSmoothVertDataTableBuffer.count;
|
|
|
|
if (!s_warnedResourceAccessPerformanceImpact && Application.isPlaying)
|
|
{
|
|
Debug.LogWarning("MudBun: Accessing resource usage impacts performance!");
|
|
s_warnedResourceAccessPerformanceImpact = true;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
}
|
|
|
|
public long LocalResourceGpuMemoryUsed
|
|
{
|
|
get
|
|
{
|
|
long bytes = 0;
|
|
|
|
if (!AllowSharedRWBuffers)
|
|
{
|
|
if (m_brushesBuffer != null)
|
|
bytes += m_brushesBuffer.stride * m_brushesBuffer.count;
|
|
|
|
if (m_brushMaterialBuffer != null)
|
|
bytes += m_brushMaterialBuffer.stride * m_brushMaterialBuffer.count;
|
|
|
|
if (m_aabbTreeBuffer != null)
|
|
bytes += m_aabbTreeBuffer.stride * m_aabbTreeBuffer.count;
|
|
}
|
|
|
|
if (m_numNodesAllocatedBuffer != null)
|
|
{
|
|
bytes += m_numNodesAllocatedBuffer.stride * ((long)m_numNodesAllocatedBuffer.count);
|
|
|
|
var aNumNodesAllocated = new int[m_numNodesAllocatedBuffer.count];
|
|
m_numNodesAllocatedBuffer.GetData(aNumNodesAllocated);
|
|
int numTotalNodes = aNumNodesAllocated[0];
|
|
bytes += numTotalNodes * m_nodePoolBuffer.stride;
|
|
|
|
if (m_genPointsBufferDefault != null)
|
|
bytes += 6 * numTotalNodes * m_genPointsBufferDefault.stride;
|
|
}
|
|
|
|
int [] aNumAllocated = null;
|
|
if (m_numAllocationsBuffer != null)
|
|
{
|
|
aNumAllocated = new int[m_numAllocationsBuffer.count];
|
|
m_numAllocationsBuffer.GetData(aNumAllocated);
|
|
}
|
|
if (aNumAllocated != null)
|
|
{
|
|
if (m_nodeHashTableBuffer != null)
|
|
{
|
|
int numTotalHashes = aNumAllocated[(int) NumAllcationIndex.VoxelHash];
|
|
bytes += NodeHashTableAllocationMultiplier * numTotalHashes * m_nodeHashTableBuffer.stride;
|
|
}
|
|
|
|
if (m_autoSmoothVertDataTableBuffer != null)
|
|
{
|
|
int numSmoothVertData = aNumAllocated[(int) NumAllcationIndex.AutoSmoothVertData];
|
|
bytes += numSmoothVertData * m_autoSmoothVertDataTableBuffer.count;
|
|
}
|
|
}
|
|
|
|
if (m_numAllocationsBuffer != null)
|
|
bytes += m_numAllocationsBuffer.stride * m_numAllocationsBuffer.count;
|
|
|
|
if (m_voxelCacheIdTableBuffer != null)
|
|
bytes += m_voxelCacheIdTableBuffer.stride * m_voxelCacheIdTableBuffer.count;
|
|
|
|
if (m_voxelCacheBuffer != null)
|
|
bytes += m_voxelCacheBuffer.stride * m_voxelCacheBuffer.count;
|
|
|
|
if (m_brushMaskPoolBuffer != null)
|
|
bytes += m_brushMaskPoolBuffer.stride * m_brushMaskPoolBuffer.count;
|
|
|
|
if (m_indirectDispatchArgsBuffer != null)
|
|
bytes += m_indirectDispatchArgsBuffer.stride * m_indirectDispatchArgsBuffer.count;
|
|
|
|
if (m_indirectDrawArgsBufferDefault != null)
|
|
bytes += m_indirectDrawArgsBufferDefault.stride * m_indirectDrawArgsBufferDefault.count;
|
|
|
|
if (!s_warnedResourceAccessPerformanceImpact && Application.isPlaying)
|
|
{
|
|
Debug.LogWarning("MudBun: Accessing resource usage impacts performance!");
|
|
s_warnedResourceAccessPerformanceImpact = true;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
}
|
|
|
|
public int NumVerticesAllocated => VoxelToVertexFactor * NumVoxelsAllocated;
|
|
public int NumVerticesGenerated
|
|
{
|
|
get
|
|
{
|
|
if (m_indirectDispatchArgsBuffer == null)
|
|
return 0;
|
|
|
|
int[] aIndirectDrawArgs = new int[5];
|
|
m_indirectDrawArgsBufferDefault.GetData(aIndirectDrawArgs);
|
|
|
|
if (!s_warnedResourceAccessPerformanceImpact && Application.isPlaying)
|
|
{
|
|
Debug.LogWarning("MudBun: Accessing resource usage impacts performance!");
|
|
s_warnedResourceAccessPerformanceImpact = true;
|
|
}
|
|
|
|
return aIndirectDrawArgs[0];
|
|
}
|
|
}
|
|
|
|
public int NumVoxelsAllocated => (m_nodePoolBuffer != null) ? MaxVoxels : 0;
|
|
public int NumChunksAllocated => (m_nodeHashTableBuffer != null) ? MaxChunks : 0;
|
|
public int NumVoxelsUsed
|
|
{
|
|
get
|
|
{
|
|
if (m_numNodesAllocatedBuffer == null)
|
|
return 0;
|
|
|
|
var aNumAllocated = new int[m_numNodesAllocatedBuffer.count];
|
|
m_numNodesAllocatedBuffer.GetData(aNumAllocated);
|
|
|
|
if (!s_warnedResourceAccessPerformanceImpact && Application.isPlaying)
|
|
{
|
|
Debug.LogWarning("MudBun: Accessing resource usage impacts performance!");
|
|
s_warnedResourceAccessPerformanceImpact = true;
|
|
}
|
|
|
|
return aNumAllocated[0];
|
|
}
|
|
}
|
|
public int NumChunksUsed
|
|
{
|
|
get
|
|
{
|
|
if (m_numAllocationsBuffer == null)
|
|
return 0;
|
|
|
|
var aNumAllocated = new int[m_numAllocationsBuffer.count];
|
|
m_numAllocationsBuffer.GetData(aNumAllocated);
|
|
int numTotalHashes = aNumAllocated[(int)NumAllcationIndex.VoxelHash];
|
|
|
|
if (!s_warnedResourceAccessPerformanceImpact && Application.isPlaying)
|
|
{
|
|
Debug.LogWarning("MudBun: Accessing resource usage impacts performance!");
|
|
s_warnedResourceAccessPerformanceImpact = true;
|
|
}
|
|
|
|
return numTotalHashes;
|
|
}
|
|
}
|
|
|
|
public bool ForceEvaluateAllBrushes = false;
|
|
|
|
private bool ShouldForceAllBrushes()
|
|
{
|
|
if (ForceEvaluateAllBrushes)
|
|
return true;
|
|
|
|
// trial version can't reference MudSolid
|
|
// should probably manually force this with the manual option anyway
|
|
/*
|
|
if (Enable2dMode)
|
|
{
|
|
if (Normal2dFade > MathUtil.Epsilon)
|
|
{
|
|
foreach (var b in m_aBrush)
|
|
{
|
|
var sb = (MudSolid) b;
|
|
if (sb.Operator == SdfBrush.OperatorEnum.Subtract)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool Enable2dMode = false;
|
|
[Range(-1.0f, 1.0f)] public float SurfaceShift = 0.0f;
|
|
|
|
public HardwareModeEnum HardwareMode = HardwareModeEnum.Gpu;
|
|
|
|
public RenderModeEnum RenderMode = RenderModeEnum.SmoothMesh;
|
|
public RenderModeCategoryEnum RenderModeCategory
|
|
{
|
|
get
|
|
{
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
case RenderModeEnum.SmoothMesh:
|
|
return RenderModeCategoryEnum.Mesh;
|
|
|
|
case RenderModeEnum.CircleSplats:
|
|
case RenderModeEnum.QuadSplats:
|
|
return RenderModeCategoryEnum.Splats;
|
|
|
|
case RenderModeEnum.Decal:
|
|
return RenderModeCategoryEnum.Decal;
|
|
|
|
/*
|
|
case RenderModeEnum.RayMarchedSurface:
|
|
return RenderModeCategoryEnum.RayMarchedSurface;
|
|
|
|
case RenderModeEnum.RayTracedVoxels:
|
|
return RenderModeCategoryEnum.RayTracedVoxels;
|
|
*/
|
|
}
|
|
return RenderModeCategoryEnum.Mesh;
|
|
}
|
|
}
|
|
|
|
public MeshingModeEnum MeshingMode = MeshingModeEnum.MarchingCubes;
|
|
public RayTracedVoxelModeEnum RayTracedVoxelMode = RayTracedVoxelModeEnum.FlatCubes;
|
|
[Range(0.0f, 1.0f)] public float RayTracedVoxelSizeMultiplier = 1.0f;
|
|
[Range(0.0f, 1.0f)] public float RayTracedVoxelSmoothCubeNormal = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float RayTracedVoxelSphereFullness = 0.0f;
|
|
public RayTracedVoxelPaddingModeEnum RayTracedVoxelPaddingMode = RayTracedVoxelPaddingModeEnum.ByDistance;
|
|
public float RayTracedVoxelInternalPaddingDistance = 0.0f;
|
|
public float RayTracedVoxelSizeFadeDistance = 0.0f;
|
|
|
|
private static RenderModeCategoryEnum GetMaterialRenderModeCategory(Material material)
|
|
{
|
|
if (material == null)
|
|
return RenderModeCategoryEnum.Unknown;
|
|
|
|
if (material.HasProperty(Const.IsMeshRenderMaterial))
|
|
return RenderModeCategoryEnum.Mesh;
|
|
|
|
if (material.HasProperty(Const.IsSplatRenderMaterial))
|
|
return RenderModeCategoryEnum.Splats;
|
|
|
|
return RenderModeCategoryEnum.Unknown;
|
|
}
|
|
|
|
private static bool MaterialNeedsSdfProperties(Material material)
|
|
{
|
|
if (material == null)
|
|
return false;
|
|
|
|
return material.HasProperty(Const.MaterialNeedsSdfProperties);
|
|
}
|
|
|
|
private static bool MaterialNeedsRayMarchingProperties(Material material)
|
|
{
|
|
if (material == null)
|
|
return false;
|
|
|
|
return material.HasProperty(Const.MaterialNeedsRayMarchingProperties);
|
|
}
|
|
|
|
private enum RenderGeometryTypeEnum
|
|
{
|
|
Unknown = -1,
|
|
Mesh,
|
|
BoxProxy,
|
|
Chunks,
|
|
}
|
|
|
|
private RenderGeometryTypeEnum RenderGeometryType
|
|
{
|
|
get
|
|
{
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Mesh:
|
|
case RenderModeCategoryEnum.Splats:
|
|
return RenderGeometryTypeEnum.Mesh;
|
|
|
|
case RenderModeCategoryEnum.Decal:
|
|
//case RenderModeCategoryEnum.RayMarchedSurface:
|
|
return RenderGeometryTypeEnum.BoxProxy;
|
|
|
|
/*
|
|
case RenderModeCategoryEnum.RayTracedVoxels:
|
|
return RenderGeometryTypeEnum.Chunks;
|
|
*/
|
|
}
|
|
|
|
return RenderGeometryTypeEnum.Unknown;
|
|
}
|
|
}
|
|
|
|
private bool RenderMaterialNeedsSdfProperties
|
|
{
|
|
get
|
|
{
|
|
if (MaterialNeedsSdfProperties(m_materialUsed))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
private RenderGeometryTypeEnum m_prevRenderGeometryType = RenderGeometryTypeEnum.Unknown;
|
|
|
|
public bool ShowAdvancedNormalOptions = false;
|
|
[Range(0.0f, 1.0f)] public float SmoothNormalBlurRelative = 0.05f;
|
|
[Range(0.0f, 0.2f)] public float SmoothNormalBlurAbsolute = 0.0f;
|
|
public float NormalDifferentialStep => Mathf.Max(0.01f * VoxelSize, SmoothNormalBlurRelative * VoxelSize + SmoothNormalBlurAbsolute);
|
|
[Range(0.0f, 1.0f)] public float NormalQuantization = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float Normal2dFade = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float Normal2dStrength = 1.0f;
|
|
public bool EnableAutoSmoothing = false;
|
|
[Range(0.0f, 180.0f)] public float AutoSmoothingMaxAngle = 30.0f;
|
|
public bool EnableSmoothCorner = false;
|
|
[Range(1, 4)] public int SmoothCornerSubdivision = 2;
|
|
[Range(0.001f, 0.1f)] public float SmoothCornerNormalBlur = 0.02f;
|
|
[Range(0.0f, 1.0f)] public float SmoothCornerFade = 0.0f;
|
|
public bool InvertNormals = false;
|
|
|
|
private bool ShouldDoAutoSmoothing
|
|
{
|
|
get
|
|
{
|
|
if (!EnableAutoSmoothing)
|
|
return false;
|
|
|
|
if (Enable2dMode)
|
|
return false;
|
|
|
|
switch (MeshingMode)
|
|
{
|
|
case MeshingModeEnum.MarchingCubes:
|
|
case MeshingModeEnum.SurfaceNets:
|
|
case MeshingModeEnum.DualContouring:
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
case RenderModeEnum.SmoothMesh:
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool ShowAdvancedSplatOptions = false;
|
|
[Range(0.0f, 5.0f)] public float SplatSize = 1.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatSizeJitter = 0.0f;
|
|
[Range(-1.0f, 1.0f)] public float SplatNormalShift = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatNormalShiftJitter = 1.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatColorJitter = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatPositionJitter = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatRotationJitter = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatOrientationJitter = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatOriginalNormalBlend = 1.0f;
|
|
[Range(0.01f, 1.0f)] public float SplatJitterNoisiness = 1.0f;
|
|
[Range(0.0f, 1.0f)] public float SplatCameraFacing = 0.0f;
|
|
public bool SplatNormalsMatchCameraFacing = false;
|
|
public bool SplatShadowsMatchCameraFacing = false;
|
|
[Range(0.0f, 1.0f)] public float SplatScreenSpaceFlattening = 1.0f;
|
|
//[Range(0.0f, 1.0f)] public float SplatSmoothNormalBlend = 0.0f;
|
|
|
|
[Range(0.0f, 1.0f)] public float SurfaceNetsDualQuadsBlend = 0.0f;
|
|
public bool ShowAdvancedGeometryOptions = false;
|
|
//[Range(0, 10)] public int SurfaceNetsBinarySearchIterations = 0;
|
|
//[Range(0, 5)] public int SurfaceNetsGradientDescentIterations = 0;
|
|
//[Range(0.0f, 1.0f)] public float SurfaceNetsGradientDescentFactor = 1.0f;
|
|
public bool SurfaceNetsHighAccuracyMode = false;
|
|
[Range(0.0f, 1.0f)] public float DualContouringDualQuadsBlend = 0.0f;
|
|
[Range(0.0f, 1.0f)] public float DualContouringRelaxation = 0.0f;
|
|
[Range(0, 20)] public int DualContouringSolverIterations = 5;
|
|
//[Range(0, 10)] public int DualContouringBinarySearchIterations = 0;
|
|
//[Range(0, 5)] public int DualContouringGradientDescentIterations = 0;
|
|
//[Range(0.0f, 1.0f)] public float DualContouringGradientDescentFactor = 1.0f;
|
|
public bool DualContouringHighAccuracyMode = false;
|
|
|
|
public ShadowCastingMode CastShadows = ShadowCastingMode.On;
|
|
public bool ReceiveShadows = true;
|
|
|
|
public IList<MudBrushBase> Brushes => m_aBrush;
|
|
private List<MudBrushBase> m_aBrush = new List<MudBrushBase>();
|
|
private List<MudBrushBase> m_aBrushToProcess = new List<MudBrushBase>();
|
|
private bool m_needRescanBrushes = false;
|
|
private static readonly float AabbTreeFatBoundsRadius = 0.25f;
|
|
internal AabbTree<MudBrushBase> m_aabbTree;
|
|
private void ValidateAabbTree()
|
|
{
|
|
if (m_aabbTree != null)
|
|
return;
|
|
|
|
m_aabbTree = new AabbTree<MudBrushBase>(AabbTreeFatBoundsRadius);
|
|
}
|
|
|
|
//[Header("Material")]
|
|
|
|
private MudSharedMaterialBase m_usedSharedMaterial;
|
|
public MudSharedMaterialBase SharedMaterial;
|
|
[SerializeField] private Color m_masterColor = Color.white;
|
|
[SerializeField] private Color m_masterEmission = Color.white;
|
|
[SerializeField] [Range(0.0f, 1.0f)] private float m_masterMetallic = 1.0f;
|
|
[SerializeField] [Range(0.0f, 1.0f)] private float m_masterSmoothness = 1.0f;
|
|
public Color MasterColor { get => m_usedSharedMaterial ? m_usedSharedMaterial.Color : m_masterColor; set { m_masterColor = value; } }
|
|
public Color MasterEmission { get => m_usedSharedMaterial ? m_usedSharedMaterial.Emission : m_masterEmission; set { m_masterEmission = value; } }
|
|
public float MasterMetallic { get => m_usedSharedMaterial ? m_usedSharedMaterial.Metallic : m_masterMetallic; set { m_masterMetallic = value; } }
|
|
public float MasterSmoothness { get => m_usedSharedMaterial ? m_usedSharedMaterial.Smoothness : m_masterSmoothness; set { m_masterSmoothness = value; } }
|
|
|
|
public Material RenderMaterialMesh;
|
|
public Material RenderMaterialSplats;
|
|
public Material RenderMaterialDecal;
|
|
//public Material RenderMaterialRayMarchedSurface;
|
|
//public Material RenderMaterialRayTracedVoxels;
|
|
public Material RenderMaterial
|
|
{
|
|
get
|
|
{
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Mesh:
|
|
return RenderMaterialMesh;
|
|
|
|
case RenderModeCategoryEnum.Splats:
|
|
return RenderMaterialSplats;
|
|
|
|
case RenderModeCategoryEnum.Decal:
|
|
return RenderMaterialDecal;
|
|
|
|
/*
|
|
case RenderModeCategoryEnum.RayMarchedSurface:
|
|
return RenderMaterialRayMarchedSurface;
|
|
|
|
case RenderModeCategoryEnum.RayTracedVoxels:
|
|
return RenderMaterialRayTracedVoxels;
|
|
*/
|
|
}
|
|
return RenderMaterialMesh;
|
|
}
|
|
}
|
|
private Material m_materialCloned;
|
|
private Material m_materialUsed;
|
|
private MaterialPropertyBlock m_materialProps;
|
|
public MaterialPropertyBlock RenderMaterialPropertyBlock
|
|
{
|
|
get
|
|
{
|
|
if (m_materialProps != null)
|
|
return m_materialProps;
|
|
|
|
m_materialProps = new MaterialPropertyBlock();
|
|
return m_materialProps;
|
|
}
|
|
}
|
|
|
|
[Range(8, 256)] public int MaxRayMarchSteps = 64;
|
|
[Range(0.0f, 1.0f)] public float RayMarchAccuracy = 0.5f;
|
|
[Range(1.0f, 2e3f)] public float RayMarchMaxRayDistance = 1e3f;
|
|
|
|
[Range(0.1f, 10.0f)] public float RayMarchStepSize = 0.5f;
|
|
[Range(1, 16)] public int NumLightMarchSteps = 8;
|
|
//[Range(0.1f, 100.0f)] public float RayMarchDistance = 20.0f;
|
|
[Range(0.0f, 20.0f)] public float RayMarchVolumeDensity = 5.0f;
|
|
public Light RayMarchLight;
|
|
[Range(0.0f, 10.0f)] public float RayMarchVolumeAbsorption = 1.0f;
|
|
[Range(0.0f, 10.0f)] public float RayMarchLightAbsorption = 1.0f;
|
|
[Range(0.0f, 1.0f)] public float RayMarchDarknesThreshold = 0.1f;
|
|
[Range(0.0f, 10.0f)] public float RayMarchTransmittanceCurve = 0.0f;
|
|
public bool UseRayMarchNoise = false;
|
|
[Range(0.0f, 1.0f)] public float RayMarchNoiseThreshold = 0.2f;
|
|
[Range(0.0f, 10.0f)] public float RayMarchNoiseEdgeFade = 2.0f;
|
|
public Vector3 RayMarchNoiseScrollSpeed = Vector3.zero;
|
|
public Vector3 RayMarchNoiseBaseOctaveSize = Vector3.one;
|
|
[Range(1, 3)] public int RayMarchNoiseNumOctaves = 2;
|
|
public float RayMarchNoiseOctaveOffsetFactor = 0.5f;
|
|
|
|
private Sdf.EvalJob[] m_aEvalJob;
|
|
|
|
//[Header("Editor")]
|
|
|
|
public enum ClickSelectionEnum
|
|
{
|
|
None,
|
|
Gizmos,
|
|
Raycast,
|
|
[InspectorName("Raycast (Forced Zero-Blend Union)")] RaycastForcedZeroBlendUnion,
|
|
}
|
|
|
|
public ClickSelectionEnum ClickSelection = ClickSelectionEnum.Raycast;
|
|
|
|
//[Header("Debug")]
|
|
|
|
public bool AlwaysDrawGizmos = false;
|
|
public bool DrawRawBrushBounds = false;
|
|
public bool DrawComputeBrushBounds = false;
|
|
public bool DrawRenderBounds = false;
|
|
public bool DrawVoxelNodes = false;
|
|
[Range(-1, 3)] public int DrawVoxelNodesDepth = -1;
|
|
[Range(0.0f, 1.0f)] public float DrawVoxelNodesScale = 1.0f;
|
|
|
|
public Aabb RenderBounds
|
|
{
|
|
get
|
|
{
|
|
var bounds = RenderBoundsRs;
|
|
if (!bounds.IsEmpty) // don't expand if empty, or it might crash the GPU!
|
|
{
|
|
bounds.Expand(SurfaceShift);
|
|
bounds.Transform(transform);
|
|
}
|
|
return bounds;
|
|
}
|
|
}
|
|
|
|
public Aabb RenderBoundsRs => m_aabbTree.Bounds;
|
|
|
|
[SerializeField] [HideInInspector] private string m_firstTrackedVersion = "";
|
|
[SerializeField] [HideInInspector] private string m_previousTrackedVersion = "";
|
|
[SerializeField] [HideInInspector] private string m_currentTrackedVersion = "";
|
|
public string FirstTrackedVersion => m_firstTrackedVersion;
|
|
public string PreviousTrackedVersion => m_previousTrackedVersion;
|
|
public string CurrentTrackedVersion => m_currentTrackedVersion;
|
|
|
|
#endregion // end: Local Resources
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Mesh Utilities
|
|
|
|
public static readonly float MaxMeshGenerationVoxelDensityFreeVersion = 8.0f;
|
|
public static readonly int MaxMeshGenerationTrianglesFreeVersion = 4096;
|
|
|
|
public float MeshGenerationVoxelDensity
|
|
{
|
|
get
|
|
{
|
|
#if MUDBUN_FREE
|
|
return Mathf.Min(MaxMeshGenerationVoxelDensityFreeVersion, VoxelDensity);
|
|
#else
|
|
return VoxelDensity;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public enum RenderableMeshMode
|
|
{
|
|
None,
|
|
Procedural,
|
|
MeshRenderer,
|
|
}
|
|
|
|
public enum AutoRiggingAlgorithm
|
|
{
|
|
New, // not ready yet
|
|
Default, // will be Legacy once New is ready
|
|
}
|
|
|
|
public bool MeshGenerationCreateNewObject = false;
|
|
public bool MeshGenerationCreateCollider = false;
|
|
public bool MeshGenerationForceConvexCollider = false;
|
|
[Range(-1.0f, 1.0f)] public float MeshGenerationColliderSurfaceShift = 0.0f;
|
|
public bool MeshGenerationCreateRigidBody = false;
|
|
public bool GenerateColliderMeshAssetByEditor = true; // editor only
|
|
public string GenerateColliderMeshAssetByEditorName = ""; // editor only
|
|
#if MUDBUN_FREE
|
|
[Range(0.0f, 8.0f)] public float MeshGenerationColliderVoxelDensity = 4.0f;
|
|
#else
|
|
[Range(0.0f, 128.0f)] public float MeshGenerationColliderVoxelDensity = 4.0f;
|
|
#endif
|
|
public RenderableMeshMode MeshGenerationRenderableMeshMode = RenderableMeshMode.Procedural;
|
|
public bool MeshGenerationAutoRigging = false;
|
|
public AutoRiggingAlgorithm MeshGenerationAutoRiggingAlgorithm = AutoRiggingAlgorithm.Default;
|
|
[Range(1, 4)] public int MeshGenerationAutoRiggingMaxBonesPerVertex = 4;
|
|
public bool MeshGenerationGenerateTextureUV = false;
|
|
public bool MeshGenerationGenerateLightMapUV = false;
|
|
public bool MeshGenerationWeldVertices = false;
|
|
public bool MeshGenerationLockOnStart = false;
|
|
public bool GenerateMeshAssetByEditor = true; // editor only
|
|
public string GenerateMeshAssetByEditorName = ""; // editor only
|
|
public bool RecursiveLockMeshByEditor = true; // editor only
|
|
public bool RememberLockedMeshMaterialByEditor = true; // editor only
|
|
[SerializeField] [HideInInspector] public bool MeshGenerationLockOnStartByEditor = false; // editor only
|
|
[SerializeField] protected Material m_lastLockedMeshMaterial;
|
|
|
|
[Serializable]
|
|
private class TransformCache
|
|
{
|
|
public Transform Transform;
|
|
public Transform Parent;
|
|
public Vector3 GlobalPosition;
|
|
public Quaternion GlobalRotation;
|
|
public Vector3 LocalPosition;
|
|
public Quaternion LocalRotation;
|
|
public Vector3 LocalScale;
|
|
public bool HasBrushDescendants;
|
|
}
|
|
|
|
// order: parent->child
|
|
[SerializeField] [HideInInspector] private List<TransformCache> m_aBrushTransformCache;
|
|
[SerializeField] [HideInInspector] private List<TransformCache> m_aNestedRendereTransformCache;
|
|
|
|
private bool HashNonMudBunObjectInHierarchy(Transform t)
|
|
{
|
|
if (t == null)
|
|
return false;
|
|
|
|
if (t.TryGetComponent(out Collider _) || t.TryGetComponent(out Collider2D _))
|
|
return true;
|
|
if (t.TryGetComponent(out MeshRenderer _) || t.TryGetComponent(out SkinnedMeshRenderer _))
|
|
{
|
|
if (!t.TryGetComponent(out MudRendererBase r) || !r.MeshLocked)
|
|
{
|
|
if (r != null)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < t.childCount; ++i)
|
|
{
|
|
if (HashNonMudBunObjectInHierarchy(t.GetChild(i)))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool HasBrushInHierarchy(Transform t)
|
|
{
|
|
if (t == null)
|
|
return false;
|
|
|
|
if (t.TryGetComponent(out MudBrushBase _))
|
|
return true;
|
|
|
|
for (int i = 0; i < t.childCount; ++i)
|
|
{
|
|
if (HasBrushInHierarchy(t.GetChild(i)))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void DetectMixedHierarchy(Transform t)
|
|
{
|
|
if (!HasBrushInHierarchy(t) || !HashNonMudBunObjectInHierarchy(t))
|
|
return;
|
|
|
|
Debug.LogWarning
|
|
(
|
|
"WARNING: Mixed MudBun objects and non-MudBun objects in renderer hierarchy detected during auto-rigging. "
|
|
+ "This can cause issues when normalizing bones to a unit scale of (1, 1, 1).\n"
|
|
+ "Please follow this guideline: "
|
|
+ "Objects with mixed MudBun objects and non-MudBun objects in their hierarchy should have a unit scale of (1, 1, 1)."
|
|
);
|
|
}
|
|
|
|
private void CacheBoneTransforms()
|
|
{
|
|
m_aBrushTransformCache = new List<TransformCache>();
|
|
m_aNestedRendereTransformCache = new List<TransformCache>();
|
|
CacheBoneTransformsRecursive(transform);
|
|
DetectMixedHierarchy(transform);
|
|
}
|
|
|
|
private void NormalizeBoneTransforms()
|
|
{
|
|
if (m_aBrushTransformCache == null)
|
|
return;
|
|
|
|
// move nested renderers out of the way
|
|
foreach (var cache in m_aNestedRendereTransformCache)
|
|
{
|
|
cache.Transform.SetParent(null, true);
|
|
}
|
|
|
|
// set each bone's local scale to unit scale to avoid shearing in child bones
|
|
foreach (var cache in m_aBrushTransformCache)
|
|
{
|
|
if (cache.HasBrushDescendants)
|
|
{
|
|
cache.Transform.localScale = Vector3.one;
|
|
cache.Transform.position = cache.GlobalPosition;
|
|
cache.Transform.rotation = cache.GlobalRotation;
|
|
}
|
|
else
|
|
{
|
|
cache.Transform.position = cache.GlobalPosition;
|
|
cache.Transform.rotation = cache.GlobalRotation;
|
|
}
|
|
}
|
|
|
|
// put nested renderers back in hierarchy
|
|
foreach (var cache in m_aNestedRendereTransformCache)
|
|
{
|
|
cache.Transform.SetParent(cache.Parent, true);
|
|
cache.Transform.position = cache.GlobalPosition;
|
|
cache.Transform.rotation = cache.GlobalRotation;
|
|
}
|
|
}
|
|
|
|
private void CacheBoneTransformsRecursive(Transform t)
|
|
{
|
|
if (t == null)
|
|
return;
|
|
|
|
var cache =
|
|
new TransformCache()
|
|
{
|
|
Transform = t,
|
|
Parent = t.parent,
|
|
GlobalPosition = t.position,
|
|
GlobalRotation = t.rotation,
|
|
LocalPosition = t.localPosition,
|
|
LocalRotation = t.localRotation,
|
|
LocalScale = t.localScale,
|
|
HasBrushDescendants = HasBrushInHierarchy(t),
|
|
};
|
|
|
|
if (t != transform)
|
|
{
|
|
if (t.GetComponent<MudRendererBase>() == null)
|
|
{
|
|
m_aBrushTransformCache.Add(cache);
|
|
}
|
|
else
|
|
{
|
|
// renderer blocks recursion
|
|
m_aNestedRendereTransformCache.Add(cache);
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < t.childCount; ++i)
|
|
{
|
|
var child = t.GetChild(i);
|
|
|
|
CacheBoneTransformsRecursive(t.GetChild(i));
|
|
}
|
|
}
|
|
|
|
private void RestoreBoneTransforms()
|
|
{
|
|
if (m_aBrushTransformCache == null)
|
|
return;
|
|
|
|
// move nested renderers out of the way
|
|
foreach (var cache in m_aNestedRendereTransformCache)
|
|
{
|
|
try
|
|
{
|
|
cache.Transform.SetParent(null, true);
|
|
}
|
|
catch (Exception)
|
|
{ }
|
|
}
|
|
|
|
// restore brush transforms
|
|
foreach (var cache in m_aBrushTransformCache)
|
|
{
|
|
try
|
|
{
|
|
cache.Transform.localScale = cache.LocalScale;
|
|
cache.Transform.localPosition = cache.LocalPosition;
|
|
cache.Transform.localRotation = cache.LocalRotation;
|
|
}
|
|
catch (Exception)
|
|
{ }
|
|
}
|
|
|
|
// restore nested renderer transforms
|
|
foreach (var cache in m_aNestedRendereTransformCache)
|
|
{
|
|
try
|
|
{
|
|
cache.Transform.SetParent(cache.Parent, true);
|
|
cache.Transform.localScale = cache.LocalScale;
|
|
cache.Transform.localPosition = cache.LocalPosition;
|
|
cache.Transform.localRotation = cache.LocalRotation;
|
|
}
|
|
catch (Exception)
|
|
{ }
|
|
}
|
|
|
|
m_aBrushTransformCache = null;
|
|
m_aNestedRendereTransformCache = null;
|
|
}
|
|
|
|
public enum GeneratedMeshType
|
|
{
|
|
Standard,
|
|
Compute,
|
|
Collider,
|
|
}
|
|
|
|
private class PendingMeshData
|
|
{
|
|
public Mesh Mesh;
|
|
public GeneratedMeshType MeshType;
|
|
public Transform RootBone;
|
|
public List<Transform> Bones;
|
|
public bool DoRigging;
|
|
public bool GenerateTextureUV;
|
|
public bool GenerateLightMapUV;
|
|
public bool WeldVertices;
|
|
public bool OptimizeMeshForRendering;
|
|
public bool Async;
|
|
public ComputeBuffer IndirectDrawArgsBuffer;
|
|
public ComputeBuffer GenPointsBuffer;
|
|
|
|
public void Dispose()
|
|
{
|
|
if (IndirectDrawArgsBuffer != null)
|
|
{
|
|
//IndirectDrawArgsBuffer.Release();
|
|
Janitor.Dispose(IndirectDrawArgsBuffer);
|
|
IndirectDrawArgsBuffer = null;
|
|
}
|
|
|
|
if (GenPointsBuffer != null)
|
|
{
|
|
//GenPointsBuffer.Release();
|
|
Janitor.Dispose(GenPointsBuffer);
|
|
GenPointsBuffer = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Dictionary<AsyncGPUReadbackRequest, PendingMeshData> m_pendingMeshTable = new Dictionary<AsyncGPUReadbackRequest, PendingMeshData>();
|
|
public bool IsAnyMeshGenerationPending => m_pendingMeshTable != null && m_pendingMeshTable.Count > 0;
|
|
public bool IsMeshGenerationPending(Mesh mesh)
|
|
{
|
|
foreach (var pair in m_pendingMeshTable)
|
|
if (pair.Value.Mesh == mesh)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
public void WaitForMeshGeneration(Mesh mesh)
|
|
{
|
|
foreach (var pair in m_pendingMeshTable)
|
|
{
|
|
if (pair.Value.Mesh != mesh)
|
|
continue;
|
|
|
|
pair.Key.WaitForCompletion();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public Mesh GenerateMesh
|
|
(
|
|
GeneratedMeshType meshType,
|
|
bool async,
|
|
Mesh mesh = null,
|
|
bool generateTextureUV = false,
|
|
bool generateLightMapUV = false,
|
|
bool weldVertices = false,
|
|
bool optimizeMeshForRendering = false
|
|
)
|
|
{
|
|
Transform [] aBone;
|
|
return GenerateMesh(meshType, null, out aBone, async, mesh, generateTextureUV, generateLightMapUV, weldVertices, optimizeMeshForRendering);
|
|
}
|
|
|
|
public Mesh GenerateMesh
|
|
(
|
|
GeneratedMeshType meshType,
|
|
Transform rootBone,
|
|
out Transform [] aBone,
|
|
bool async,
|
|
Mesh mesh = null,
|
|
bool genreateTextureUV = false,
|
|
bool generateLightMapUV = false,
|
|
bool weldVertices = false,
|
|
bool optimizeMeshForRendering =false
|
|
)
|
|
{
|
|
aBone = null;
|
|
|
|
if (meshType == GeneratedMeshType.Compute)
|
|
return null;
|
|
|
|
UpdateComputeData();
|
|
|
|
ValidateLocalResources();
|
|
|
|
var prevRenderMode = RenderMode;
|
|
var prevMeshingMode = MeshingMode;
|
|
float prevVoxelDensity = VoxelDensity;
|
|
int prevMaxVoxelsK = MaxVoxelsK;
|
|
int prevMaxChunks = MaxChunks;
|
|
float prevSurfaceShift = SurfaceShift;
|
|
|
|
if (meshType == GeneratedMeshType.Collider)
|
|
{
|
|
RenderMode = RenderModeEnum.FlatMesh;
|
|
VoxelDensity = MeshGenerationColliderVoxelDensity;
|
|
SurfaceShift += MeshGenerationColliderSurfaceShift;
|
|
}
|
|
else
|
|
{
|
|
VoxelDensity = MeshGenerationVoxelDensity;
|
|
}
|
|
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Splats:
|
|
RenderMode = RenderModeEnum.FlatMesh;
|
|
break;
|
|
|
|
/*
|
|
case RenderModeCategoryEnum.RayMarchedSurface:
|
|
RenderMode = RenderModeEnum.FlatMesh;
|
|
MeshingMode = MeshingModeEnum.DualQuads;
|
|
break;
|
|
*/
|
|
}
|
|
|
|
// always override buffers to work in Metal
|
|
m_indirectDrawArgsBufferOverride = new ComputeBuffer(5, sizeof(int), ComputeBufferType.IndirectArguments);
|
|
m_genPointsBufferOverride = new ComputeBuffer(MaxGenPoints, GenPoint.Stride);
|
|
var indirectDrawArgsBuffer = m_indirectDrawArgsBufferOverride;
|
|
var genPointsBuffer = m_genPointsBufferOverride;
|
|
|
|
indirectDrawArgsBuffer.SetData(IndirectDrawArgsInitData);
|
|
ForceCompute();
|
|
|
|
RenderMode = prevRenderMode;
|
|
MeshingMode = prevMeshingMode;
|
|
VoxelDensity = prevVoxelDensity;
|
|
MaxVoxelsK = prevMaxVoxelsK;
|
|
MaxChunks = prevMaxChunks;
|
|
SurfaceShift = prevSurfaceShift;
|
|
MarkNeedsCompute();
|
|
|
|
if (indirectDrawArgsBuffer == null)
|
|
return null;
|
|
|
|
if (genPointsBuffer == null)
|
|
return null;
|
|
|
|
if (mesh == null)
|
|
mesh = new Mesh();
|
|
|
|
var pendingMeshData =
|
|
new PendingMeshData()
|
|
{
|
|
Mesh = mesh,
|
|
MeshType = meshType,
|
|
RootBone = rootBone,
|
|
Bones = m_aBone,
|
|
DoRigging = m_doRigging,
|
|
GenerateTextureUV = genreateTextureUV,
|
|
GenerateLightMapUV = generateLightMapUV,
|
|
WeldVertices = weldVertices,
|
|
OptimizeMeshForRendering = optimizeMeshForRendering,
|
|
Async = async,
|
|
IndirectDrawArgsBuffer = indirectDrawArgsBuffer,
|
|
GenPointsBuffer = genPointsBuffer,
|
|
};
|
|
|
|
if (m_aBone != null)
|
|
{
|
|
aBone = m_aBone.ToArray();
|
|
m_aBone = null;
|
|
}
|
|
|
|
var request = AsyncGPUReadback.Request(pendingMeshData.IndirectDrawArgsBuffer, OnIndirectDrawArgsBufferRead);
|
|
m_pendingMeshTable.Add(request, pendingMeshData);
|
|
if (!async)
|
|
request.WaitForCompletion();
|
|
|
|
return mesh;
|
|
}
|
|
|
|
private void OnIndirectDrawArgsBufferRead(AsyncGPUReadbackRequest request)
|
|
{
|
|
PendingMeshData pendingMeshData;
|
|
bool dataFound = m_pendingMeshTable.TryGetValue(request, out pendingMeshData);
|
|
m_pendingMeshTable.Remove(request);
|
|
var aDrawArgs = request.GetData<int>();
|
|
if (!dataFound
|
|
|| aDrawArgs.Length <= 0
|
|
|| request.hasError)
|
|
{
|
|
if (pendingMeshData != null)
|
|
pendingMeshData.Dispose();
|
|
return;
|
|
}
|
|
|
|
int numVerts = aDrawArgs[0];
|
|
if (MudBun.IsFreeVersion)
|
|
numVerts = Mathf.Min(numVerts, 3 * MaxMeshGenerationTrianglesFreeVersion);
|
|
|
|
if (numVerts <= 0)
|
|
{
|
|
pendingMeshData.Dispose();
|
|
return;
|
|
}
|
|
|
|
var newRequest = AsyncGPUReadback.Request(pendingMeshData.GenPointsBuffer, numVerts * pendingMeshData.GenPointsBuffer.stride, 0, OnGenPointsBufferRead);
|
|
m_pendingMeshTable.Add(newRequest, pendingMeshData);
|
|
if (!pendingMeshData.Async)
|
|
newRequest.WaitForCompletion();
|
|
}
|
|
|
|
private void OnGenPointsBufferRead(AsyncGPUReadbackRequest request)
|
|
{
|
|
PendingMeshData pendingMeshData;
|
|
bool dataFound = m_pendingMeshTable.TryGetValue(request, out pendingMeshData);
|
|
m_pendingMeshTable.Remove(request);
|
|
if (!dataFound
|
|
|| request.hasError)
|
|
{
|
|
if (pendingMeshData != null)
|
|
pendingMeshData.Dispose();
|
|
return;
|
|
}
|
|
|
|
var aGenPoint = request.GetData<GenPoint>();
|
|
BuildMesh
|
|
(
|
|
pendingMeshData.Mesh,
|
|
pendingMeshData.MeshType,
|
|
aGenPoint,
|
|
pendingMeshData.RootBone,
|
|
pendingMeshData.Bones,
|
|
pendingMeshData.DoRigging,
|
|
pendingMeshData.GenerateTextureUV,
|
|
pendingMeshData.GenerateLightMapUV,
|
|
pendingMeshData.WeldVertices,
|
|
pendingMeshData.OptimizeMeshForRendering
|
|
);
|
|
|
|
if (pendingMeshData.Async
|
|
&& pendingMeshData.IndirectDrawArgsBuffer == m_indirectDrawArgsBufferDefault
|
|
&& pendingMeshData.GenPointsBuffer == m_genPointsBufferDefault
|
|
&& m_isMeshLocked)
|
|
{
|
|
DisposeLocalResources();
|
|
}
|
|
|
|
InvokeOnMeshGenerated(pendingMeshData.Mesh);
|
|
|
|
pendingMeshData.Dispose();
|
|
}
|
|
|
|
private void BuildMesh
|
|
(
|
|
Mesh mesh,
|
|
GeneratedMeshType meshType,
|
|
NativeArray<GenPoint> aGenPoint,
|
|
Transform rootBone,
|
|
List<Transform> bones,
|
|
bool doRigging,
|
|
bool generateTextureUV,
|
|
bool generateLightMapUV,
|
|
bool weldVertices,
|
|
bool optimizeMeshForRendering
|
|
)
|
|
{
|
|
int numVerts = aGenPoint.Length;
|
|
var aVertex = new NativeArray<Vector3>(numVerts, Allocator.Temp);
|
|
var aNormal = new NativeArray<Vector3>(numVerts, Allocator.Temp);
|
|
var aTangent = new NativeArray<Vector4>(numVerts, Allocator.Temp);
|
|
var aVertIndex = new NativeArray<int>(numVerts, Allocator.Temp);
|
|
bool invertNormals = InvertNormals && !Enable2dMode;
|
|
for (int i = 0; i < numVerts; ++i)
|
|
{
|
|
aVertex[i] = aGenPoint[i].PosNorm;
|
|
aNormal[i] = Codec.UnpackNormal(aGenPoint[i].PosNorm.w);
|
|
aTangent[i] = VectorUtil.FindOrthogonal(aNormal[i]);
|
|
aVertIndex[i] = invertNormals ? (3 * (i / 3) + 2 - (i % 3) ) : i;
|
|
}
|
|
|
|
mesh.Clear();
|
|
mesh.SetVertices(aVertex);
|
|
mesh.SetNormals(aNormal);
|
|
mesh.SetTangents(aTangent);
|
|
mesh.indexFormat = numVerts > 65535 ? IndexFormat.UInt32 : IndexFormat.UInt16;
|
|
mesh.SetIndices(aVertIndex, MeshTopology.Triangles, 0);
|
|
|
|
if (meshType == GeneratedMeshType.Standard)
|
|
{
|
|
Color [] aColor = new Color[numVerts];
|
|
Vector4 [] aEmissionHash = new Vector4[numVerts];
|
|
Vector2 [] aMetallicSmoothness = new Vector2[numVerts];
|
|
Vector4 [] aTextureWeight = new Vector4[numVerts];
|
|
|
|
BoneWeight [] aBoneWeight = null;
|
|
if (doRigging)
|
|
{
|
|
CacheBoneTransforms();
|
|
aBoneWeight = new BoneWeight[numVerts];
|
|
}
|
|
|
|
for (int i = 0; i < numVerts; ++i)
|
|
{
|
|
Color c = Codec.UnpackRgba(aGenPoint[i].Material.Color);
|
|
Color et = Codec.UnpackRgba(aGenPoint[i].Material.EmissionTightness);
|
|
|
|
/*
|
|
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
|
{
|
|
float gamma = 2.2f;
|
|
aColor[i] =
|
|
new Color
|
|
(
|
|
Mathf.Pow(c.r * MasterColor.r, gamma),
|
|
Mathf.Pow(c.g * MasterColor.g, gamma),
|
|
Mathf.Pow(c.b * MasterColor.b, gamma),
|
|
c.a * MasterColor.a
|
|
);
|
|
aEmissionHash[i] =
|
|
new Vector4
|
|
(
|
|
Mathf.Pow(et.r * MasterEmission.r, gamma),
|
|
Mathf.Pow(et.g * MasterEmission.g, gamma),
|
|
Mathf.Pow(et.b * MasterEmission.b, gamma),
|
|
aGenPoint[i].Material.Hash
|
|
);
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
aColor[i] = c * MasterColor;
|
|
aEmissionHash[i] =
|
|
new Vector4
|
|
(
|
|
et.r * MasterEmission.r,
|
|
et.g * MasterEmission.g,
|
|
et.b * MasterEmission.b,
|
|
aGenPoint[i].Material.Hash
|
|
);
|
|
}
|
|
|
|
Vector2 ms = Codec.UnpackSaturated(aGenPoint[i].Material.MetallicSmoothness);
|
|
aMetallicSmoothness[i] = new Vector2(ms.x * MasterMetallic, ms.y * MasterSmoothness);
|
|
|
|
aTextureWeight[i] = Codec.UnpackRgba(aGenPoint[i].Material.TextureWeight);
|
|
|
|
if (aBoneWeight != null)
|
|
{
|
|
aBoneWeight[i].boneIndex0 = aGenPoint[i].BoneIndex0;
|
|
aBoneWeight[i].boneIndex1 = aGenPoint[i].BoneIndex1;
|
|
aBoneWeight[i].boneIndex2 = aGenPoint[i].BoneIndex2;
|
|
aBoneWeight[i].boneIndex3 = aGenPoint[i].BoneIndex3;
|
|
|
|
Vector4 boneWeight = Codec.UnpackRgba(aGenPoint[i].BoneWeight);
|
|
for (int iWeightComp = 4; iWeightComp > MeshGenerationAutoRiggingMaxBonesPerVertex && iWeightComp >= 0; --iWeightComp)
|
|
boneWeight[iWeightComp - 1] = 0.0f;
|
|
|
|
if (aBoneWeight[i].boneIndex0 < 0)
|
|
{
|
|
aBoneWeight[i].boneIndex0 = 0;
|
|
boneWeight.x = 0.0f;
|
|
}
|
|
|
|
if (aBoneWeight[i].boneIndex1 < 0)
|
|
{
|
|
aBoneWeight[i].boneIndex1 = 0;
|
|
boneWeight.y = 0.0f;
|
|
}
|
|
|
|
if (aBoneWeight[i].boneIndex2 < 0)
|
|
{
|
|
aBoneWeight[i].boneIndex2 = 0;
|
|
boneWeight.z = 0.0f;
|
|
}
|
|
|
|
if (aBoneWeight[i].boneIndex3 < 0)
|
|
{
|
|
aBoneWeight[i].boneIndex3 = 0;
|
|
boneWeight.w = 0.0f;
|
|
}
|
|
|
|
boneWeight /= Mathf.Max(MathUtil.Epsilon, Vector4.Dot(boneWeight, Vector4.one));
|
|
aBoneWeight[i].weight0 = MathUtil.Saturate(boneWeight.x);
|
|
aBoneWeight[i].weight1 = MathUtil.Saturate(boneWeight.y);
|
|
aBoneWeight[i].weight2 = MathUtil.Saturate(boneWeight.z);
|
|
aBoneWeight[i].weight3 = MathUtil.Saturate(boneWeight.w);
|
|
}
|
|
}
|
|
mesh.SetColors(aColor);
|
|
mesh.SetUVs(MeshUtil.EmissionHashUvIndex, aEmissionHash);
|
|
mesh.SetUVs(MeshUtil.MetallicSmoothnessUvIndex, aMetallicSmoothness);
|
|
mesh.SetUVs(MeshUtil.TextureWeightIndex, aTextureWeight);
|
|
if (aBoneWeight != null
|
|
&& rootBone != null
|
|
&& bones != null)
|
|
{
|
|
NormalizeBoneTransforms();
|
|
mesh.boneWeights = aBoneWeight;
|
|
mesh.bindposes = bones.Select(x => x.worldToLocalMatrix * rootBone.localToWorldMatrix).ToArray();
|
|
}
|
|
|
|
bool uvGenerated = GenerateUV(mesh, generateTextureUV, generateLightMapUV);
|
|
|
|
if (weldVertices)
|
|
{
|
|
MeshUtil.Weld(mesh, (uvGenerated ? 0 : -1));
|
|
}
|
|
|
|
if (optimizeMeshForRendering)
|
|
{
|
|
mesh.Optimize();
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void RectifyNonUnitScaledParents() { }
|
|
|
|
virtual protected bool GenerateUV(Mesh mesh, bool generateTextureUV, bool generateLightMapUV) { return false; }
|
|
|
|
[SerializeField] [HideInInspector] private bool m_isMeshLocked = false;
|
|
public bool MeshLocked => m_isMeshLocked;
|
|
|
|
protected enum LockMeshIntermediateStateEnum
|
|
{
|
|
Idle,
|
|
PreLock,
|
|
PostLock,
|
|
PreUnlock,
|
|
}
|
|
protected virtual LockMeshIntermediateStateEnum LockMeshIntermediateState => LockMeshIntermediateStateEnum.Idle;
|
|
|
|
protected bool m_doRigging = false;
|
|
|
|
public virtual Mesh AddCollider
|
|
(
|
|
GameObject go,
|
|
bool async,
|
|
Mesh mesh = null,
|
|
bool forceConvexCollider = false,
|
|
bool makeRigidBody = false
|
|
)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public virtual Mesh AddLockedStandardMesh
|
|
(
|
|
GameObject go,
|
|
bool autoRigging,
|
|
bool async,
|
|
Mesh mesh = null,
|
|
bool generateTextureUV = false,
|
|
bool generateLightMapUV = false,
|
|
bool weldVertices = false,
|
|
bool optimizeMeshForRendering = false
|
|
)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public virtual void LockMesh
|
|
(
|
|
bool autoRigging,
|
|
bool async,
|
|
Mesh mesh = null,
|
|
bool generateTextureUV = false,
|
|
bool generateLightMapUV = false,
|
|
bool weldVertices = false,
|
|
bool optimizeMeshForRendering = false
|
|
)
|
|
{
|
|
m_isMeshLocked = true;
|
|
}
|
|
|
|
public void RememberLockedMeshMaterial()
|
|
{
|
|
var meshRenderer = GetComponent<MeshRenderer>();
|
|
if (meshRenderer != null)
|
|
{
|
|
m_lastLockedMeshMaterial = meshRenderer.sharedMaterial;
|
|
}
|
|
else
|
|
{
|
|
var skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
|
|
if (skinnedMeshRenderer != null)
|
|
m_lastLockedMeshMaterial = skinnedMeshRenderer.sharedMaterial;
|
|
}
|
|
}
|
|
|
|
public virtual void UnlockMesh()
|
|
{
|
|
m_isMeshLocked = false;
|
|
MarkNeedsCompute();
|
|
RestoreBoneTransforms();
|
|
|
|
MarkNeedsCompute();
|
|
}
|
|
|
|
#endregion // end: Mesh Utilities
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region SDF
|
|
|
|
public bool DrawGenerateSdfGizmos = false; // editor only
|
|
public string GenerateSdfByEditorName = ""; // editor only
|
|
public Vector3 GenerateSdfCenter = Vector3.zero;
|
|
public Vector3 GenerateSdfDimension = Vector3.one;
|
|
public Vector3Int GenerateSdfTextureSize = new Vector3Int(64, 64, 64);
|
|
[NonSerialized] protected List<Sdf.EvalJobHandle> m_jobQueue = new List<Sdf.EvalJobHandle>();
|
|
[NonSerialized] protected List<Sdf.EvalJobHandle> m_jobCompleteQueue = new List<Sdf.EvalJobHandle>();
|
|
|
|
public void ValidateAssetNames()
|
|
{
|
|
if (GenerateColliderMeshAssetByEditorName.Equals(""))
|
|
GenerateColliderMeshAssetByEditorName = $"{gameObject.name} Collider Mesh {(uint)gameObject.GetInstanceID()}";
|
|
|
|
if (GenerateMeshAssetByEditorName.Equals(""))
|
|
GenerateMeshAssetByEditorName = $"{gameObject.name} Mesh {(uint) gameObject.GetInstanceID()}";
|
|
|
|
if (GenerateSdfByEditorName.Equals(""))
|
|
GenerateSdfByEditorName = $"{gameObject.name} SDF {(uint) gameObject.GetInstanceID()}";
|
|
}
|
|
|
|
public virtual void GenerateSdf
|
|
(
|
|
RenderTexture sdf,
|
|
Vector3 origin,
|
|
Vector3 dimension
|
|
)
|
|
{
|
|
if (sdf == null)
|
|
return;
|
|
|
|
ValidateResources();
|
|
SetUpResources();
|
|
|
|
ComputeManager.SetTexture(Const.SdfOutput, sdf);
|
|
ComputeManager.SetInts(Const.SdfOutputSize, new int[] { sdf.width, sdf.height, sdf.volumeDepth });
|
|
ComputeManager.SetVector(Const.SdfCenter, origin);
|
|
ComputeManager.SetVector(Const.SdfDimension, dimension);
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeSdfGen,
|
|
Const.Kernel.GenerateSdf,
|
|
(sdf.width + ThreadGroupExtent - 1) / ThreadGroupExtent,
|
|
(sdf.height + ThreadGroupExtent - 1) / ThreadGroupExtent,
|
|
(sdf.volumeDepth + ThreadGroupExtent - 1) / ThreadGroupExtent
|
|
);
|
|
}
|
|
|
|
public virtual void GenerateSdf
|
|
(
|
|
Texture3D sdf,
|
|
Vector3 origin,
|
|
Vector3 dimension
|
|
)
|
|
{
|
|
if (sdf == null)
|
|
return;
|
|
|
|
var rt = new RenderTexture(sdf.width, sdf.height, 0, RenderTextureFormat.RFloat);
|
|
rt.dimension = TextureDimension.Tex3D;
|
|
rt.volumeDepth = sdf.depth;
|
|
rt.enableRandomWrite = true;
|
|
rt.Create();
|
|
|
|
GenerateSdf(rt, origin, dimension);
|
|
TextureUtil.RenderTextureToTexture3D(sdf, rt);
|
|
|
|
rt.Release();
|
|
}
|
|
|
|
internal void UpdateComputeData()
|
|
{
|
|
Assert.True(m_initialized, "Renderer not initialized. Either an automatic call to OnEnable() or a manual call to Init() needs to be done before any computation.");
|
|
|
|
if (m_needRescanBrushes)
|
|
{
|
|
RescanBrushesImmediate();
|
|
m_needRescanBrushes = false;
|
|
}
|
|
|
|
UpdateNeedsCompute();
|
|
UpdateBrushData();
|
|
UpdateAabbTreeData();
|
|
}
|
|
|
|
public static MudBrushBase LookupBrush(float hash)
|
|
{
|
|
return s_brushMap.TryGetValue(hash, out var brush) ? brush : null;
|
|
}
|
|
|
|
#endregion // end: SDf
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Optimization
|
|
|
|
public bool UseCutoffVolume = false;
|
|
public Transform CutoffVolumeCenter;
|
|
public Vector3 CutoffVolumeSize = Vector3.one;
|
|
|
|
/*
|
|
public Transform OptimizationRendererReference;
|
|
public Transform OptimizationCameraRefernce;
|
|
|
|
public bool EnableDistanceLod = false;
|
|
public float DistanceLodStartDistance = 10.0f;
|
|
public float DistanceLodFadeDistance = 5.0f;
|
|
public float DistanceLodFarVoxelDensity = 4.0f;
|
|
|
|
public bool EnableDistanceFade = false;
|
|
public float DistanceFadeFarStartDistance = 10.0f;
|
|
public float DistanceFadeFarFadeDistance = 5.0f;
|
|
public float DistanceFadeNearStartDistance = 1.0f;
|
|
public float DistanceFadeNearEndDistance = 1.0f;
|
|
*/
|
|
|
|
#endregion // end: Optimization
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Callbacks
|
|
|
|
protected virtual void OnSharedMaterialChanged(UnityEngine.Object material) { }
|
|
|
|
protected virtual void InitBeforeFirstRenderer()
|
|
{
|
|
Sdf.InitEvalMap();
|
|
}
|
|
|
|
protected virtual void CleanUpAfterLastRenderer()
|
|
{
|
|
DisposeGlobalResources();
|
|
Sdf.DisposeEvalMap();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if ((MeshGenerationLockOnStart || (MeshGenerationLockOnStartByEditor && MeshGenerationRenderableMeshMode == RenderableMeshMode.Procedural))
|
|
&& Application.isPlaying
|
|
&& !m_isMeshLocked)
|
|
{
|
|
if (MeshGenerationCreateCollider)
|
|
AddCollider(gameObject, false, null, MeshGenerationForceConvexCollider, MeshGenerationCreateRigidBody);
|
|
|
|
MarkNeedsCompute();
|
|
LockMesh(MeshGenerationAutoRigging, false);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnEnable() { Init(); }
|
|
protected virtual void OnDisable() { ShutDown();}
|
|
|
|
public void Init()
|
|
{
|
|
if (m_initialized)
|
|
return;
|
|
|
|
Janitor.Init();
|
|
|
|
if (s_renderers.Count == 0)
|
|
{
|
|
InitBeforeFirstRenderer();
|
|
}
|
|
|
|
s_renderers.Add(this);
|
|
m_rendererIndex = s_renderers.Count - 1;
|
|
|
|
m_needRescanBrushes = true;
|
|
MarkNeedsCompute();
|
|
|
|
m_aSdfBrush = new NativeArray<SdfBrush>(MaxBrushes, Allocator.Persistent);
|
|
m_aSdfBrushMaterial = new NativeArray<SdfBrushMaterial>(MaxBrushes, Allocator.Persistent);
|
|
m_sdfBrushMaterialIndexMap = new Dictionary<int, int>();
|
|
|
|
m_aabbTree = new AabbTree<MudBrushBase>(AabbTreeFatBoundsRadius);
|
|
|
|
MarkNeedsCompute();
|
|
|
|
MudSharedMaterialBase.OnSharedMaterialChanged += OnSharedMaterialChanged;
|
|
|
|
m_previousTrackedVersion = m_currentTrackedVersion;
|
|
m_currentTrackedVersion = MudBun.Version;
|
|
if (m_firstTrackedVersion.Equals(""))
|
|
m_firstTrackedVersion = m_currentTrackedVersion;
|
|
if (m_previousTrackedVersion.Equals(""))
|
|
m_previousTrackedVersion = m_currentTrackedVersion;
|
|
|
|
m_initialized = true;
|
|
}
|
|
|
|
public void ShutDown()
|
|
{
|
|
if (!m_initialized)
|
|
return;
|
|
|
|
m_initialized = false;
|
|
|
|
// complete lingering jobs
|
|
for (int i = 0; i < m_jobCompleteQueue.Count; ++i)
|
|
{
|
|
m_jobCompleteQueue[i].Complete();
|
|
}
|
|
m_jobCompleteQueue.Clear();
|
|
|
|
ClearBrushes();
|
|
|
|
DisposeLocalResources();
|
|
|
|
if (m_aSdfBrush.IsCreated)
|
|
m_aSdfBrush.Dispose();
|
|
if (m_aSdfBrushMaterial.IsCreated)
|
|
m_aSdfBrushMaterial.Dispose();
|
|
m_sdfBrushMaterialIndexMap = null;
|
|
|
|
m_aabbTree.Dispose();
|
|
m_aabbTree = null;
|
|
|
|
MudSharedMaterialBase.OnSharedMaterialChanged -= OnSharedMaterialChanged;
|
|
s_renderers.Remove(this);
|
|
m_rendererIndex = -1;
|
|
|
|
if (s_renderers.Count == 0)
|
|
{
|
|
CleanUpAfterLastRenderer();
|
|
}
|
|
}
|
|
|
|
protected virtual void OnValidate()
|
|
{
|
|
SanitizeParameters();
|
|
m_numVoxelsHighWaterMark = 0;
|
|
m_numChunksHighWaterMark = 0;
|
|
|
|
if (!m_isMeshLocked)
|
|
MarkNeedsCompute();
|
|
}
|
|
|
|
internal void OnBrushDisabled(MudBrushBase brush)
|
|
{
|
|
RemoveBrush(brush);
|
|
}
|
|
|
|
// SDF evaluation interface would need brush & AABB tree data ready before Compute()
|
|
// don't update it again for Compute() if they are already updated
|
|
private bool m_brushDataDirty = false;
|
|
private bool m_aabbTreeDirty = false;
|
|
|
|
public void MarkNeedsCompute()
|
|
{
|
|
m_needsCompute = true;
|
|
m_brushDataDirty = true;
|
|
m_aabbTreeDirty = true;
|
|
}
|
|
private bool m_needsCompute = false;
|
|
private bool UpdateNeedsCompute()
|
|
{
|
|
if (MeshLocked)
|
|
{
|
|
bool needsCompute = false;
|
|
if (MeshGenerationRenderableMeshMode == RenderableMeshMode.Procedural)
|
|
needsCompute = m_needsCompute;
|
|
|
|
m_needsCompute = false;
|
|
return needsCompute;
|
|
}
|
|
|
|
switch (ComputeMode)
|
|
{
|
|
case ComputeModeEnum.Auto:
|
|
break;
|
|
|
|
case ComputeModeEnum.Manual:
|
|
case ComputeModeEnum.ManualNoRender:
|
|
return m_needsCompute;
|
|
|
|
case ComputeModeEnum.EveryFrame:
|
|
MarkNeedsCompute();
|
|
return true;
|
|
|
|
case ComputeModeEnum.TimeSliced:
|
|
switch (TimeSliceMode)
|
|
{
|
|
case TimeSliceModeEnum.ByFramesAutoOffset:
|
|
if (((Time.frameCount + m_rendererIndex) % TimeSliceFrames) != 0)
|
|
return false;
|
|
break;
|
|
|
|
case TimeSliceModeEnum.ByFramesManualOffset:
|
|
if (((Time.frameCount + TimeSliceFramesOffset) % TimeSliceFrames) != 0)
|
|
return false;
|
|
break;
|
|
|
|
case TimeSliceModeEnum.ByPeriodAutoOffset:
|
|
{
|
|
int q = (int) Mathf.Floor((Time.time + Mathf.Repeat(m_rendererIndex * Time.deltaTime, TimeSlicePeriod)) / TimeSlicePeriod);
|
|
float qT = q * TimeSlicePeriod;
|
|
if (qT <= m_lastUpdateTimeSliceTime)
|
|
return false;
|
|
|
|
m_lastUpdateTimeSliceTime = qT;
|
|
break;
|
|
}
|
|
|
|
case TimeSliceModeEnum.ByPeriodManualOffset:
|
|
{
|
|
int q = (int) Mathf.Floor((Time.time + Mathf.Repeat(TimeSliceTimeOffset, TimeSlicePeriod)) / TimeSlicePeriod);
|
|
float qT = q * TimeSlicePeriod;
|
|
if (qT <= m_lastUpdateTimeSliceTime)
|
|
return false;
|
|
|
|
m_lastUpdateTimeSliceTime = qT;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (m_needsCompute)
|
|
return true;
|
|
|
|
Profiler.BeginSample("UpdateNeedsCompute");
|
|
|
|
// check need for rendering geometry type change
|
|
if (m_needsCompute)
|
|
{
|
|
var currRenderGeometryType = RenderGeometryType;
|
|
bool renderGeometryTypeChanged = (currRenderGeometryType != m_prevRenderGeometryType);
|
|
m_prevRenderGeometryType = currRenderGeometryType;
|
|
if (renderGeometryTypeChanged)
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
// check dirty brushes
|
|
if (!m_needsCompute)
|
|
{
|
|
foreach (var b in m_aBrush)
|
|
{
|
|
if (!b.m_dirty && !b.transform.hasChanged)
|
|
continue;
|
|
|
|
MarkNeedsCompute();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check animation
|
|
if (!m_needsCompute)
|
|
{
|
|
if (TryGetComponent(out Animation animation)
|
|
&& animation.isPlaying)
|
|
{
|
|
MarkNeedsCompute();
|
|
}
|
|
}
|
|
|
|
// check animator
|
|
if (!m_needsCompute)
|
|
{
|
|
if (TryGetComponent(out Animator animator)
|
|
&& animator.layerCount > 0)
|
|
{
|
|
var animState = animator.GetCurrentAnimatorStateInfo(0);
|
|
if (animState.length > 0.0f && animState.speed > 0.0f && animState.speedMultiplier > 0.0f)
|
|
MarkNeedsCompute();
|
|
}
|
|
}
|
|
|
|
if (m_needsCompute)
|
|
{
|
|
Profiler.BeginSample("Clear Transform Change Flags");
|
|
|
|
foreach (var b in m_aBrush)
|
|
{
|
|
b.m_dirty = false;
|
|
b.transform.hasChanged = false;
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
|
|
return m_needsCompute;
|
|
}
|
|
|
|
public RenderMaterialModeEnum RenderMaterialMode = RenderMaterialModeEnum.Static;
|
|
public void MarkRenderMaterialDirty() { m_renderMaterialDirty = true; }
|
|
private bool m_renderMaterialDirty = true;
|
|
|
|
protected virtual bool IsEditorBusy() { return false; }
|
|
|
|
private int m_numVoxelsHighWaterMark = 0;
|
|
private int m_numChunksHighWaterMark = 0;
|
|
private void TryAutoAdjustBudgets()
|
|
{
|
|
|
|
if (!Application.isEditor)
|
|
return;
|
|
|
|
if (!ShowGpuMemoryUsage)
|
|
{
|
|
m_autoAdjustBudgetsToHighWaterMarks = false;
|
|
return;
|
|
}
|
|
|
|
if (!AutoAdjustBudgetsToHighWaterMarks)
|
|
{
|
|
m_autoAdjustBudgetsToHighWaterMarks = false;
|
|
return;
|
|
}
|
|
|
|
Profiler.BeginSample("TryAutoAdjustBudgets");
|
|
|
|
if (AutoAdjustBudgetsToHighWaterMarks && !m_autoAdjustBudgetsToHighWaterMarks)
|
|
{
|
|
m_numVoxelsHighWaterMark = 0;
|
|
m_numChunksHighWaterMark = 0;
|
|
}
|
|
m_autoAdjustBudgetsToHighWaterMarks = AutoAdjustBudgetsToHighWaterMarks;
|
|
|
|
m_numVoxelsHighWaterMark = Mathf.Max(NumVoxelsUsed, m_numVoxelsHighWaterMark);
|
|
m_numChunksHighWaterMark = Mathf.Max(NumChunksUsed, m_numChunksHighWaterMark);
|
|
|
|
int effectiveNumVoxelsHighWaterMark = m_numVoxelsHighWaterMark;
|
|
if (ShouldDoAutoSmoothing && EnableSmoothCorner)
|
|
{
|
|
effectiveNumVoxelsHighWaterMark = Mathf.Max(effectiveNumVoxelsHighWaterMark, NumVerticesGenerated / VoxelToVertexFactor);
|
|
}
|
|
|
|
MaxVoxelsK = Mathf.Max(1, (int) Mathf.Ceil(effectiveNumVoxelsHighWaterMark * (1.0f + AutoAdjustBudgetsToHighWaterMarksMarginPercent / 100.0f) / 1024.0f));
|
|
MaxChunks = Mathf.Max(16, (int) Mathf.Ceil(m_numChunksHighWaterMark * (1.0f + AutoAdjustBudgetsToHighWaterMarksMarginPercent / 100.0f)));
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
protected virtual bool PreUpdateValidate() { return true; }
|
|
|
|
protected void LateUpdate()
|
|
{
|
|
UpdateComputeData();
|
|
|
|
if (m_jobQueue.Count > 0)
|
|
{
|
|
// complete lingering jobs
|
|
for (int i = 0; i < m_jobCompleteQueue.Count; ++i)
|
|
{
|
|
m_jobCompleteQueue[i].Complete();
|
|
}
|
|
m_jobCompleteQueue.Clear();
|
|
|
|
// schedule queued jobs
|
|
for (int i = 0; i < m_jobQueue.Count; ++i)
|
|
{
|
|
m_jobQueue[i].Schedule(true);
|
|
m_jobCompleteQueue.Add(m_jobQueue[i]);
|
|
}
|
|
JobHandle.ScheduleBatchedJobs();
|
|
m_jobQueue.Clear();
|
|
}
|
|
|
|
if (!PreUpdateValidate())
|
|
return;
|
|
|
|
if (m_isMeshLocked)
|
|
{
|
|
switch (MeshGenerationRenderableMeshMode)
|
|
{
|
|
case RenderableMeshMode.Procedural:
|
|
// keep on rendering in procedural mode
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
TryCompute();
|
|
|
|
switch (ComputeMode)
|
|
{
|
|
case ComputeModeEnum.ManualNoRender:
|
|
break;
|
|
|
|
default:
|
|
Render();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void ForceCompute()
|
|
{
|
|
TryCompute(true);
|
|
}
|
|
|
|
public virtual void ReloadShaders()
|
|
{
|
|
DisposeGlobalResources();
|
|
DisposeLocalResources();
|
|
MarkNeedsCompute();
|
|
}
|
|
|
|
private void TryCompute(bool forceCompute = false)
|
|
{
|
|
if (IsEditorBusy())
|
|
return;
|
|
|
|
TryAutoAdjustBudgets();
|
|
|
|
SanitizeParameters();
|
|
if (!ValidateResources())
|
|
return;
|
|
|
|
if (!s_globalResourcesValid || !m_localResourcesValid)
|
|
return;
|
|
|
|
if (forceCompute || m_needsCompute)
|
|
{
|
|
switch (HardwareMode)
|
|
{
|
|
case HardwareModeEnum.Gpu:
|
|
ComputeGpu();
|
|
break;
|
|
|
|
/*
|
|
case HardwareModeEnum.Cpu:
|
|
ComputeCpu();
|
|
break;
|
|
*/
|
|
}
|
|
|
|
m_needsCompute = false;
|
|
}
|
|
}
|
|
|
|
private void SanitizeParameters()
|
|
{
|
|
Validate.Range(-1, VoxelNodeDepth, ref DrawVoxelNodesDepth);
|
|
|
|
Validate.NonNegative(ref RayTracedVoxelInternalPaddingDistance);
|
|
Validate.NonNegative(ref RayTracedVoxelSizeFadeDistance);
|
|
}
|
|
|
|
#if MUDBUN_FREE
|
|
private static readonly int s_watermarkWidth = 300;
|
|
private static readonly int s_watermariHeight = 100;
|
|
private static readonly string s_watermarkStr = "iVBORw0KGgoAAAANSUhEUgAAAgAAAACACAYAAAB9V9ELAAAgAElEQVR4AeydB4BdRfX/7/bNlmxJ77vpPYQESAKEGHo1IL1JEaQIinR/goDCX0VARVERQRBQqkGQGpqQEEkoAQIhCUlI73032/f//cy75+Xmsft2k2wEzZzdeTN37syZmXPnnnPmTLkp9fX1gQdPAU8BTwFPAU8BT4HdiwKpu1dzfWs9BTwFPAU8BTwFPAWggFcAfD/wFPAU8BTwFPAU2A0p4BWA3fCh+yZ7CngKeAp4CngKeAXA9wFPAU8BTwFPAU+B3ZACXgHYDR+6b7KngKeAp4CngKeAVwB8H/AU8BTwFPAU8BTYDSngFYDd8KH7JnsKeAp4CngKeAp4BcD3AU8BTwFPAU8BT4HdkAJeAdgNH7pvsqeAp4CngKeAp4BXAHwf8BTwFPAU8BTwFNgNKeAVgN3wofsmewp4CngKeAp4CngFwPcBTwFPAU8BTwFPgd2QAl4B2A0fum+yp4CngKeAp4CngFcAfB/wFPAU8BTwFPAU2A0p4BWA3fCh+yZ7CngKeAp4CngKeAXA9wFPAU8BTwFPAU+B3ZACXgHYDR+6b7KngKeAp4CngKeAVwB8H/AU8BTwFPAU8BTYDSngFYDd8KH7JnsKeAp4CngKeAp4BcD3AU8BTwFPAU8BT4HdkAJeAdgNH7pvsqeAp4CngKeAp4BXAHwf8BTwFPAU8BTwFNgNKeAVgN3wofsmewp4CngKeAp4CngFwPcBTwFPAU8BTwFPgd2QAl4B2A0fum+yp4CngKeAp4CngFcAfB/wFPAU8BTwFPAU2A0p4BWA3fCh+yZ7CngKeAp4CngKeAXA9wFPAU8BTwFPAU+B3ZACXgHYDR+6b7KngKeAp4CngKeAVwB8H/AU8BTwFPAU8BTYDSngFYDd8KH7JnsKeAp4CngKeAp4BcD3AU8BTwFPAU8BT4HdkAJeAdgNH7pvsqeAp4CngKeAp4BXAHwf8BTwFPAU8BTwFNgNKZCe2OaUlJTEKH/tKeAp4CnwlaJAfX39V6o+vjKeAv+NFPAWgP/Gp+br7CngKeAp4CngKbCTFPiCBWA78TXXXODV9e0krE/uKeAp4CngKeApsCspsCMKQFToE7Zr862+JvTNT4y3a+97CngKeAp4CngKeAr8hymwPQqACXjzmT7AcW1+tPoI/jq5qB9VBqLhaD4f9hT4KlDA+nliXXy/TaSIv/YU8BT4r6RAcxUAY4b4uDQ5hD6+uagSAJPE1SY4FAJTCgynZ6giiocvnQLWH6lIQ2Hrp9yzMGmjYa49eAp4CngK/FdQoDkKgDFD/KjQz9A1Dhw4FAHS4EzQ1yic6EwpgHHiSO+ZqIjg4UujgPVbKkDYlFmLt77KfcKmxO5I/wUn4Pt8jA7+11PAU+BLokBzFACqZkzRhH2m4sxlKWyKgDFOE/LVuoerCp1dk440piiA3zNEEcHDf5wCJuTxzbJliq7do1Im+OmzKLXR64b6L3EG0XBiXLTfR8OWzvueAp4CngK7hAJNKQDGAPFhjqRH8GeHLkc+CgCOeNIAxiQR/JVyFaFPGGeKAEoAEGV80XDsbuw3kYkmXkfTRnFEw9E0PuwpkNi/rY+j0BLGWT+jT9NfEf4oCPjRe4Str1k8vjnyJALpwYuPi+LQpQdPAU8BT4FdR4GmFABKhikZMzThn6s4HApA7sEHHdT14IMO7L3vqNH9dV0/eeqU2c8//+LcV157bbmuEf7lcltCR5nEgRdFAIAJGiNMmfzy5PoMqRipKnXkqH1JZ0AYBzO1ePON+RpTJY/FBe9MmR4Pc6MpSBH6elVpS92WoL6+LsjKygxqqmuDpUtWB6mqWOJ5SRs2bAz2GbVX0H9A36ZQ+/tfEQpEDr2y/o3gp4+bo6+a4KZ/muIatWgp2gH3rS/i40yBMN9wkcH6e9QS5vqoDrnZrr4Ksv8ViDyT/5Um+XZ4CnxlKZCSyGsSXkBjYjBCRvmt5BD6reXyBYX33fPHY8aOHTs8PT09qKurc8IS3lddWR28+OKL79zy85+9OXvOnDVKXyaHIoCPMhC1CjCaMkbYEPOLMlSYaNRxDyAfzvDAYI3J2r1mKwJeARD1/sdBfZ2+Q1+ifyP0zZplli3iuAfQr1AA6LdRR5z1XwUdRN8bhD848KMKAPhw5MXRV63v6j3aPZWABP4jkjQMuyl5GiaGj/UU2EEKJFMATOjCvBgZRYU/CkDhB+++e2mPkh5ta2pqYFhhFeoVliTWT211TbB548bqJ5/6x5Sr/+8HbyoBwn9z6FAGcDBTRlRRRmjIrA4wTmOg1MecKQKKigt/Y6rmG2PdLiXAKwCQ9H8bJGysX9G/TcGNW7duu+22PQYOHNj1888/X/ezn/1s5vz58+m71m8JmyJA/zXhbX3S3huUCPBzTR82oL+jPEStCeDA6fWJv1C63H3AKwC7z7P2Lf3yKQBTSgYmgG0UYyOk3Kcn/v3k7j26t62urpY5PFXmepLGBH9QhxIgpwFWTn5exumnnHLAmFGj+t/4k588M+nVVz5XMvCZQLcyYgi2joZAR5yljTJUG5kRZ/lN0NuIDMZKGAfAWAFTLmJX/ne3pIAEjfU3/ERFIGfWrFnf6tev31Ajzumnn775mmuuefQ3v/nNrDC93TIrE9fgAR/9MmpRYM0M1/Rl7tMX6ZcoEOQxoG9G8Vm89z0FPAU8BVqcAlHm0xhyY44mgLOOPvLIHqP2GTWQkT98FOGflpbuXCqDqpC3porV1ddrLl2Bnj17dvjjXb87+8c/uuEAFVQo56YR5OfJYV2ICnUT+vhWLkwU0yzp8+UK5MBTHLqi8Jp40iSacY35powYMxIm7MFTwChAf7B+nvHAAw+Migp/EuXm5ubdfvvtp/fq1au9Lul/WArotyjFtnbAfPoy/ZU09HPXV08++eQ+jz322KGyJuwVxtNPyW/KAX2Uevj+KSJ48BTwFNi1FEC4JgMYUZQ5upHNUUccNRDBzyjfDaQUTkmFbwk0+o8NYmJDbTIrVVCXUh9kZmemnnXG6Qd279693TfPPWeiboWZFIolTxydc9/Ms6YAINhhvG5Uddihh3SU8pG6bNmysnffe2+t4s0sy3QD9cVkGwVnYo1G+PBuTQHr49bPU0tKSjo2RJGMjIzMf/3rX2d26dLlbt03i5P1JyxOxCHEEeimrLrFsloPc9jBBx+8v+IpJzjkkEOmDh8+/C8K2tQX+a0uvFdMzyW+D2T14CngKeAp0CIUiArgZAiNOcLc0jp26tAWziQjv5QA+RL6dbW1bhFgTI7rN4yPcjCnG8hC8LWxY4c+/tdHTxYKRkc4m3d1Ql3XMFAEf1T4M1oibeHoUaNKH3rggQkff/jBFQ/c9+eL7/vTPRc+/dTE7096/rmzrrr88jFKw4gr0RIArvgIy1sBRA0PUCDWlSP+P//5z08bI03nzp3bv/XWWxN03wl2+Qh6+q05WytDf3V99u233z5Zwn+srp3wlx/sscceo371q18NUxAl1b1X8pv7PiqpB08BTwFPgZ2jwI4wnJRUTfrXyvyPlK/TFrm62rqgFgVAzs39K56tc3UoBi6MNiCH1UD1xWqw18g9+/7j8Ymn6RJzatSkakqACX9bnAUzzb/6yiv3fvzRRy49/PDDRnfq1LFAg39ty0sNsrOzUofvuWffK77//eOffPTRU0Kc5DEGjVIBs42OslxdqE+Dbiu/VjYP/8MUMCWA0XyNTPRz33///Q8aa++oUaMGX3HFFQN1n77VkDPhnz9t2rST9tprr6EN4RoyZEg3xSP844pBQ+l8nKeAp4CnwK6gQHMVgCiDrPts3ucrndCXgEfgowTUhkqAUwS0HdAJf8XphiwE2h6oIJYCFAH+4HhDhw7uec9v7z5GQRQAmCajKhQAhL6NqPBhsrkXnH/eMCkAx7dq1SrVWR2cNpGq6YeYTKceKVqPsN9++w599KG/nqQ8DSkApgSo3lJakrnYgmyh2bUg5WO7oLm1aQSp9Dd0uIahubj/29NFzOv0Ikz3CH9bNFop8/xj77zzzszG2nn99dcfpXtmubK+yzVh5yZOnHjQyJEjBzWG46mnnvpE9yibOnjwFPAU8BT4j1KgKQUAxmQOBumY5EMPPzSjYktFUM+ovyY28q+rqw1qFTZXU1Wjg3Oq45YBZx1QGmchEMtz0wFCPX78uD0u+vaFI4Ub5hkdTUUVAWdWverKq45H2IODNQeM/GOOg3kYxafGOKnC++47eugZp542IMQJLrMA0GZcysgxe6fU1mi7YgOupro+qFIbHOyC8VlU/FIXOasXI0KUlKiLT12QNgq63gYS7kXxgg+riuG1cBR3HPk2SP93L0z4I4RtWx4nVXJORZmE9xNaEPivhpqvMzBybrrpJkb2UaFv1qy8M844o9fXv/71sQ3l1eLZmgcffHCipgAW6D7l2rtFPRxEFBSL8r6ngKeAp0CLUgCh0xTAJGFQcQY57Z1pKz744JOlNZU1GunXBjUIfu35Z1qgRn51VXVQWVkZVBGuqQuqsQ6gIMjHMoAAxyTgfImfi7514eE9S3qyupqRE0qALfKLWwJ+esstY1rn52fW1FINFh2y+0AKgHYfuAWIKACxOw4vBxOddfrZh4a4wGMCzwl/XTvYXLkxSHRlVRuDtZtWB2kZqUFmRmbMcmEZdtI3AS00serGTMAmlFFSzFFnnF1T/8Q2GLq4rzSACf4oXvKCy/Am4iYtygB5nSKAvxuAKQHWv1lEigKAK//mN785+Qc/+MGzsmzFhbPR5Pzzz99XYRvxI/xZo+KUgB//+MeHWrqo/9JLL707bty430pBmKJ4lA0W/2F5oHzK+EI5ivPgKeAp4CnQ4hRoSgEw5mgKAMwKBll++513PPXpx4uCzRvKZAXQSJ/RvhSAKgn+TRs3BxsVX7ml0ikDTinQMbo14qHOaUqgFh1ADoWgVW522o3X3XC48JoFwMz/JqSy9h45sh9TB7EhPtUCJKukCEj2OyDW7uB37tih/YRjju2jYFRwmpBzudavKwuiboOuly9d7xSWoqJcN73hkLfAD1I6RIMP7U1AUz/a6iwd8o0O5hOPI40JcvKCwxQacBpe2mi4yWPTKIYP33CadcRoZHgTlQpl+Z8FG4EjhOnjZgVgB0nF//t//+/TY489duKaNWu22VHSoUOHYq3m76w0KAE2+s8/5ZRTSnv06NFJcXHQKZn111133bNK/8LkyZOX6wa7VFAyeJ8o0+oQ7caK9uAp4CngKbBrKACzbwxgRAgURiQwJ0YppgCU/euN1+b/of3dj3z98BOP7dCuKDO/dZZG4uJo5VVBeXmlE+5ZWelBdqvMoJVcps7ST09Pc6N25CAj+NiYXcUo3x5DhvUZP+7Akldee3mOyqFsygOc0EtPz8hAWXBTAIrEesA6AG0wdGW5lM6yELMwYJlAM+jRpQ+MGIGIoNxG+JOnsozoGFCvKlkvGCh379xN9U13Uxp2f2d8pKnym7O6mKBG+JoAtrqSFoAWPAOEkz0HC5tPGpzhN+GPb3jxrVwFHU7DS6PNgRPgHk7nOX11t6SFdKW+cWiu+Zx0scfishotoD+0oK+bX/X000+vGj169HNaF3CUzP/0SQcS9v20xY9TAY1u6bIYjAlvx73TTjtt4t/+9rd5inCWBfkoEziUDcohvz1HBVsOGqKRYW8urSx91E+Cl35IW74AO1PeF5D5CE8BT4GdokAyBQDExpAQPDAomJUJqNTHn3j4nQ8+fHfJ0YefvH+Pbv0G5eVkazTJRDwHA6UGGRkpQUbmFn1IJy3Iyc0KWrfOcQpBusz2qVq975QAsQoEOQrCuWeePV4KwGKVATM2yeyE2ZbyLbUsJiS6XmcKoAwgD1PqSRYKfZQCOXdP/uZNFW4krwQmTBXcFrJzY7cQzzWarkiRmOzXr3PQujA7KCurwBS+bYYduAoZJYhw0A+HQMaZWR6fa9rLfSuYhkJ7E/4mmKICm3sG5AUHuBBUht/iuA+QJ4qTZ4sDP2WbQIPoTgmQnwhWx8R4u25QCNjNiN8QnmR5Lb35EVSqfOyZRfPHw40IIO7TTnO03ZzRqW7OnDlbxowZ8/J77713mJRD1z/333//Hkr7qZx7Bh07dswaPHhwF13H4ayzznpOwn+pIqAvI35z9iwpy8pW0LXB2ma+i9dPvC3xCDq9oAGBbHnNtyxxP4FWcdwN0SkBv+HEj7o47jDg+k8YjipcvKvx8hIz+WtPAU+BXU8BhEJTwEvKSwyTgunBvHjhia+dPXtW1W2zb3gyO7vVC127divs2KFzUa+e/ToVFbUratemY/uObbt2kbyWIlCp7wJUBMVtcoL8gjxJpcyALXxgwhKAQtCzpFfXkh492iz4/HPKoyx8JyjXrF5X5XYTKII8qSgBCP8UkqgyUgjczgDNLbDgUD/BqhVlwcrVK9frNomsHfg4BykShzBBpnhr6quD0h4S/nm5QbkWOYbM0ZLukB9hmtAsUThjfo86Z+1QHM/FaExdTVCbkDZBjW+jRwUdmKAHF7ht6oAw90wBgCbkRQjxTBmZ2n3KNkfZRj8F4/E8H4B0gNWXsNE4ms9oHk1P2PCQLxEMTzQveRpy0byWj/IBrl1dwudh+JwQisRZPpcp8mN1Tv3oo48qzznnnOlaHLg393UyYLEOCMrRkdgO/3HHHRcX/lVVVbWXXXbZ5Pvvv3+5kkJHUyrsmXFt9FXQgdHE2mjxUT/eHiIT+qnVFd+eNTRuCJ/Rx9VdacyPK3wI6YQ+rGQOF7gNJ/gTyzBaGk7zaa+7Z3i9IiCKePAU+BIoAMNPBryoAC8vDsYFGAPiZUaAbKmo2FI2d+7s9XJL35z82mzFudHt8D1Gdhw6ZO/SQQOG9quoaN++bHNV0KlLnRQB1ktlyFIgPiLWwQkBmekZweGHHD3od3/8zVTdBCiTOqa/9OrLi/bZe0TvnNaal5ew5nhhGaZJ42rDYAJn2xDXrNgYrJLSMOlVd6iLMVxrRyyffrNz9BVD4asT/y7t0ino3KGtRv7IwhYFmCMMk7bYyDw6H+/m5L/xjW90Oeyww3rpGFqdbpjmtuqtXLlyo8zOS7RqfMH8+fM3Kj9CH9MxQtsUAhtBUg5lRIV/jk6uK7jllltGaD9679atW+dJYKVu2bKlcuHChcv//Oc/v3PvvffOVx6zQBhjV5Rj8OZD7ESGT3m4KFjfgNbG7AmHD8vhII8JKHy7VtABaQ0PEZaXsKW3sq184gFLa8+aa6sHPmDXicINHObAmyba5Rypo68139+hf//+neQVaBG/+4iWCd6PP/54XFlZWQ3z/CUlJawFcPDhhx+uueuuu1bowuoY3nEe9TJndTfak5448+2+pbe2GV3Nt3TgIS/OwvgAcYYHn7zQA59+ZHEuTSikDa/hNLzgNEcc6cxZnfANN+WQjuttnoFXAkQRD54C/2EKNKUAWHVgBrywBsYkYBgoAE7Yh74bsVv4vfenb5JbpOtpE445fuCYvQ7bp7qmtggLalGbgtiaAMczhCQjI+jXq3+J0s6Qg5FQJgwm8777711wwoQTyocM7ZOTKkVBZwvHRj6kUm3c6F9TBHXaJVC2qTyY/fHK4O0Zk99Yu3btJqWgjolKAG1QxlQ3+u/aoUPQuVP7QIJRCxTrg8HD9gBzs+DvT/wjhishdYR5GsM04YzAt9XjeVowVqxR4sEHHHDA8AQU7lLbyQJ9iKbi9ddf/1Bbx9554YUXMCejAETnkGGqlBNVMFppAdvwiy666EAJ/rhgUhoHKreLTNgjhP9NuZcUSf2MkccSxX6NWUMTY/iWlmvyANF+QR76By4KiTgsf7Rc2mK4CNu1pbE6cE09wGnPi3w4qzPlGw7CxJPP4vANDI/hTz/11FO7/fznPz/VEjTk9+7dG232C6CDftosWLDgUClZH91www30aepqzsrApw5Wf66tXYSJ59roYW0z+uKThniAMPkoh76Az7XhBRdAmeTF593Akdfw4RsYTsNjbQC/lQVewqQFrL7gsX6Ab+8h6a18NzXglQBRxIOnwH+QAsk+BxytBi+1OXvR8aMMpqGwzT9jfo4Lvcsuvf7AvYbu1W/gkM5BVqtst15A0jyoragJpk59f/3ZF53+hNIzuoVhwFTAnXv/H56Y0KZNce6gIR21RS9TWaiCgJG/hD/bDzeuLwvmz1kTzF+8ZPmV/3fOXbrLFAAORYCV1whOmFDts8+8UFdRVRW0b1MUdO/SQTsUat0iwP5DhhgTS/SVLQ7GcJ3/53sfrB89Zp+gb7/e8QShAkAlYZjQIkoHt2VM28H66AtzJ0pAs5+8OVCvo2qnaVX6yzI72ypy1x5lNlphAWj13HPPHSKLAmcsNAkffPDB7GHDhv1VCbEy4FjYBr3sOdBOawvPwxxtCx9EXKhQH5SuqOJl9IKmlheamDCh7uAhHc4EBwIKRxx5SYezfFa+PatofhMwRp+oADL8lsbaZs+I51N03nnnDb377rvPVXinQFacBVLwJspSsEaI1skZjXmG1M/aR3uMPoRpq7UNOpgwJY85a4OiHA3JY+8efpTODeHiGdvzwqeMKM2hjdEcXNQvipfrxLraM6Ru1g+iZUTrThp7bvhNAtY+D54CngI7RwFe2uaAvW32ksIcYAj4vMiEebnxzRkjQxhxj5ccSLnj1ze9ftX3r0/p0GF83249NUUtloQ5lVP80tNTYCzMW8N0wA/DSu/bp09B//49ct+eujjYuLEyKCkpCHLzpAToMCDm76sqq4MN67cEK5aXBZ8vXrTwxz/73v3KZ0LMzOXG2Bxz45yCooL8oE1Rawl+VVF1SBD+lE098M0ZDfDBA9Sfdc7pKW//e7rRifZYeqMHTBJamCKU/93vfnfwL3/5y1NBsB2QIpP03osWLep94oknTtTHaVYqL/SlbMqE7tk6f/4omfz7KtwsGDp0aN+ZM2eeMWjQoL8oA+0yoQJOnjEALXg+tANHmHbRRoA8pKU+0DxKO6MVacmHoDU84MBRFgAew2Vh8nOfdNa3LB/XllfBeN0bEpbUDWcCiDSUAVA36owPzvRNm9Abdx5GjBhRokWEZ/Tt2/eezZs3m8ClDtYuConSFxrhrE7cN5qQDxzQGKDttANw9ZZvfQ064xKfFentWZkiaTQ0fPQp6mT0Boc9M3x7hvZMonUlr9HfaE59KcvqTjnUAbBnQDj+HnHhwVPAU2DXUIAXu7lgAgbfHC8wDIIXHd8cjAAHY+Ce5eUaJlL589tvmtqrtEe7zt3aFGVkS5DrLy07LcjNzs/U6X45mk+lbiY00nX+esd27fOC0p75waxZ64M1ayu1vTBN3wDQAkKtB9i8uSZYt27Vug9mvTXtoYfveVt5bYRl8+UwGuoCTuoT5Oe1kvDPDwYMHWqMj2jCOGNmtMnaiU9emJUxbnyHs6LC+LFiYmD5aAvthmGi3OSOHTu282233XaywjsE7EHX9rPTTzrppKd1pOxyIaFOqVqdnqG556M1X915exEPHDiw58svv3z0gQce+PcQn6OTwtACoB20AYcig0+7XD/SJ3PrNMrN0hx5ueq2TPGA4YBGgOFwdNA1PsIEPJRDehMcPDNzxENP60OZ+qBOkT4z3VpHQ2er3enanpeuKZ8qHcG7ory83J43vgl8BE+is3vgp2446oFLl2LI828R6NSpUxtZAk7RGo8/CSH1sHfD2m20MRrj0167zzO2+tOvoQdAx7MwaU04Y1XKlcLYJTs7O1dTFcXys2bPnr3x888/36TnVFlcXFw9ffr0latXr96gtFEwfLTf+q7Vi2fPc+M6S9NTfaXgdG7fvn3rtm3b6ryu/Fbr1q3bDM7PPvtsxdVXX/2eru3cA3BRd+MVUfrSPgPrN3btfU8BT4EWpkBzpwASizXmQLyF8XH2YsPMYF4wCZgFc958oa/QXHZWduHrL71yVEnP7mlVOkiIhYDVOoJ39qefbapLqdiSmpqWUla2uWbWp7M3DRk0pO2ggQOLN6zZEMydszJYvY5TBoVJCwFrlWfewg/m3HnXj15UDIwMZ6ZsGA8MB0aPg8mYMFLQQbQNMFDagG/CwNpEYvKCg9Kjft3LL71aP/6gcdHRP/lxJuycWVnXRcuXL79IQrytwjsFYuJ1X/va15558803N2Rpv+Unn3xyWGlpafHOIP3Od77z4G9/+9uZwgENoR1CFIbM88wRQ++vqYXhYvgdNHXRWkIlW0pbitZwpIn5527cuHFNQUHBTUprShhCy5i7w6HrfCkbE/r06dNfCzdTNZ2hZ11WpTUY1WqTzpOqrCgsLMzQ9rnpUpQ+C/PznDJfeeWVI7TVrq/uF6lM8G0DKr+ctR8SOpu0an/Ju+++u1SWFnBQDxuFRn3irU8goBBwPKtiWVkGPPLII2co3GKgNQVPiYZThZB+avQFv6PNlVde2e/CCy88fP369ZUoIFKGnUFJC0NFqtpKmb/LdS7B21rfwTPCREFb7BnR33jn8vRoiubNm3d1mzZtOut6GxAObZaprWc7o+j5spS+iUrA8+J9gR70b4A6oVBAE5w7slu7HbqpjiM1bVTarl27IsU3CrKilL366qsf6CyEV2X9sDIoBwudWR+sTPqJPYtGlQA/BdAouf0NT4FmU2BHFYCGCogKUROcMFOYh52Uto0CUCQGPun5lw7t1acks7KySvv364LMzAwtBkzTYUKS1Zrny8zKCDat3xysX7sxyCvIcfP8y5eslql/s1ust2VLXfDvd/495+57b3ld5dh8vykAMEcYLMzFRoQwF2Ms1BmHgMdH6JuD8eGsLaQhHwwqOqqEUZqrl+CqlyA2nOSl/XZePIyy8Oabbx6lw2KOUbhFQCOt8gkTJky9/fbbB+69994ddxapBOcGjQx/LTzQDyZNewHokbtkyZJL9Fnc7i6mgR8J8yqNBG9AEdBtcMDkoRF0MQFbqFHod7t370yrtaUAACAASURBVN5LcY3CjBkzPtZInzUh8fwbNmy4RMItv9FMDdxYsWLFWi2i/FiKwPv6nO9KJaFOCCH6B2FrowlQ8Bdry9/gP/3pTycp3GIg5WSDhPKvhJB+agoAtHH01XqMM7SAcGiyAl977bVJUvyeVBr6PDhQbgGrf4EUhiLR6keyzCRdX6JR+lxZB/6gvNSH523C2JRgBH980eo//vGPg44++uhRitsuUD9dr+8n/PPOO++cpYwoAvSN6DOgDfF3SWF7TxXcFrwCsC09/JWnwI5QAKHWUmAvK4wMwDcGAlOC8cfdbbfeusfMDz44sluPLpmVFfAbJdaWQL4rULGliul4Z9qv1jA/OydLZwfkuO16ObmtghyZ7tkCWFlRHbz02t8/lPCfpuwmlGEiIMQnDgdTSRT8tN3qB+M1s6mN1k1pQRAwGmx90YUXDiloXYAFA4bIKIv2gIO2unaHwl+X27Q/ij/nW9/61n4kaCmQsM2RBWB8Swh/6lRUVFRw8cUX91EQWiS6HI3Qk/YbtsNpdA79aDfPHhoZvQk7emiLIwIgKahPxEedSkg4RwIUgbddwJSJRvP7vfHGGxdqEaVNkTiFTIh4vtSXttIPqJ97rjIwJG2rhOGS008/fbpGt29/+9vfnq4Fg7Kwz0a4NQpSrgqOOOIIFDXKijpHa00VdG40c3hDZSCoqafV1WhMfaF5hkb4GVKylimcFGS9oR/Tn6N1gdbUB7pAH+rcU5arC3dE+Ct/oH5a+Otf//q0P/7xj/uDTw68KCdRulN/XPydUtiDp4CnwC6gAIyipcBeWHuBjTnBWBxjk58zdv/9u9x+661HsvWNV1yWSHcioL3vsbVzsc8FUzGZKNAEpADka5V+jT7OkxHkSCFAaVg0f0tQU1EP4wNQQHAm6Bmp4yweH4jWk7yOWUZ8mCAM0Zgh99PPOeus7lddfvkFjzzy6DW6BsBj5VEO5eIA7kEHw2/4sq+66qoBMp0Xk+irDBdccMHemgaYrzrSppiGFqNLq1BgNFp9jc4wWTu6KZH1B3tORpMMjU5t1N0oLpnAoSV9iHyEszIF8ncIpFCkSZDtpdHzUG29fE1m7ClCRF3NCsAztb6brrZS/0bhF7/4xQIpFeuUwPoa6efKrL6nykDINwgyofd+9tlnEc4op+RxbZOfnZOTk3TErjSBTPvUFzpAFxw4qDu+uQytS7E+qeiGQeQ04W/9lLoA0IV3N/+SSy4ZeMcdd5ws8oF7p0AK8CHMHGn9yiQhsvcm+g7RDnM7VZbP7CngKdA4BXb6ZQ5RG8PABycMFGYCY7ERXN6JJ5zQ+68PPnhaSUlJMYI/drQv+/l1LLCG/Iz6Y45wzHGyMKBjfmQh0Nn8miYobts6QH8o1th8nwHjB1576Q37KgkJo8zQBJD5do9rqx9C3pST+EhHcYzybXTo/AnHfP2AosKC7L1GjOyuezZapH2Gn7ZHndUnWlb2ySefPEzpvvKg1erdZM1AEEEj2mkuS6Ninm2jwPyyFuFZX4g9wFhqwsS7ZyEFAOGXFJhSUQLKM6GcIZlM/p0CLRzMkpJzqKYDThQiG43yXOmvtJny0mTNiNZfUduCFk5CF4SYCTD8Wn1F8OPwdMBtM4RXw4cP76qg9R3rk1kHHXRQRykA9MmkoPUB0MX6tPU78kTpTv25bgpoI+21Z0350MG9ExyEpJH7qS0h/IXTgawxY2+88cbhusDCZlYAe860y/pKc+rvcPofTwFPge2jQFLmtn2otjJ25TNmYsI//9gJE/re+ctfnqLRRiqfBnaSXoMrJ+iVYavw/2LY3QQ91gD9p2VkBd1KOwX9BhQF7TukB93a9Olx7aU3Hyo0MBCYmDEymLNdW5z53DMmhwAwoY/AbyPHKL2tmF7ba664cvTee+81vEb1HrX3Pn0VD8MiLzgo0xi5MS18nDF2/GyZfnO13a6nwl950HPKOPfcc0tUUdpodHT05V6yBkho1+jLeQgoY97mk83CKZqXZxTbFBgdjcbpLTn/q90lg3TC4jmqBOboqDCinzCCtvo2WE89U6PFNum0TbNai98aVXDCKRIEnbULPOla3Ngs65DWaaB0QBtzlG9OQRcfvSauQQiVBMrH8YzjCoCmI4oef/zxMxvMuJOR119//bFqb3uhsfcJmhs9aNc2NN3J4nx2TwFPgQQK8LK1FPCy8tIaE4kL2LZt2xTffusvTmRVf129PuATSnvHneKveMwCEHvnY4KeUb9LKqSaKIjV0x0AkhLkag1YyYASTQssCFYs3hx0qu5ZetWl1x/081/f9JwSwngRQABM1hY1wTSj9YThmAXAMb0fXnvtiP79+3XVPHhhcVFx67y8vFZtiotz+NQxpwwedODX9rrh5pveVz7KYJ0BDBPfRi1Whl1DY9JkaNX2sJYcRQnnLoWRI0d2UAEL5IyWGVq0l6uV/jzbRkFCs1pChZEw+cxZesMVLF26tMm5fK1SNzrStwDXbWLBlvktKSnpot0Tpw0YMOBRYeRZmnDNaGq9g1a10x7qaJCi6a2cP/zhDwPVh3juDUKoxNAm8oKDcLoWB9IPmwRZABKVi/ibFMncUFzkdiwY1oV+yrtrz4twtg6TmsDWwVjKlv/Vls3jtQDxHmHmHa2QszU7tI/ngPPgKeApsAso0BIKgDFkGBnOBJ6NInIf/+vfdNJdfqaYaTiYl7BXQoQ7ED/RL3ZJTPivjYFO4MfWBGhmOZbCxaUGhTrBr+/QVH1UaFEQzF8XdAkGDj1o/CFzJ73y4qcxJPEROMwFxmLChzriTEnJufnGG0cdceQR+3Tu1LkN5woAlI2TMJPwl6+vBfbo1q3DcROO6/vkxCdnKgl4cQgNGBZCDx86OIYu3+iRpS/J9dL1fw1odNZJlTXmDyPOGDduXLtQKDfaDikA0MMESdQHR/xauwRIlxRk7g8fukvmwlKionFJ8zf3ps5N6P6Xv/xlP53M+Lby8AwB+izPslHQeoL2MtmnaqdCXteuXVtp+2OmBFqBphiS5tMivtVCav3EFIFU5UPwNgnsvEySaEfoQ11MYQF3hrYj9tc2v55Jytnm1rJlyzZ9+umna4ksLS0tkCKEVS0p6GNKXc4+++ye9913H9YgHEoA7wz14TlYW+zdVZQHTwFPgZagAC9aSwAvKUzDhB2C1SkAl1z8nWGDBw/ptlX4y+yvm7G3Opzn13Uo8wk5sLcdVQF57z78I5948saEs2y2RQVOCcgS35zz4arg8P1PO1wKwHIloS4IL5wpADaa4J4b4cjPeeKRRyfsv9++g/SJQRCrDCuFctUwtw4shc8P6OODKcFVl33/YCkA85UXZmUOYQbTIjO0IIyjrHRZErJKS0s7KvxfAxoRd5C5P1ML8aCbUwDUBszkSUGjU7Z2WR58aIIPPQCu2TKJwpQUnLUoIUWCUpBwd8cvtZp/lOal5wpsd0J6UwqAzkPohNveUmUhmKs81k+gh+svIjf9pUmQpQBhzasANOQT94Vtvi51wk9IT3snyEddsq644oqxCUkbvNRugzqt7J+uBZUfKAHP2fECfcBqhHZHDGkwUyTy2muvHScFYJ6i4Bv2vvI+gYf6QB8PngKeAi1MAV6wlgDw4GAcCFZeYqcEXHLRxYfE315JUwQqbzQ/xtxjcS5CkUJjiwJJJ7B04YXz+EEJqK2p17Lp3KDXgB7B0H26BpkpGa3OP/uCvfr27d1Zi9WYyzfXNhJmntW5vz344HFjx+43KM5mpATEFyUi+KmL4hiIsvaMrxB269a56I5bbxsnHLTRmBbtdsJePnQwehBO10d3irUdu1nmXaVvUZCZukr7xhdpH/xibeNCODcLUFq0WI1RHG1z7dPcNe1NCjonYKMSOCEfJrQuYHHOR3AkRaSb2zz7phKH9/V1vvU6eGa5tkYu00FAa5qZzSXTNr4xCrC+wymPqiPPr0VBJ+8t1emN64XU9Q358X7T1PSKVSS0APAqudcpjCdMvwNcvOgXvR+7k/ArBY/nQV1QKty7+73vfa+3dquwNiYpsN5DiwQfl/CfqoTrIm69FKq3pkyZsiApAt3UYVDd9ttvv3YK0rfifU1h2mLtUdCDp4CnQEtSoFmjjSQFwlzMGTODieCyz//WtwYWFBa0qq2r0eA6wocUNLN/LNpFKG5rSdpJRiJFSEY48UHYBWIlhkFG63zON0XCuYsG2MO21Gpq4Mi9zjzx1BFVddosWF2xeWPZhvXvzHhn4ZNP/mP+3LmfMe8MsoxTTjq519fGjRugbeuuKAQ9RcZ4Zqw8bVZwFghyxO6JH+n/mCOO3OcXd9w2ZcnSpZgtaa8pAAg1Mhvzgi5pWvyHItJs0Cr6qscee2zutGnT1ohB5p911lkDZF6GOW8XaLvYOpntX9WiNNrtGL1WdA/Stq5hzUGkVe4F//73vxHojNbTVYcmFYBlMgWHZVEEZZrjOg7NEU7xxJEAil8y0FqL2Rp9LlMaZ8rXyvqi3//+9yNkbm5SoGnrXk8dwvORjlNmn32qytrZd+QLVdWiQ3CDlz5Df7G+kq7pjWaVJwWAvPSzqNOlA/C5PtjUgk1S6/RF6ES51MX1Y50DsafCTcLxxx//pL5OuVAJ6V9Y2qw99NXagw8+eJL6w+ls+9N1o6CtgQOlsC1RAvJRF9rAu2PTAMkfuhJ68BTwFNg+CvCS7SyYsONlhXnERxGnnnzKPk5owoti0tN5Md4Ui+I9N8Ebiwed3bOULiryE0vj0jnZIq4jJaBGRwKX6gj8orbZweQXPk6d+caCnIUz1rWvXZnTd/weRxz01z89dM7zzzx1/EUXfnsP5S284Lzz9qZsJ59UP6qIuT9VBxKZc/e5EQJBlA4stddd88Oxirb2Osapa+hgzAvfhTWaYqVzs0ACd4nmpCdK6E/VXvxPNRp7V0LpKS2aQxBvF0j4vyThzyiYvAjmTZdeeul7Oqt/XnMQaW67WOmsbTBm2pcUNLdv+/uTMu1mDE6dlUeFGZ5Ev8F6aAsj9UUYMT2zZdKkScsVN0k7E1DWmgR9Prm3EiGIMrTegTa3KJxwwgl9J0+ePE5IKcP6j1MiRZMm6UtlOnbsiJWCjpno6G/Eub6nVfxNKj3hWgzKpa0ZpZrm0ToGRuRJQecYfPTMM88sUiL61oaIs75WJkV2s7ZaLtC9pKD1Jp2VwNFcvvU3awt5aZMHTwFPgRakAC/YzoIxG2MgMJGsIYMHt9HItYsbrYWvrr3BjvG7i5jQ5d2Om92dsI1Wy3I1XE0kgkkFFuvVVNcFXUraBG065UuxqNd1dbBq+drgo+nzg2mTZqXVbcjq8r0LLxk7fcqUY7p37VbA2oRUzjYJ64MWgKlfI7F4nRJLduUp3cg9RwyQfIBx02ac0QAfjDTEOTFs9lQ3CVoctkZb016Q0GaRGIzUOa4PPfTQZ0VPa26TuPSlwHnKh1mWEScOBQC/bMqUKYvlNwklJSVsj7N2pUuRSTqSA6FGe9ACiD48wts4mdddomQ/ESXB2q3jI2SySQKauuAuc8goAfjsSqh64okn5ivcJOgrim2VyAkhTZ80mX5HEmhBaHc9gwOVF3riEH5Zqie0bhK0w4A81r/Ik+hSZb3J1el7TSoA6nP0C/LT5szLL7+8j/ykINN/1TnnnPMvJYJAOOurTsnUNVNNuAoptE32Ne0u6aC09BscdTGfNkb7kS49eAp4CrQEBXi5dhaiTIiXFiaSoYNzejGaZrQs8R7702tsDN290Qh7ua0KQawqRG+F2JK8+DWsPyoDE0SBvo0TpOu0wNz8VjovIFXrAzL0DYGsoLCtjg/WaP/T9xcFMybPClrntc5Nz0hLqSqvdKcKupG/6mu8xkpNQB9TNhSJHNbq75z9x+zPyCWRWdECQ+boo5EYgrRJ0NGys5WIkSqMFKbKyAqfD9us0md+FyjcLHjggQdmKSGmWRgxTNqYcrlM3Ct13SRosRmChvbhUnXNyDMpiCwoRQZRWhBn15oVCk95spSN+5iVeRT47MpIfCxEx0FrLRAgpMVhQkbTqNPneKFjk6DV6/laPwKOVO23T1pWk8iSJBg9enQPnUa4l5KwNgQ6Z0opor80CaIxCkP8fVPYWRDku/cPX8pbvr1vum4UZFlCUbJnnKHvSvRqNHF4Qx9y+kTnONA3o33L+hh9jj6MBaZKX0BcJT8p6INCBcceeyyLZKm/62vy7R3ahiMkReRvegp4CjSbAs1iNkmw2YsJHhgmzjGgwQMHdYP5uAT8WEpUAXcdHgJEGl2T0sUrKWBc18l6d2ExsXtcmZAmsaVzA2Rd1MuSysheHzvTNsGUIF3hVlIGcvKyg/KNFQFfFWRhX5q2mVeWVQRlGzY7fOSRgHFTCvj1kjXgtvJYE0AE5XBv8KBBKAC0vyFHS118KFB0mRw04oR5RoW2jahgruWaEng/OYatdzXXzEIzGLExZJg14Yonn3xy6apVq5oUiF26dGE4HW9bc7bgiW602wRK1Dfh5OLCdEraOPB1QN2F/E74h+HGM+iOLADgN6AuQIqmAfJjweS/KD1aL4BQTqEP7Eo488wzh2gRXSeV4awAKo93qEnQYkEUMeiJ4Mc5C0LEz2xq3l1pHUiQQ2OecZqmmlrrmTdJpx/+8IdvK320b7l+pTiEPgoFDrxVy5YtK2uO4UqfkuZdMj4S73OKs2eooAdPAU+BlqJAlFHuKE5eVBN04HNKQBuZHmMCPfruhmEn9BH4MReX/LB5xHBc4rqIMC4mBZw0dsl0L/bv7nPhWLUTzBLg9VIwtJ4KKwDoSMte/vT0+iCvKNd9YAg0qVIAMuszgyp9jRCloKBNgdKka+qgxtUDARAT9vhCIw2AuDpdVOljRCqkIYZtjYY2QIqEEgy+SdDHWxDaMFET2oxgKYNRbKr2qn+uRXxlWo2fdE2BRpJ1mvNG4FfJwYzxoQRk4jlV6/5mjbySWiY0dZHLgTYaCYNDjyyqpimmAZA5t1DRlGECirobYzeBlV5SUkK6pCDhgQLkRvDyXf2bEiY6wpiyTYCA311rwVovLpoC2qhFdu4Zqi/Ys2wwm3YbLNVUy1LVU7rb5gotugv0bNJFg3ztoGivNRSdmlo4qUWLe+gDRZNVQIqOR26WxqEyUFCgJf3KFvFBH9rqlAl9sTHps1U6B9q1Qd9w9NLov0MY3ainhaUr3nvvvbVKQD81Z/3M6EWdnNMUQxlTBqIp9W0UQisZ9be+Ai5zjebzNzwFPAV2jAK8bDsD9rLbCwsTSWPlcaeOHYsdYpdCP/ybwNdFPIw8IQ2sKwGcwFWcVILYHUW4sC5diGji3CidSCkBcnxRkIFbmkb/KakS3IgPlZOhs1PadSkIuvTsoJ0ChbqnbX3g1rkyfHa4sqo6WLN8jaYLCjWNoO8OVNcKJfgR+sJNOVpsyO414jZt3BJ8vtAtsINp46hRQ5ASmmwbuhePU1n1+nY9C/aMmTLCcoI/TIRArdLnW1eMGDGiZxjXoKfDeCq1nx2rAbjcSEy+1Y/rGh1VC/NOCmLaaZoTz9OiQacAaI8/+JJCaWlpOyWwUaltfbR2IJycyVsLHdskRaSbs2bNYg2DKQD0lDqdsY9gaRQ0nUO/hlbWs9K0DXJMOG/eaD67ISFcpekCaF8nZcKiG/T1WeeZU6dOxcQNLaGR9QPeiQxNR+TceuutQ7RNboiuGwSNutuIFvlqa4WsMrS1SdDcPqN0aGlTMjwXni/tdjRWH+mocFLQGpg6zdHTT6BVipQWjsJOClqtP1cJaCttplzrY9TdPSP50ME9N+gpBXKzBHyMJ+hGQyCrC/0Gupnyhg8+wJ5l7Mr/egp4Cuw0BXjBdhbsBQUP+NKGyowYM1HG5v95dSXy4+V8QfiHd5ywFQuL+Yhm/SGAXVwYr7SMwmF13JNMdgqAG5VLKKMMVJRXabRfG3QTP+kztIdc96DvsO7BoL16BwNH9gk6du8YZLQSj3Q7AFQz5v7lOOKeeq5dtS7QiAWdwU0F1DrhjyJR45QLFIxqjf5XrNhY//b0qYtVJQSSCSkYH87ANZw2NwUakW/St+CZV40yVcLbMFudttbknKpGo5VlZWXkdaMw+U7oh9fUtbYpQao0DiQ4ESpAvUZ/WBWSghYKtpbCg2BC0ONjrWAqAUfYKQDui5C6SAZa94BFhPoajWu1b53rRkErz7mH5EYQZv/0pz8dIPNydyKbAxL+60Pa1UoBSppFC11RdKCtKQBmuUGB4BlUaFfBTC1AnJcMkdJ01f20xYsX88yahHCVPnQ02qIQMOLHx+VIsWhSAUCh00JRKzNVixPbK29S0BbL2UpAn6Td5uz50Pf1VsadglrIsmED9EkKoVULHmKOl8Zc0rz+pqeAp8D2U4AXbUfBJJq9oPHrLp275LHvH8H9BbBU3IiGw8QI/TjrUBxC3kWFPqKVICN9l5ZROSN0XbtRugT/5k2VCtcFnbq3DXoOKJUC0CfoPaRX0LVX1yC3QDyStWdKj7BHLjsnZQAhnaXt1bIbBBtWb3DTAq4UCX4NO0Phr+OMVYmF89YEH336yZzly5cioEzQmhIQbTmtTMEkT5OTgbZjuVGn0pjAg6lGBbdjtqtXr2bElhSEC0FEmTjwUSe7xuebvfKaBj0Da0+9ym6SkWOCP/fcc0uF2YQTK9ERTvgIpzxt+yrec889EXpJITyVj3bTBkdfjVqhS6PAeQkl2r0wTscWS1gNv/rqq/doNHEDN2TtQKnjmVbLmgWtGoVwD72rlxKZELS6co2r0/TDjHAapUFcOnURugSyVGxUXzF6N5iWSNUrTafvjVCQfNCV6RQc4Tyd89C3OQqAnid9zkG/fv2yO3ToYBYFi97GX7hw4eqXXnpppSJ5Jo5G8q2PuX6la+pvbXDh5qxHUL9BmWpI+DevoyqzB08BT4HmU2BnpwCiJTlBR4Q0+aytb39oBYimtLAl0jUyJibsYz6j/Nh17B78xNI44U/6uPCXAsBZ/e4sgNpgw/qKgKOBW7XKlLle8/4S7jGjAXkoLFYBx1VMCDqdQD/6hk2mppArtPZs47pN2k2Q7RSLWu0uqBH+FM0nrNJ2/E9nrwwemXjPc8KEQIQRRpUAzJjbQLJPw1pCjWydsNA1tYwyVcImTGrCk/YsW4O+RnYoAI75NuCTR+R01CCcFML5cEc5WR+Yk28Svv71r/e+8847FykhfQzakN+ZxTXyL3j66acP0fw6zL5RkEVko07NY64ZYUN+0ks+JheQOp+/s7ZMdtLCy6T4hesLwMl2MtnP0Q3qnCYaQfdGITxFz/o+5VmZ+MTHr1EWZE1pcE5Ba0RIVyMLQC2Kgkz8yU0PSqzDc4Yccsgh3bQGYbGmDpwg15qOVmPHju0arsNQquSgvCuUAoWlXgpDUuEPJlmATPjzTHDQxxSgyBvt2q5bGNhSUzUV0mR7wv5gtIz64PHgKeAp0MIUaCkFICpoApk9q52wlvxhlI0YcpxBwRQCRLkReKw1sbSxuNh8fmxE7/I5RSC8FyoJLj3CXwIZU38tFgCcwltk/t+kVf7tte0+VfKFgXdqmtIiPxAhAPXQH7EaB8fiFHaH/rB4UJXMzE4PtsiCvmHtZhcmB1aAZdpWP+P9lcHUj158ZtasT2CeKACmBJgAh5m7JofImVJIKkhIh9k+zEdeHDWGuYKPsLvWHOwqRz9TXnQjEUITNumjuCzZNnWzyMZ8jd4o3wkJHfyySkKvTiNQ4hoFnajX47LLLuv//PPPL1P6asmAes6vP/XUU3vo4y9DJPAaFIRRhBr9L9c1ghhBQ/n0V6YAiGsUVBZCxx5so+kaunHbbbdNjXzLILWpsrSFzurFNAl0NeUP+tBGRrXp+qTuUC3KwyLSIMgaQ17amaJFc+ulAHRsMGFCJIJeR+4y8t8h+Nvf/rZYGembqXvvvTfWg6SgY5Z5Jib8abs5+lqDQP9ppjLGM0t0DeL0kZ4CngI7T4GdUQBMiER9wrWfzp69DsGbwRXOsWIF3L8uJLwRaQgxg7hQl8BnhO/SOoEfS+cUA0XG02lEzhdnayT4GRDWMi+vRXtrVpe5cFsdvMd5AHEztwS7NnU5vFQH1QRtxFXNVUIhypNQJQ8uS4uWyzbWBKt1kFCNFggunL8hWLx8czBj9r9eeOSxe6cpm9uaJz+qAIAtygwpYmsx3G0ENLKFEUMUXKLw5hpmWzdlypQNjI4lJDCrNwhSiAyP+V9Ih9LUHJCwB4dj9GvXrq3TCLVMpmJnsm4svwRw6u233z7m5z//ufSy2npdBs3dCmk4//73v89SGNpGFaMajXabXIdgOLbHx7z9f//3fx8qjylrGaIRwq5R2GeffYq1KLNMNOEZ8z7VycKRqVF4G31OuV3Pnj2LtBOgo74UmJReK1eupC+5Ubw+jDNbc/HNUgAarVgzbkjR2fLqq69iYeHZpmkRXpMWAO3/X6q00Adnwp/+AZhvfd71+3AnRXPeAfJH0xkeh9z/eAp4CrQsBXZGAaAmvLA4E06OIcz8eOaG1dpj3rVbl9YI81RnaUYAK6kLY5K39xyfeI3RncCXEGZ0r7ATyGHcNvcY+SP4w1E/q/VZGL5Zi9pXi48W6JC0oja5QUZmlrYBWhMpZ6sSEJP/oRXAeA4KgZLVa42ATgMI6nSSYGFxfrBwwfJg+ttzg7VlqxZOfW/SW9OmTZkrZLbYCx8hhaCAKaoQB9AlDjKBNjniDRNH8xE2ZwoBNK5jy1kTCgDpLG+I2nlx/M0dJUtwk4f2ueerY2wXHXfccQOjSBsLY9aVa+x2o/HaoVD+s5/9DAUA4Y8zaNbuBUvcXF/9qU5f9Zuo9DxPe47W7kbRaJpjpLbxDZOloAYrD8KObX+az7aFk43mjd7Q+Q4zdY1iU3/PPffME95RTW2bi+bfkbC+NfGp8sWVK43Ukz4oLb2olfK5RnlcPwh9e/cb1SbZSdKcSzWR9wAAIABJREFU8yPUz5KWvyNt9Hk8BTwFGqdAS7xwvPjmYAwalNdVLVq8eGWXLpx+p334TtaLlyog0e7Erb5TqqQx4U+c+zcFwPxQEXCjfuIk+Fnwh+CvxVKgaxP+rPxfsWyj9u/XBl37t9M8vuStpLmMwWGZKBWJhFD5zvIa6iZOKyCb0mIFUHLqVlCUW/3Yc3e/9vGsD5nTXieHkDAFAAZqwj+RCbqW6z6Ltkwx4DIZUMsoHsLgwYe+ztd8clIzuLYBUifDRR7C8foozHkH21wT1xCIgZMXfLiUW2655cPmKgAN4WtO3MMPP/ym0hmNXbm6hoYIWq5bFPR9hCc/+eQTm9+GXs6Ur7UbScuSpShFO14w8+N2CGbMmLFQH9Shb/FMoXW6Phc89bvf/e7YHULYjEz0H+08eFdJUXboB/VSUpP2B013rAm/JglNyGf9kTp/oX8pzoHOkpAxrmnhzuJRZYD2BobXrr3vKeAp0IIUaK5QaqpIXlqYAYzBubenTf8M3slI3e2fl8BmZA+bwGdEX4cQD+NJh3CPOYld8nEfnxG/TPwyJQfVcjXM+0vQ12jNXLUcwn/lio3BWpn/O3TOD9p2aO1O+MPsHEpxV39G9zErwFZJiJh30fpx97lA+IeuSm1o164ovVvXTtyhbQh8GLX5xgxhiNAhyrQsXKcRUJO0VpmkNxxR5mpxRucabXVDODYKohv5ozisLvE8rVgl2QzQegJrK36FjnZdre15C5uRdYeSaCHcigsuuGCqMpsCYOU7Wmv6o0WnAKTQPK0R+McqDzM8uDHFY9WpkvJJmbsM2NFw2mmnsZjUjnzmdMaN+gDU21pwh7l9l4CmOl5U0TaFRXsrtXg3qdVCW/lIDz2sz1sfo28BUd/6bK0WPupV5GVMDpgJlAKc9i4ZjuQZ/V1PAU+BHaJAky9lE1hNYPGi8tLiEI4VD/71wZnlOmK3XnIIWeSUgFCouxX+jO5RBIiTI85t43OKQbiwLy74tf9e0+NO+EsR4JQ+BH+VBoLlkk0rl28Mli3eGOTrzP+uPdq4uf80mZ055Q+eFBP8CsbBifytWoCLD+MiaWJKAEcJp6VcdN532HJlzMmYYJQRQgNjWCZs4/RppgmU9NCQcuJ5Q7zGbLnPIkv8RsFWlStBYr3I49QcWQDcKLdRJOENbSl0wlCXCGKEcplOjOPDROBuUZDSWHP00Uf/TUgRxKYARMuvZg1CSxV6ww03PClhOF34ELzscDAlgDIrZbnhGe8yuPLKK5+YOXMmC+soHyXAFIENWpT3sI7pZY6+ReGRRx6ZfMcdd5jCY0pAuaaUOFegUdC0DHWkD+AS+yn9FYj6pKmRBSlpX3W5Yj/0J+htfR1c5mIp/K+ngKdAi1FgZxUAKsILyovLS8vLC3OoWLxk8boXXnp5epUWvzN632a1flTwW5htfCgBTujL1wi/Vtu9qxH8CHw5FuJVS+hzBK8OutN2v/Jg6eJ1wdIlG3TOf3pQ2qut+wiQzI1BhrYUu2/NhKv8v6gEqJYNgLMHRHQBNygXlbp27lpUWlJqDNKEqrUb3xiV+XYP5lctBYD4pCBTMiMw6GeKRWI5Dhdp1EbuNQqhOddw8WysjpYnJdwpYNeN+jK5o9TFn63CZVr4tubGG2/8R6OZduAG5Wi//L3vv/8+uytMENto3Noio0w1wnmnQAvgNulrdg+oDe8JkQldFICoBaByO4TXdtVHSm/d9ddf/9gvf/nLj8LyTfjjrydOlo7VWkD4R1lbPtsu5EkS6wNRL5988smvKAltjSs8gwYNqtMWwqS7CfR8oA20py9YH6VvRSHKDxxPkOWuWc9L6ayPRXHb+xQtw4c9BTwFWoACu0IBcBYA1a38e1d+9/nlS1ZV1WnFfm1NtRPoMVN+bNTvRv8IfJysBKzkR+jLNBkb8YcjfUb71VIknODfUqltfuXBymUbgiWL1sv0v9kJ/9792muuPk8L/zKCzFZa/MfnfCGQk/xRiZ5Itci96K14dCyQocHyMUce2zOaRGET6sakoj4CFwaI0K7UwXhNmtu7du3agbRyUQYInm1w6bqiuLg46YrtcDQHLp4H9cBZfRVUxTjSsBkQ7jGnTjByBDKCYJOE5/t/+tOfXlR4p0Ej3dX6KM49+hriAiFjpEkZOGeelk87aE+lnm2zBIrSfgFosxayfSiB9zuttp+lBCb8bSRsCgdlVGqahHJbFLTNb8Exxxzz+x//+MemfFgdTCDjQ4ONmnNfrf35f9GhPy+yMHJHKyKFbdG555577ze/+c1XhcOUDcqg3Zt1CJDkr7ahCFBOsO5oHUkVU01acCpdsWyzLC8oZtQB2li/ok/RPxP7flxZ1b1yLZLcAm4BxVAEZWzTH1UU9bHnTX+jf4Lbg6eAp8AuoMDOLgK0F9gEFC8tTBoGAaPI+vmvbnvyykuvPLlzt2Ltx9fbrPl7TOsxwawUgPgArEA8IXTa1qd0bpEfB/BIIaisqNEe/0q30n/z5iqFNfcva0Dr/KygV5/2QZt2BRr1ZwTZOuKXc/xjeGO27tiyQ6tq7FZzfs0aQN34rsBew3WOcBC8IYdWkOiiKI0eTvhLYFUyahWUY9LlQBiNpurghspUq/AWuU06lQ0GawzQ3eN+iJjyjL7ljz766POlpaXdNJKFPmlyfMCGqVY+ulIzb968RUrPM4BRkw+ACHGGqn35HM3bJOi5UBccuHi24EB5rNJhNP+ar68OXnXVVUdoFXmz8ClfHBAEOltgqg4OmqRIBL4TSPKpO32J9puiyoOt0ip7o4kumwbNXZdpod18WRYWaQQ8mzUMygV+HGU6YS/fyqIc6F0hSwt12GnQx4LWTJs2ba7a+qmE+VwhjJYffeY8I6Zm7Lnx7KrOP//81zRd8I7WKwzbb7/9+kmBKVW/MrooyRdhwYIFS/X56HnaTjlb+/0/VwrKsbLAy3OknRk6EGiJ8P5YgjpTbc7WO5quRX/VnE2hvlWhflWhvmZKEjShP0Av6gsO6oKPs35GGRU6WXGZlJgfa1oqT487S7gzVXfN0qWnaIqlVucjpJaUlKTqkCmmQqALz4O8lEEdwYfz4CngKdCCFNBi/G3fKyect68Ae+lhmpiws+XsCFhMioVnnXH+vidMOOnQ7t2LnYk+JpDDN9oVH1sUyJoAJ/g1MOVQvAotdOdgn3IdyFOucMUW4rUGQEoB088MgruXtAmK2+Tr5L/soJUOG8vQ19hiy/pYvy/ksX/55LEyCbi7MV9hFR1PIyYVHjIk5QPLRHVst4E2NlQcOuGgO0SzVUrN3KyNoGBaMCywwLyNDtAiR4wub9999+2gL/0FYsowShMwCsaFOkwPh0ACH4waIQATBAwv0xCM/vFxbC8EH3hhltQjqoRFhShWCIQ0B7601d7zi2T2LVI4KRx00EH3af/3fCVi5Ei9KIPnTrm0MU8rvQt+9atfjda++L7aB99RcY2ChEy1lIZlEsgL7rrrrhnhaXS02Ub8USEATa1v0e5c0bKTRrKD1VdaaeV4K2SJRqj1KFYoFAqzTqBC19USYpt1dO1qKVjQwWhDG4ze5kNnyoKO0Ana5uq8g6Jf/OIX+8kU31/CKkfoU3ln5PQdyDQ+F1wvAak1q1tHtLSPDy1JCVuj+f3VEmzrdCASOwyoA47yo87qZgKVOtCHqAf0tWdNGJepDzQV6ZyBNvruQq6EMycW8jyoV52ea7kOUdpIuxVFH8JRBm21OlAW/QWwsiiPsPUn7pEOuuGMVvimoESFNHWw/g0O+ibO+in4cfRlHNAQfnv+VvdoGS4Tz8CDp4CnwM5RoCUVAHvxjWkhaOLnlB926NeHHjb+G+O7dWnfuo326Be3ydH3d9gWqBP2EPwIfZn52b0my6MEP75cpVb+V0kAi1UhpFESsrNSgrbtcoPOXYqCvHw+7ZsZ5OTmOPO/+7APNCGt+zFB34AC4HhITPmIJZUFwpVhCoCUDSkD7Dioq6nXYsMNweXXffeP09+ZPkclwFwRiJhrjbGCESYIEzWmagzcMW7FwxhhfqQjvTFAY3bGZGHUMD7uA+QhL/Q1xkqYcqL4yBNl2FxTDmmoA8pZgb7M1lFm4ctk4oY5Nwow2nHjxt0rIf2ZEtFeRoHUFZw8c+qCYMaBP0uj+U6jRo1qLwtDjhRKJ5gUH8jEWy2T9kZ9GGeRzODQzYQRbTamb8LFyiA/7aadiWURl0hP6oVDuJmL0gS8lBv1oVeUzuClLbSJfmxtS6S3tc18JXVg5dqzBT/lWZmUb33G4u05Ufdom+1541MnowPtjrZdl3GIlg9ea3+0LEtDJsOFzzPFUQejo+EwPLTH8uMbzcmDMxz41Nec9WG7r1sOj+EHrz0b6so196CjlaGgLrwC4OjgfzwFdoYCvPA7C7yYAIzAGB5MgJfdXviM5194atYLL/5j5WWXXjducN+RffmgXZ5W7WfoU7y82mztq0LYa7TNmfu6lGIgp4ENZwbw/R5N7wetladN29ygsChXc/+M+rOCnLycbU/9U8GNQlhbq7TjI7rg2sUZY4knMExSJKQd9Czt2UYKwGeKpW1RRkabLVeUFiAgHmZmDJt8lp60UQZIOpifxRlOfHOWB2ZpdDZ8PAN7DsY87Z7hrBk6dGhWU8JfeJiSYS6YfJRtuA0P7aAuAD51r3jqqafK5BYoTLk4wOoODvKTFmcMHx9HHGkA8lr7zCee+0ajRFpyn7rgonUmD7it7Khvaa2uSubyk4ZyiCe/0ZsyAeItj8W5G/oBJ/mtHMoGl7XXrq29VgclcTit7twHuE8dEKbgwKdM6BKthy5dWnzSGx7C1IVrgDxWZ0uDb+0hjcVTtpVPHGWSN5pWlw0C6SmX/OSxfJY3ipu2miMPdea+B08BT4FdQIGWUACsWrzoxiR4iWFS4IdRuRGrtPbsd957Zdb5557c941JM4MFs1cHGTpul0/xOm4kiwAjeKwCbDBj7M55atmt0oIcufy8TI34JfRzstwxvXn5OUFuXm6QlpmuHMZPVFocqJJAQh25Hl7F4hJ/owlcWssTy8htd25OXTYj5igTo2Ar3IqAcRkQh4P5RxkneYiPMkDyGaM25mc4dcuB5YFBQl/wUB+DRHykt/qC0zFYfVCI0fw2cMIJJ/xbC/v6DRw4ML4aPKIARPEacwYfYOVzbUpOomCiHlZ30oEjyuy55j4APnPgoQ/hbATOPcNFPgCcVkcry9LYPSvXrslnuKLl0QajLTitDHx71vhRF22vlU96HO3k+Vt78YkHN2mBKC6rC76VR50JR9tk/UnRcbA08YhIwPDStmjZkSRx/FaOpeMa3FYna6/5URzkiTrukT9Kd+IAi+ceDrpYOu5FnS49eAp4CrQUBWAELQG8pMZ4eHkBmJyNVJjvxHxZMWTw0LyCghyNpAuCivVlOiFPRwVrR5vmU7VIEMe+ex3FK2WAj/nwQTeu06QYaC6dE/WC1q1zg/xCTP/Zuqf9/vpDWdgWdJ0Y5RIQH7sR/d0mr1MGuEtaQ8MCRXGn6vhHZmgvkOjH0MaYGPdhhNDEGKWl5x4QFuTSEI4yTsPlEurHGKPhhFkCUZyGz3Bx35g2zwRBWqmtZet0+M0jF1988UkkeO6552brgzVLdQBND64NpLTVs2pb14Y3fisMWH2tLlxTHu0FonXjGjy0w9pCHEA68pAXsGv6qAl+wjhLY/UyXOYTDxgN8A0sL/gJg8/Sc00drBx8q5PVO4rLcBhOfAtb3czXrTiQz/JGy4/GW13M5x51wbd2WRjfIDHMNTgox8DSGB58C1NfniXXiWB1aYg+UZzkj7roc0nEa9f4DbnEOvhrTwFPgRaiQJQp7CxKe5HBwwsPA0DgmNnTze1qbz4W/qB1UesgJ391oJ1+AVvsdGS8hL+EvpxTAKQIaHGTuJ2sAcKGZYDj9Nu2ax3ka7tfVnaWi+Mo38T5wJgyEKtOTNaHVQvZi7tyYRvlw3nCXMoQ6gex9QCkk+mfMtxHh/RFYMU0Ba4IJTLGB+OEHkBifkvraqT7Ud9liPxwj/wwacODb2EF4/ktbPeoiylljoF/5zvfmfrhhx+u15bCdjrPnjUNeVoxz1x8HFjbpikA8lq97J6VS9tMMOADpI3W0UXqx+qCb2ktTJ2sfcRFBTEWJBQX0nAPZ4LK+hlxBuDmPkAYvAD5ibdrfJzVlTLNkY/0JnQVdOksv9WDdJYHn2uAMHUjHXFWP7vmvvUPBR0YLnwLWzmWj4QWF8XrEIT5omkoJ9oOww0O2m7PFh9HH8Gn7rQVB5APPLi4NUY7P7J0UJTVx2hJXt77qNWDOCuLdIClJx4cgJWJb3Huhv/xFPAUaFkK8FK3JPBCmzMmwosPU3FMYUt5hfYD1waF+pBdF63gZ8SPElCrjwPxxrOYWQvvtSiwXqv9OUGwTov+0oO27fODjl2LXb4s7fN3i/3CkrSMT4Vu/XMSXPdigjxc/Eda8LvqWSUtksTc3Ooj8N2ffHdssZQAFiamZ+hAA8sOwq1hh+wv9090fhhPk6J0MFqAwxxx5kjryCBf1fkiEB060jWE33AYnsQ0lGsr0DfrzPlPJfxnKM5t8dLhM/jbgGphZVk8/cYES4Y+2tNv/vz5F2gff1vFIxxMWJuP0GAUj0OYYw2yRXYssLNdI/p2RIBzu0dCv1h+kawTh2lF/yWqy81a4X/5D3/4w2GKZ4EeeW2VPL4t2MOP4iYtjoWpVg4+OyKsPMI4i8/r06dPsb4RcI4+E7yH4t1UlvxoW4iz8nP09b9ifVXwQp20N1Lx1A1ndbH6Wl2sPuZTN6sfdTJaWJ0sn9ErET/lGA3ibR83blxXbeG77qyzzuqv+4X67sAEKX5nK1yE07a/Ii0Ivfj3v//9/rq2sqI0Mnpwj3oVy3I0RLtavqPdH5103Wbq1Kkn6blcoefzkzlz5lyw//77lyge/KQ3nPjWRtpi9cen3vQJ+gx9iz5mioWCHjwFPAVamgIw5haFGdNm1A/baxg4GxI81YuXLFrHin+EeNeeHbS/vzpYs6rczfkj+J3Kr1E9x/hka31AQVEr90W+An2VD5N/zCog7E66s4tAeZzINbkbk5DcQDGI+VRH4OQYPs4lcEF3KxrttgxK/IfpkH91OqmwXGcPlFe4vdAmEPFJBTi/Y6fM4PFH/1rfqVOPYMx+o2N3tqax6x32UQm2J3O4Cp889jwYlQHGYPHjAl1TMSgjcZACViulgKkcazP3LK8T7CNGjOirfdz76Cz5V3QPBYPHSBrA0hIHY49CYlssnykX4HdlfOMb3xjPeoQHH3zwbQm0Uh2ic9Jbb73F9sRVSoMQptyo8qPLZgsQ2kbZVsd4nUtLS4v69+8/Utvq1ur+AjnKsHpTN+pqik5Gly5dCrt161aqfjpL8QhO6EkefOqIH3WGy9pubcanHlYXBeNAHtID+IbDrs0nb7q2TO6hsxOKJfRJWyD67aWptAy1rYMUty1SAPtKcemra9aFzJczWlpbyYdzz0J+ptrZtbtA51ogyANt/xyonR0rn3322bknnXTSHlIyvq3Dr36rW2YJsDZTVxw0xze60Mei1idLQzoPngKeAruAAjCIFoXqWpMv7uW2lxhG4pjfG5PfXCmToSS+hgI6N6akb6egu47wLWzTKsjLywpaF/Ip35ygfcfWQbeStkG30g5B247FWu3fygl/EDrZHZPO7iJ2bfH4CG/xDSUmvfMR6hZ2UYzvCZCWhKGTxYGgBvwuXhZwWSHq3VbEmrrq+tmzZ61RLtoDYzKn1DEo31yj9QrZwaKFiwIdomLRX7ZP/XAmiHhITMngYLo4d62zWhTcCjqcaJ2mBUhPWw0PCRAI9J8MpXEPXaNMBISNQPHzvv3tb/fRyPBK4bha5+6jGbqRpb50N0iWg73feOONb8idoP3s7XWv+PDDD++trYLf0QeBztfe+SNuvfXWvRVfwDqEN998c+EZZ5zxmeI+VpzWh2QUyARd+JOf/GSEDpphJFqgQ3YO0Gd9eypcdOGFFw5W2lFSEo5V3hN1OqIrQ4cWDb/55ptHSYE4Wdsbj1fa4jFjxnTXgTUTpMh00HWhPpV7iOo7/IMPPqCdgepE26Oj1nwJu8PXrl37fS2ovEDrKUbpfr7SZevQp9rzzjtvvOhx0W9+8xu0QEa+BapXiQTuhaLFdToQ6EjF2Sjf0YQ0avMxOsfgRlkRLtZWym6kkUDto9MYLxO+K7VIE8tCkXZwFMsKsqcsE6N1wNAp2nVxhI42HqDwya+88soEnY8Abjfa1rcV9lGZZToAiTbkSmizBTNQ/j3k5R188MEDuFa5KDKtdchQJ1kwRlPG8OHDu4imY3VYD7QrlOI1Qs/z25dffvnXUEbVVkbvrtOIXrP0YaPPRNdFyotS1lpbQkt/+tOf8gwLRZNBd99991iFi0TnjjrUaC8pdONlYTlPX38cp3hwmRUgmQKkZB48BTwFdpYCvGQtCny0Z+rkt+pH7TsaZoPQMKGDXy0mU7Fk2fI1RUWFOanaIl5YXKhtfK1kXq90J/9laEU/i/3wmedP194/20ruBLXygBiu7K7lx+SSC2zzgyAHYhZsArGUphy4ayVysl8XTmdw1zGlgG1/7quEWrRQIfP/6rUbyj+bN3edMFmbvqAAZGq3gg5RC3SIarDw84XBwEEDqcKXBjDp0ApAXQGoYiS0kTaMHwWgUnv3CcdBzB4thvYmtpVHQP40CQHXj+TD9GHgKAZpGmkWyax8roT5Mj3TjB/96EfH6wTDez/++OOK22+//USNkuMK6LXXXrvpsssumy1BdooUpyrlWXvooYcOHjBgwHqdgLdCh+msGTt2bInO8+mm0WvalClTFkpYbpHA6aqP+Rz+7rvvPq4Rbp1OJjxUI88puveeBM8EKQgIFQdKt15lfCLF4wSLw5dgWiQT9noJwr2POuqoVRLaS/RNgjHLli37lwT6UtKobdCFtkELlA/anfnaa6/N0aE8PfVp3fHf//73F8v87Q4IkgDfKKG7Rabyr+k0vk06gXCZFlqeL4Vh/euvv/6xnolNC9hzSXn66acPUJvHSiDO69sXo0pJm3nz5mXoFL8zFy1atEoHG9Xq+wFfnzRp0kMS9GUSxsdSFwMdL4yy4eDcc89drEOWlmiknq1nWvC73/3uLd3gOelRxD4CpY8NddH1rF69erUjk86GQGlopTr3k/I0RnRfIOtOB9H0YCkLi1S3AvkHSylaKhpnKV8bpWc6JEWHIdWpjftJoGt2LjVFCtbbis/Stw6+pna0v+aaaxboWe1xwAEHDNKphp9JqemuZ36M0jiQlWWYypsuZQpLAP2KvhHvHy6R//EU8BRoUQq0/AtWp3cXFwMEjQkOMwFW6zS85W5kLWGLCGiV0yoobluoz/gWB0Xy3QJBbe/TR8SVXXImLpR1GYqvmNCOX7rSTLK5e7pAQfiC8Gcpv7uHF7MKKFVYS0b/4Zw/eSX4WYNA3IYNFcGqtasZ/WPJwCEIthGMf3/imfqKcq0VKGOlYKvgs7kL3UeMlO5LBdUf0gD2LKh31PRqYY5+ZX1AHCQATeGJthU8htMxfDJolI2ygJDhwWXok76D5AcyiT8p4fIY4TPPPLNUXibCX0J6pqYc7uXkvN69e3OqXZ4Ea7pGm8/plLt/a7S8nmulz5Agz9YouFxfspsj8/J8Cci2OssgV2kQGMF7772HAuOUFykJKCcZ+iBSKx0BvFBl3EMZGs12VjxKSqC1D/8W7vsIH3HEEaVSHmo1Mt5wxRVX7KMT9A6AZpdeeukcnQSIJSOQMoCVI942WSQyZLlYpfuFYR0D1Zu0NC1VFo5pEp5vqNyaH/zgB4yAM0TLtZy9oHlz1hVsVDIUCurjHAqIBOBybcN8VkL6bgn+9TfddJOjoaztT+OUFoWlrxZmUpdACsGrstrcT1hWiLesTaINQj1dSk8/7klB+QRfxQeyDlCXjapHnhSukRzQpPn8dTrBkfUWaWob9HNHTIsu0DUQbeqxiEjQ1w4bNux1TSu8jWIuZQweUq+2pEgxWC0FYLbyrDzxxBN7Kj5V1r4qPQ/el3Q9K2d5UDhTx1XT9kBl/vYnP/nJo4Sl4KFQRIW/qwf3PHgKeAq0PAVaXAFA1uAE/OAQFib8YaKVL7z0wics8COdE7BKwaI+tgG6bwSEr73hiosvoYuN3oWWSCshvOSaUTv3YoKfBAKi+GOIz2V4TXzsQvcY7TNNIMeiv3q+Tijhzw44rABrVpcHH34y9T3loA04UwJiSBWRxpbF0OXKqrFh0/pg1arVuvPlg2gZEsO1mjqbAoNvbanRqPkdMWwnVKm1RpnTw7SWB98ceTkG1+FW2r4a3XWW2b+rPi6TI+GLwhSMHz++4MADD2R0GUjAoWC49HxkSHkZPdbzsSQJNZIEEp7dZIbO1dcRM3WkLrSulaDN0UK19VIgPtDo8hOZ83N0dn2uRtfryXPKKad00OgSk3cgawFz2WwtTZVwq4o9x9o6LAeKdmVzVC7lkk6yyAlTCdbXJZDa6ujjfpoCmEFaCUl3T1MEHVR2R42GO+t+kT7clKXphaNEqhopJLPBg7CXB00Cmd07SAiryMx0hK2i6q677ro39fGkt6S8dNVo90itmciQ4pOjtAjrVJn4N2pHRqGOHc7VIrp8CdVAgtkJTUbfsjRgNQhkXUDR4hlwtHS5rGquzFmzZm2yNqku7tlo7cRAreGgfJ5xtZ5LOh+S0vcBZiltjawGfTVFMk+KwBy11a1ZkPUF/Mzr5+jLgZ0JC2q1CHMT1gMpUlnKh7Kg96WevlKJAvDQQw/NlWIwQ9aY5Vo82VbxNcqzEYVj8ODBWaNHj+5GHkGd1iQ4uqotlToumfphZaFN7plw7cFTwFNg11LAvYQtWUSd+6JnHGNUUMCAYOaVT//z6QXXXH71pk5dOuQjO1LEMxmY8/nhjZReAAAQS0lEQVReDSoCTjW33fYY/Os5BjBkC+6+XcRlWrw8FzAOEr+NQA8v8HSln1gc8TFTv+qgcK27jo389c0yl27tqi3Buk2ba5959rGZ1F+OdphSY22sd0cEuRpgt6gPcqpT9cniVRoZdgxjv1xPbXWksSkV1cbqjo/AqJVJe50E4m8lzPtLuK6cPHlyQxYAJ1yU3lkOJATLFA5kAj8eH+ArgRKWH2queJ0EzOnESbCsuPPOO+eaCVpCAAW0GuGvOtUxWtT89TzmjOXIEmhhGUpEpczp5ZoT76wmnEi8lIcNTz755OeSYZUaWS6RUnAw8RKIS2Tin41A4lq4KYOv+mVpOmOjBDL9MNA3EIjnOQZSMlBKamSCX8EonRG6LAHvKo4P4ZAu0Pz9cBxhCSzM/s9IsK6TQG0XCjusBJtEO1eulKAROJntK4877rjXFF/z61//+mAJxFVCUSd/mcqt1DqCQyRo91D7fypaPasR9FmyZpxNObIIPKAFep9KIRoha8k3iBMNV8oMP1NWAqcMSDFKET1dO/DlXPuEY7nM/3WyqhTqWbyirO4Zqawi8Gh64CMpO+myfux5zz33zJTy1DbsF1vuu+++ebIclGta5FTSasriA3kVmhqYKkWulwT8ccQDUjQ2qkwX1nqEMXIurPUGnylQdv/9938k5aW/rAJncEPP5ll5FaK/8Z5KjfydcqhvQ6DM0besX9qrrCgPngKeAi1NAXsJWwxvFZv8twIvMC80zhQAhnlb7vnzvS9dc/kVx2Vo8FWnUXcqKdzMAXv/nYiOWQMcC8CkLr6q//CbJ0rsLsMfd4lkd+A8/cSwuEAsHuHOH1Gxn1D4M/IX15EystVJIWAKQN8BmKtp/xmzpk0Rs4OJUn8YLu0xZqXc2ke3YZu2a11DarBo0ZpgwEDufuWAOkedMd0ajfraSICslkBcqTSm6ODTXrtGMCLsKmVO/3DevHm3SRC0El0zEJoS+mt1b4vM1r/VyLev4urlzyUPIKH2sKYMYPgV2p72qMzHWyS0KyVgXpPA+Ei4UiTgD5MQw6y+SXPIL++5556tJZxbSeCv1kK+TzSypz71WsH+Z5mne8r8nSrBNUdxAGb4v2i9AaPZjRLGD0iQrZdVoEKKyl/12eFVKq9ao/6HpeRgMUAJ4At1CNnlmnN3io/K2qzFdffKGpEiJYL2Boy0Jdg3aVrjLikqAxXP1/RWqj7gTzv33HMflFk+TcI5S8J1oeb9K1W3eikVj2neva2UlPWq72yhqtN6gzekBGBZKtcIer5GxLdPmDChu8ovR4grvkZt/gPWFdKHNETwVuvQpodFoxUiZ7Xa9+DEiRNXq/hazd8/qEV1S7RgsoOUlFVah/G+8jLKrlM9q3X+w590ENQS1XOVFunN0LNaRjq5FUqzQR8TqpeC8ZtLLrmkVAs8K2Tp+FzxLIRMLS0tvUt07annnCIlBmPRWrWNOf9/SKHIl8KVJsVhmfLMpzxNY6yT1ec3xx57bJfp06evUb0oI9DCwvf0zOkPm7FGCPdtssrwHHi3rK/RJ927Jd+Dp4CnQAtToCU+BrRNlSa9+Lq7PuiQA2CWOMQ6c7PM+bFaGDMtGn/x3x545NyRI/bompYu8a6UYsiBVlDFLQFEEg8a58WCW6+IdOxBgTCBE+yk40bIOpyH8MdxJ1H4Y+pXHKZitvvx8Z9aLWas1QEFM2esCD5bvGrD9Tef/StlRSggtGCmKAMIDRQBGFb9s89OCkvUlUAmTZmXs2QC398tbIzFfvm/CGDVAuWPBVwIWJ4L5t9CmYIPk3n3EIXZxbBJjPt3WnS2WJcwZ4QpbUbwAjxbnqs5njN4iTcFIXwy9oR0Z+s90pCefM5JqHyT58CqdQmhUgmSf0rYz9R9ozO0ThQQ0J1yjP7RMqNhJXFAHI7yqau75hhkzamfqoWC92rx2gLFU44pRqbsKcqB4TA80XgLW32i1ybUuGdhu2+4DLfF4xMXhcQ00Wtw10sZUD/mqxquHHtmhoP00WfEtdXXfEtrvpVBPsB84gFXbsRPbJ9LFP6QlvvQmGeL4Me6Rv9CySZsz5y6b1Onre+57njwFPAU2CEKtLgC8Owzz8UrcsRRhxuTgblHhU2BrguLCovaPvznxy7t3atLNpYATPEc+Zuiw4FYE+AUACWMySsX0I+LjrEDYzsuNvwRm4hzCheICX2G+Fw6xqFymNd3TvFR4V8XHj5UVVEZfPLhymDm7LXV/3zl1/e8//70+cqOEET4IwjL5YxJ1b08aVvhr3sUqa8ZVgZjRo8OioqLiPpKQKgAIPjsmeQqjALQWiPbW2SuRiFw8Oqrr74wfvz4ibqwdlubISc47NmCqznCX8kcIDxw5MGRP1NTBMNklh6ueeMsjYyna00Bo1cTECb8TQFwj1T3o0CcCapofDTOwqaoUI8UjVb30fy2rPr9HtQ1QsccgipRCFnvS/SVNC6sqQuQ6BMHzihYvYmz+kXvNxSOlh3NY+WZAMZPLA98lsd84iyv+cQZRNM5mukGcQaWx8rl2uIsTdQnndGYZ4oSYM6eNfcNn4Ix8AqAUcL7ngI7TgEYb4sCo7cEgAEQyQsNI0e7d0x/3fp1qVdfd+W9115x/ekD+5W2LtJX/lx+rc1KTZXZHyVADkEaswTEuA3XLqIx1qIEsVvywzTO11QDG/wpAwaCq7VrzP0aLGFV3rC2LPjog1XBwhXry5577Y8PSfgvUokm9BmhmBCMM6aa6i9WhlrU6FPGDdBEKL4yQMVhsjybSq32nidT7lCrneZl5xAf3iedMWbLBw1w5Eeg4qKCQpcOogSy+1EFgD6RIbPzv+Qmh3nwrDzrP/gmFP5/e2fXG1UVheEjpbTlm2n5iMQQPyBqIiVGEi+I3phoFG64MPFfeOG9/8D/QGLSxARulASCXhGMMZAQEw0ajdDECoQqpbROK4jr2TPvsLp7ZjqUMkynayW7a++1P8+7O/tde58zZ+i3lXhyyuOkFzgAduvjnNm+tqBrox/F0b4/355lPZLQFqGV0H6rMuT7MeRp1UUzbulWdaxYU6G+6qovaV+Jcj74POLkSYgzNgJYE/g/QmuefXkzhwQCgcBKIbDiJwCnv+QZn4fywbH3WSS00LPL4ytPPMDELjMdPY+M7Bz+5ONPjx8+NPqivUitGNrMiXJtpeBdAeYJpFMAngVMa5DZaLRMGqtFitRIHi+g5gDUj/nr5J/u9/PMgjkEHPnP2jfgxq9OFb/+druYnLl5beyLz06Oj1/loS2exNaxPzt/PQfAIsXiVZw9c67RNWkEB2Nubr44Ym8ErAxXasYu+Fs/AQBN7d4BnFOAjfbVtR1jY2Mf2X3tzbb7/9aefP/e7LrdkTs/TIMn0Wbkb8UWLPyk6V+BeowFJ0Dt0bbIAZxFCJCD7Al7S7cj+peRpm+NH03AJlE/zCv9oBfNsQovoamnftWGdLOqlG+nDPXVtrRvkzYUcntZeV+mWZx6vq7ifrztzA3lPbbCHBtxP27fdvpsWX5IIBAIPAYCnXIAWCBYXFngcQJ0z1hOAOSz6djRD1975+2jb71y4LmdIyNb7CVB9lO//XVO4eMP8ael5qE2a6nUjgiN+G0pYSeuHX86oEgOALcA7hfz9iri23/PFH9O3LGnuGeLW1NTt3/85fz5k6dO8GAWu34FiF/kzy5FhPSgjPwtv9sdAJBMu27TOGWaE+LYyWcR5lpxeMruy5o5zavmV2l0mWgRT7NoBbwDIOKXpr4IgHEIb8hBpKEy6DJRP2V5cgByTVn1q35IK17W1krZ6KfVmOmHMkizcrld5alTFs/LUy4X1VNZ6bxcnlY92fO0tytPOJOWTVrlwwFoIBGRQGD5CDxxB4Ch1U8BWDS0w2O3J8LhITROBAg4AkPvvXv81cOvHzn48v4D+ys7NhWVHRvttcGDxeDQBnuYrnYawJcHCY01wpYIrRJpt68UZG+l8AT4Tj8P9lVn5+3ref8Ut+x3b/6arBbT9o7/65N/jP905dLlr05//oOVFtmjtfstI0AWq9LdP/YuPwEAPMiWgFOm0wDtxM2USA/i1X1ZtIgYWAkiA2kztSWUh3wRxqDxiJCxqw9w9kF29HKEvhQ0BmnsajcnI/Wb9+nr5HmdSjMGiY9jazZulV+uzvtRO8JP6aW0L+/j1MvTqa2ag79Us5EfCAQCrRCAkDslfJDZyXlhgdUuk50m95qHzpw9dcmCfdf54K5Do2/s27vnpX17n927Z/eunZUNfevtZ4H77Y1m9spge1PgwMA6ey0r/GErejohqH2VL/10773/7B3+drRvhF+t3itm7HW+szMW7MVkd2fv3rlx88b1m5O/j1/5+fLVixe/m7AmtNPlqFtBxA/56f4kY2bsTcmfvC4X5oNrYBGH1BFsxEWGmjNsBMoTsNsanFwtvWoY26MKONI/mj5935ZMkvqyWKNfiy+nr1prC//St0iM/hVXn9LUWqk+aasrpD5/aSz120IdH5cfA53zGQ4JBAKBziDQkRMALqV+CkCUhRbGRrPbVODouSywO0071NHRN/e88PyB3Vu3bNu6fdvI9pHhSmVgw+BAf/9A/3r7+sC6Z/rW29sE++zp/gd2T//+3Ly9JWb+33vVuWp1enpqenrGXol2d+rOxMS1WxcufDNu7UI42t1C9MRF+DgjyoP4CZAQZJWIodnRv+UngR+78RkABldf8EWAmg/Njexcp0hfTo+uP3kA6UKX+ScjHa380r5VkW/SOWn4gu3Gs76p1qrfx77Wdse11svZvLQFAZ+tkEAgEHg8BFbcAVhiOPp0oyEbAqcQCg2yN5vuRSfyt7SOplXWkxbt+WDJRNKQFyIS004WEiMuYtfu3hO+bJSjvAhQK4+0Za1K8XMh7JgPxbkorlEBDBVXHnolRGNZqq0nhXmr/p9Un0tda+S3QCAcgBbgRFYg0CYCnXYAGJYWWxGNJ3KRO1onA95GWdK+jicttW1FEllJa9cqIkeL2L0jgENAWkGOg+qLDKRpfzWLx0txaV2XrlUau4+rXOhAoGMIhAPQMaijox5GADLttHjyIE6AdCB1ETNxduBogpwAnRpgU5y6ChZNcd+HTgFE4mgCdjkB6tfnkU9aY7RozxGfx4nrQ8pstZzWeSoTOhAIBAKBQGAVIPA0HADB4olGJAuRQ7oid7TIXhob5aRF/tKW1RDalQOAVpq4CN5rX0ZjojHivS5r4Rp7fQ7j+gKBQCAQaBuBp+kAaJCeeBSHiEXoInrpZuRPe+R5ob2yUEb0slFf45D2bUY8EAgEAoFAIBBY9Qh0gwMgEHOyVRpiRuQQSHtbKtDiD22pPcWlqaa8PE46JBAIBAKBQCAQ6DkEuskB8ODmhAzpextl892+r98snrdBuTJbs/phDwQCgUAgEAgEegKBbnUAcnDLSLrMlteLdCAQCAQCgUAgEAiUIMB99ZBAIBAIBAKBQCAQWGMIhAOwxiY8LjcQCAQCgUAgEACBRS8CClgCgUAgEAgEAoFAoPcRiBOA3p/juMJAIBAIBAKBQGARAuEALIIkDIFAIBAIBAKBQO8j8D8Pr3cPuEQUQgAAAABJRU5ErkJggg==";
|
|
private static Texture2D s_watermark;
|
|
private void OnGUI()
|
|
{
|
|
switch (Event.current.type)
|
|
{
|
|
case EventType.Repaint:
|
|
//if (MudBun.IsFreeVersion)
|
|
{
|
|
if (s_watermark == null)
|
|
{
|
|
s_watermark = new Texture2D(s_watermarkWidth, s_watermariHeight);
|
|
s_watermark.LoadImage(Convert.FromBase64String(s_watermarkStr));
|
|
}
|
|
|
|
// just let one renderer draw
|
|
var itRenderer = s_renderers.GetEnumerator();
|
|
if (!itRenderer.MoveNext() || itRenderer.Current != this)
|
|
return;
|
|
|
|
Graphics.DrawTexture(new Rect(0.0f, Screen.height - s_watermark.height, s_watermark.width, s_watermark.height), s_watermark);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endregion // end: Callbacks
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Resources
|
|
|
|
private bool ValidateResources()
|
|
{
|
|
Profiler.BeginSample("ValidateResources");
|
|
|
|
if (m_needRescanBrushes)
|
|
{
|
|
RescanBrushesImmediate();
|
|
m_needRescanBrushes = false;
|
|
}
|
|
|
|
if (!ValidateGlobalResources())
|
|
return false;
|
|
|
|
if (!ValidateLocalResources())
|
|
return false;
|
|
|
|
/*
|
|
foreach (var b in m_aBrush)
|
|
b.ValidateMaterial();
|
|
*/
|
|
|
|
Profiler.EndSample();
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool s_shaderConstantIdPopulated = false;
|
|
public static void ValidateShaderConstantId()
|
|
{
|
|
if (s_shaderConstantIdPopulated)
|
|
return;
|
|
|
|
Const.TriTable = Shader.PropertyToID("triTable");
|
|
Const.VertTable = Shader.PropertyToID("vertTable");
|
|
Const.TriTable2d = Shader.PropertyToID("triTable2d");
|
|
|
|
Const.Brushes = Shader.PropertyToID("aBrush");
|
|
Const.BrushMaterials = Shader.PropertyToID("aBrushMaterial");
|
|
Const.NumBrushes = Shader.PropertyToID("numBrushes");
|
|
|
|
Const.SurfaceShift = Shader.PropertyToID("surfaceShift");
|
|
|
|
Const.RenderMode = Shader.PropertyToID("renderMode");
|
|
Const.MeshingMode = Shader.PropertyToID("meshingMode");
|
|
Const.RayTracedVoxelMode = Shader.PropertyToID("rayTracedVoxelMode");
|
|
Const.RayTracedVoxelSizeMultiplier = Shader.PropertyToID("rayTracedVoxelSizeMultiplier");
|
|
Const.RayTracedVoxelSmoothCubeNormal = Shader.PropertyToID("rayTracedVoxelSmoothCubeNormal");
|
|
Const.RayTracedVoxelRadius = Shader.PropertyToID("rayTracedVoxelRadius");
|
|
Const.RayTracedVoxelPaddingMode = Shader.PropertyToID("rayTracedVoxelPaddingMode");
|
|
Const.RayTracedVoxelInternalPaddingDistance = Shader.PropertyToID("rayTracedVoxelInternalPaddingDistance");
|
|
Const.RayTracedVoxelSizeFadeDistance = Shader.PropertyToID("rayTracedVoxelSizeFadeDistance");
|
|
|
|
Const.NormalDifferentiationStep = Shader.PropertyToID("normalDifferentiationStep");
|
|
Const.NormalQuantization = Shader.PropertyToID("normalQuantization");
|
|
Const.Normal2dFadeDist = Shader.PropertyToID("normal2dFadeDist");
|
|
Const.Normal2dStrength = Shader.PropertyToID("normal2dStrength");
|
|
Const.EnableAutoSmooth = Shader.PropertyToID("enableAutoSmooth");
|
|
Const.AutoSmoothMaxAngle = Shader.PropertyToID("autoSmoothMaxAngle");
|
|
Const.AutoSmoothVertDataTable = Shader.PropertyToID("autoSmoothVertDataTable");
|
|
Const.AutoSmoothVertDataPoolSize = Shader.PropertyToID("autoSmoothVertDataPoolSize");
|
|
Const.EnableSmoothCorner = Shader.PropertyToID("enableSmoothCorner");
|
|
Const.SmoothCornerSubdivision = Shader.PropertyToID("smoothCornerSubdivision");
|
|
Const.SmoothCornerNormalBlur = Shader.PropertyToID("smoothCornerNormalBlur");
|
|
Const.SmoothCornerFade = Shader.PropertyToID("smoothCornerFade");
|
|
Const.InvertNormals = Shader.PropertyToID("invertNormals");
|
|
|
|
Const.SplatSize = Shader.PropertyToID("splatSize");
|
|
Const.SplatSizeJitter = Shader.PropertyToID("splatSizeJitter");
|
|
Const.SplatNormalShift = Shader.PropertyToID("splatNormalShift");
|
|
Const.SplatNormalShiftJitter = Shader.PropertyToID("splatNormalShiftJitter");
|
|
Const.SplatPositionJitter = Shader.PropertyToID("splatPositionJitter");
|
|
Const.SplatColorJitter = Shader.PropertyToID("splatColorJitter");
|
|
Const.SplatRotationJitter = Shader.PropertyToID("splatRotationJitter");
|
|
Const.SplatOrientationJitter = Shader.PropertyToID("splatOrientationJitter");
|
|
Const.SplatOriginalNormalBlend = Shader.PropertyToID("splatOriginalNormalBlend");
|
|
Const.SplatJitterNoisiness = Shader.PropertyToID("splatJitterNoisiness");
|
|
Const.SplatCameraFacing = Shader.PropertyToID("splatCameraFacing");
|
|
Const.SplatNormalsMatchCameraFacing = Shader.PropertyToID("splatNormalsMatchCameraFacing");
|
|
Const.SplatShadowsMatchCameraFacing = Shader.PropertyToID("splatShadowsMatchCameraFacing");
|
|
Const.SplatScreenSpaceFlattening = Shader.PropertyToID("splatScreenSpaceFlattening");
|
|
//Const.SplatSmoothNormalBlend = Shader.PropertyToID("splatSmoothNormalBlend");
|
|
|
|
Const.SurfaceNetsDualQuadsBlend = Shader.PropertyToID("surfaceNetsDualQuadsBlend");
|
|
Const.SurfaceNetsBinarySearchIterations = Shader.PropertyToID("surfaceNetsBinarySearchIterations");
|
|
Const.SurfaceNetsGradientDescentIterations = Shader.PropertyToID("surfaceNetsGradientDescentIterations");
|
|
Const.SurfaceNetsGradientDescentFactor = Shader.PropertyToID("surfaceNetsGradientDescentFactor");
|
|
|
|
Const.DualContouringDualQuadsBlend = Shader.PropertyToID("dualContouringDualQuadsBlend");
|
|
Const.DualContouringRelaxation = Shader.PropertyToID("dualContouringRelaxation");
|
|
Const.DualContouringSolverIterations = Shader.PropertyToID("dualContouringSolverIterations");
|
|
Const.DualContouringBinarySearchIterations = Shader.PropertyToID("dualContouringBinarySearchIterations");
|
|
Const.DualContouringGradientDescentIterations = Shader.PropertyToID("dualContouringGradientDescentIterations");
|
|
Const.DualContouringGradientDescentFactor = Shader.PropertyToID("dualContouringGradientDescentFactor");
|
|
|
|
Const.AabbTree = Shader.PropertyToID("aabbTree");
|
|
Const.AabbRoot = Shader.PropertyToID("aabbRoot");
|
|
|
|
Const.Enable2dMode = Shader.PropertyToID("enable2dMode");
|
|
Const.ForceAllBrushes = Shader.PropertyToID("forceAllBrushes");
|
|
Const.NumAllocations = Shader.PropertyToID("aNumAllocation");
|
|
Const.NodeHashTable = Shader.PropertyToID("nodeHashTable");
|
|
Const.NodeHashTableSize = Shader.PropertyToID("nodeHashTableSize");
|
|
Const.NodePool = Shader.PropertyToID("nodePool");
|
|
Const.NodePoolSize = Shader.PropertyToID("nodePoolSize");
|
|
Const.NumNodesAllocated = Shader.PropertyToID("aNumNodesAllocated");
|
|
Const.UseVoxelCache = Shader.PropertyToID("useVoxelCache");
|
|
Const.VoxelCacheIdTable = Shader.PropertyToID("voxelCacheIdTable");
|
|
Const.VoxelCache = Shader.PropertyToID("voxelCache");
|
|
Const.VoxelCacheSize = Shader.PropertyToID("voxelCacheSize");
|
|
Const.BrushMaskPool = Shader.PropertyToID("brushMaskPool");
|
|
Const.BrushMaskPoolSize = Shader.PropertyToID("brushMaskPoolSize");
|
|
Const.IndirectDispatchArgs = Shader.PropertyToID("indirectDispatchArgs");
|
|
Const.CurrentNodeDepth = Shader.PropertyToID("currentNodeDepth");
|
|
Const.CurrentNodeBranchingFactor = Shader.PropertyToID("currentNodeBranchingFactor");
|
|
Const.CurrentNodeSize = Shader.PropertyToID("currentNodeSize");
|
|
Const.VoxelSize = Shader.PropertyToID("voxelSize");
|
|
Const.VoxelTreeBranchingFactorsCompressed = Shader.PropertyToID("voxelTreeBranchingFactorsCompressed");
|
|
Const.VoxelNodeSizes = Shader.PropertyToID("voxelNodeSizes");
|
|
Const.MaxNodeDepth = Shader.PropertyToID("maxNodeDepth");
|
|
Const.ChunkVoxelDensity = Shader.PropertyToID("chunkVoxelDensity");
|
|
Const.GenPoints = Shader.PropertyToID("aGenPoint");
|
|
Const.MaxGenPoints = Shader.PropertyToID("maxGenPoints");
|
|
Const.IndirectDrawArgs = Shader.PropertyToID("indirectDrawArgs");
|
|
|
|
Const.MasterColor = Shader.PropertyToID("_Color");
|
|
Const.MasterEmission = Shader.PropertyToID("_Emission");
|
|
Const.MasterMetallic = Shader.PropertyToID("_Metallic");
|
|
Const.MasterSmoothness = Shader.PropertyToID("_Smoothness");
|
|
|
|
Const.ScaleSign = Shader.PropertyToID("scaleSign");
|
|
Const.LocalToWorld = Shader.PropertyToID("localToWorld");
|
|
Const.LocalToWorldIt = Shader.PropertyToID("localToWorldIt");
|
|
Const.LocalToWorldScale = Shader.PropertyToID("localToWorldScale");
|
|
Const.WorldToLocal = Shader.PropertyToID("worldToLocal");
|
|
Const.WorldToLocalIt = Shader.PropertyToID("worldToLocalIt");
|
|
|
|
Const.NoiseCache = Shader.PropertyToID("noiseCache");
|
|
Const.NoiseCacheDimension = Shader.PropertyToID("noiseCacheDimension");
|
|
Const.NoiseCacheDensity = Shader.PropertyToID("noiseCacheDensity");
|
|
Const.NoiseCachePeriod = Shader.PropertyToID("noiseCachePeriod");
|
|
|
|
Const.SdfOutput = Shader.PropertyToID("sdfOutput");
|
|
Const.SdfOutputSize = Shader.PropertyToID("sdfOutputSize");
|
|
Const.SdfCenter = Shader.PropertyToID("sdfCenter");
|
|
Const.SdfDimension = Shader.PropertyToID("sdfDimension");
|
|
|
|
Const.MaxRayMarchSteps = Shader.PropertyToID("maxRayMarchSteps");
|
|
Const.RayMarchHitDistance = Shader.PropertyToID("rayMarchHitDistance");
|
|
Const.RayMarchMaxRayDistance = Shader.PropertyToID("rayMarchMaxRayDistance");
|
|
|
|
Const.MeshGenerationAutoRiggingAlgorithm = Shader.PropertyToID("autoRiggingAlgorithm");
|
|
|
|
/*
|
|
Const.NumLightMarchSteps = Shader.PropertyToID("numLightMarchSteps");
|
|
Const.RayMarchStepSize = Shader.PropertyToID("rayMarchStepSize");
|
|
Const.RayMarchVolumeDensity = Shader.PropertyToID("rayMarchVolumeDensity");
|
|
Const.RayMarchLightPositionType = Shader.PropertyToID("rayMarchLightPositionType");
|
|
Const.RayMarchLightDirection = Shader.PropertyToID("rayMarchLightDirection");
|
|
Const.RayMarchAbsorption = Shader.PropertyToID("rayMarchAbsorption");
|
|
Const.RayMarchDarknesThreshold = Shader.PropertyToID("rayMarchDarknesThreshold");
|
|
Const.RayMarchTransmittanceCurve = Shader.PropertyToID("rayMarchTransmittanceCurve");
|
|
Const.RayMarchNoiseEdgeFade = Shader.PropertyToID("rayMarchNoiseEdgeFade");
|
|
Const.RayMarchNoiseThreshold = Shader.PropertyToID("rayMarchNoiseThreshold");
|
|
Const.RayMarchNoiseScrollSpeed = Shader.PropertyToID("rayMarchNoiseScrollSpeed");
|
|
Const.RayMarchNoiseBaseOctaveSize = Shader.PropertyToID("rayMarchNoiseBaseOctaveSize");
|
|
Const.RayMarchNoiseNumOctaves = Shader.PropertyToID("rayMarchNoiseNumOctaves");
|
|
Const.RayMarchNoiseOctaveOffsetFactor = Shader.PropertyToID("rayMarchNoiseOctaveOffsetFactor");
|
|
*/
|
|
|
|
Const.IsMeshRenderMaterial = Shader.PropertyToID("_IsMeshRenderMaterial");
|
|
Const.IsSplatRenderMaterial = Shader.PropertyToID("_IsSplatRenderMaterial");
|
|
Const.MaterialNeedsSdfProperties= Shader.PropertyToID("_MaterialNeedsSdfProperties");
|
|
Const.MaterialNeedsRayMarchingProperties = Shader.PropertyToID("_MaterialNeedsRayMarchingProperties");
|
|
|
|
s_shaderConstantIdPopulated = true;
|
|
}
|
|
|
|
private static void RegisterCommonMeshingConstants(ComputeShader shader)
|
|
{
|
|
ComputeManager.RegisterConstantId(shader, Const.RenderMode);
|
|
ComputeManager.RegisterConstantId(shader, Const.MeshingMode);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.NormalDifferentiationStep);
|
|
ComputeManager.RegisterConstantId(shader, Const.NormalQuantization);
|
|
ComputeManager.RegisterConstantId(shader, Const.Normal2dFadeDist);
|
|
ComputeManager.RegisterConstantId(shader, Const.Normal2dStrength);
|
|
ComputeManager.RegisterConstantId(shader, Const.EnableAutoSmooth);
|
|
ComputeManager.RegisterConstantId(shader, Const.AutoSmoothMaxAngle);
|
|
ComputeManager.RegisterConstantId(shader, Const.AutoSmoothVertDataTable);
|
|
ComputeManager.RegisterConstantId(shader, Const.AutoSmoothVertDataPoolSize);
|
|
ComputeManager.RegisterConstantId(shader, Const.EnableSmoothCorner);
|
|
ComputeManager.RegisterConstantId(shader, Const.SmoothCornerSubdivision);
|
|
ComputeManager.RegisterConstantId(shader, Const.SmoothCornerNormalBlur);
|
|
ComputeManager.RegisterConstantId(shader, Const.SmoothCornerFade);
|
|
ComputeManager.RegisterConstantId(shader, Const.InvertNormals);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.NodeHashTableSize);
|
|
ComputeManager.RegisterConstantId(shader, Const.NodePoolSize);
|
|
ComputeManager.RegisterConstantId(shader, Const.UseVoxelCache);
|
|
ComputeManager.RegisterConstantId(shader, Const.VoxelCacheSize);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.BrushMaskPoolSize);
|
|
ComputeManager.RegisterConstantId(shader, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(shader, Const.NumBrushes);
|
|
ComputeManager.RegisterConstantId(shader, Const.BrushMaterials);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.SurfaceShift);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.AabbTree);
|
|
ComputeManager.RegisterConstantId(shader, Const.AabbRoot);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.Enable2dMode);
|
|
ComputeManager.RegisterConstantId(shader, Const.ForceAllBrushes);
|
|
ComputeManager.RegisterConstantId(shader, Const.NodeHashTable);
|
|
ComputeManager.RegisterConstantId(shader, Const.NodePool);
|
|
ComputeManager.RegisterConstantId(shader, Const.NumNodesAllocated);
|
|
ComputeManager.RegisterConstantId(shader, Const.NumAllocations);
|
|
ComputeManager.RegisterConstantId(shader, Const.VoxelCacheIdTable);
|
|
ComputeManager.RegisterConstantId(shader, Const.VoxelCache);
|
|
ComputeManager.RegisterConstantId(shader, Const.BrushMaskPool);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.IndirectDispatchArgs);
|
|
ComputeManager.RegisterConstantId(shader, Const.GenPoints);
|
|
ComputeManager.RegisterConstantId(shader, Const.IndirectDrawArgs);
|
|
ComputeManager.RegisterConstantId(shader, Const.VoxelSize);
|
|
ComputeManager.RegisterConstantId(shader, Const.VoxelTreeBranchingFactorsCompressed);
|
|
ComputeManager.RegisterConstantId(shader, Const.VoxelNodeSizes);
|
|
ComputeManager.RegisterConstantId(shader, Const.MaxNodeDepth);
|
|
ComputeManager.RegisterConstantId(shader, Const.ChunkVoxelDensity);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(shader, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(shader, Const.NoiseCacheDensity);
|
|
|
|
ComputeManager.RegisterConstantId(shader, Const.CurrentNodeDepth);
|
|
ComputeManager.RegisterConstantId(shader, Const.CurrentNodeBranchingFactor);
|
|
ComputeManager.RegisterConstantId(shader, Const.CurrentNodeSize);
|
|
}
|
|
|
|
public static bool ValidateComputeShaders()
|
|
{
|
|
if (s_computeVoxelGen != null
|
|
&& s_computeMarchingCubes != null
|
|
&& s_computeDualMeshing != null
|
|
&& s_computeNoiseCache != null
|
|
&& s_computeMeshLock != null)
|
|
return true;
|
|
|
|
ComputeManager.Reset();
|
|
|
|
ValidateShaderConstantId();
|
|
|
|
// voxel gen
|
|
{
|
|
s_computeVoxelGen = ResourcesUtil.VoxelGen;
|
|
if (s_computeVoxelGen == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeVoxelGen);
|
|
|
|
Const.Kernel.ClearVoxelHashTable =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "clear_voxel_hash_table");
|
|
Const.Kernel.ClearAutoSmoothVertDataTable =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "clear_auto_smooth_vert_data_table");
|
|
Const.Kernel.ClearVoxelCache =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "clear_voxel_cache");
|
|
Const.Kernel.RegisterTopNodes =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "register_top_nodes");
|
|
Const.Kernel.UpdateBranchingIndirectDispatchArgs =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "update_branching_indirect_dispatch_args");
|
|
Const.Kernel.AllocateChildNodes =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "allocate_child_nodes");
|
|
Const.Kernel.UpdateVoxelIndirectDispatchArgs =
|
|
ComputeManager.RegisterKernel(s_computeVoxelGen, "update_voxel_indirect_dispatch_args");
|
|
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.RenderMode);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.RayTracedVoxelMode);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.RayTracedVoxelPaddingMode);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.RayTracedVoxelInternalPaddingDistance);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.RayTracedVoxelSizeFadeDistance);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NumBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodeHashTableSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodePoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.BrushMaskPoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.BrushMaterials);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.SurfaceShift);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AabbTree);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AabbRoot);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.Enable2dMode);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.ForceAllBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodeHashTable);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodePool);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NumNodesAllocated);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NumAllocations);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.BrushMaskPool);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.IndirectDispatchArgs);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.GenPoints);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.IndirectDrawArgs);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.VoxelSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.VoxelTreeBranchingFactorsCompressed);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.VoxelNodeSizes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.MaxNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.ChunkVoxelDensity);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NoiseCacheDensity);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.CurrentNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.CurrentNodeBranchingFactor);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.CurrentNodeSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NormalDifferentiationStep);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.EnableAutoSmooth);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AutoSmoothMaxAngle);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AutoSmoothVertDataTable);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AutoSmoothVertDataPoolSize);
|
|
} // end: voxel gen
|
|
|
|
// marching cubes
|
|
{
|
|
s_computeMarchingCubes = ResourcesUtil.MarchingCubes;
|
|
if (s_computeMarchingCubes == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeMarchingCubes);
|
|
|
|
Const.Kernel.GenerateFlatMarchingCubesMesh =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "generate_flat_marching_cubes_mesh");
|
|
Const.Kernel.GenerateSmoothMarchingCubesMesh =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "generate_smooth_marching_cubes_mesh");
|
|
Const.Kernel.GenerateMarchingCubesSplats =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "generate_marching_splats");
|
|
Const.Kernel.GenerateFlatMarchingCubesMesh2d =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "generate_flat_marching_cubes_mesh_2d");
|
|
Const.Kernel.GenerateSmoothMarchingCubesMesh2d =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "generate_smooth_marching_cubes_mesh_2d");
|
|
Const.Kernel.GenerateMarchingCubesSplats2d =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "generate_marching_splats_2d");
|
|
Const.Kernel.UpdateMarchingCubesAutoSmoothIndirectDispatchArgs =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "update_marching_cubes_auto_smooth_indirect_dispatch_args");
|
|
Const.Kernel.MarchingCubesUpdateAutoSmooth =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "marching_cubes_update_auto_smooth");
|
|
Const.Kernel.MarchingCubesComputeAutoSmooth =
|
|
ComputeManager.RegisterKernel(s_computeMarchingCubes, "marching_cubes_compute_auto_smooth");
|
|
|
|
RegisterCommonMeshingConstants(s_computeMarchingCubes);
|
|
ComputeManager.RegisterConstantId(s_computeMarchingCubes, Const.TriTable);
|
|
ComputeManager.RegisterConstantId(s_computeMarchingCubes, Const.VertTable);
|
|
ComputeManager.RegisterConstantId(s_computeMarchingCubes, Const.TriTable2d);
|
|
}
|
|
|
|
// dual meshing
|
|
{
|
|
s_computeDualMeshing = ResourcesUtil.DualMeshing;
|
|
if (s_computeDualMeshing == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeDualMeshing);
|
|
|
|
Const.Kernel.GenerateDualQuads =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "generate_dual_quads");
|
|
Const.Kernel.GenerateDualQuads2d =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "generate_dual_quads_2d");
|
|
Const.Kernel.UpdateDualMeshingIndirectDispatchArgs =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "update_dual_meshing_indirect_dispatch_args");
|
|
Const.Kernel.DualMeshingFlatMeshNormal =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_flat_mesh_normal");
|
|
Const.Kernel.DualMeshingSmoothMeshNormal =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_smooth_mesh_normal");
|
|
Const.Kernel.DualMeshingFlatMeshNormal2d =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_flat_mesh_normal_2d");
|
|
Const.Kernel.DualMeshingSmoothMeshNormal2d =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_smooth_mesh_normal_2d");
|
|
Const.Kernel.DualMeshingUpdateAutoSmooth =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_update_auto_smooth");
|
|
Const.Kernel.DualMeshingComputeAutoSmooth =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_compute_auto_smooth");
|
|
Const.Kernel.DualMeshingUpdateSmoothCornerIndirectDispatchArgs =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_udpate_auto_smooth_SmoothCorner_indirect_dispatch_args");
|
|
Const.Kernel.DualMeshingSmoothCorner =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "dual_meshing_auto_smooth_smooth_corner");
|
|
Const.Kernel.UpdateDualMeshingSplatsIndirectArgs =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "update_dual_meshing_splats_indirect_args");
|
|
Const.Kernel.ConvertDualMeshingSplats =
|
|
ComputeManager.RegisterKernel(s_computeDualMeshing, "convert_dual_meshing_splats");
|
|
|
|
RegisterCommonMeshingConstants(s_computeDualMeshing);
|
|
}
|
|
|
|
// surface nets
|
|
{
|
|
s_computeSurfaceNets = ResourcesUtil.SurfaceNets;
|
|
if (s_computeSurfaceNets == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeSurfaceNets);
|
|
|
|
Const.Kernel.SurfaceNetsMovePoint =
|
|
ComputeManager.RegisterKernel(s_computeSurfaceNets, "surface_nets_move_point");
|
|
|
|
Const.Kernel.SurfaceNetsMovePoint2d =
|
|
ComputeManager.RegisterKernel(s_computeSurfaceNets, "surface_nets_move_point_2d");
|
|
|
|
RegisterCommonMeshingConstants(s_computeSurfaceNets);
|
|
ComputeManager.RegisterConstantId(s_computeSurfaceNets, Const.SurfaceNetsDualQuadsBlend);
|
|
ComputeManager.RegisterConstantId(s_computeSurfaceNets, Const.SurfaceNetsBinarySearchIterations);
|
|
ComputeManager.RegisterConstantId(s_computeSurfaceNets, Const.SurfaceNetsGradientDescentIterations);
|
|
ComputeManager.RegisterConstantId(s_computeSurfaceNets, Const.SurfaceNetsGradientDescentFactor);
|
|
}
|
|
|
|
// dual contouring
|
|
{
|
|
s_computeDualContouring = ResourcesUtil.DualContouring;
|
|
if (s_computeDualContouring == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeDualContouring);
|
|
|
|
Const.Kernel.DualContouringMovePoint =
|
|
ComputeManager.RegisterKernel(s_computeDualContouring, "dual_contouring_move_point");
|
|
Const.Kernel.DualContouringMovePoint2d =
|
|
ComputeManager.RegisterKernel(s_computeDualContouring, "dual_contouring_move_point_2d");
|
|
|
|
RegisterCommonMeshingConstants(s_computeDualContouring);
|
|
ComputeManager.RegisterConstantId(s_computeDualContouring, Const.DualContouringDualQuadsBlend);
|
|
ComputeManager.RegisterConstantId(s_computeDualContouring, Const.DualContouringRelaxation);
|
|
ComputeManager.RegisterConstantId(s_computeDualContouring, Const.DualContouringSolverIterations);
|
|
ComputeManager.RegisterConstantId(s_computeDualContouring, Const.DualContouringBinarySearchIterations);
|
|
ComputeManager.RegisterConstantId(s_computeDualContouring, Const.DualContouringGradientDescentIterations);
|
|
ComputeManager.RegisterConstantId(s_computeDualContouring, Const.DualContouringGradientDescentFactor);
|
|
}
|
|
|
|
// ray-traced voxels
|
|
{
|
|
s_computeRayTracedVoxels = ResourcesUtil.RayTracedVoxels;
|
|
if (s_computeRayTracedVoxels == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeRayTracedVoxels);
|
|
|
|
Const.Kernel.UpdateRayTracedVoxelIndirectDispatchArgs =
|
|
ComputeManager.RegisterKernel(s_computeRayTracedVoxels, "update_ray_traced_voxel_indirect_dispatch_args");
|
|
Const.Kernel.ComputeRayTracedVoxelGenPoints =
|
|
ComputeManager.RegisterKernel(s_computeRayTracedVoxels, "compute_ray_traced_voxel_gen_points");
|
|
Const.Kernel.ComputeRayTracedVoxelGenPointsWithNormals =
|
|
ComputeManager.RegisterKernel(s_computeRayTracedVoxels, "compute_ray_traced_voxel_gen_points_with_normals");
|
|
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RenderMode);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelMode);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelSizeMultiplier);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelSmoothCubeNormal);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelRadius);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelPaddingMode);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelInternalPaddingDistance);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.RayTracedVoxelSizeFadeDistance);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NumBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NodeHashTableSize);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NodePoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.BrushMaskPoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.BrushMaterials);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.SurfaceShift);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.AabbTree);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.AabbRoot);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.ForceAllBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NodeHashTable);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NodePool);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NumNodesAllocated);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NumAllocations);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.BrushMaskPool);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.IndirectDispatchArgs);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.GenPoints);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.IndirectDrawArgs);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.VoxelSize);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.VoxelTreeBranchingFactorsCompressed);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.VoxelNodeSizes);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.MaxNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.ChunkVoxelDensity);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NoiseCacheDensity);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.CurrentNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.CurrentNodeBranchingFactor);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.CurrentNodeSize);
|
|
ComputeManager.RegisterConstantId(s_computeRayTracedVoxels, Const.NormalDifferentiationStep);
|
|
}
|
|
|
|
// noise cache
|
|
{
|
|
s_computeNoiseCache = ResourcesUtil.NoiseCache;
|
|
if (s_computeNoiseCache == null)
|
|
return false;
|
|
|
|
// switched to using based noise texture
|
|
ComputeManager.RegisterShader(s_computeNoiseCache);
|
|
|
|
Const.Kernel.GenerateNoiseCache =
|
|
ComputeManager.RegisterKernel(s_computeNoiseCache, "generate_noise_cache");
|
|
|
|
ComputeManager.RegisterConstantId(s_computeNoiseCache, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(s_computeNoiseCache, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(s_computeNoiseCache, Const.NoiseCacheDensity);
|
|
ComputeManager.RegisterConstantId(s_computeNoiseCache, Const.NoiseCachePeriod);
|
|
} // end: noise cache
|
|
|
|
// mesh lock
|
|
{
|
|
s_computeMeshLock = ResourcesUtil.MeshLock;
|
|
if (s_computeMeshLock == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeMeshLock);
|
|
|
|
Const.Kernel.RigBones =
|
|
ComputeManager.RegisterKernel(s_computeMeshLock, "rig_bones");
|
|
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NumBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.BrushMaskPoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.BrushMaterials);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.AabbTree);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.AabbRoot);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NodeHashTable);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NodePool);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NumNodesAllocated);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NumAllocations);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.VoxelCacheIdTable);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.VoxelCache);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.BrushMaskPool);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.IndirectDispatchArgs);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.GenPoints);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.MaxGenPoints);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.IndirectDrawArgs);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.VoxelSize);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.MaxNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.ChunkVoxelDensity);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.NoiseCacheDensity);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.CurrentNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.CurrentNodeBranchingFactor);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.CurrentNodeSize);
|
|
ComputeManager.RegisterConstantId(s_computeMeshLock, Const.MeshGenerationAutoRiggingAlgorithm);
|
|
} // end: mesh lock
|
|
|
|
// SDF gen
|
|
{
|
|
s_computeSdfGen = ResourcesUtil.SdfGen;
|
|
if (s_computeSdfGen == null)
|
|
return false;
|
|
|
|
ComputeManager.RegisterShader(s_computeSdfGen);
|
|
|
|
Const.Kernel.GenerateSdf =
|
|
ComputeManager.RegisterKernel(s_computeSdfGen, "generate_sdf");
|
|
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.SdfOutput);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.SdfOutputSize);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.SdfCenter);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.SdfDimension);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.NumBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.BrushMaskPoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.BrushMaterials);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.AabbTree);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.AabbRoot);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(s_computeSdfGen, Const.NoiseCacheDensity);
|
|
} // end: SDF gen
|
|
|
|
ComputeManager.ActivateAllShaders();
|
|
|
|
// generate noise cache
|
|
{
|
|
if (s_noiseCache != null)
|
|
{
|
|
s_noiseCache.Release();
|
|
s_noiseCache = null;
|
|
}
|
|
s_noiseCache = new RenderTexture(NoiseCacheDimensionInts[0], NoiseCacheDimensionInts[1], 0, RenderTextureFormat.RFloat);
|
|
s_noiseCache.dimension = TextureDimension.Tex3D;
|
|
s_noiseCache.volumeDepth = NoiseCacheDimensionInts[2];
|
|
s_noiseCache.enableRandomWrite = true;
|
|
s_noiseCache.Create();
|
|
ComputeManager.SetTexture(Const.NoiseCache, s_noiseCache);
|
|
//ComputeManager.SetTexture(Const.NoiseCache, ResourcesUtil.NoiseTexture);
|
|
ComputeManager.SetInts(Const.NoiseCacheDimension, NoiseCacheDimensionInts);
|
|
ComputeManager.SetFloat(Const.NoiseCacheDensity, NoiseCacheDensity);
|
|
ComputeManager.SetFloats(Const.NoiseCachePeriod, NoiseCachePeriod);
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeNoiseCache,
|
|
Const.Kernel.GenerateNoiseCache,
|
|
(s_noiseCache.width + ThreadGroupExtent - 1) / ThreadGroupExtent,
|
|
(s_noiseCache.height + ThreadGroupExtent - 1) / ThreadGroupExtent,
|
|
(s_noiseCache.volumeDepth + ThreadGroupExtent - 1) / ThreadGroupExtent
|
|
);
|
|
ComputeManager.Deactivate(s_computeNoiseCache);
|
|
} // end: generate noise cache
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool ValidateGlobalResources()
|
|
{
|
|
Profiler.BeginSample("ValidateGlobalResources");
|
|
|
|
if (!ValidateComputeShaders())
|
|
return false;
|
|
|
|
if (s_triTableBuffer == null)
|
|
{
|
|
s_triTableBuffer = new ComputeBuffer(16 * 256, sizeof(int));
|
|
s_triTableBuffer.SetData(MarchingCubes.TriTable);
|
|
ComputeManager.SetBuffer(Const.TriTable, s_triTableBuffer);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (s_vertTableBuffer == null)
|
|
{
|
|
s_vertTableBuffer = new ComputeBuffer(2 * 12, sizeof(int));
|
|
s_vertTableBuffer.SetData(MarchingCubes.VertTable);
|
|
ComputeManager.SetBuffer(Const.VertTable, s_vertTableBuffer);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (s_triTable2dBuffer == null)
|
|
{
|
|
s_triTable2dBuffer = new ComputeBuffer(12 * 16, sizeof(int));
|
|
s_triTable2dBuffer.SetData(MarchingCubes.TriTable2d);
|
|
ComputeManager.SetBuffer(Const.TriTable2d, s_triTable2dBuffer);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (AllowSharedRWBuffers)
|
|
{
|
|
if (s_brushesBuffer == null)
|
|
{
|
|
s_brushesBuffer = new ComputeBuffer(MaxBrushes, SdfBrush.Stride);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (s_brushMaterialBuffer == null)
|
|
{
|
|
s_brushMaterialBuffer = new ComputeBuffer(MaxBrushes, SdfBrushMaterial.Stride);
|
|
m_needsCompute = true;
|
|
}
|
|
}
|
|
|
|
if (s_dummyBuffer == null)
|
|
{
|
|
s_dummyBuffer = new ComputeBuffer(4, sizeof(int));
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
|
|
s_globalResourcesValid = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
protected virtual bool ValidateLocalResources()
|
|
{
|
|
Profiler.BeginSample("ValidateLocalResources (Renderer Base)");
|
|
|
|
if (AllowSharedRWBuffers)
|
|
{
|
|
if (m_brushesBuffer != null
|
|
&& m_brushesBuffer != s_brushesBuffer)
|
|
{
|
|
//m_brushesBuffer.Release();
|
|
Janitor.Dispose(m_brushesBuffer);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (m_brushMaterialBuffer != null
|
|
&& m_brushMaterialBuffer != s_brushMaterialBuffer)
|
|
{
|
|
//m_brushMaterialBuffer.Release();
|
|
Janitor.Dispose(m_brushMaterialBuffer);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (m_aabbTreeBuffer != null
|
|
&& m_aabbTreeBuffer != s_aabbTreeBuffer)
|
|
{
|
|
//m_aabbTreeBuffer.Release();
|
|
Janitor.Dispose(m_aabbTreeBuffer);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
m_brushesBuffer = s_brushesBuffer;
|
|
m_brushMaterialBuffer = s_brushMaterialBuffer;
|
|
m_aabbTreeBuffer = s_aabbTreeBuffer;
|
|
}
|
|
else
|
|
{
|
|
if (m_brushesBuffer == null
|
|
|| m_brushesBuffer == s_brushesBuffer)
|
|
{
|
|
m_brushesBuffer = new ComputeBuffer(MaxBrushes, SdfBrush.Stride);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (m_brushMaterialBuffer == null
|
|
|| m_brushMaterialBuffer == s_brushMaterialBuffer)
|
|
{
|
|
m_brushMaterialBuffer = new ComputeBuffer(MaxBrushes, SdfBrushMaterial.Stride);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (m_aabbTreeBuffer == s_aabbTreeBuffer)
|
|
{
|
|
m_aabbTreeBuffer = null;
|
|
}
|
|
}
|
|
|
|
if (m_nodeHashTableBuffer == null
|
|
|| m_nodeHashTableBuffer.count != NodeHashTableSize)
|
|
{
|
|
if (m_nodeHashTableBuffer != null)
|
|
{
|
|
//m_nodeHashTableBuffer.Release();
|
|
Janitor.Dispose(m_nodeHashTableBuffer);
|
|
}
|
|
|
|
m_nodeHashTableBuffer = new ComputeBuffer(NodeHashTableSize, VoxelHashEntry.Stride);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (m_nodePoolBuffer == null
|
|
|| m_nodePoolBuffer.count != MaxVoxels)
|
|
{
|
|
if (m_nodePoolBuffer != null)
|
|
{
|
|
//m_nodePoolBuffer.Release();
|
|
Janitor.Dispose(m_nodePoolBuffer);
|
|
}
|
|
|
|
m_nodePoolBuffer = new ComputeBuffer(MaxVoxels, VoxelNode.Stride);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
int voxelCacheSize = MaxVoxels * 2;
|
|
if (UseVoxelCache)
|
|
{
|
|
if (m_voxelCacheIdTableBuffer == null
|
|
|| m_voxelCacheIdTableBuffer.count != voxelCacheSize)
|
|
{
|
|
if (m_voxelCacheIdTableBuffer != null)
|
|
{
|
|
//m_voxelCacheIdTableBuffer.Release();
|
|
//m_voxelCacheBuffer.Release();
|
|
Janitor.Dispose(m_voxelCacheIdTableBuffer);
|
|
Janitor.Dispose(m_voxelCacheBuffer);
|
|
}
|
|
|
|
m_voxelCacheIdTableBuffer = new ComputeBuffer(voxelCacheSize, sizeof(int));
|
|
m_voxelCacheBuffer = new ComputeBuffer(voxelCacheSize, 4 * sizeof(float));
|
|
m_needsCompute = true;
|
|
}
|
|
}
|
|
else if (m_voxelCacheBuffer != null)
|
|
{
|
|
//m_voxelCacheIdTableBuffer.Release();
|
|
//m_voxelCacheBuffer.Release();
|
|
Janitor.Dispose(m_voxelCacheIdTableBuffer);
|
|
Janitor.Dispose(m_voxelCacheBuffer);
|
|
|
|
m_voxelCacheIdTableBuffer = null;
|
|
m_voxelCacheBuffer = null;
|
|
}
|
|
|
|
if (m_brushMaskPoolBuffer == null
|
|
|| m_brushMaskPoolBuffer.count != MaxBrushMasks * MaxBrushMaskInts)
|
|
{
|
|
if (m_brushMaskPoolBuffer != null)
|
|
{
|
|
//m_brushMaskPoolBuffer.Release();
|
|
Janitor.Dispose(m_brushMaskPoolBuffer);
|
|
}
|
|
|
|
m_brushMaskPoolBuffer = new ComputeBuffer(MaxBrushMasks * MaxBrushMaskInts, sizeof(int));
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
int maxGenPoints = MaxGenPoints;
|
|
if (m_genPointsBufferDefault == null
|
|
|| m_genPointsBufferDefault.count != maxGenPoints)
|
|
{
|
|
if (m_genPointsBufferDefault != null)
|
|
{
|
|
//m_numNodesAllocatedBuffer.Release();
|
|
//m_numAllocationsBuffer.Release();
|
|
//m_indirectDispatchArgsBuffer.Release();
|
|
//m_genPointsBufferDefault.Release();
|
|
//m_indirectDrawArgsBufferDefault.Release();
|
|
Janitor.Dispose(m_numNodesAllocatedBuffer);
|
|
Janitor.Dispose(m_numAllocationsBuffer);
|
|
Janitor.Dispose(m_indirectDispatchArgsBuffer);
|
|
Janitor.Dispose(m_genPointsBufferDefault);
|
|
Janitor.Dispose(m_indirectDrawArgsBufferDefault);
|
|
}
|
|
|
|
m_numNodesAllocatedBuffer = new ComputeBuffer(VoxelNodeDepth + 2, sizeof(int));
|
|
m_numAllocationsBuffer = new ComputeBuffer(4, sizeof(int));
|
|
m_indirectDispatchArgsBuffer = new ComputeBuffer(3, sizeof(int), ComputeBufferType.IndirectArguments);
|
|
m_genPointsBufferDefault = new ComputeBuffer(maxGenPoints, GenPoint.Stride);
|
|
m_indirectDrawArgsBufferDefault = new ComputeBuffer(5, sizeof(int), ComputeBufferType.IndirectArguments);
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
if (m_autoSmoothVertDataTableBuffer != null
|
|
&& m_autoSmoothVertDataTableBuffer.count != AutoSmoothVertDataTableSize)
|
|
{
|
|
//m_autoSmoothVertDataTableBuffer.Release();
|
|
Janitor.Dispose(m_autoSmoothVertDataTableBuffer);
|
|
m_autoSmoothVertDataTableBuffer = null;
|
|
}
|
|
|
|
if (m_autoSmoothVertDataTableBuffer == null)
|
|
{
|
|
m_autoSmoothVertDataTableBuffer = new ComputeBuffer(AutoSmoothVertDataTableSize, AutoSmoothVertData.Stride);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_autoSmoothVertDataTableBuffer != null)
|
|
{
|
|
//m_autoSmoothVertDataTableBuffer.Release();
|
|
Janitor.Dispose(m_autoSmoothVertDataTableBuffer);
|
|
m_autoSmoothVertDataTableBuffer = null;
|
|
}
|
|
}
|
|
|
|
if (m_usedSharedMaterial != SharedMaterial)
|
|
{
|
|
m_usedSharedMaterial = SharedMaterial;
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
|
|
m_localResourcesValid = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
protected static void DisposeGlobalResources()
|
|
{
|
|
s_globalResourcesValid = false;
|
|
|
|
s_computeVoxelGen = null;
|
|
|
|
if (s_triTableBuffer != null)
|
|
{
|
|
//s_triTableBuffer.Release();
|
|
Janitor.Dispose(s_triTableBuffer);
|
|
s_triTableBuffer = null;
|
|
}
|
|
|
|
if (s_vertTableBuffer != null)
|
|
{
|
|
//s_vertTableBuffer.Release();
|
|
Janitor.Dispose(s_vertTableBuffer);
|
|
s_vertTableBuffer = null;
|
|
}
|
|
|
|
if (s_triTable2dBuffer != null)
|
|
{
|
|
//s_triTable2dBuffer.Release();
|
|
Janitor.Dispose(s_triTable2dBuffer);
|
|
s_triTable2dBuffer = null;
|
|
}
|
|
|
|
if (s_brushesBuffer != null)
|
|
{
|
|
//s_brushesBuffer.Release();
|
|
Janitor.Dispose(s_brushesBuffer);
|
|
s_brushesBuffer = null;
|
|
}
|
|
|
|
if (s_brushMaterialBuffer != null)
|
|
{
|
|
//s_brushMaterialBuffer.Release();
|
|
Janitor.Dispose(s_brushMaterialBuffer);
|
|
s_brushMaterialBuffer = null;
|
|
}
|
|
|
|
if (s_aabbTreeBuffer != null)
|
|
{
|
|
//s_aabbTreeBuffer.Release();
|
|
Janitor.Dispose(s_aabbTreeBuffer);
|
|
s_aabbTreeBuffer = null;
|
|
}
|
|
|
|
if (s_dummyBuffer != null)
|
|
{
|
|
//s_dummyBuffer.Release();
|
|
Janitor.Dispose(s_dummyBuffer);
|
|
s_dummyBuffer = null;
|
|
}
|
|
|
|
if (s_numAllocatoinsBufferInitData.IsCreated)
|
|
s_numAllocatoinsBufferInitData.Dispose();
|
|
|
|
if (s_unitIndirectDispatchArgsInitData.IsCreated)
|
|
s_unitIndirectDispatchArgsInitData.Dispose();
|
|
}
|
|
|
|
protected void DisposeLocalResources()
|
|
{
|
|
m_localResourcesValid = false;
|
|
|
|
if (m_brushesBuffer != null
|
|
&& m_brushesBuffer != s_brushesBuffer)
|
|
{
|
|
//m_brushesBuffer.Release();
|
|
Janitor.Dispose(m_brushesBuffer);
|
|
m_brushesBuffer = null;
|
|
}
|
|
|
|
if (m_brushMaterialBuffer != null
|
|
&& m_brushMaterialBuffer != s_brushMaterialBuffer)
|
|
{
|
|
//m_brushMaterialBuffer.Release();
|
|
Janitor.Dispose(m_brushMaterialBuffer);
|
|
m_brushMaterialBuffer = null;
|
|
}
|
|
|
|
if (m_aabbTreeBuffer != null
|
|
&& m_aabbTreeBuffer != s_aabbTreeBuffer)
|
|
{
|
|
//m_aabbTreeBuffer.Release();
|
|
Janitor.Dispose(m_aabbTreeBuffer);
|
|
m_aabbTreeBuffer = null;
|
|
}
|
|
|
|
if (m_nodeHashTableBuffer != null)
|
|
{
|
|
//m_nodeHashTableBuffer.Release();
|
|
Janitor.Dispose(m_nodeHashTableBuffer);
|
|
m_nodeHashTableBuffer = null;
|
|
}
|
|
|
|
if (m_nodePoolBuffer != null)
|
|
{
|
|
//m_nodePoolBuffer.Release();
|
|
Janitor.Dispose(m_nodePoolBuffer);
|
|
m_nodePoolBuffer = null;
|
|
}
|
|
|
|
if (m_voxelCacheIdTableBuffer != null)
|
|
{
|
|
//m_voxelCacheIdTableBuffer.Release();
|
|
//m_voxelCacheBuffer.Release();
|
|
Janitor.Dispose(m_voxelCacheIdTableBuffer);
|
|
Janitor.Dispose(m_voxelCacheBuffer);
|
|
|
|
m_voxelCacheIdTableBuffer = null;
|
|
m_voxelCacheBuffer = null;
|
|
}
|
|
|
|
if (m_brushMaskPoolBuffer != null)
|
|
{
|
|
//m_brushMaskPoolBuffer.Release();
|
|
Janitor.Dispose(m_brushMaskPoolBuffer);
|
|
m_brushMaskPoolBuffer = null;
|
|
}
|
|
|
|
if (m_genPointsBufferDefault != null)
|
|
{
|
|
//m_numNodesAllocatedBuffer.Release();
|
|
//m_numAllocationsBuffer.Release();
|
|
//m_indirectDispatchArgsBuffer.Release();
|
|
//m_genPointsBufferDefault.Release();
|
|
//m_indirectDrawArgsBufferDefault.Release();
|
|
Janitor.Dispose(m_numNodesAllocatedBuffer);
|
|
Janitor.Dispose(m_numAllocationsBuffer);
|
|
Janitor.Dispose(m_indirectDispatchArgsBuffer);
|
|
Janitor.Dispose(m_genPointsBufferDefault);
|
|
Janitor.Dispose(m_indirectDrawArgsBufferDefault);
|
|
|
|
m_numNodesAllocatedBuffer = null;
|
|
m_numAllocationsBuffer = null;
|
|
m_indirectDispatchArgsBuffer = null;
|
|
m_genPointsBufferDefault = null;
|
|
m_indirectDrawArgsBufferDefault = null;
|
|
}
|
|
|
|
if (m_autoSmoothVertDataTableBuffer != null)
|
|
{
|
|
//m_autoSmoothVertDataTableBuffer.Release();
|
|
Janitor.Dispose(m_autoSmoothVertDataTableBuffer);
|
|
m_autoSmoothVertDataTableBuffer = null;
|
|
}
|
|
|
|
m_materialCloned = null;
|
|
m_materialUsed = null;
|
|
|
|
if (m_pendingMeshTable != null)
|
|
{
|
|
foreach (var pair in m_pendingMeshTable)
|
|
pair.Value.Dispose();
|
|
m_pendingMeshTable.Clear();
|
|
}
|
|
|
|
if (m_indirectDrawArgsInitData.IsCreated)
|
|
m_indirectDrawArgsInitData.Dispose();
|
|
}
|
|
|
|
#endregion // end: Resources
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Brushes
|
|
|
|
private static readonly string MaxBrushWarningMessage =
|
|
$"Maximum of {MaxBrushes} compute brushes per renderer exceeded (some brushes can count as more than one compute brushes).\n"
|
|
+ "You may try bumping the maximum compute brushes by following the instructions in comments above where MudRendererBase.MaxBrushes is declared, but beware of performance.";
|
|
|
|
public void AddBrush(MudBrushBase brush)
|
|
{
|
|
if (brush.m_renderer != null)
|
|
brush.m_renderer.RemoveBrush(brush);
|
|
|
|
brush.m_renderer = this;
|
|
|
|
ValidateAabbTree();
|
|
brush.UpdateProxies(m_aabbTree, brush.BoundsRs);
|
|
m_aabbTreeDirty = true;
|
|
|
|
m_aBrush.Add(brush);
|
|
m_aBrushToProcess.Add(brush);
|
|
|
|
s_brushMap[brush.GetFloatHash()] = brush;
|
|
|
|
Assert.True(m_aBrushToProcess.Count <= MaxBrushes, MaxBrushWarningMessage);
|
|
|
|
RescanBrushes();
|
|
}
|
|
|
|
public void RemoveBrush(MudBrushBase brush)
|
|
{
|
|
#if MUDBUN_DEV
|
|
Assert.True(brush.m_renderer != null, "Brush was never added.");
|
|
Assert.True(brush.m_renderer == this, "Brush was not added to this renderer.");
|
|
#endif
|
|
|
|
ValidateAabbTree();
|
|
brush.DestroyProxies(m_aabbTree);
|
|
m_aabbTreeDirty = true;
|
|
|
|
brush.m_renderer = null;
|
|
|
|
m_aBrush.Remove(brush);
|
|
m_aBrushToProcess.Remove(brush);
|
|
if (brush.IsBrushGroup)
|
|
m_aBrushToProcess.Remove(brush);
|
|
|
|
s_brushMap.Remove(brush.GetFloatHash());
|
|
|
|
RescanBrushes();
|
|
}
|
|
|
|
public void DestroyAllBrushes()
|
|
{
|
|
var aBrushCopy = Brushes.ToArray();
|
|
foreach (var b in aBrushCopy)
|
|
{
|
|
var m = b.GetComponent<MudMaterialBase>();
|
|
Destroy(b);
|
|
Destroy(m);
|
|
}
|
|
}
|
|
|
|
public void DestroyAllBrushesImmediate()
|
|
{
|
|
var aBrushCopy = Brushes.ToArray();
|
|
foreach (var b in aBrushCopy)
|
|
{
|
|
var m = b.GetComponent<MudMaterialBase>();
|
|
DestroyImmediate(b);
|
|
DestroyImmediate(m);
|
|
}
|
|
}
|
|
|
|
public virtual void NotifyHierarchyChange()
|
|
{
|
|
RescanBrushes();
|
|
}
|
|
|
|
private void ClearBrushes()
|
|
{
|
|
ValidateAabbTree();
|
|
foreach (var brush in m_aBrush)
|
|
{
|
|
brush.m_renderer = null;
|
|
brush.DestroyProxies(m_aabbTree);
|
|
}
|
|
|
|
m_aBrush.Clear();
|
|
m_aBrushToProcess.Clear();
|
|
|
|
RescanBrushes();
|
|
}
|
|
|
|
public void RescanBrushes()
|
|
{
|
|
m_needRescanBrushes = true;
|
|
}
|
|
|
|
public void RescanBrushesImmediate()
|
|
{
|
|
ClearBrushes();
|
|
ScanHierarchyRecursive(transform);
|
|
ValidateBrushSetHash();
|
|
}
|
|
|
|
private int ComputeBrushListHash()
|
|
{
|
|
int hash = 0;
|
|
for (int iBrush = 0, numBrushes = m_aBrushToProcess.Count; iBrush < numBrushes; ++iBrush)
|
|
{
|
|
var brush = m_aBrushToProcess[iBrush];
|
|
hash = Codec.HashConcat(hash, brush.GetInstanceID());
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
private int m_brushSetHash = -1;
|
|
private void ValidateBrushSetHash()
|
|
{
|
|
int brushListHash = ComputeBrushListHash();
|
|
if (brushListHash != m_brushSetHash)
|
|
{
|
|
MarkNeedsCompute();
|
|
m_brushSetHash = brushListHash;
|
|
m_brushDataDirty = true;
|
|
}
|
|
}
|
|
|
|
private int m_brushGroupDepth = 0;
|
|
private void ScanHierarchyRecursive(Transform parent)
|
|
{
|
|
if (parent == null)
|
|
return;
|
|
|
|
parent.TryGetComponent(out MudBrushBase parentBrush);
|
|
bool parentIsGroup = (parentBrush != null && parentBrush.IsBrushGroup && parentBrush.isActiveAndEnabled);
|
|
if (parentIsGroup)
|
|
{
|
|
++m_brushGroupDepth;
|
|
if (m_brushGroupDepth >= MaxBrushGroupDepth)
|
|
Assert.Warn($"MudBun: Exceeded maximum group depth of {MaxBrushGroupDepth}!");
|
|
}
|
|
|
|
for (int iChild = 0; iChild < parent.childCount; ++iChild)
|
|
{
|
|
var child = parent.GetChild(iChild);
|
|
|
|
// renderer blocks recursion
|
|
if (child.TryGetComponent(out MudRendererBase _))
|
|
continue;
|
|
|
|
if (child.TryGetComponent(out MudBrushBase brush) && brush.isActiveAndEnabled)
|
|
AddBrush(brush);
|
|
|
|
ScanHierarchyRecursive(child);
|
|
}
|
|
|
|
if (parentIsGroup)
|
|
{
|
|
m_aBrushToProcess.Add(parentBrush);
|
|
--m_brushGroupDepth;
|
|
}
|
|
}
|
|
|
|
private void SetUpResources()
|
|
{
|
|
Profiler.BeginSample("SetUpResources");
|
|
|
|
WriteResources();
|
|
BindComputeResources();
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
private void UpdateActivePreCompute()
|
|
{
|
|
if (m_doRigging)
|
|
ComputeManager.Activate(s_computeMeshLock);
|
|
else
|
|
ComputeManager.Deactivate(s_computeMeshLock);
|
|
|
|
switch (MeshingMode)
|
|
{
|
|
case MeshingModeEnum.MarchingCubes:
|
|
ComputeManager.Activate(s_computeMarchingCubes);
|
|
ComputeManager.Deactivate(s_computeDualMeshing);
|
|
ComputeManager.Deactivate(s_computeSurfaceNets);
|
|
ComputeManager.Deactivate(s_computeDualContouring);
|
|
break;
|
|
|
|
case MeshingModeEnum.DualQuads:
|
|
ComputeManager.Activate(s_computeDualMeshing);
|
|
ComputeManager.Deactivate(s_computeMarchingCubes);
|
|
ComputeManager.Deactivate(s_computeSurfaceNets);
|
|
ComputeManager.Deactivate(s_computeDualContouring);
|
|
break;
|
|
|
|
case MeshingModeEnum.SurfaceNets:
|
|
ComputeManager.Activate(s_computeDualMeshing);
|
|
ComputeManager.Activate(s_computeSurfaceNets);
|
|
ComputeManager.Deactivate(s_computeMarchingCubes);
|
|
ComputeManager.Deactivate(s_computeDualContouring);
|
|
break;
|
|
|
|
case MeshingModeEnum.DualContouring:
|
|
ComputeManager.Activate(s_computeDualMeshing);
|
|
ComputeManager.Activate(s_computeDualContouring);
|
|
ComputeManager.Deactivate(s_computeMarchingCubes);
|
|
ComputeManager.Deactivate(s_computeSurfaceNets);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
if (RenderModeCategory == RenderModeCategoryEnum.RayTracedVoxels)
|
|
ComputeManager.Activate(s_computeRayTracedVoxels);
|
|
else
|
|
*/
|
|
ComputeManager.Deactivate(s_computeRayTracedVoxels);
|
|
}
|
|
|
|
private void UpdateActivePostCompute()
|
|
{
|
|
if (m_doRigging)
|
|
ComputeManager.Deactivate(s_computeMeshLock);
|
|
}
|
|
|
|
private bool ValidateAabbTreeBuffer(ref ComputeBuffer aabbTreeBuffer)
|
|
{
|
|
if (m_aabbTreeBuffer != null
|
|
&& m_aabbTreeBuffer.count >= m_aabbTree.Capacity)
|
|
return false;
|
|
|
|
if (aabbTreeBuffer != null)
|
|
aabbTreeBuffer.Release();
|
|
|
|
aabbTreeBuffer = new ComputeBuffer(m_aabbTree.Capacity, AabbTree<MudBrushBase>.NodePod.Stride);
|
|
|
|
return true;
|
|
}
|
|
|
|
private void ValidateRenderMaterial()
|
|
{
|
|
Material material = null;
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Mesh:
|
|
material = RenderMaterialMesh;
|
|
break;
|
|
|
|
case RenderModeCategoryEnum.Splats:
|
|
material = RenderMaterialSplats;
|
|
break;
|
|
|
|
case RenderModeCategoryEnum.Decal:
|
|
material = RenderMaterialDecal;
|
|
break;
|
|
|
|
/*
|
|
case RenderModeCategoryEnum.RayMarchedSurface:
|
|
material = RenderMaterialRayMarchedSurface;
|
|
break;
|
|
|
|
case RenderModeCategoryEnum.RayTracedVoxels:
|
|
material = RenderMaterialRayTracedVoxels;
|
|
break;
|
|
*/
|
|
}
|
|
|
|
{
|
|
Profiler.BeginSample("Copy Render Material Properties");
|
|
|
|
if (m_materialCloned != material)
|
|
{
|
|
m_materialUsed = new Material(material);
|
|
m_materialCloned = material;
|
|
|
|
if (!Application.isEditor)
|
|
{
|
|
m_renderMaterialDirty = true;
|
|
}
|
|
}
|
|
|
|
if (Application.isEditor)
|
|
{
|
|
// need to do this constantly in editor because the user can change the referenced material
|
|
// TODO: timeslice this when in play mode
|
|
m_renderMaterialDirty = true;
|
|
}
|
|
|
|
if (RenderMaterialMode == RenderMaterialModeEnum.Dynamic)
|
|
{
|
|
m_renderMaterialDirty = true;
|
|
}
|
|
|
|
if (m_renderMaterialDirty)
|
|
{
|
|
m_materialUsed.CopyPropertiesFromMaterial(m_materialCloned);
|
|
m_materialUsed.enableInstancing = true;
|
|
|
|
m_renderMaterialDirty = false;
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
m_materialUsed.EnableKeyword("MUDBUN_PROCEDURAL");
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.QuadSplats:
|
|
m_materialUsed.EnableKeyword("MUDBUN_QUAD_SPLATS");
|
|
break;
|
|
default:
|
|
m_materialUsed.DisableKeyword("MUDBUN_QUAD_SPLATS");
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected virtual bool ShouldHighlightBrushFromSelection(MudBrushBase brush)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private void UpdateBrushData()
|
|
{
|
|
if (!m_brushDataDirty && !m_doRigging)
|
|
return;
|
|
|
|
// need to complete queued jobs before writing to native arrays again
|
|
for (int i = 0; i < m_jobCompleteQueue.Count; ++i)
|
|
{
|
|
m_jobCompleteQueue[i].Complete();
|
|
}
|
|
m_jobCompleteQueue.Clear();
|
|
|
|
Profiler.BeginSample("UpdateBrushData");
|
|
|
|
m_numSdfBrushes = 0;
|
|
m_numSdfMaterials = 0;
|
|
m_sdfBrushMaterialIndexMap.Clear();
|
|
m_aBone = (m_doRigging ? new List<Transform>() : null);
|
|
for (int iBrush = 0, numBrushes = m_aBrushToProcess.Count; iBrush < numBrushes; ++iBrush)
|
|
{
|
|
var brush = m_aBrushToProcess[iBrush];
|
|
|
|
Profiler.BeginSample("Each Brush");
|
|
|
|
brush.m_iSdfBrush = m_numSdfBrushes;
|
|
|
|
Profiler.BeginSample("Fill Material");
|
|
int materialIndex = -1;
|
|
bool selectionHighlight = ShouldHighlightBrushFromSelection(brush);
|
|
/*
|
|
if (selectionHighlight)
|
|
{
|
|
materialIndex = m_numSdfMaterials;
|
|
m_sdfBrushMaterialIndexMap[0] = materialIndex;
|
|
var mat = m_aSdfBrushMaterial[m_numSdfMaterials];
|
|
brush.FillBrushMaterialData(ref mat);
|
|
var color = mat.Color;
|
|
color.r = Mathf.Min(1.0f, color.r + 0.1f);
|
|
color.g = Mathf.Min(1.0f, color.g + 0.1f);
|
|
color.b = Mathf.Min(1.0f, color.b + 0.1f);
|
|
mat.Color = color;
|
|
var emissionHash = mat.EmissionHash;
|
|
emissionHash.r = Mathf.Min(1.0f, emissionHash.r + 0.1f);
|
|
emissionHash.g = Mathf.Min(1.0f, emissionHash.g + 0.1f);
|
|
emissionHash.b = Mathf.Min(1.0f, emissionHash.b + 0.1f);
|
|
mat.EmissionHash = emissionHash;
|
|
m_aSdfBrushMaterial[m_numSdfMaterials] = mat;
|
|
++m_numSdfMaterials;
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
if (brush.UsesMaterial
|
|
&& !m_sdfBrushMaterialIndexMap.TryGetValue(brush.MaterialHash, out materialIndex))
|
|
{
|
|
materialIndex = m_numSdfMaterials;
|
|
m_sdfBrushMaterialIndexMap.Add(brush.MaterialHash, materialIndex);
|
|
var mat = m_aSdfBrushMaterial[m_numSdfMaterials];
|
|
brush.FillBrushMaterialData(ref mat);
|
|
m_aSdfBrushMaterial[m_numSdfMaterials] = mat;
|
|
++m_numSdfMaterials;
|
|
}
|
|
}
|
|
#if MUDBUN_DEV
|
|
Assert.True(!brush.UsesMaterial || materialIndex >= 0);
|
|
#endif
|
|
Profiler.EndSample();
|
|
|
|
Profiler.BeginSample("Fill Compute Data");
|
|
int numNewBrushes =
|
|
(!brush.IsBrushGroup || !brush.m_preChildrenFlag)
|
|
? brush.FillComputeData(m_aSdfBrush, m_numSdfBrushes, (brush.CountAsBone ? m_aBone : null))
|
|
: brush.FillComputeDataPostChildren(m_aSdfBrush, m_numSdfBrushes);
|
|
Profiler.EndSample();
|
|
|
|
Profiler.BeginSample("Fill Brush Data");
|
|
float hash = brush.GetFloatHash();
|
|
for (int iNewBrush = 0; iNewBrush < numNewBrushes; ++iNewBrush)
|
|
{
|
|
int iSdfBrush = m_numSdfBrushes + iNewBrush;
|
|
var b = m_aSdfBrush[iSdfBrush];
|
|
b.Index = iSdfBrush;
|
|
|
|
if (!brush.IsBrushGroup || !brush.m_preChildrenFlag)
|
|
brush.FillBrushData(ref b, iSdfBrush);
|
|
else
|
|
brush.FillBrushDataPostChildren(ref b, iSdfBrush);
|
|
|
|
b.MaterialIndex = materialIndex;
|
|
b.Hash =
|
|
selectionHighlight
|
|
? -hash // encode selection highlight in negative hash sign
|
|
: hash;
|
|
|
|
m_aSdfBrush[iSdfBrush] = b;
|
|
}
|
|
Profiler.EndSample();
|
|
|
|
m_numSdfBrushes += numNewBrushes;
|
|
|
|
if (brush.IsBrushGroup)
|
|
brush.m_preChildrenFlag = !brush.m_preChildrenFlag;
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
m_brushDataDirty = false;
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
private void UpdateAabbTreeData()
|
|
{
|
|
if (!m_aabbTreeDirty)
|
|
return;
|
|
|
|
Profiler.BeginSample("UpdateAabbTree");
|
|
|
|
Aabb successorModifierBounds = Aabb.Empty;
|
|
Aabb accumulatedBounds = Aabb.Empty;
|
|
Aabb groupBounds = Aabb.Empty;
|
|
var groupSymmetry = MudSolid.SymmetryMode.None;
|
|
foreach (var brush in m_aBrushToProcess)
|
|
{
|
|
Aabb opBounds = brush.BoundsRs;
|
|
|
|
if (brush.IsBrushGroup)
|
|
{
|
|
if (!brush.m_preChildrenFlag)
|
|
{
|
|
// begin group
|
|
m_brushGroupBoundsStack.Push(groupBounds);
|
|
m_accumulatedBoundsStack.Push(accumulatedBounds);
|
|
m_brushGroupSymmetryStack.Push(groupSymmetry);
|
|
groupBounds = Aabb.Empty;
|
|
accumulatedBounds = Aabb.Empty;
|
|
groupSymmetry = ((MudBrushGroup) brush).Symmetry;
|
|
}
|
|
else
|
|
{
|
|
// end group
|
|
opBounds = groupBounds;
|
|
opBounds.Expand(m_aabbTree.FatBoundsRadius);
|
|
groupBounds = m_brushGroupBoundsStack.Pop();
|
|
accumulatedBounds = m_accumulatedBoundsStack.Pop();
|
|
groupSymmetry = m_brushGroupSymmetryStack.Pop();
|
|
}
|
|
brush.m_preChildrenFlag = !brush.m_preChildrenFlag;
|
|
}
|
|
|
|
if (groupSymmetry != MudSolid.SymmetryMode.None)
|
|
opBounds = MudSolid.SymmetryBounds(groupSymmetry, opBounds);
|
|
|
|
if (opBounds.IsEmpty)
|
|
{
|
|
if (brush.IsBrushGroup)
|
|
brush.UpdateProxies(m_aabbTree, opBounds);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (brush.IsSuccessorModifier)
|
|
successorModifierBounds.Include(opBounds);
|
|
|
|
opBounds.Include(successorModifierBounds);
|
|
|
|
accumulatedBounds.Include(opBounds);
|
|
groupBounds.Include(opBounds);
|
|
|
|
if (brush.ShouldUseAccumulatedBounds)
|
|
opBounds = accumulatedBounds;
|
|
|
|
opBounds.Expand(brush.BoundsRsPadding);
|
|
accumulatedBounds.Include(opBounds);
|
|
groupBounds.Include(opBounds);
|
|
|
|
brush.UpdateProxies(m_aabbTree, opBounds);
|
|
}
|
|
|
|
m_aabbTree.UpdatePods();
|
|
|
|
m_aabbTreeDirty = false;
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
protected int m_numSdfBrushes;
|
|
protected int m_numSdfMaterials;
|
|
protected List<Transform> m_aBone;
|
|
private Stack<Aabb> m_brushGroupBoundsStack = new Stack<Aabb>();
|
|
private Stack<Aabb> m_accumulatedBoundsStack = new Stack<Aabb>();
|
|
private Stack<MudSolid.SymmetryMode> m_brushGroupSymmetryStack = new Stack<MudSolid.SymmetryMode>();
|
|
private void WriteResources()
|
|
{
|
|
Profiler.BeginSample("WriteResources");
|
|
|
|
|
|
Profiler.BeginSample("Brushes");
|
|
|
|
if (m_materialUsed == null)
|
|
ValidateRenderMaterial();
|
|
|
|
float effectiveSurfaceShift = SurfaceShift + 1e-5f; // tiny offset to fix voxel edges perfectly lining up with zero isosurface
|
|
if (RenderModeCategory == RenderModeCategoryEnum.Decal)
|
|
effectiveSurfaceShift += 0.5f * VoxelSize;
|
|
|
|
Profiler.BeginSample("Set Brush Data");
|
|
m_brushesBuffer.SetData(m_aSdfBrush, 0, 0, m_numSdfBrushes);
|
|
Profiler.EndSample();
|
|
Profiler.BeginSample("Set Material Data");
|
|
m_brushMaterialBuffer.SetData(m_aSdfBrushMaterial, 0, 0, m_numSdfMaterials);
|
|
Profiler.EndSample();
|
|
ComputeManager.SetInt(Const.NumBrushes, m_numSdfBrushes);
|
|
ComputeManager.SetFloat(Const.SurfaceShift, effectiveSurfaceShift);
|
|
ComputeManager.SetInt(Const.RenderMode, (int) RenderMode);
|
|
ComputeManager.SetInt(Const.MeshingMode, (int) MeshingMode);
|
|
ComputeManager.SetInt(Const.RayTracedVoxelMode, (int) RayTracedVoxelMode);
|
|
ComputeManager.SetFloat(Const.RayTracedVoxelSizeMultiplier, RayTracedVoxelSizeMultiplier);
|
|
ComputeManager.SetInt(Const.RayTracedVoxelPaddingMode, (int) RayTracedVoxelPaddingMode);
|
|
ComputeManager.SetFloat(Const.RayTracedVoxelSmoothCubeNormal, RayTracedVoxelSmoothCubeNormal);
|
|
ComputeManager.SetFloat(Const.RayTracedVoxelRadius, 1.0f + 0.733f * RayTracedVoxelSphereFullness);
|
|
ComputeManager.SetInt(Const.RayTracedVoxelPaddingMode, (int) RayTracedVoxelPaddingMode);
|
|
ComputeManager.SetFloat(Const.RayTracedVoxelInternalPaddingDistance, RayTracedVoxelInternalPaddingDistance);
|
|
ComputeManager.SetFloat(Const.RayTracedVoxelSizeFadeDistance, RayTracedVoxelSizeFadeDistance);
|
|
ComputeManager.SetFloat(Const.NormalDifferentiationStep, NormalDifferentialStep);
|
|
ComputeManager.SetFloat(Const.NormalQuantization, NormalQuantization);
|
|
ComputeManager.SetFloat(Const.Normal2dFadeDist, Normal2dFade);
|
|
ComputeManager.SetFloat(Const.Normal2dStrength, Normal2dStrength);
|
|
bool shouldDoAutoSmoothing = ShouldDoAutoSmoothing;
|
|
ComputeManager.SetBool(Const.EnableAutoSmooth, shouldDoAutoSmoothing);
|
|
ComputeManager.SetFloat(Const.AutoSmoothMaxAngle, AutoSmoothingMaxAngle * MathUtil.Deg2Rad);
|
|
ComputeManager.SetBuffer(Const.AutoSmoothVertDataTable, (shouldDoAutoSmoothing && m_autoSmoothVertDataTableBuffer != null) ? m_autoSmoothVertDataTableBuffer : s_dummyBuffer);
|
|
ComputeManager.SetInt(Const.AutoSmoothVertDataPoolSize, (shouldDoAutoSmoothing && m_autoSmoothVertDataTableBuffer != null) ? m_autoSmoothVertDataTableBuffer.count : 0);
|
|
ComputeManager.SetBool(Const.EnableSmoothCorner, EnableSmoothCorner);
|
|
ComputeManager.SetInt(Const.SmoothCornerSubdivision, SmoothCornerSubdivision);
|
|
ComputeManager.SetFloat(Const.SmoothCornerNormalBlur, 0.05f * VoxelSize + SmoothCornerNormalBlur);
|
|
ComputeManager.SetFloat(Const.SmoothCornerFade, SmoothCornerFade);
|
|
ComputeManager.SetInt(Const.InvertNormals, (InvertNormals && !Enable2dMode ? 1 : 0));
|
|
|
|
Profiler.EndSample();
|
|
|
|
|
|
Profiler.BeginSample("BVH");
|
|
|
|
bool needComputeFromAabbTree = false;
|
|
if (AllowSharedRWBuffers)
|
|
{
|
|
needComputeFromAabbTree = ValidateAabbTreeBuffer(ref s_aabbTreeBuffer);
|
|
m_aabbTreeBuffer = s_aabbTreeBuffer;
|
|
}
|
|
else
|
|
{
|
|
needComputeFromAabbTree = ValidateAabbTreeBuffer(ref m_aabbTreeBuffer);
|
|
}
|
|
|
|
if (needComputeFromAabbTree)
|
|
{
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
m_aabbTree.FillComputeBuffer(m_aabbTreeBuffer);
|
|
m_aabbTreeBufferRoot = m_aabbTree.Root;
|
|
|
|
Profiler.EndSample();
|
|
|
|
|
|
Profiler.BeginSample("Voxel Tree");
|
|
|
|
ComputeManager.SetInt(Const.NodeHashTableSize, m_nodeHashTableBuffer.count);
|
|
|
|
// general allocation counters
|
|
m_numAllocationsBuffer.SetData(NumAllocatoinsBufferInitData);
|
|
|
|
// node pool
|
|
ComputeManager.SetInt(Const.NodePoolSize, m_nodePoolBuffer.count);
|
|
if (m_numAllocationsBufferInitData == null || m_numAllocationsBufferInitData.Length != m_numNodesAllocatedBuffer.count)
|
|
m_numAllocationsBufferInitData = new int[m_numNodesAllocatedBuffer.count];
|
|
for (int depth = 0; depth < m_numAllocationsBufferInitData.Length; ++depth)
|
|
m_numAllocationsBufferInitData[depth] = 0;
|
|
m_numNodesAllocatedBuffer.SetData(m_numAllocationsBufferInitData);
|
|
|
|
// voxel cache
|
|
ComputeManager.SetBool(Const.UseVoxelCache, UseVoxelCache);
|
|
ComputeManager.SetInt(Const.VoxelCacheSize, (m_voxelCacheBuffer != null ? m_voxelCacheBuffer.count : 0));
|
|
|
|
// brush bit masks
|
|
ComputeManager.SetInt(Const.BrushMaskPoolSize, MaxBrushMasks);
|
|
|
|
// dispatch args
|
|
m_indirectDispatchArgsBuffer.SetData(UnitIndirectDispatchArgsInitData);
|
|
|
|
Profiler.EndSample();
|
|
|
|
|
|
Profiler.BeginSample("Indirect Draw Args");
|
|
|
|
// indirect draw args
|
|
m_indirectDrawArgsBufferDefault.SetData(IndirectDrawArgsInitData);
|
|
if (m_indirectDrawArgsBufferOverride != null)
|
|
m_indirectDrawArgsBufferOverride.SetData(IndirectDrawArgsInitData);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.RenderMode);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NumBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodeHashTableSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodePoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.BrushMaskPoolSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.Brushes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.BrushMaterials);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.SurfaceShift);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AabbTree);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AabbRoot);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.Enable2dMode);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.ForceAllBrushes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodeHashTable);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NodePool);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NumNodesAllocated);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NumAllocations);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.BrushMaskPool);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.IndirectDispatchArgs);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.GenPoints);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.IndirectDrawArgs);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.VoxelSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.VoxelTreeBranchingFactorsCompressed);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.VoxelNodeSizes);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.MaxNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.ChunkVoxelDensity);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NoiseCache);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NoiseCacheDimension);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NoiseCacheDensity);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.CurrentNodeDepth);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.CurrentNodeBranchingFactor);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.CurrentNodeSize);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.NormalDifferentiationStep);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.EnableAutoSmooth);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AutoSmoothMaxAngle);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AutoSmoothVertDataTable);
|
|
ComputeManager.RegisterConstantId(s_computeVoxelGen, Const.AutoSmoothVertDataPoolSize);
|
|
|
|
Profiler.EndSample();
|
|
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
private void BindComputeResources()
|
|
{
|
|
Profiler.BeginSample("BindComputeResources");
|
|
|
|
m_genPointsBufferUsedForCompute = m_genPointsBufferOverride != null ? m_genPointsBufferOverride : m_genPointsBufferDefault;
|
|
m_indirectDrawArgsBufferUsedForCompute = m_indirectDrawArgsBufferOverride != null ? m_indirectDrawArgsBufferOverride : m_indirectDrawArgsBufferDefault;
|
|
|
|
ComputeManager.SetBuffer(Const.Brushes, m_brushesBuffer);
|
|
ComputeManager.SetBuffer(Const.BrushMaterials, m_brushMaterialBuffer);
|
|
|
|
ComputeManager.SetBuffer(Const.AabbTree, m_aabbTreeBuffer);
|
|
ComputeManager.SetInt(Const.AabbRoot, m_aabbTreeBufferRoot);
|
|
|
|
ComputeManager.SetBuffer(Const.NodeHashTable, m_nodeHashTableBuffer);
|
|
ComputeManager.SetBuffer(Const.NodePool, m_nodePoolBuffer);
|
|
ComputeManager.SetBuffer(Const.NumNodesAllocated, m_numNodesAllocatedBuffer);
|
|
ComputeManager.SetBuffer(Const.NumAllocations, m_numAllocationsBuffer);
|
|
ComputeManager.SetBuffer(Const.VoxelCacheIdTable, UseVoxelCache ? m_voxelCacheIdTableBuffer : m_numAllocationsBuffer);
|
|
ComputeManager.SetBuffer(Const.VoxelCache, UseVoxelCache ? m_voxelCacheBuffer : m_numAllocationsBuffer);
|
|
ComputeManager.SetBuffer(Const.BrushMaskPool, m_brushMaskPoolBuffer);
|
|
ComputeManager.SetBuffer(Const.IndirectDispatchArgs, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.SetBuffer(Const.GenPoints, m_genPointsBufferUsedForCompute);
|
|
ComputeManager.SetBuffer(Const.IndirectDrawArgs, m_indirectDrawArgsBufferUsedForCompute);
|
|
|
|
ComputeManager.SetBool(Const.Enable2dMode, Enable2dMode);
|
|
ComputeManager.SetBool(Const.ForceAllBrushes, ShouldForceAllBrushes());
|
|
ComputeManager.SetFloat(Const.VoxelSize, VoxelSize);
|
|
ComputeManager.SetInt(Const.VoxelTreeBranchingFactorsCompressed, VoxelTreeBranchingFactorsComrpessed);
|
|
ComputeManager.SetVector(Const.VoxelNodeSizes, NodeSizesVector);
|
|
ComputeManager.SetInt(Const.MaxNodeDepth, VoxelNodeDepth);
|
|
ComputeManager.SetInt(Const.ChunkVoxelDensity, ChunkVoxelDensity);
|
|
ComputeManager.SetInt(Const.MaxGenPoints, MaxGenPoints);
|
|
|
|
ComputeManager.SetTexture(Const.NoiseCache, s_noiseCache);
|
|
//ComputeManager.SetTexture(Const.NoiseCache, NoiseCache);
|
|
|
|
ComputeManager.SetFloats(Const.NoiseCacheDimension, NoiseCacheDimensionFloats);
|
|
ComputeManager.SetFloat(Const.NoiseCacheDensity, NoiseCacheDensity);
|
|
|
|
ComputeManager.SetInt(Const.MeshGenerationAutoRiggingAlgorithm, (int) MeshGenerationAutoRiggingAlgorithm);
|
|
|
|
switch (MeshingMode)
|
|
{
|
|
case MeshingModeEnum.SurfaceNets:
|
|
ComputeManager.SetFloat(Const.SurfaceNetsDualQuadsBlend, SurfaceNetsDualQuadsBlend);
|
|
/*
|
|
ComputeManager.SetInt(Const.SurfaceNetsBinarySearchIterations, SurfaceNetsBinarySearchIterations);
|
|
ComputeManager.SetInt(Const.SurfaceNetsGradientDescentIterations, SurfaceNetsGradientDescentIterations);
|
|
ComputeManager.SetFloat(Const.SurfaceNetsGradientDescentFactor, SurfaceNetsGradientDescentFactor);
|
|
*/
|
|
/*
|
|
if (SurfaceNetsHighAccuracyMode)
|
|
{
|
|
ComputeManager.SetInt(Const.SurfaceNetsBinarySearchIterations, 6);
|
|
ComputeManager.SetInt(Const.SurfaceNetsGradientDescentIterations, 1);
|
|
ComputeManager.SetFloat(Const.SurfaceNetsGradientDescentFactor, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
ComputeManager.SetInt(Const.SurfaceNetsBinarySearchIterations, 0);
|
|
ComputeManager.SetInt(Const.SurfaceNetsGradientDescentIterations, 0);
|
|
ComputeManager.SetFloat(Const.SurfaceNetsGradientDescentFactor, 0.0f);
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case MeshingModeEnum.DualContouring:
|
|
ComputeManager.SetFloat(Const.DualContouringDualQuadsBlend, DualContouringDualQuadsBlend);
|
|
ComputeManager.SetFloat(Const.DualContouringRelaxation, 0.15f + 0.85f * DualContouringRelaxation);
|
|
//ComputeManager.SetInt(Const.DualContouringSolverIterations, DualContouringSolverIterations);
|
|
/*
|
|
ComputeManager.SetInt(Const.DualContouringBinarySearchIterations, DualContouringBinarySearchIterations);
|
|
ComputeManager.SetInt(Const.DualContouringGradientDescentIterations, DualContouringGradientDescentIterations);
|
|
ComputeManager.SetFloat(Const.DualContouringGradientDescentFactor, DualContouringGradientDescentFactor);
|
|
*/
|
|
if (DualContouringHighAccuracyMode)
|
|
{
|
|
ComputeManager.SetInt(Const.DualContouringSolverIterations, 0);
|
|
ComputeManager.SetInt(Const.DualContouringBinarySearchIterations, 10);
|
|
ComputeManager.SetInt(Const.DualContouringGradientDescentIterations, 1);
|
|
ComputeManager.SetFloat(Const.DualContouringGradientDescentFactor, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
ComputeManager.SetInt(Const.DualContouringSolverIterations, 0);
|
|
ComputeManager.SetInt(Const.DualContouringBinarySearchIterations, 0);
|
|
ComputeManager.SetInt(Const.DualContouringGradientDescentIterations, 0);
|
|
ComputeManager.SetFloat(Const.DualContouringGradientDescentFactor, 0.0f);
|
|
}
|
|
break;
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
private void BindRenderResources()
|
|
{
|
|
Profiler.BeginSample("BindRenderResources");
|
|
|
|
if (m_materialProps == null)
|
|
{
|
|
m_materialProps = new MaterialPropertyBlock();
|
|
m_needsCompute = true;
|
|
}
|
|
|
|
m_materialProps.SetBuffer(Const.GenPoints, m_genPointsBufferDefault);
|
|
|
|
m_materialProps.SetVector(Const.MasterColor, MasterColor);
|
|
m_materialProps.SetVector(Const.MasterEmission, MasterEmission);
|
|
m_materialProps.SetFloat(Const.MasterMetallic, MasterMetallic);
|
|
m_materialProps.SetFloat(Const.MasterSmoothness, MasterSmoothness);
|
|
|
|
m_materialProps.SetInt(Const.InvertNormals, (InvertNormals && !Enable2dMode ? 1 : 0));
|
|
|
|
m_materialProps.SetInt(Const.Enable2dMode, Enable2dMode ? 1 : 0);
|
|
m_materialProps.SetFloat(Const.VoxelSize, VoxelSize);
|
|
m_materialProps.SetInt(Const.VoxelTreeBranchingFactorsCompressed, VoxelTreeBranchingFactorsComrpessed);
|
|
m_materialProps.SetVector(Const.VoxelNodeSizes, NodeSizesVector);
|
|
m_materialProps.SetFloat(Const.SplatSize, SplatSize * (1.5f / VoxelDensity));
|
|
m_materialProps.SetFloat(Const.SplatSizeJitter, SplatSizeJitter);
|
|
m_materialProps.SetFloat(Const.SplatNormalShift, SplatNormalShift);
|
|
m_materialProps.SetFloat(Const.SplatNormalShiftJitter, SplatNormalShiftJitter);
|
|
m_materialProps.SetFloat(Const.SplatColorJitter, SplatColorJitter);
|
|
m_materialProps.SetFloat(Const.SplatPositionJitter, SplatPositionJitter);
|
|
m_materialProps.SetFloat(Const.SplatRotationJitter, SplatRotationJitter);
|
|
m_materialProps.SetFloat(Const.SplatOrientationJitter, SplatOrientationJitter);
|
|
m_materialProps.SetFloat(Const.SplatOriginalNormalBlend, SplatOriginalNormalBlend);
|
|
m_materialProps.SetFloat(Const.SplatJitterNoisiness, SplatJitterNoisiness);
|
|
m_materialProps.SetFloat(Const.SplatCameraFacing, SplatCameraFacing);
|
|
m_materialProps.SetInt(Const.SplatNormalsMatchCameraFacing, SplatNormalsMatchCameraFacing ? 1 : 0);
|
|
m_materialProps.SetInt(Const.SplatShadowsMatchCameraFacing, SplatShadowsMatchCameraFacing ? 1 : 0);
|
|
m_materialProps.SetFloat(Const.SplatScreenSpaceFlattening, SplatScreenSpaceFlattening);
|
|
//m_materialProps.SetFloat(Const.SplatSmoothNormalBlend, SplatSmoothNormalBlend);
|
|
|
|
Vector3 scale = transform.localToWorldMatrix.lossyScale;
|
|
m_materialProps.SetInt(Const.ScaleSign, (scale.x * scale.y * scale.z) >= 0.0f ? 1 : -1);
|
|
m_materialProps.SetMatrix(Const.LocalToWorld, transform.localToWorldMatrix);
|
|
m_materialProps.SetMatrix(Const.LocalToWorldIt, transform.localToWorldMatrix.inverse.transpose);
|
|
m_materialProps.SetVector(Const.LocalToWorldScale, transform.localScale);
|
|
m_materialProps.SetMatrix(Const.WorldToLocal, transform.worldToLocalMatrix);
|
|
m_materialProps.SetMatrix(Const.WorldToLocalIt, transform.worldToLocalMatrix.inverse.transpose);
|
|
|
|
m_materialProps.SetInt(Const.RenderMode, (int) RenderMode);
|
|
m_materialProps.SetInt(Const.MeshingMode, (int) MeshingMode);
|
|
m_materialProps.SetInt(Const.RayTracedVoxelMode, (int) RayTracedVoxelMode);
|
|
m_materialProps.SetFloat(Const.RayTracedVoxelSizeMultiplier, RayTracedVoxelSizeMultiplier);
|
|
m_materialProps.SetFloat(Const.RayTracedVoxelSmoothCubeNormal, RayTracedVoxelSmoothCubeNormal);
|
|
m_materialProps.SetFloat(Const.RayTracedVoxelRadius, 1.0f + 0.733f * RayTracedVoxelSphereFullness);
|
|
m_materialProps.SetInt(Const.RayTracedVoxelPaddingMode, (int) RayTracedVoxelPaddingMode);
|
|
m_materialProps.SetInt(Const.RayTracedVoxelPaddingMode, (int)RayTracedVoxelPaddingMode);
|
|
m_materialProps.SetFloat(Const.RayTracedVoxelInternalPaddingDistance, RayTracedVoxelInternalPaddingDistance);
|
|
m_materialProps.SetFloat(Const.RayTracedVoxelSizeFadeDistance, RayTracedVoxelSizeFadeDistance);
|
|
m_materialProps.SetFloat(Const.NormalQuantization, NormalQuantization);
|
|
m_materialProps.SetFloat(Const.Normal2dFadeDist, Normal2dFade);
|
|
m_materialProps.SetFloat(Const.Normal2dStrength, Normal2dStrength);
|
|
|
|
m_materialProps.SetFloat(Const.AutoSmoothMaxAngle, EnableAutoSmoothing ? AutoSmoothingMaxAngle * MathUtil.Deg2Rad : -1.0f);
|
|
|
|
//if (MaterialNeedsSdfProperties(m_materialUsed))
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Decal:
|
|
//case RenderModeCategoryEnum.RayMarchedSurface:
|
|
//case RenderModeCategoryEnum.RayTracedVoxels:
|
|
m_materialProps.SetBuffer(Const.NodeHashTable, m_nodeHashTableBuffer);
|
|
m_materialProps.SetInt(Const.NodeHashTableSize, m_nodeHashTableBuffer.count);
|
|
m_materialProps.SetBuffer(Const.NodePool, m_nodePoolBuffer);
|
|
m_materialProps.SetBuffer(Const.VoxelCacheIdTable, UseVoxelCache ? m_voxelCacheIdTableBuffer : m_numAllocationsBuffer);
|
|
m_materialProps.SetBuffer(Const.VoxelCache, UseVoxelCache ? m_voxelCacheBuffer : m_numAllocationsBuffer);
|
|
m_materialProps.SetBuffer(Const.BrushMaskPool, m_brushMaskPoolBuffer);
|
|
|
|
m_materialProps.SetBuffer(Const.Brushes, m_brushesBuffer);
|
|
m_materialProps.SetBuffer(Const.BrushMaterials, m_brushMaterialBuffer);
|
|
m_materialProps.SetInt(Const.NumBrushes, m_numSdfBrushes);
|
|
|
|
m_materialProps.SetBuffer(Const.AabbTree, m_aabbTreeBuffer);
|
|
m_materialProps.SetInt(Const.AabbRoot, m_aabbTreeBufferRoot);
|
|
|
|
m_materialProps.SetTexture(Const.NoiseCache, NoiseCache);
|
|
m_materialProps.SetVector(Const.NoiseCacheDimension, new Vector4(NoiseCacheDimensionFloats[0], NoiseCacheDimensionFloats[1], NoiseCacheDimensionFloats[2]));
|
|
m_materialProps.SetFloat(Const.NoiseCacheDensity, NoiseCacheDensity);
|
|
|
|
m_materialProps.SetFloat(Const.SurfaceShift, SurfaceShift);
|
|
|
|
//if (MaterialNeedsRayMarchingProperties(m_materialUsed))
|
|
if (false /* RenderModeCategory == RenderModeCategoryEnum.RayMarchedSurface */)
|
|
{
|
|
/*
|
|
m_materialProps.SetInt(Const.MaxRayMarchSteps, MaxRayMarchSteps);
|
|
m_materialProps.SetFloat(Const.RayMarchHitDistance, 1e-1f * Mathf.Pow(1e-1f, 2.0f * RayMarchAccuracy));
|
|
m_materialProps.SetFloat(Const.RayMarchMaxRayDistance, RayMarchMaxRayDistance);
|
|
*/
|
|
|
|
/*
|
|
m_materialProps.SetFloat(Const.RayMarchStepSize, RayMarchDistance / Mathf.Max(1, MaxRayMarchSteps));
|
|
m_materialProps.SetFloat(Const.RayMarchStepSize, RayMarchStepSize);
|
|
m_materialProps.SetInt(Const.NumLightMarchSteps, NumLightMarchSteps);
|
|
m_materialProps.SetFloat(Const.RayMarchVolumeDensity, RayMarchVolumeDensity);
|
|
if (RayMarchLight != null)
|
|
{
|
|
Vector3 lightPos = RayMarchLight.transform.position;
|
|
m_materialProps.SetVector(Const.RayMarchLightPositionType, new Vector4(lightPos.x, lightPos.y, lightPos.z, (int) RayMarchLight.type));
|
|
m_materialProps.SetVector(Const.RayMarchLightDirection, RayMarchLight.transform.forward);
|
|
}
|
|
else
|
|
{
|
|
m_materialProps.SetVector(Const.RayMarchLightPositionType, new Vector4(0.0f, 0.0f, 0.0f, (int) LightType.Directional));
|
|
m_materialProps.SetVector(Const.RayMarchLightDirection, Vector3.down);
|
|
}
|
|
m_materialProps.SetVector(Const.RayMarchAbsorption, new Vector4(RayMarchVolumeAbsorption, RayMarchLightAbsorption));
|
|
m_materialProps.SetFloat(Const.RayMarchDarknesThreshold, RayMarchDarknesThreshold);
|
|
m_materialProps.SetFloat(Const.RayMarchTransmittanceCurve, RayMarchTransmittanceCurve);
|
|
m_materialProps.SetFloat(Const.RayMarchNoiseEdgeFade, RayMarchNoiseEdgeFade);
|
|
m_materialProps.SetFloat(Const.RayMarchNoiseThreshold, UseRayMarchNoise ? RayMarchNoiseThreshold : 0.0f);
|
|
m_materialProps.SetVector(Const.RayMarchNoiseScrollSpeed, RayMarchNoiseScrollSpeed);
|
|
m_materialProps.SetVector(Const.RayMarchNoiseBaseOctaveSize, RayMarchNoiseBaseOctaveSize);
|
|
m_materialProps.SetInt(Const.RayMarchNoiseNumOctaves, RayMarchNoiseNumOctaves);
|
|
m_materialProps.SetFloat(Const.RayMarchNoiseOctaveOffsetFactor, RayMarchNoiseOctaveOffsetFactor);
|
|
*/
|
|
}
|
|
break;
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
#endregion // end: Brushes
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
#region Core
|
|
|
|
public ComputeModeEnum ComputeMode = ComputeModeEnum.Auto;
|
|
public TimeSliceModeEnum TimeSliceMode = TimeSliceModeEnum.ByPeriodAutoOffset;
|
|
[Min(1)] public int TimeSliceFrames = 3;
|
|
public int TimeSliceFramesOffset = 0;
|
|
[Min(0.0001f)] public float TimeSlicePeriod = 0.05f;
|
|
public float TimeSliceTimeOffset = 0;
|
|
private float m_lastUpdateTimeSliceTime = -1.0f;
|
|
|
|
private int m_rendererIndex = -1;
|
|
|
|
private void SetComputeNodeDepth(int depth)
|
|
{
|
|
ComputeManager.SetInt(Const.CurrentNodeDepth, depth);
|
|
ComputeManager.SetInt(Const.CurrentNodeBranchingFactor, (depth < VoxelNodeDepth ? VoxelTreeBranchingFactors[depth] : 0));
|
|
ComputeManager.SetFloat(Const.CurrentNodeSize, NodeSizes[depth]);
|
|
}
|
|
|
|
private void ComputeGpu()
|
|
{
|
|
Profiler.BeginSample("Compute (GPU)");
|
|
|
|
UpdateActivePreCompute();
|
|
|
|
SetUpResources();
|
|
|
|
Profiler.BeginSample("Core Dispatch");
|
|
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeVoxelGen,
|
|
Const.Kernel.ClearVoxelHashTable,
|
|
Mathf.Max(1, (m_nodeHashTableBuffer.count + ClearThreadGroupSize - 1) / ClearThreadGroupSize), 1, 1
|
|
);
|
|
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeVoxelGen,
|
|
Const.Kernel.ClearAutoSmoothVertDataTable,
|
|
Mathf.Max(1, (m_autoSmoothVertDataTableBuffer.count + ClearThreadGroupSize - 1) / ClearThreadGroupSize), 1, 1
|
|
);
|
|
}
|
|
|
|
if (UseVoxelCache)
|
|
{
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeVoxelGen,
|
|
Const.Kernel.ClearVoxelCache,
|
|
Mathf.Max(1, (m_voxelCacheIdTableBuffer.count + ClearThreadGroupSize - 1) / ClearThreadGroupSize), 1, 1
|
|
);
|
|
}
|
|
|
|
SetComputeNodeDepth(0);
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeVoxelGen,
|
|
Const.Kernel.RegisterTopNodes,
|
|
Mathf.Max(1, (m_numSdfBrushes + ThreadGroupSize - 1) / ThreadGroupSize), 1, 1
|
|
);
|
|
|
|
for (int depth = 0; depth < VoxelNodeDepth; ++depth)
|
|
{
|
|
SetComputeNodeDepth(depth);
|
|
ComputeManager.Dispatch(s_computeVoxelGen, Const.Kernel.UpdateBranchingIndirectDispatchArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeVoxelGen, Const.Kernel.AllocateChildNodes, m_indirectDispatchArgsBuffer);
|
|
}
|
|
|
|
SetComputeNodeDepth(VoxelNodeDepth);
|
|
ComputeManager.Dispatch(s_computeVoxelGen, Const.Kernel.UpdateVoxelIndirectDispatchArgs, 1, 1, 1);
|
|
|
|
switch (RenderModeCategory)
|
|
{
|
|
case RenderModeCategoryEnum.Mesh:
|
|
case RenderModeCategoryEnum.Splats:
|
|
case RenderModeCategoryEnum.Decal:
|
|
switch (MeshingMode)
|
|
{
|
|
case MeshingModeEnum.MarchingCubes:
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateFlatMarchingCubesMesh2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateFlatMarchingCubesMesh, m_indirectDispatchArgsBuffer);
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.Dispatch(s_computeMarchingCubes, Const.Kernel.UpdateMarchingCubesAutoSmoothIndirectDispatchArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.MarchingCubesUpdateAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.MarchingCubesComputeAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
}
|
|
break;
|
|
|
|
case RenderModeEnum.SmoothMesh:
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateFlatMarchingCubesMesh, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.Dispatch(s_computeMarchingCubes, Const.Kernel.UpdateMarchingCubesAutoSmoothIndirectDispatchArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.MarchingCubesUpdateAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.MarchingCubesComputeAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
}
|
|
else
|
|
{
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateSmoothMarchingCubesMesh2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateSmoothMarchingCubesMesh, m_indirectDispatchArgsBuffer);
|
|
}
|
|
break;
|
|
|
|
case RenderModeEnum.CircleSplats:
|
|
case RenderModeEnum.QuadSplats:
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateMarchingCubesSplats2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeMarchingCubes, Const.Kernel.GenerateMarchingCubesSplats, m_indirectDispatchArgsBuffer);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MeshingModeEnum.DualQuads:
|
|
if (Enable2dMode)
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.GenerateDualQuads2d, m_indirectDispatchArgsBuffer);
|
|
}
|
|
else
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.GenerateDualQuads, m_indirectDispatchArgsBuffer);
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
// do nothing
|
|
break;
|
|
|
|
case RenderModeEnum.SmoothMesh:
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.UpdateDualMeshingIndirectDispatchArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothMeshNormal, m_indirectDispatchArgsBuffer);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MeshingModeEnum.SurfaceNets:
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.GenerateDualQuads2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.GenerateDualQuads, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.UpdateDualMeshingIndirectDispatchArgs, 1, 1, 1);
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeSurfaceNets, Const.Kernel.SurfaceNetsMovePoint2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeSurfaceNets, Const.Kernel.SurfaceNetsMovePoint, m_indirectDispatchArgsBuffer);
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingUpdateAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingComputeAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
}
|
|
else
|
|
{
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingFlatMeshNormal2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingFlatMeshNormal, m_indirectDispatchArgsBuffer);
|
|
}
|
|
break;
|
|
|
|
case RenderModeEnum.SmoothMesh:
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingUpdateAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingComputeAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
}
|
|
else
|
|
{
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothMeshNormal2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothMeshNormal, m_indirectDispatchArgsBuffer);
|
|
}
|
|
break;
|
|
|
|
case RenderModeEnum.CircleSplats:
|
|
case RenderModeEnum.QuadSplats:
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.UpdateDualMeshingSplatsIndirectArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.ConvertDualMeshingSplats, m_indirectDispatchArgsBuffer);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MeshingModeEnum.DualContouring:
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.GenerateDualQuads2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.GenerateDualQuads, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.UpdateDualMeshingIndirectDispatchArgs, 1, 1, 1);
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualContouring, Const.Kernel.DualContouringMovePoint2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualContouring, Const.Kernel.DualContouringMovePoint, m_indirectDispatchArgsBuffer);
|
|
switch (RenderMode)
|
|
{
|
|
case RenderModeEnum.FlatMesh:
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingUpdateAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingComputeAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
if (EnableSmoothCorner)
|
|
{
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.DualMeshingUpdateSmoothCornerIndirectDispatchArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothCorner, m_indirectDispatchArgsBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingFlatMeshNormal2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingFlatMeshNormal, m_indirectDispatchArgsBuffer);
|
|
}
|
|
break;
|
|
|
|
case RenderModeEnum.SmoothMesh:
|
|
if (ShouldDoAutoSmoothing)
|
|
{
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingUpdateAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingComputeAutoSmooth, m_indirectDispatchArgsBuffer);
|
|
if (EnableSmoothCorner)
|
|
{
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.DualMeshingUpdateSmoothCornerIndirectDispatchArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothCorner, m_indirectDispatchArgsBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Enable2dMode)
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothMeshNormal2d, m_indirectDispatchArgsBuffer);
|
|
else
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.DualMeshingSmoothMeshNormal, m_indirectDispatchArgsBuffer);
|
|
}
|
|
break;
|
|
|
|
case RenderModeEnum.CircleSplats:
|
|
case RenderModeEnum.QuadSplats:
|
|
ComputeManager.Dispatch(s_computeDualMeshing, Const.Kernel.UpdateDualMeshingSplatsIndirectArgs, 1, 1, 1);
|
|
ComputeManager.DispatchIndirect(s_computeDualMeshing, Const.Kernel.ConvertDualMeshingSplats, m_indirectDispatchArgsBuffer);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// done in voxel gen
|
|
/*
|
|
case RenderModeCategoryEnum.RayTracedVoxels:
|
|
ComputeManager.Dispatch(s_computeRayTracedVoxels, Const.Kernel.UpdateRayTracedVoxelIndirectDispatchArgs, 1, 1, 1);
|
|
switch(RayTracedVoxelMode)
|
|
{
|
|
case RayTracedVoxelModeEnum.CubesFaceted:
|
|
ComputeManager.DispatchIndirect(s_computeRayTracedVoxels, Const.Kernel.ComputeRayTracedVoxelGenPoints, m_indirectDispatchArgsBuffer);
|
|
break;
|
|
case RayTracedVoxelModeEnum.CubesFlat:
|
|
ComputeManager.DispatchIndirect(s_computeRayTracedVoxels, Const.Kernel.ComputeRayTracedVoxelGenPointsWithNormals, m_indirectDispatchArgsBuffer);
|
|
break;
|
|
}
|
|
break;
|
|
*/
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
|
|
if (MudBun.IsFreeVersion)
|
|
{
|
|
if (LockMeshIntermediateState != LockMeshIntermediateStateEnum.Idle
|
|
&& m_indirectDrawArgsBufferUsedForCompute != null)
|
|
{
|
|
int[] aIndirectDrawArgs = new int[5];
|
|
m_indirectDrawArgsBufferUsedForCompute.GetData(aIndirectDrawArgs);
|
|
aIndirectDrawArgs[0] = Mathf.Min(aIndirectDrawArgs[0], 3 * MaxMeshGenerationTrianglesFreeVersion);
|
|
m_indirectDrawArgsBufferUsedForCompute.SetData(aIndirectDrawArgs);
|
|
}
|
|
}
|
|
|
|
if (m_doRigging)
|
|
{
|
|
Profiler.BeginSample("Rigging Dispatch");
|
|
|
|
ComputeManager.SetBuffer(Const.IndirectDrawArgs, m_indirectDrawArgsBufferUsedForCompute);
|
|
ComputeManager.SetBuffer(Const.GenPoints, m_genPointsBufferUsedForCompute);
|
|
ComputeManager.SetBuffer(Const.BrushMaterials, m_brushMaterialBuffer);
|
|
ComputeManager.SetBuffer(Const.Brushes, m_brushesBuffer);
|
|
ComputeManager.SetTexture(Const.NoiseCache, NoiseCache);
|
|
ComputeManager.SetInt(Const.NumBrushes, m_numSdfBrushes);
|
|
|
|
int[] aIndirectDrawArgs = new int[5];
|
|
m_indirectDrawArgsBufferUsedForCompute.GetData(aIndirectDrawArgs);
|
|
ComputeManager.Dispatch
|
|
(
|
|
s_computeMeshLock,
|
|
Const.Kernel.RigBones,
|
|
(aIndirectDrawArgs[0] + ThreadGroupSize - 1) / ThreadGroupSize, 1, 1
|
|
);
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
// only use buffer overrides once
|
|
if (m_genPointsBufferOverride != null)
|
|
m_genPointsBufferOverride = null;
|
|
if (m_indirectDrawArgsBufferOverride != null)
|
|
m_indirectDrawArgsBufferOverride = null;
|
|
|
|
UpdateActivePostCompute();
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
private void ComputeCpu()
|
|
{
|
|
Profiler.BeginSample("Compute (CPU)");
|
|
|
|
// TODO
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
private Mesh m_renderBoxProxy;
|
|
|
|
private void Render()
|
|
{
|
|
if (IsEditorBusy())
|
|
return;
|
|
|
|
if (m_indirectDrawArgsBufferDefault == null)
|
|
return;
|
|
|
|
if (!s_globalResourcesValid || !m_localResourcesValid)
|
|
return;
|
|
|
|
Profiler.BeginSample("Render");
|
|
|
|
ValidateRenderMaterial();
|
|
BindRenderResources();
|
|
|
|
Aabb renderBounds = RenderBounds;
|
|
if (renderBounds.IsEmpty)
|
|
{
|
|
renderBounds.Min = -Vector3.one;
|
|
renderBounds.Max = Vector3.one;
|
|
}
|
|
|
|
switch (RenderGeometryType)
|
|
{
|
|
case RenderGeometryTypeEnum.Mesh:
|
|
case RenderGeometryTypeEnum.Chunks:
|
|
Graphics.DrawProceduralIndirect
|
|
(
|
|
m_materialUsed,
|
|
new Bounds(renderBounds.Center, renderBounds.Size),
|
|
MeshTopology.Triangles,
|
|
m_indirectDrawArgsBufferDefault,
|
|
0,
|
|
null,
|
|
m_materialProps,
|
|
CastShadows,
|
|
ReceiveShadows,
|
|
gameObject.layer
|
|
);
|
|
break;
|
|
|
|
case RenderGeometryTypeEnum.BoxProxy:
|
|
MeshUtil.UpdateRenderBoxProxy(ref m_renderBoxProxy, renderBounds);
|
|
Graphics.DrawMesh
|
|
(
|
|
m_renderBoxProxy,
|
|
Matrix4x4.identity,
|
|
m_materialUsed,
|
|
gameObject.layer,
|
|
null,
|
|
0,
|
|
m_materialProps,
|
|
CastShadows,
|
|
ReceiveShadows
|
|
);
|
|
break;
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
#endregion // end: Core
|
|
}
|
|
}
|
|
|