|
|
|
|
/******************************************************************************/
|
|
|
|
|
/*
|
|
|
|
|
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/29NFzO
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|