1472 lines
73 KiB
C#
1472 lines
73 KiB
C#
|
/************************************************************************************
|
||
|
|
||
|
Depthkit Unity SDK License v1
|
||
|
Copyright 2016-2024 Simile Inc dba Scatter. All Rights reserved.
|
||
|
|
||
|
Licensed under the the Simile Inc dba Scatter ("Scatter")
|
||
|
Software Development Kit License Agreement (the "License");
|
||
|
you may not use this SDK except in compliance with the License,
|
||
|
which is provided at the time of installation or download,
|
||
|
or which otherwise accompanies this software in either electronic or hard copy form.
|
||
|
|
||
|
You may obtain a copy of the License at http://www.depthkit.tv/license-agreement-v1
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing,
|
||
|
the SDK distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and limitations under the License.
|
||
|
|
||
|
************************************************************************************/
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
using System.Runtime.InteropServices;
|
||
|
|
||
|
namespace Depthkit
|
||
|
{
|
||
|
//data textures are one dataset per triangle (based on the 0th (non-shared) vertex in the triangle)
|
||
|
[RequireComponent(typeof(Clip))]
|
||
|
[ExecuteInEditMode]
|
||
|
[DisallowMultipleComponent]
|
||
|
[AddComponentMenu("Depthkit/Studio/Sources/Depthkit Studio Mesh Source")]
|
||
|
public class StudioMeshSource : MeshSource
|
||
|
{
|
||
|
public enum VolumeGenerationMethod
|
||
|
{
|
||
|
SinglePass,
|
||
|
MultiPass
|
||
|
}
|
||
|
|
||
|
public enum VolumeDensity
|
||
|
{
|
||
|
VeryLow = 16,
|
||
|
Low = 8,
|
||
|
Medium = 4,
|
||
|
High = 2,
|
||
|
Full = 1
|
||
|
}
|
||
|
|
||
|
public enum UntexturedGeometrySettings
|
||
|
{
|
||
|
Infer,
|
||
|
Colorize,
|
||
|
Clip
|
||
|
}
|
||
|
|
||
|
public VolumeGenerationMethod generationMethod = VolumeGenerationMethod.SinglePass;
|
||
|
|
||
|
//Shaders
|
||
|
private ComputeShader m_generateVolumeCompute;
|
||
|
private ComputeShader m_generateVolumePreviewCompute;
|
||
|
private ComputeShader m_extractSurfaceCompute;
|
||
|
private ComputeShader m_sdfFilterCompute;
|
||
|
private ComputeShader m_generateNormalWeightsCompute;
|
||
|
|
||
|
public bool showVolumePreview = false;
|
||
|
private Material m_volumePreviewMaterial;
|
||
|
|
||
|
[Range(0.001f, 0.3f)]
|
||
|
public float volumePreviewAlpha = 0.02f;
|
||
|
|
||
|
[Range(0.1f, 5.0f)]
|
||
|
public float volumePreviewPointSize = 1.0f;
|
||
|
|
||
|
///LOD SETTINGS
|
||
|
public bool automaticLevelOfDetail = false;
|
||
|
|
||
|
[Range(1.0f, 100.0f)]
|
||
|
public float levelOfDetailDistance = 1.0f;
|
||
|
|
||
|
private int m_currentLODLevel = 0;
|
||
|
|
||
|
[Min(1)]
|
||
|
private int m_currentLODIsoScalar = 1;
|
||
|
public int currentLevelOfDetailLevel
|
||
|
{
|
||
|
set
|
||
|
{
|
||
|
m_currentLODLevel = Math.Max(value, 0);
|
||
|
m_currentLODIsoScalar = (int)Mathf.Pow(2, m_currentLODLevel);
|
||
|
ScheduleGenerate();
|
||
|
}
|
||
|
get { return m_currentLODLevel; }
|
||
|
}
|
||
|
|
||
|
private Camera m_mainCamera;
|
||
|
|
||
|
//SDF settings
|
||
|
[SerializeField]
|
||
|
private Bounds m_volumeBounds = new Bounds(Vector3.zero, Vector3.zero);
|
||
|
public Bounds volumeBounds
|
||
|
{
|
||
|
get { return m_volumeBounds; }
|
||
|
set
|
||
|
{
|
||
|
m_volumeBounds = value;
|
||
|
if (useTriangleMesh)
|
||
|
{
|
||
|
triangleMesh.ResetMeshCube(m_volumeBounds.center, m_volumeBounds.size);
|
||
|
}
|
||
|
ScheduleResize();
|
||
|
ScheduleGenerate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override Bounds GetLocalBounds()
|
||
|
{
|
||
|
return m_volumeBounds;
|
||
|
}
|
||
|
|
||
|
//volume density is in voxels per meter
|
||
|
[SerializeField, Range(30.0f, 300.0f)]
|
||
|
private float m_volumeDensity = 100.0f; //1cm = 1 voxel
|
||
|
public float volumeDensity
|
||
|
{
|
||
|
get { return m_volumeDensity; }
|
||
|
set
|
||
|
{
|
||
|
m_volumeDensity = value;
|
||
|
ScheduleResize();
|
||
|
ScheduleGenerate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[SerializeField, HideInInspector]
|
||
|
private Vector3Int m_voxelGridDimensions = Vector3Int.one;
|
||
|
|
||
|
public int numLevelOfDetailLevels { get; private set; } = 0;
|
||
|
|
||
|
[SerializeField, HideInInspector]
|
||
|
private int m_totalVoxelCount;
|
||
|
|
||
|
//Gaussian Filter Sigma
|
||
|
[Range(0.3f, 1.12f)]
|
||
|
public float surfaceSmoothingRadius = 0.3f;
|
||
|
|
||
|
public bool enableSurfaceSmoothing = false;
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
public bool showLevelOfDetailGizmo = false;
|
||
|
#endif
|
||
|
private float m_surfaceSensitivityThreshold = 0.0f;
|
||
|
|
||
|
const float surfaceSensitivityDefault = 0.1f;
|
||
|
const float weightUnknownDefault = 0.005f;
|
||
|
const float weightUnseenMaxDefault = 1.0f;
|
||
|
const float weightUnseenMinDefault = 0.0025f;
|
||
|
const float weightUnseenFalloffPowerDefault = 10.0f;
|
||
|
const float weightInFrontMaxDefault = 1.0f;
|
||
|
const float weightInFrontMinDefault = 0.1f;
|
||
|
|
||
|
[Range(0.001f, 0.225f)]
|
||
|
public float surfaceSensitivity = surfaceSensitivityDefault;
|
||
|
|
||
|
[Range(0.0f, 0.05f)]
|
||
|
public float weightUnknown = weightUnknownDefault;
|
||
|
|
||
|
[Range(0.0f, 1.0f)]
|
||
|
public float weightUnseenMax = weightUnseenMaxDefault;
|
||
|
|
||
|
[Range(0.0f, 0.01f)]
|
||
|
public float weightUnseenMin = weightUnseenMinDefault;
|
||
|
|
||
|
[Range(1.0f, 10.0f)]
|
||
|
public float weightUnseenFalloffPower = weightUnseenFalloffPowerDefault;
|
||
|
|
||
|
[Range(0.0f, 1.0f)]
|
||
|
public float weightInFrontMax = weightInFrontMaxDefault;
|
||
|
|
||
|
[Range(0.0f, 1.0f)]
|
||
|
public float weightInFrontMin = weightInFrontMinDefault;
|
||
|
|
||
|
public Transform volumeViewpoint;
|
||
|
|
||
|
[Range(0.001f, 10.0f)]
|
||
|
public float surfaceNormalColorBlendingPower = Metadata.DefaultReconstructionSettingsDefaults.surfaceNormalColorBlendPower;
|
||
|
|
||
|
[Range(0.001f, 0.1f)]
|
||
|
public float perViewDisparityThreshold = 0.0125f;
|
||
|
|
||
|
[Range(0.0001f, 0.1f)]
|
||
|
public float perViewDisparityBlendWidth = 0.025f;
|
||
|
|
||
|
[Range(0.0f, 0.1f)]
|
||
|
public float disparityMin = 0.0f;
|
||
|
|
||
|
[Range(0.001f, 20.0f)]
|
||
|
public float globalViewDependentColorBlendWeight = Metadata.DefaultReconstructionSettingsDefaults.viewDependentColorBlendPower;
|
||
|
|
||
|
[Range(0.001f, 20.0f)]
|
||
|
public float globalViewDependentGeometryBlendWeight = 1.0f;
|
||
|
|
||
|
public bool enableViewDependentGeometry = false;
|
||
|
|
||
|
public UntexturedGeometrySettings untexturedFragmentSetting = UntexturedGeometrySettings.Infer;
|
||
|
|
||
|
public Color untexturedColor = Color.black;
|
||
|
|
||
|
//buffers
|
||
|
private ComputeBuffer[] m_sdfBuffers;
|
||
|
private int m_currentSdfBuffer = 0;
|
||
|
private ComputeBuffer m_pointsBuffer;
|
||
|
|
||
|
private const int m_triangleConnectionTableSize = 256 * 16;
|
||
|
private const int m_triangleOffsetsSize = 72;
|
||
|
private const int m_numberOfTrianglesSize = 256;
|
||
|
|
||
|
private const int m_triangleBufferSize = m_triangleConnectionTableSize + m_triangleOffsetsSize + m_numberOfTrianglesSize;
|
||
|
private ComputeBuffer m_triangleBuffer;
|
||
|
|
||
|
protected Material m_halfBlitMaterial;
|
||
|
|
||
|
private RenderTexture m_normalWeightTexture;
|
||
|
private Vector4 m_normalWeightTextureTexelSize;
|
||
|
private Material m_normalWeightGenerationMaterial;
|
||
|
|
||
|
private int m_generateVolumeKernelGroupSize = 8;
|
||
|
private int m_extractSurfaceKernelGroupSize = 8;
|
||
|
|
||
|
private int m_extractSurfaceKId = -1;
|
||
|
private int m_normalWeightKId = -1;
|
||
|
private int m_generateVolumeSinglePassKId = -1;
|
||
|
private int m_generateVolumeMultiPassInitKId = -1;
|
||
|
private int m_generateVolumeMultiPassAccumulateKId = -1;
|
||
|
private int m_generateVolumeMultiPassResolveKId = -1;
|
||
|
private int m_generateVolumePreviewKId = -1;
|
||
|
|
||
|
public PerspectiveColorBlendingData perspectiveColorBlendingData;
|
||
|
public PerspectiveGeometryData perspectiveGeometryData;
|
||
|
|
||
|
public bool[] overrideRadialBias = null;
|
||
|
public int perspectivesCount = 0;
|
||
|
|
||
|
[Range(1, 4)]
|
||
|
public int normalWeightResolutionReduction = 1;
|
||
|
|
||
|
private bool m_useTextureAtlas = false;
|
||
|
public bool useTextureAtlas
|
||
|
{
|
||
|
set{ m_useTextureAtlas = value; }
|
||
|
}
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
[HideInInspector]
|
||
|
public bool[] showPerspectiveGizmo = null;
|
||
|
|
||
|
protected override void OnAssemblyReload()
|
||
|
{
|
||
|
base.OnAssemblyReload();
|
||
|
EnsureSyncedBuffers();
|
||
|
EnsurePerPerspectiveBuffer(ref overrideRadialBias, clip.metadata.perspectivesCount, false);
|
||
|
EnsurePerPerspectiveBuffer(ref showPerspectiveGizmo, clip.metadata.perspectivesCount, false);
|
||
|
perspectivesCount = clip.metadata.perspectivesCount;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
public override string DataSourceName()
|
||
|
{
|
||
|
return "Depthkit Studio Mesh Source";
|
||
|
}
|
||
|
|
||
|
private string GetScaledKernelName(string baseName)
|
||
|
{
|
||
|
if (SystemInfo.maxComputeWorkGroupSize >= 16 * 16 && SystemInfo.maxComputeWorkGroupSizeX >= 16 && SystemInfo.maxComputeWorkGroupSizeY >= 16)
|
||
|
{
|
||
|
return baseName + "16x16";
|
||
|
}
|
||
|
|
||
|
if (SystemInfo.maxComputeWorkGroupSize >= 8 * 8 && SystemInfo.maxComputeWorkGroupSizeX >= 8 && SystemInfo.maxComputeWorkGroupSizeY >= 8)
|
||
|
{
|
||
|
return baseName + "8x8";
|
||
|
}
|
||
|
|
||
|
return baseName + "4x4";
|
||
|
}
|
||
|
|
||
|
private string GetExtractVolumeKernelName()
|
||
|
{
|
||
|
string baseName = "ExtractSurfaceFromVolume";
|
||
|
|
||
|
if (m_useTextureAtlas)
|
||
|
{
|
||
|
baseName += "WithUVs";
|
||
|
}
|
||
|
|
||
|
if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.IPhonePlayer)
|
||
|
{
|
||
|
return baseName + "4x4x4";
|
||
|
}
|
||
|
|
||
|
return baseName + "8x8x8";
|
||
|
}
|
||
|
|
||
|
protected override void OnAwake()
|
||
|
{
|
||
|
if (SystemInfo.maxComputeWorkGroupSize < 8 * 8 * 8)
|
||
|
{
|
||
|
Debug.LogError("This platform cannot support Depthkit Studio. Max compute work group size too small: " + SystemInfo.maxComputeWorkGroupSize);
|
||
|
}
|
||
|
base.OnAwake();
|
||
|
}
|
||
|
|
||
|
public override bool OnSetup()
|
||
|
{
|
||
|
Util.EnsureComputeShader(ref m_generateVolumeCompute, "Shaders/DataSource/GenerateVolume", "Depthkit Studio Mesh Source Generate Volume Compute");
|
||
|
Util.EnsureComputeShader(ref m_extractSurfaceCompute, "Shaders/DataSource/ExtractSurfaceFromVolume", "Depthkit Studio Mesh Source Extract Surface Compute");
|
||
|
Util.EnsureComputeShader(ref m_generateVolumePreviewCompute, "Shaders/DataSource/GenerateVolumePreview", "Depthkit Studio Mesh Source Generate Volume Preview Compute");
|
||
|
Util.EnsureComputeShader(ref m_sdfFilterCompute, "Shaders/Util/GaussianBlurBuffer", "Depthkit Studio SDF Filter Compute");
|
||
|
Util.EnsureComputeShader(ref m_generateNormalWeightsCompute, "Shaders/DataSource/GenerateNormalWeights", "Depthkit Generate Normal Weights Compute");
|
||
|
|
||
|
if (m_halfBlitMaterial == null)
|
||
|
{
|
||
|
m_halfBlitMaterial = new Material(Shader.Find("Depthkit/HalfTextureBlit"));
|
||
|
}
|
||
|
|
||
|
if (m_normalWeightGenerationMaterial == null)
|
||
|
{
|
||
|
m_normalWeightGenerationMaterial = new Material(Shader.Find("Depthkit/GenerateNormalWeights"));
|
||
|
}
|
||
|
|
||
|
m_generateVolumeSinglePassKId = m_generateVolumeCompute.FindKernel("GenerateVolumeSinglePass");
|
||
|
|
||
|
m_generateVolumeMultiPassInitKId = m_generateVolumeCompute.FindKernel("KGenerateVolumeMultiPassInit");
|
||
|
m_generateVolumeMultiPassAccumulateKId = m_generateVolumeCompute.FindKernel("KGenerateVolumeMultiPassAccumulate");
|
||
|
m_generateVolumeMultiPassResolveKId = m_generateVolumeCompute.FindKernel("KGenerateVolumeMultiPassResolve");
|
||
|
|
||
|
m_generateVolumePreviewKId = m_generateVolumePreviewCompute.FindKernel("GenerateVolumePreview");
|
||
|
|
||
|
uint sizeX, sizeY, sizeZ;
|
||
|
|
||
|
m_generateVolumeCompute.GetKernelThreadGroupSizes(m_generateVolumeSinglePassKId, out sizeX, out sizeY, out sizeZ);
|
||
|
m_generateVolumeKernelGroupSize = (int)sizeX;
|
||
|
|
||
|
EnsureMaskGenerator();
|
||
|
|
||
|
|
||
|
return base.OnSetup();
|
||
|
}
|
||
|
protected void ResetGPUResources()
|
||
|
{
|
||
|
triangleBuffer.SetCounterValue(0u); // clear our append count buffer for number of iso surface vertices emmited
|
||
|
}
|
||
|
|
||
|
protected override void AcquireResources()
|
||
|
{
|
||
|
if (Depthkit.Util.EnsureComputeBuffer(ComputeBufferType.Default, ref m_triangleBuffer, m_triangleBufferSize, sizeof(int)))
|
||
|
{
|
||
|
m_triangleBuffer.SetData(triangleConnectionTable, 0, 0, m_triangleConnectionTableSize);
|
||
|
m_triangleBuffer.SetData(triangleOffsets, 0, m_triangleConnectionTableSize, m_triangleOffsetsSize);
|
||
|
m_triangleBuffer.SetData(nrOfTriangles, 0, m_triangleConnectionTableSize + m_triangleOffsetsSize, m_numberOfTrianglesSize);
|
||
|
}
|
||
|
|
||
|
base.AcquireResources();
|
||
|
|
||
|
if (m_clip)
|
||
|
{
|
||
|
m_clip.newMetadata += OnNewMetadata;
|
||
|
}
|
||
|
|
||
|
if (!m_clip.isSetup || m_clip.metadata.textureWidth == 0 || m_clip.metadata.textureHeight == 0) return;
|
||
|
EnsureSyncedBuffers();
|
||
|
EnsureTextures();
|
||
|
EnsureBuffers();
|
||
|
|
||
|
EnsurePerPerspectiveBuffer(ref overrideRadialBias, clip.metadata.perspectivesCount, false);
|
||
|
perspectivesCount = clip.metadata.perspectivesCount;
|
||
|
|
||
|
}
|
||
|
|
||
|
protected override void FreeResources()
|
||
|
{
|
||
|
if (m_clip)
|
||
|
{
|
||
|
m_clip.newMetadata -= OnNewMetadata;
|
||
|
}
|
||
|
|
||
|
if (m_sdfBuffers != null)
|
||
|
{
|
||
|
Util.ReleaseComputeBuffer(ref m_sdfBuffers[0]);
|
||
|
Util.ReleaseComputeBuffer(ref m_sdfBuffers[1]);
|
||
|
m_sdfBuffers = null;
|
||
|
}
|
||
|
|
||
|
Util.ReleaseComputeBuffer(ref m_pointsBuffer);
|
||
|
Util.ReleaseComputeBuffer(ref m_triangleBuffer);
|
||
|
|
||
|
perspectiveColorBlendingData.Release();
|
||
|
perspectiveGeometryData.Release();
|
||
|
|
||
|
Util.ReleaseRenderTexture(ref m_normalWeightTexture);
|
||
|
maskGenerator?.Release();
|
||
|
|
||
|
overrideRadialBias = null;
|
||
|
perspectivesCount = 0;
|
||
|
base.FreeResources();
|
||
|
}
|
||
|
|
||
|
internal void EnsureBuffers()
|
||
|
{
|
||
|
if (m_sdfBuffers == null)
|
||
|
{
|
||
|
m_sdfBuffers = new ComputeBuffer[2];
|
||
|
}
|
||
|
|
||
|
if (m_totalVoxelCount == 0) return;
|
||
|
|
||
|
if (Depthkit.Util.EnsureComputeBuffer(ComputeBufferType.Default, ref m_sdfBuffers[0], m_totalVoxelCount, sizeof(float)))
|
||
|
{
|
||
|
m_sdfBuffers[0].name = "Depthkit Studio SDF Buffer 0";
|
||
|
}
|
||
|
if (Depthkit.Util.EnsureComputeBuffer(ComputeBufferType.Default, ref m_sdfBuffers[1], m_totalVoxelCount, sizeof(float)))
|
||
|
{
|
||
|
m_sdfBuffers[1].name = "Depthkit Studio SDF Buffer 1";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void EnsureTextures()
|
||
|
{
|
||
|
if (Util.EnsureRenderTexture(ref m_normalWeightTexture, Math.Max(clip.metadata.textureWidth / normalWeightResolutionReduction, 1), Math.Max(clip.metadata.textureHeight / 2 / normalWeightResolutionReduction, 1), RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear, false, FilterMode.Bilinear))
|
||
|
{
|
||
|
m_normalWeightTexture.name = "Depthkit Studio Normal Weights Texture";
|
||
|
m_normalWeightTextureTexelSize = new Vector4(1.0f / m_normalWeightTexture.width, 1.0f / m_normalWeightTexture.height, m_normalWeightTexture.width, m_normalWeightTexture.height);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void EnsurePerPerspectiveBuffer<T>(ref T[] buffer, int expectedSize, T defaultValue)
|
||
|
{
|
||
|
if (buffer == null || buffer.Length != expectedSize)
|
||
|
{
|
||
|
buffer = new T[expectedSize];
|
||
|
for (int i = 0; i < expectedSize; ++i)
|
||
|
{
|
||
|
buffer[i] = defaultValue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void EnsureSyncedBuffers()
|
||
|
{
|
||
|
if (perspectiveGeometryData == null || perspectiveGeometryData.Length != clip.metadata.perspectivesCount)
|
||
|
{
|
||
|
perspectiveGeometryData = new PerspectiveGeometryData("Depthkit Per Perspective Geometry Data", clip.metadata.perspectivesCount);
|
||
|
}
|
||
|
|
||
|
if (perspectiveColorBlendingData == null || perspectiveColorBlendingData.Length != clip.metadata.perspectivesCount)
|
||
|
{
|
||
|
perspectiveColorBlendingData = new PerspectiveColorBlendingData("Depthkit Per Perspective Color Blending Data", clip.metadata.perspectivesCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void SetupViewDependence()
|
||
|
{
|
||
|
if (volumeViewpoint == null && Camera.main != null)
|
||
|
{
|
||
|
volumeViewpoint = Camera.main.transform; //use main camera by default
|
||
|
}
|
||
|
|
||
|
for (int perspectiveIndex = 0; perspectiveIndex < clip.metadata.perspectivesCount; ++perspectiveIndex)
|
||
|
{
|
||
|
float viewWeight = 1.0f;
|
||
|
if (enableViewDependentGeometry)
|
||
|
{
|
||
|
Vector3 cameraNormal = transform.localToWorldMatrix * clip.metadata.perspectives[perspectiveIndex].cameraNormal;
|
||
|
viewWeight = Mathf.Max(Vector3.Dot(volumeViewpoint.transform.forward, cameraNormal), 0.0001f);
|
||
|
|
||
|
float power;
|
||
|
if (perspectiveGeometryData.MatchViewDependentColorWeight(perspectiveIndex))
|
||
|
{
|
||
|
power = Mathf.Lerp(0.0f, globalViewDependentColorBlendWeight, perspectiveColorBlendingData.GetViewDependentColorBlendContribution(perspectiveIndex));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
power = Mathf.Lerp(0.0f, globalViewDependentGeometryBlendWeight, perspectiveGeometryData.GetViewDependentContribution(perspectiveIndex));
|
||
|
}
|
||
|
viewWeight = Mathf.Max(Mathf.Clamp01(Mathf.Pow(viewWeight, power)), 0.0001f);
|
||
|
}
|
||
|
perspectiveGeometryData.SetViewDependentWeight(perspectiveIndex, viewWeight);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected void OnNewMetadata()
|
||
|
{
|
||
|
|
||
|
// if the metatada is completely different (differing number of perspectives) or it contains defaultReconstructionSettings, reset the reconstruction settings, else leave them be
|
||
|
if (maskGenerator.sliceCount != clip.metadata.perspectivesCount || clip.metadata._versionMajor > 0 || (clip.metadata._versionMajor == 0 && m_clip.metadata._versionMinor > 4))
|
||
|
{
|
||
|
RangeAttribute range = Util.GetFieldRange(typeof(StudioMeshSource), nameof(surfaceNormalColorBlendingPower));
|
||
|
surfaceNormalColorBlendingPower = Mathf.Clamp(clip.metadata.defaultReconstructionSettings.surfaceNormalColorBlendPower, range.min, range.max);
|
||
|
range = Util.GetFieldRange(typeof(StudioMeshSource), nameof(globalViewDependentColorBlendWeight));
|
||
|
globalViewDependentColorBlendWeight = Mathf.Clamp(clip.metadata.defaultReconstructionSettings.viewDependentColorBlendPower, range.min, range.max);
|
||
|
|
||
|
radialBias = Util.metersToCm(clip.metadata.defaultReconstructionSettings.depthBiasAdjustment);
|
||
|
maskGenerator.blurRadius = clip.metadata.defaultReconstructionSettings.edgeMaskBlurAmount;
|
||
|
maskGenerator.sobelMultiplier = clip.metadata.defaultReconstructionSettings.edgeMaskSobelMultiplier;
|
||
|
}
|
||
|
|
||
|
if (maskGenerator.sliceCount != clip.metadata.perspectivesCount || (m_volumeBounds.center == Vector3.zero && m_volumeBounds.size == Vector3.one))
|
||
|
{
|
||
|
ResetVolumeBounds();
|
||
|
}
|
||
|
|
||
|
EnsureMaskGenerator();
|
||
|
|
||
|
enableEdgeMask = maskGenerator.blurRadius > float.Epsilon || maskGenerator.sobelMultiplier > float.Epsilon;
|
||
|
}
|
||
|
|
||
|
public void ResetVolumeBounds()
|
||
|
{
|
||
|
m_volumeBounds.center = clip.metadata.boundsCenter;
|
||
|
m_volumeBounds.size = clip.metadata.boundsSize;
|
||
|
}
|
||
|
|
||
|
public void ResetSurfaceSensitivity()
|
||
|
{
|
||
|
surfaceSensitivity = surfaceSensitivityDefault;
|
||
|
weightUnknown = weightUnknownDefault;
|
||
|
weightUnseenMax = weightUnseenMaxDefault;
|
||
|
weightUnseenMin = weightUnseenMinDefault;
|
||
|
weightUnseenFalloffPower = weightUnseenFalloffPowerDefault;
|
||
|
weightInFrontMax = weightInFrontMaxDefault;
|
||
|
weightInFrontMin = weightInFrontMinDefault;
|
||
|
for (int i = 0; i < radialBiasPersp.Length; ++i)
|
||
|
{
|
||
|
radialBiasPersp[i] = radialBias;
|
||
|
overrideRadialBias[i] = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void LoadFrontBiasedDefaults()
|
||
|
{
|
||
|
surfaceSensitivity = 0.2f;
|
||
|
weightUnknown = 0.005f;
|
||
|
weightUnseenMax = 1.0f;
|
||
|
weightUnseenMin = 0.0f;
|
||
|
weightUnseenFalloffPower = 8.0f;
|
||
|
weightInFrontMax = 1.0f;
|
||
|
weightInFrontMin = 0.1f;
|
||
|
}
|
||
|
|
||
|
protected override bool OnResize()
|
||
|
{
|
||
|
if (m_volumeBounds.center == Vector3.zero && m_volumeBounds.size == Vector3.zero)
|
||
|
{
|
||
|
m_volumeBounds.center = clip.metadata.boundsCenter;
|
||
|
m_volumeBounds.size = clip.metadata.boundsSize;
|
||
|
}
|
||
|
|
||
|
ReserveSubMeshes<PackedCoreTriangleSubMesh>(1);
|
||
|
|
||
|
CurrentSubMesh().Init();
|
||
|
|
||
|
//voxel size in meters
|
||
|
m_voxelGridDimensions = new Vector3Int((int)Mathf.Floor(m_volumeBounds.size.x * m_volumeDensity), (int)Mathf.Floor(m_volumeBounds.size.y * m_volumeDensity), (int)Mathf.Floor(m_volumeBounds.size.z * m_volumeDensity));
|
||
|
m_totalVoxelCount = m_voxelGridDimensions.x * m_voxelGridDimensions.y * m_voxelGridDimensions.z;
|
||
|
|
||
|
int smallestDim = Math.Min(Math.Min(m_voxelGridDimensions.x, m_voxelGridDimensions.y), m_voxelGridDimensions.z);
|
||
|
|
||
|
numLevelOfDetailLevels = (int)Math.Max(Math.Log(Convert.ToDouble((int)smallestDim), 2.0) - 4.0, 0.0);
|
||
|
|
||
|
if (!m_clip.isSetup || m_clip.metadata.textureWidth == 0 || m_clip.metadata.textureHeight == 0) return true;
|
||
|
EnsureSyncedBuffers();
|
||
|
EnsureBuffers();
|
||
|
if (enableEdgeMask)
|
||
|
{
|
||
|
EnsureMaskGenerator();
|
||
|
}
|
||
|
EnsureTextures();
|
||
|
EnsurePerPerspectiveBuffer(ref overrideRadialBias, clip.metadata.perspectivesCount, false);
|
||
|
perspectivesCount = clip.metadata.perspectivesCount;
|
||
|
#if UNITY_EDITOR
|
||
|
EnsurePerPerspectiveBuffer(ref showPerspectiveGizmo, clip.metadata.perspectivesCount, false);
|
||
|
#endif
|
||
|
return base.OnResize();
|
||
|
}
|
||
|
|
||
|
static class StudioMeshSourceShaderIds
|
||
|
{
|
||
|
/////////////// Look Uniforms /////////////////
|
||
|
internal static readonly int _GlobalViewDependentColorBlendWeight = Shader.PropertyToID("_GlobalViewDependentColorBlendWeight");
|
||
|
internal static readonly int _SurfaceNormalColorBlendingPower = Shader.PropertyToID("_SurfaceNormalColorBlendingPower");
|
||
|
internal static readonly int _PerViewDisparityThreshold = Shader.PropertyToID("_PerViewDisparityThreshold");
|
||
|
internal static readonly int _PerViewDisparityBlendWidth = Shader.PropertyToID("_PerViewDisparityBlendWidth");
|
||
|
internal static readonly int _PerspectiveColorBlending = Shader.PropertyToID("_PerspectiveColorBlending");
|
||
|
internal static readonly int _UntexturedFragDefaultColor = Shader.PropertyToID("_UntexturedFragDefaultColor");
|
||
|
internal static readonly string _UntexturedFragmentInfer = "DK_UNTEXTURED_FRAGMENT_INFER";
|
||
|
internal static readonly string _UntexturedFragmentColorize = "DK_UNTEXTURED_FRAGMENT_COLORIZE";
|
||
|
internal static readonly string _UntexturedFragmentClip = "DK_UNTEXTURED_FRAGMENT_CLIP";
|
||
|
|
||
|
/////////////// SdfCompute Uniforms ///////////////////
|
||
|
|
||
|
internal static readonly int _SdfBuffer = Shader.PropertyToID("_SdfBuffer");
|
||
|
internal static readonly int _SdfWeightBuffer = Shader.PropertyToID("_SdfWeightBuffer");
|
||
|
internal static readonly int _VoxelGridX = Shader.PropertyToID("_VoxelGridX");
|
||
|
internal static readonly int _VoxelGridY = Shader.PropertyToID("_VoxelGridY");
|
||
|
internal static readonly int _VoxelGridZ = Shader.PropertyToID("_VoxelGridZ");
|
||
|
internal static readonly int _VoxelGridf = Shader.PropertyToID("_VoxelGridf");
|
||
|
internal static readonly int _BoundsSize = Shader.PropertyToID("_BoundsSize");
|
||
|
internal static readonly int _BoundsCenter = Shader.PropertyToID("_BoundsCenter");
|
||
|
internal static readonly int _IsoLODScalar = Shader.PropertyToID("_IsoLODScalar");
|
||
|
internal static readonly int _SdfSensitivity = Shader.PropertyToID("_SdfSensitivity");
|
||
|
internal static readonly int _WeightUnknown = Shader.PropertyToID("_WeightUnknown");
|
||
|
internal static readonly int _WeightUnseenMax = Shader.PropertyToID("_WeightUnseenMax");
|
||
|
internal static readonly int _WeightUnseenMin = Shader.PropertyToID("_WeightUnseenMin");
|
||
|
internal static readonly int _WeightUnseenFalloffPower = Shader.PropertyToID("_WeightUnseenFalloffPower");
|
||
|
internal static readonly int _WeightInFrontMax = Shader.PropertyToID("_WeightInFrontMax");
|
||
|
internal static readonly int _WeightInFrontMin = Shader.PropertyToID("_WeightInFrontMin");
|
||
|
internal static readonly int _NormalTexture = Shader.PropertyToID("_NormalTexture");
|
||
|
internal static readonly int _NormalTexture_TexelSize = Shader.PropertyToID("_NormalTexture_TexelSize");
|
||
|
internal static readonly int _NormalWeights = Shader.PropertyToID("_NormalWeights");
|
||
|
internal static readonly int _PerspectiveGeometryData = Shader.PropertyToID("_PerspectiveGeometryData");
|
||
|
internal static readonly int _WSDepth = Shader.PropertyToID("_WSDepth");
|
||
|
internal static readonly int _CurrentPerspective = Shader.PropertyToID("_CurrentPerspective");
|
||
|
internal static readonly int _DispatchSize = Shader.PropertyToID("_DispatchSize");
|
||
|
|
||
|
/////////////// Edge Mask Uniforms ///////////////////
|
||
|
internal static readonly int _MainTex = Shader.PropertyToID("_MainTex");
|
||
|
|
||
|
/////////////// Debug Uniforms ///////////////////
|
||
|
internal static readonly int _Points = Shader.PropertyToID("_Points");
|
||
|
internal static readonly int _SdfAlpha = Shader.PropertyToID("_SdfAlpha");
|
||
|
internal static readonly int _PointSize = Shader.PropertyToID("_PointSize");
|
||
|
internal static readonly int _LocalToWorldMatrix = Shader.PropertyToID("_LocalToWorldMatrix");
|
||
|
|
||
|
/////////////// Gaussian Blur Uniforms ///////////////////
|
||
|
internal static readonly int _PingData = Shader.PropertyToID("_PingData");
|
||
|
internal static readonly int _PongData = Shader.PropertyToID("_PongData");
|
||
|
internal static readonly int _DataSize = Shader.PropertyToID("_DataSize");
|
||
|
internal static readonly int _Axis = Shader.PropertyToID("_Axis");
|
||
|
internal static readonly int _PowerAmount = Shader.PropertyToID("_PowerAmount");
|
||
|
internal static readonly int _GaussianNormalization = Shader.PropertyToID("_GaussianNormalization");
|
||
|
internal static readonly int _GaussianExponential = Shader.PropertyToID("_GaussianExponential");
|
||
|
|
||
|
/////////////// IsoCompute Uniforms ///////////////////
|
||
|
internal static readonly int _TriangleDataBuffer = Shader.PropertyToID("_TriangleDataBuffer");
|
||
|
internal static readonly int _SdfThreshold = Shader.PropertyToID("_SdfThreshold");
|
||
|
internal static readonly int _TriangleBuffer = Shader.PropertyToID("_TriangleBuffer");
|
||
|
internal static readonly int _TriangleCullingThreshold = Shader.PropertyToID("_TriangleCullingThreshold");
|
||
|
public static readonly int
|
||
|
_IndirectArgs = Shader.PropertyToID("_IndirectArgs");
|
||
|
}
|
||
|
|
||
|
#region IPropertyTransfer
|
||
|
public override void SetProperties(ref Material material)
|
||
|
{
|
||
|
EnsureTextures();
|
||
|
perspectiveColorBlendingData.Sync();
|
||
|
material.SetFloat(StudioMeshSourceShaderIds._GlobalViewDependentColorBlendWeight, globalViewDependentColorBlendWeight);
|
||
|
material.SetBuffer(StudioMeshSourceShaderIds._PerspectiveColorBlending, perspectiveColorBlendingData.buffer);
|
||
|
material.SetFloat(StudioMeshSourceShaderIds._SurfaceNormalColorBlendingPower, surfaceNormalColorBlendingPower);
|
||
|
material.SetFloat(StudioMeshSourceShaderIds._PerViewDisparityThreshold, perViewDisparityThreshold);
|
||
|
material.SetFloat(StudioMeshSourceShaderIds._PerViewDisparityBlendWidth, perViewDisparityBlendWidth);
|
||
|
material.SetVector(StudioMeshSourceShaderIds._UntexturedFragDefaultColor, new Vector3(untexturedColor.r, untexturedColor.g, untexturedColor.b));
|
||
|
Util.EnsureKeyword(ref material, StudioMeshSourceShaderIds._UntexturedFragmentInfer, untexturedFragmentSetting == UntexturedGeometrySettings.Infer);
|
||
|
Util.EnsureKeyword(ref material, StudioMeshSourceShaderIds._UntexturedFragmentColorize, untexturedFragmentSetting == UntexturedGeometrySettings.Colorize);
|
||
|
Util.EnsureKeyword(ref material, StudioMeshSourceShaderIds._UntexturedFragmentClip, untexturedFragmentSetting == UntexturedGeometrySettings.Clip);
|
||
|
|
||
|
if (enableEdgeMask)
|
||
|
maskGenerator.SetProperties(ref material);
|
||
|
else
|
||
|
Util.EnsureKeyword(ref material, MaskGenerator.MaskGeneratorShaderIds._UseEdgeMask, enableEdgeMask);
|
||
|
|
||
|
base.SetProperties(ref material);
|
||
|
}
|
||
|
|
||
|
public override void SetProperties(ref Material material, ref MaterialPropertyBlock block)
|
||
|
{
|
||
|
EnsureTextures();
|
||
|
perspectiveColorBlendingData.Sync();
|
||
|
block.SetFloat(StudioMeshSourceShaderIds._GlobalViewDependentColorBlendWeight, globalViewDependentColorBlendWeight);
|
||
|
block.SetBuffer(StudioMeshSourceShaderIds._PerspectiveColorBlending, perspectiveColorBlendingData.buffer);
|
||
|
block.SetFloat(StudioMeshSourceShaderIds._SurfaceNormalColorBlendingPower, surfaceNormalColorBlendingPower);
|
||
|
block.SetFloat(StudioMeshSourceShaderIds._PerViewDisparityThreshold, perViewDisparityThreshold);
|
||
|
block.SetFloat(StudioMeshSourceShaderIds._PerViewDisparityBlendWidth, perViewDisparityBlendWidth);
|
||
|
block.SetVector(StudioMeshSourceShaderIds._UntexturedFragDefaultColor, new Vector3(untexturedColor.r, untexturedColor.g, untexturedColor.b));
|
||
|
Util.EnsureKeyword(ref material, StudioMeshSourceShaderIds._UntexturedFragmentInfer, untexturedFragmentSetting == UntexturedGeometrySettings.Infer);
|
||
|
Util.EnsureKeyword(ref material, StudioMeshSourceShaderIds._UntexturedFragmentColorize, untexturedFragmentSetting == UntexturedGeometrySettings.Colorize);
|
||
|
Util.EnsureKeyword(ref material, StudioMeshSourceShaderIds._UntexturedFragmentClip, untexturedFragmentSetting == UntexturedGeometrySettings.Clip);
|
||
|
|
||
|
if(enableEdgeMask)
|
||
|
maskGenerator.SetProperties(ref material, ref block);
|
||
|
else
|
||
|
Util.EnsureKeyword(ref material, MaskGenerator.MaskGeneratorShaderIds._UseEdgeMask, enableEdgeMask);
|
||
|
base.SetProperties(ref material, ref block);
|
||
|
}
|
||
|
|
||
|
public override void SetProperties(ref ComputeShader compute, int kernel)
|
||
|
{
|
||
|
EnsureTextures();
|
||
|
perspectiveColorBlendingData.Sync();
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._GlobalViewDependentColorBlendWeight, globalViewDependentColorBlendWeight);
|
||
|
compute.SetBuffer(kernel, StudioMeshSourceShaderIds._PerspectiveColorBlending, perspectiveColorBlendingData.buffer);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._SurfaceNormalColorBlendingPower, surfaceNormalColorBlendingPower);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._PerViewDisparityThreshold, perViewDisparityThreshold);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._PerViewDisparityBlendWidth, perViewDisparityBlendWidth);
|
||
|
|
||
|
if (enableEdgeMask)
|
||
|
maskGenerator.SetProperties(ref compute, kernel);
|
||
|
|
||
|
//todo there are no shaderkeywords for compute shaders yet
|
||
|
base.SetProperties(ref compute, kernel);
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
internal void SetCommonComputeProperties(ComputeShader compute, int kernel)
|
||
|
{
|
||
|
// LOD example -
|
||
|
// LOD 0 top level occupies whole voxel grid
|
||
|
// LOD 1 top level occupies top left octant only - skip histo-pyramid level 1 as is same level as top level
|
||
|
// LOD 2 top level occupies half top left octant - skip histo pyramid levels 1 & 2
|
||
|
// LOD 3 top level occupies quarter top left octant - skip histo pyramid levels 1, 2 & 3
|
||
|
|
||
|
compute.SetInt(StudioMeshSourceShaderIds._VoxelGridX, m_voxelGridDimensions.x);
|
||
|
compute.SetInt(StudioMeshSourceShaderIds._VoxelGridY, m_voxelGridDimensions.y);
|
||
|
compute.SetInt(StudioMeshSourceShaderIds._VoxelGridZ, m_voxelGridDimensions.z);
|
||
|
compute.SetVector(StudioMeshSourceShaderIds._VoxelGridf, new Vector3(m_voxelGridDimensions.x, m_voxelGridDimensions.y, m_voxelGridDimensions.z));
|
||
|
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._IsoLODScalar, m_currentLODIsoScalar);
|
||
|
compute.SetVector(StudioMeshSourceShaderIds._BoundsSize, volumeBounds.size);
|
||
|
compute.SetVector(StudioMeshSourceShaderIds._BoundsCenter, volumeBounds.center);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._SdfSensitivity, surfaceSensitivity);
|
||
|
if(radialBiasPerspInMeters != null)
|
||
|
compute.SetVectorArray(MeshSourceShaderIds._RadialBiasPerspInMeters, radialBiasPerspInMeters);
|
||
|
compute.SetBuffer(kernel, StudioMeshSourceShaderIds._SdfBuffer, m_sdfBuffers[m_currentSdfBuffer]);
|
||
|
compute.SetTexture(kernel, StudioMeshSourceShaderIds._NormalTexture, m_normalWeightTexture);
|
||
|
compute.SetVector(StudioMeshSourceShaderIds._NormalTexture_TexelSize, m_normalWeightTextureTexelSize);
|
||
|
}
|
||
|
|
||
|
internal void SetVolumeGenerationPassProperties(ComputeShader compute, int kernel)
|
||
|
{
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._WeightUnknown, weightUnknown);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._WeightUnseenMax, weightUnseenMax);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._WeightUnseenMin, weightUnseenMin);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._WeightUnseenFalloffPower, weightUnseenFalloffPower);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._WeightInFrontMax, weightInFrontMax);
|
||
|
compute.SetFloat(StudioMeshSourceShaderIds._WeightInFrontMin, weightInFrontMin);
|
||
|
|
||
|
compute.SetTexture(kernel, StudioMeshSourceShaderIds._NormalTexture, m_normalWeightTexture);
|
||
|
compute.SetVector(StudioMeshSourceShaderIds._NormalTexture_TexelSize, m_normalWeightTextureTexelSize);
|
||
|
|
||
|
compute.SetBuffer(kernel, StudioMeshSourceShaderIds._PerspectiveGeometryData, perspectiveGeometryData.buffer);
|
||
|
}
|
||
|
|
||
|
private void FilterSdf(Vector3Int dispatchSize)
|
||
|
{
|
||
|
int pong = (m_currentSdfBuffer + 1) % 2;
|
||
|
// pre compute gaussian parameters based on current sigma
|
||
|
double sigmaSq = surfaceSmoothingRadius * surfaceSmoothingRadius;
|
||
|
double sigmaSq2 = sigmaSq * 2.0f;
|
||
|
float gaussianNormalization = (float)(1.0 / Math.Sqrt(Math.PI * sigmaSq2)); // gaussian normalization coefficient
|
||
|
float gaussianExponential = (float)(-1.0 / sigmaSq2); // gaussian exponential coefficient
|
||
|
int kernelSize = (int)(Math.Ceiling(Math.PI * sigmaSq)); // compute the kernel size based on the sigma parameter
|
||
|
|
||
|
m_sdfFilterCompute.SetFloat(StudioMeshSourceShaderIds._GaussianNormalization, gaussianNormalization);
|
||
|
m_sdfFilterCompute.SetFloat(StudioMeshSourceShaderIds._GaussianExponential, gaussianExponential);
|
||
|
|
||
|
m_sdfFilterCompute.SetVector(StudioMeshSourceShaderIds._DataSize, new Vector3(m_voxelGridDimensions.x, m_voxelGridDimensions.y, m_voxelGridDimensions.z));
|
||
|
|
||
|
int kernelIndex = kernelSize - 1;
|
||
|
|
||
|
// 3 pass 1D gaussian approximates 3D gaussian kernel
|
||
|
// x axis
|
||
|
m_sdfFilterCompute.SetBuffer(kernelIndex, StudioMeshSourceShaderIds._PingData, m_sdfBuffers[m_currentSdfBuffer]);
|
||
|
m_sdfFilterCompute.SetBuffer(kernelIndex, StudioMeshSourceShaderIds._PongData, m_sdfBuffers[pong]);
|
||
|
m_sdfFilterCompute.SetVector(StudioMeshSourceShaderIds._Axis, new Vector3(1, 0, 0));
|
||
|
m_sdfFilterCompute.Dispatch(kernelIndex, dispatchSize.x, dispatchSize.y, dispatchSize.z);
|
||
|
|
||
|
// y axis
|
||
|
m_sdfFilterCompute.SetBuffer(kernelIndex, StudioMeshSourceShaderIds._PingData, m_sdfBuffers[pong]);
|
||
|
m_sdfFilterCompute.SetBuffer(kernelIndex, StudioMeshSourceShaderIds._PongData, m_sdfBuffers[m_currentSdfBuffer]);
|
||
|
m_sdfFilterCompute.SetVector(StudioMeshSourceShaderIds._Axis, new Vector3(0, 1, 0));
|
||
|
m_sdfFilterCompute.Dispatch(kernelIndex, dispatchSize.x, dispatchSize.y, dispatchSize.z);
|
||
|
|
||
|
// z axis
|
||
|
m_sdfFilterCompute.SetBuffer(kernelIndex, StudioMeshSourceShaderIds._PingData, m_sdfBuffers[m_currentSdfBuffer]);
|
||
|
m_sdfFilterCompute.SetBuffer(kernelIndex, StudioMeshSourceShaderIds._PongData, m_sdfBuffers[pong]);
|
||
|
m_sdfFilterCompute.SetVector(StudioMeshSourceShaderIds._Axis, new Vector3(0, 0, 1));
|
||
|
m_sdfFilterCompute.Dispatch(kernelIndex, dispatchSize.x, dispatchSize.y, dispatchSize.z);
|
||
|
|
||
|
m_currentSdfBuffer = pong;
|
||
|
}
|
||
|
|
||
|
//todo keep this function for performance testing and possible older platforms
|
||
|
private void GenerateNormalWeights()
|
||
|
{
|
||
|
clip.SetProperties(ref m_normalWeightGenerationMaterial);
|
||
|
if (radialBiasPerspInMeters != null)
|
||
|
m_normalWeightGenerationMaterial.SetVectorArray(MeshSourceShaderIds._RadialBiasPerspInMeters, radialBiasPerspInMeters);
|
||
|
m_normalWeightGenerationMaterial.SetVector(StudioMeshSourceShaderIds._NormalTexture_TexelSize, m_normalWeightTextureTexelSize);
|
||
|
Graphics.Blit(clip.cppTexture, m_normalWeightTexture, m_normalWeightGenerationMaterial, 0);
|
||
|
}
|
||
|
|
||
|
private void GenerateNormalWeightsCompute()
|
||
|
{
|
||
|
m_normalWeightKId = m_generateNormalWeightsCompute.FindKernel(GetScaledKernelName("GeneratePerPixelNormalWeights"));
|
||
|
|
||
|
if (m_normalWeightKId == -1)
|
||
|
{
|
||
|
Debug.LogError("GeneratePerPixelNormalWeights kernel not found");
|
||
|
}
|
||
|
|
||
|
clip.SetProperties(ref m_generateNormalWeightsCompute, m_normalWeightKId);
|
||
|
m_generateNormalWeightsCompute.SetVector(StudioMeshSourceShaderIds._NormalTexture_TexelSize, m_normalWeightTextureTexelSize);
|
||
|
m_generateNormalWeightsCompute.SetTexture(m_normalWeightKId, StudioMeshSourceShaderIds._NormalWeights, m_normalWeightTexture);
|
||
|
if (radialBiasPerspInMeters != null)
|
||
|
m_generateNormalWeightsCompute.SetVectorArray(MeshSourceShaderIds._RadialBiasPerspInMeters, radialBiasPerspInMeters);
|
||
|
|
||
|
Util.DispatchGroups(m_generateNormalWeightsCompute, m_normalWeightKId, m_normalWeightTexture.width, m_normalWeightTexture.height, 1);
|
||
|
}
|
||
|
|
||
|
private void GenerateEdgeBlendMask()
|
||
|
{
|
||
|
if (enableEdgeMask)
|
||
|
{
|
||
|
maskGenerator.GenerateMask();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private Vector3Int DispatchSize(int kernelGroupSize)
|
||
|
{
|
||
|
Vector3 gridf = new Vector3(m_voxelGridDimensions.x, m_voxelGridDimensions.y, m_voxelGridDimensions.z);
|
||
|
Vector3 dispatchSizef = (gridf / kernelGroupSize) / m_currentLODIsoScalar;
|
||
|
return new Vector3Int((int)Mathf.Ceil(dispatchSizef.x), (int)Mathf.Ceil(dispatchSizef.y), (int)Mathf.Ceil(dispatchSizef.z));
|
||
|
}
|
||
|
|
||
|
void GenerateVolumePass(Vector3Int dispatchSize, int kernel)
|
||
|
{
|
||
|
SetCommonComputeProperties(m_generateVolumeCompute, kernel);
|
||
|
SetVolumeGenerationPassProperties(m_generateVolumeCompute, kernel);
|
||
|
clip.SetProperties(ref m_generateVolumeCompute, kernel);
|
||
|
m_generateVolumeCompute.Dispatch(kernel, dispatchSize.x, dispatchSize.y, dispatchSize.z);
|
||
|
}
|
||
|
|
||
|
private void GenerateVolume()
|
||
|
{
|
||
|
EnsureTextures();
|
||
|
GenerateNormalWeightsCompute();
|
||
|
GenerateEdgeBlendMask();
|
||
|
|
||
|
SetupViewDependence();
|
||
|
|
||
|
perspectiveGeometryData.Sync();
|
||
|
|
||
|
switch (generationMethod)
|
||
|
{
|
||
|
case VolumeGenerationMethod.SinglePass:
|
||
|
GenerateVolumeSinglePass();
|
||
|
break;
|
||
|
case VolumeGenerationMethod.MultiPass:
|
||
|
GenerateVolumeMultiPass(m_generateVolumeMultiPassInitKId, m_generateVolumeMultiPassAccumulateKId, m_generateVolumeMultiPassResolveKId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
List<int> ActivePerspectives()
|
||
|
{
|
||
|
List<int> activePerspectives = new List<int>();
|
||
|
for (int perspective = 0; perspective < m_clip.metadata.perspectivesCount; ++perspective)
|
||
|
{
|
||
|
if (perspectiveGeometryData.EnableGeometry(perspective))
|
||
|
{
|
||
|
activePerspectives.Add(perspective);
|
||
|
}
|
||
|
}
|
||
|
return activePerspectives;
|
||
|
}
|
||
|
|
||
|
private void GenerateVolumeMultiPass(int kInit, int kAccum, int kResolve)
|
||
|
{
|
||
|
if (kInit == -1)
|
||
|
{
|
||
|
Debug.LogError("Init Kernel Index not found");
|
||
|
}
|
||
|
if (kAccum == -1)
|
||
|
{
|
||
|
Debug.LogError("Accumulate Kernel Index not found");
|
||
|
}
|
||
|
if (kResolve == -1)
|
||
|
{
|
||
|
Debug.LogError("Resolve Kernel Index not found");
|
||
|
}
|
||
|
|
||
|
int weightsIndex = (m_currentSdfBuffer + 1) % 2;
|
||
|
//they should all have the same dispatch size
|
||
|
var dispatchSize = DispatchSize(8);
|
||
|
var activePerspectives = ActivePerspectives();
|
||
|
|
||
|
for (int perspective = 0; perspective < activePerspectives.Count; ++perspective)
|
||
|
{
|
||
|
m_generateVolumeCompute.SetInt(StudioMeshSourceShaderIds._CurrentPerspective, activePerspectives[perspective]);
|
||
|
|
||
|
if (perspective == 0)
|
||
|
{
|
||
|
m_generateVolumeCompute.SetBuffer(kInit, StudioMeshSourceShaderIds._SdfWeightBuffer, m_sdfBuffers[weightsIndex]);
|
||
|
GenerateVolumePass(dispatchSize, kInit);
|
||
|
}
|
||
|
else if (perspective == activePerspectives.Count - 1)
|
||
|
{
|
||
|
m_generateVolumeCompute.SetBuffer(kResolve, StudioMeshSourceShaderIds._SdfWeightBuffer, m_sdfBuffers[weightsIndex]);
|
||
|
GenerateVolumePass(dispatchSize, kResolve);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_generateVolumeCompute.SetBuffer(kAccum, StudioMeshSourceShaderIds._SdfWeightBuffer, m_sdfBuffers[weightsIndex]);
|
||
|
GenerateVolumePass(dispatchSize, kAccum);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (enableSurfaceSmoothing)
|
||
|
{
|
||
|
FilterSdf(dispatchSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void GenerateVolumeSinglePass()
|
||
|
{
|
||
|
if (m_generateVolumeSinglePassKId == -1)
|
||
|
{
|
||
|
Debug.LogError("GenerateVolumeSinglePass Kernel Index not found");
|
||
|
}
|
||
|
|
||
|
var dispatchSize = DispatchSize(m_generateVolumeKernelGroupSize);
|
||
|
|
||
|
GenerateVolumePass(dispatchSize, m_generateVolumeSinglePassKId);
|
||
|
|
||
|
if (enableSurfaceSmoothing)
|
||
|
{
|
||
|
FilterSdf(dispatchSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void ExtractSurfaceFromVolume()
|
||
|
{
|
||
|
m_extractSurfaceKId = m_extractSurfaceCompute.FindKernel(GetExtractVolumeKernelName());
|
||
|
m_extractSurfaceCompute.GetKernelThreadGroupSizes(m_extractSurfaceKId, out uint sizeX, out uint sizeY, out uint sizeZ);
|
||
|
m_extractSurfaceKernelGroupSize = (int)sizeX;
|
||
|
|
||
|
if (m_extractSurfaceKId == -1)
|
||
|
{
|
||
|
Debug.LogError("ExtractSurfaceFromVolume Kernel not found");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Vector3Int dispatchSize = DispatchSize(m_extractSurfaceKernelGroupSize);
|
||
|
|
||
|
SetCommonComputeProperties(m_extractSurfaceCompute, m_extractSurfaceKId);
|
||
|
clip.SetProperties(ref m_extractSurfaceCompute, m_extractSurfaceKId);
|
||
|
SetProperties(ref m_extractSurfaceCompute, m_extractSurfaceKId);
|
||
|
|
||
|
m_extractSurfaceCompute.SetFloat(StudioMeshSourceShaderIds._SdfThreshold, m_surfaceSensitivityThreshold);
|
||
|
m_extractSurfaceCompute.SetFloat(StudioMeshSourceShaderIds._TriangleCullingThreshold, Mathf.Pow(1.0f - 0.0f, 6.0f)); //TODO remove this?
|
||
|
m_extractSurfaceCompute.SetBuffer(m_extractSurfaceKId, StudioMeshSourceShaderIds._SdfBuffer, m_sdfBuffers[m_currentSdfBuffer]);
|
||
|
m_extractSurfaceCompute.SetBuffer(m_extractSurfaceKId, StudioMeshSourceShaderIds._TriangleBuffer, triangleBuffer);
|
||
|
m_extractSurfaceCompute.SetBuffer(m_extractSurfaceKId, StudioMeshSourceShaderIds._TriangleDataBuffer, m_triangleBuffer);
|
||
|
|
||
|
m_extractSurfaceCompute.Dispatch(m_extractSurfaceKId, dispatchSize.x, dispatchSize.y, dispatchSize.z);
|
||
|
}
|
||
|
|
||
|
private void DrawDebug()
|
||
|
{
|
||
|
if (m_sdfBuffers == null) return;
|
||
|
if (m_generateVolumePreviewCompute == null || m_sdfBuffers[m_currentSdfBuffer] == null)
|
||
|
{
|
||
|
Debug.LogError("sdf compute shader or sdf buffers are null");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (m_generateVolumePreviewKId == -1)
|
||
|
{
|
||
|
Debug.LogError("GenerateVolumePreview Kernel not found");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int kernelGroupSize = 8;
|
||
|
Vector3Int dispatchSize;
|
||
|
|
||
|
if (Depthkit.Util.EnsureComputeBuffer(ComputeBufferType.Default, ref m_pointsBuffer, m_totalVoxelCount, sizeof(float) * 3 + sizeof(float) * 4))
|
||
|
{
|
||
|
m_pointsBuffer.name = "Depthkit Studio Debug SDF Buffer";
|
||
|
}
|
||
|
dispatchSize = DispatchSize(kernelGroupSize);
|
||
|
SetCommonComputeProperties(m_generateVolumePreviewCompute, m_generateVolumePreviewKId);
|
||
|
m_generateVolumePreviewCompute.SetBuffer(m_generateVolumePreviewKId, StudioMeshSourceShaderIds._Points, m_pointsBuffer);
|
||
|
m_generateVolumePreviewCompute.SetMatrix(StudioMeshSourceShaderIds._LocalToWorldMatrix, transform.localToWorldMatrix);
|
||
|
m_generateVolumePreviewCompute.Dispatch(m_generateVolumePreviewKId, dispatchSize.x, dispatchSize.y, dispatchSize.z);
|
||
|
|
||
|
if (m_volumePreviewMaterial == null)
|
||
|
{
|
||
|
m_volumePreviewMaterial = new Material(Shader.Find("Depthkit/Studio/VolumePreview"));
|
||
|
}
|
||
|
|
||
|
m_volumePreviewMaterial.SetFloat(StudioMeshSourceShaderIds._SdfAlpha, volumePreviewAlpha);
|
||
|
m_volumePreviewMaterial.SetBuffer(StudioMeshSourceShaderIds._Points, m_pointsBuffer);
|
||
|
m_volumePreviewMaterial.SetFloat(StudioMeshSourceShaderIds._PointSize, volumePreviewPointSize);
|
||
|
m_volumePreviewMaterial.SetPass(0);
|
||
|
|
||
|
//scale back up by group size
|
||
|
Vector3Int scaledDims = dispatchSize * kernelGroupSize;
|
||
|
|
||
|
Graphics.DrawProcedural(
|
||
|
m_volumePreviewMaterial,
|
||
|
GetWorldBounds(),
|
||
|
MeshTopology.Points,
|
||
|
scaledDims.x * scaledDims.y * scaledDims.z,
|
||
|
1,
|
||
|
null,
|
||
|
null,
|
||
|
UnityEngine.Rendering.ShadowCastingMode.Off,
|
||
|
false,
|
||
|
gameObject.layer);
|
||
|
}
|
||
|
|
||
|
protected override bool OnGenerate()
|
||
|
{
|
||
|
if (clip.cppTexture == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//reset the clip, this is when a script is reloaded, invalidating all our buffers
|
||
|
if (m_sdfBuffers == null)
|
||
|
{
|
||
|
Setup();
|
||
|
if (!IsSetup()) return false;
|
||
|
Resize();
|
||
|
}
|
||
|
else if (m_sdfBuffers[m_currentSdfBuffer] == null || !m_sdfBuffers[m_currentSdfBuffer].IsValid())
|
||
|
{
|
||
|
Setup();
|
||
|
if (!IsSetup()) return false;
|
||
|
Resize();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
triangleBuffer?.SetCounterValue(0);
|
||
|
}
|
||
|
|
||
|
if (m_generateVolumeCompute == null || m_generateNormalWeightsCompute == null || m_extractSurfaceCompute == null)
|
||
|
{
|
||
|
Debug.LogWarning("Couldn't process: Studio Compute shader is null");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//force iso level to be within the rage of the current voxel size
|
||
|
m_currentLODLevel = (int)Math.Min(m_currentLODLevel, numLevelOfDetailLevels);
|
||
|
|
||
|
GenerateVolume();
|
||
|
if (!showVolumePreview)
|
||
|
{
|
||
|
ExtractSurfaceFromVolume();
|
||
|
}
|
||
|
|
||
|
base.OnGenerate();
|
||
|
|
||
|
ResetGPUResources();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
protected override void OnUpdate()
|
||
|
{
|
||
|
base.OnUpdate();
|
||
|
if(clip.isSetup && radialBiasPersp != null && radialBiasPerspInMeters != null)
|
||
|
{
|
||
|
// convert per perspective radial bias from cm to meters
|
||
|
for (int i = 0; i < radialBiasPersp.Length; ++i)
|
||
|
{
|
||
|
if (overrideRadialBias.Length > 0 && overrideRadialBias[i])
|
||
|
{
|
||
|
radialBiasPerspInMeters[i].x = Util.cmToMeters(radialBiasPersp[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (enableViewDependentGeometry && globalViewDependentGeometryBlendWeight > 0)
|
||
|
{
|
||
|
if (volumeViewpoint.transform.hasChanged)
|
||
|
{
|
||
|
ScheduleGenerate();
|
||
|
volumeViewpoint.transform.hasChanged = false;
|
||
|
}
|
||
|
|
||
|
if (transform.hasChanged)
|
||
|
{
|
||
|
ScheduleGenerate();
|
||
|
transform.hasChanged = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (automaticLevelOfDetail)
|
||
|
{
|
||
|
if (m_mainCamera == null)
|
||
|
{
|
||
|
m_mainCamera = Camera.main;
|
||
|
}
|
||
|
//if the main camera position changed and we are using distance based LOD then force an update
|
||
|
float dist = Vector3.Magnitude((transform.position + volumeBounds.center) - m_mainCamera.transform.position);
|
||
|
float nrmdist = dist / (m_mainCamera.farClipPlane / levelOfDetailDistance);
|
||
|
int newLOD = Math.Min((int)((float)numLevelOfDetailLevels * nrmdist), numLevelOfDetailLevels);
|
||
|
#if UNITY_EDITOR
|
||
|
if (newLOD != currentLevelOfDetailLevel)
|
||
|
{
|
||
|
Generate();
|
||
|
}
|
||
|
#endif
|
||
|
currentLevelOfDetailLevel = newLOD;
|
||
|
}
|
||
|
if (showVolumePreview)
|
||
|
{
|
||
|
DrawDebug();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//free up the resources when done
|
||
|
Util.ReleaseComputeBuffer(ref m_pointsBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int[] triangleOffsets = new int[72]
|
||
|
{
|
||
|
// 0
|
||
|
0,0,0,
|
||
|
1,0,0,
|
||
|
// 1
|
||
|
1,0,0,
|
||
|
1,0,1,
|
||
|
// 2
|
||
|
1,0,1,
|
||
|
0,0,1,
|
||
|
// 3
|
||
|
0,0,1,
|
||
|
0,0,0,
|
||
|
// 4
|
||
|
0,1,0,
|
||
|
1,1,0,
|
||
|
// 5
|
||
|
1,1,0,
|
||
|
1,1,1,
|
||
|
// 6
|
||
|
1,1,1,
|
||
|
0,1,1,
|
||
|
// 7
|
||
|
0,1,1,
|
||
|
0,1,0,
|
||
|
// 8
|
||
|
0,0,0,
|
||
|
0,1,0,
|
||
|
// 9
|
||
|
1,0,0,
|
||
|
1,1,0,
|
||
|
// 10
|
||
|
1,0,1,
|
||
|
1,1,1,
|
||
|
// 11
|
||
|
0,0,1,
|
||
|
0,1,1
|
||
|
};
|
||
|
|
||
|
// For each of the possible vertex states listed in cubeEdgeFlags there is a specific triangulation
|
||
|
// of the edge intersection points. triangleConnectionTable lists all of them in the form of
|
||
|
// 0-5 edge triples with the list terminated by the invalid value -1.
|
||
|
// For example: triangleConnectionTable[3] list the 2 triangles formed when corner[0]
|
||
|
// and corner[1] are inside of the surface, but the rest of the cube is not.
|
||
|
// triangleConnectionTable[256][16]
|
||
|
static int[,] triangleConnectionTable = new int[,]
|
||
|
{
|
||
|
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
|
||
|
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
|
||
|
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
|
||
|
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
|
||
|
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
|
||
|
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
|
||
|
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
|
||
|
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
|
||
|
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
|
||
|
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
|
||
|
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
|
||
|
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
|
||
|
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
|
||
|
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
|
||
|
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
|
||
|
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
|
||
|
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
|
||
|
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
|
||
|
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
|
||
|
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
|
||
|
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
|
||
|
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
|
||
|
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
|
||
|
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
|
||
|
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
|
||
|
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
|
||
|
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
|
||
|
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
|
||
|
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
|
||
|
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
|
||
|
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
|
||
|
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
|
||
|
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
|
||
|
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
|
||
|
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
|
||
|
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
|
||
|
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
|
||
|
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
|
||
|
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
|
||
|
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
|
||
|
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
|
||
|
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
|
||
|
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
|
||
|
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
|
||
|
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
|
||
|
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
|
||
|
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
|
||
|
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
|
||
|
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
|
||
|
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
|
||
|
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
|
||
|
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
|
||
|
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
|
||
|
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
|
||
|
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
|
||
|
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
|
||
|
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
|
||
|
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
|
||
|
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
|
||
|
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
|
||
|
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
|
||
|
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
|
||
|
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
|
||
|
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
|
||
|
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
|
||
|
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
|
||
|
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
|
||
|
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
|
||
|
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
|
||
|
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
|
||
|
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
|
||
|
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
|
||
|
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
|
||
|
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
|
||
|
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
|
||
|
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
|
||
|
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
|
||
|
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
|
||
|
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
|
||
|
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
|
||
|
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
|
||
|
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
|
||
|
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
|
||
|
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
|
||
|
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
|
||
|
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
|
||
|
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
|
||
|
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
|
||
|
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
|
||
|
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
|
||
|
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
|
||
|
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
|
||
|
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
|
||
|
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
|
||
|
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
|
||
|
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
|
||
|
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
|
||
|
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
|
||
|
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
|
||
|
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
|
||
|
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
|
||
|
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
|
||
|
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
|
||
|
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
|
||
|
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
|
||
|
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
|
||
|
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
|
||
|
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
|
||
|
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||
|
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
|
||
|
};
|
||
|
|
||
|
//number of triangles to use per classification
|
||
|
static int[] nrOfTriangles = new int[256] { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 2, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 2, 3, 3, 2, 3, 4, 4, 3, 3, 4, 4, 3, 4, 5, 5, 2, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 4, 2, 3, 3, 4, 3, 4, 2, 3, 3, 4, 4, 5, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 3, 2, 4, 5, 5, 4, 5, 2, 4, 1, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 2, 3, 3, 4, 3, 4, 4, 5, 3, 2, 4, 3, 4, 3, 5, 2, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 4, 3, 4, 4, 3, 4, 5, 5, 4, 4, 3, 5, 2, 5, 4, 2, 1, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 2, 3, 3, 2, 3, 4, 4, 5, 4, 5, 5, 2, 4, 3, 5, 4, 3, 2, 4, 1, 3, 4, 4, 5, 4, 5, 3, 4, 4, 5, 5, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 2, 1, 3, 2, 4, 1, 2, 1, 1, 0 };
|
||
|
|
||
|
#region MaskGenerator
|
||
|
|
||
|
[SerializeField]
|
||
|
public MaskGenerator maskGenerator = null;
|
||
|
|
||
|
public void EnsureMaskGenerator()
|
||
|
{
|
||
|
if (maskGenerator == null)
|
||
|
{
|
||
|
maskGenerator = new MaskGenerator();
|
||
|
}
|
||
|
|
||
|
if (clip != null)
|
||
|
{
|
||
|
maskGenerator.clip = clip;
|
||
|
maskGenerator.sliceCount = (int)clip.metadata?.perspectivesCount;
|
||
|
}
|
||
|
|
||
|
maskGenerator.useStudioCoefficients = true;
|
||
|
maskGenerator.Setup();
|
||
|
}
|
||
|
|
||
|
[SerializeField]
|
||
|
private bool m_enableEdgeMask = false;
|
||
|
public bool enableEdgeMask
|
||
|
{
|
||
|
get { return maskGenerator != null ? m_enableEdgeMask : false; }
|
||
|
set {
|
||
|
m_enableEdgeMask = value;
|
||
|
EnsureMaskGenerator();
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
}
|
||
|
}
|