浏览代码

cleanup

/main
Lasse Jon Fuglsang Pedersen 5 年前
当前提交
b593808d
共有 8 个文件被更改,包括 599 次插入795 次删除
  1. 57
      Editor/CustomPass/NormalBufferBlurPassDrawer.cs
  2. 5
      Editor/SkinAttachmentTargetEditor.cs
  3. 351
      Runtime/CustomPass/NormalBufferBlurPass.cs
  4. 354
      Runtime/SkinAttachment.cs
  5. 277
      Runtime/SkinAttachmentDataBuilder.cs
  6. 309
      Runtime/SkinAttachmentTarget.cs
  7. 17
      Runtime/SkinDeformationRenderer.cs
  8. 24
      Runtime/SnappersHeadRenderer.cs

57
Editor/CustomPass/NormalBufferBlurPassDrawer.cs


using UnityEditor;
using UnityEditor.Rendering.HighDefinition;
[CustomPassDrawer(typeof(NormalBufferBlurPass))]
class NormalBufferBlurPassDrawer : CustomPassDrawer
namespace Unity.DemoTeam.DigitalHuman
static readonly float lineFeed = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
[CustomPassDrawer(typeof(NormalBufferBlurPass))]
class NormalBufferBlurPassDrawer : CustomPassDrawer
{
static readonly float lineFeed = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
SerializedProperty queue;
SerializedProperty layerMask;
SerializedProperty queue;
SerializedProperty layerMask;
protected override void Initialize(SerializedProperty customPass)
{
queue = customPass.FindPropertyRelative("queue");
layerMask = customPass.FindPropertyRelative("layerMask");
}
protected override void Initialize(SerializedProperty customPass)
{
queue = customPass.FindPropertyRelative("queue");
layerMask = customPass.FindPropertyRelative("layerMask");
}
protected override PassUIFlag commonPassUIFlags => PassUIFlag.Name;
protected override PassUIFlag commonPassUIFlags => PassUIFlag.Name;
protected override float GetPassHeight(SerializedProperty customPass)
{
float height = base.GetPassHeight(customPass);
protected override float GetPassHeight(SerializedProperty customPass)
{
float height = base.GetPassHeight(customPass);
height += lineFeed;
height += lineFeed;
height += lineFeed;
height += lineFeed;
return height;
}
return height;
}
protected override void DoPassGUI(SerializedProperty customPass, Rect rect)
{
base.DoPassGUI(customPass, rect);
protected override void DoPassGUI(SerializedProperty customPass, Rect rect)
{
base.DoPassGUI(customPass, rect);
// queue
queue.intValue = (int)(CustomPass.RenderQueueType)EditorGUI.EnumPopup(rect, "Queue", (CustomPass.RenderQueueType)queue.intValue);
rect.y += lineFeed;
// queue
queue.intValue = (int)(CustomPass.RenderQueueType)EditorGUI.EnumPopup(rect, "Queue", (CustomPass.RenderQueueType)queue.intValue);
rect.y += lineFeed;
// layerMask
EditorGUI.PropertyField(rect, layerMask);
rect.y += lineFeed;
// layerMask
EditorGUI.PropertyField(rect, layerMask);
rect.y += lineFeed;
}
}
}

5
Editor/SkinAttachmentTargetEditor.cs


if (driver == null)
return;
if (driver.showWireframe)
{
}
if (driver.showMouseOver)
{
DrawSceneGUIMouseOver(driver);

351
Runtime/CustomPass/NormalBufferBlurPass.cs


using UnityEngine.Experimental.Rendering;
using System.Reflection;
// basic procedure:
//
// 1. alloc temp
// b. custom color (R8)
// c. custom normal (ARGBHalf)
//
// 2. clear
// b. write 1 -> custom color
//
// 3. mark decals
// a. write 0 -> custom color
// b. write 1 -> custom stencil
//
// 4. enable stencil
//
// 5. render fullscreen
// a. write decoded normal -> custom normal
//
// 6. render fullscreen
// a. write blurred decoded normal -> normal
//
// 7. free temp
public class NormalBufferBlurPass : CustomPass
namespace Unity.DemoTeam.DigitalHuman
[HideInInspector] public RenderQueueType queue = RenderQueueType.AllOpaque;
[HideInInspector] public LayerMask layerMask = 0;// default to 'None'
// basic procedure:
//
// 1. alloc temp
// b. custom color (R8)
// c. custom normal (ARGBHalf)
//
// 2. clear
// b. write 1 -> custom color
//
// 3. mark decals
// a. write 0 -> custom color
// b. write 1 -> custom stencil
//
// 4. enable stencil
//
// 5. render fullscreen
// a. write decoded normal -> custom normal
//
// 6. render fullscreen
// a. write blurred decoded normal -> normal
//
// 7. free temp
static readonly int rtRegions = Shader.PropertyToID("_NormalBufferBlur_Regions");
static readonly int rtDecoded = Shader.PropertyToID("_NormalBufferBlur_Decoded");
public class NormalBufferBlurPass : CustomPass
{
[HideInInspector] public RenderQueueType queue = RenderQueueType.AllOpaque;
[HideInInspector] public LayerMask layerMask = 0;// default to 'None'
const string NAME_SHADER = "Hidden/DigitalHuman/NormalBufferBlurPass";
static readonly int rtRegions = Shader.PropertyToID("_NormalBufferBlur_Regions");
static readonly int rtDecoded = Shader.PropertyToID("_NormalBufferBlur_Decoded");
static readonly string[] NAME_PASS_REPLACE = new string[]
{
"Forward",// HDShaderPassNames.s_ForwardStr
"ForwardOnly",// HDShaderPassNames.s_ForwardOnlyStr
"SRPDefaultUnlit", // HDShaderPassNames.s_SRPDefaultUnlitStr
"DBufferMesh_3RT",// HDShaderPassNames.s_MeshDecalsMStr
};
static ShaderTagId[] NAME_PASS_REPLACE_TAG = null;
const string NAME_SHADER = "Hidden/DigitalHuman/NormalBufferBlurPass";
const int PASS_MARK = 0;
const int PASS_DECODE = 1;
const int PASS_BLUR_AND_ENCODE = 2;
const int PASS_BLUR_AND_ENCODE_AND_DECAL = 3;
static readonly string[] NAME_PASS_REPLACE = new string[]
{
"Forward",// HDShaderPassNames.s_ForwardStr
"ForwardOnly",// HDShaderPassNames.s_ForwardOnlyStr
"SRPDefaultUnlit", // HDShaderPassNames.s_SRPDefaultUnlitStr
"DBufferMesh_3RT",// HDShaderPassNames.s_MeshDecalsMStr
};
static ShaderTagId[] NAME_PASS_REPLACE_TAG = null;
Material passMaterial;
const int PASS_MARK = 0;
const int PASS_DECODE = 1;
const int PASS_BLUR_AND_ENCODE = 2;
const int PASS_BLUR_AND_ENCODE_AND_DECAL = 3;
const int DBUFFER_NORMALS = 1;
const int DBUFFER_MASK = 2;
Material passMaterial;
private RTHandle[] dbufferRTs;
private RenderTargetIdentifier[] dbufferNormalMaskRTI;
private void FindDbufferRTs(HDRenderPipeline hdPipeline)
{
dbufferRTs = null;
const int DBUFFER_NORMALS = 1;
const int DBUFFER_MASK = 2;
var fieldInfo_m_DbufferManager = typeof(HDRenderPipeline).GetField("m_DbufferManager", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo_m_DbufferManager != null)
private RTHandle[] dbufferRTs;
private RenderTargetIdentifier[] dbufferNormalMaskRTI;
private void FindDbufferRTs(HDRenderPipeline hdPipeline)
//Debug.Log("FindDbufferRTs : " + fieldInfo_m_DbufferManager);
var m_DbufferManager = fieldInfo_m_DbufferManager.GetValue(hdPipeline);
if (m_DbufferManager != null)
dbufferRTs = null;
var fieldInfo_m_DbufferManager = typeof(HDRenderPipeline).GetField("m_DbufferManager", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo_m_DbufferManager != null)
var fieldInfo_m_RTs = m_DbufferManager.GetType().GetField("m_RTs", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo_m_RTs != null)
//Debug.Log("FindDbufferRTs : " + fieldInfo_m_DbufferManager);
var m_DbufferManager = fieldInfo_m_DbufferManager.GetValue(hdPipeline);
if (m_DbufferManager != null)
//Debug.Log("FindDbufferRTs : " + fieldInfo_m_RTs);
dbufferRTs = fieldInfo_m_RTs.GetValue(m_DbufferManager) as RTHandle[];
var fieldInfo_m_RTs = m_DbufferManager.GetType().GetField("m_RTs", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo_m_RTs != null)
{
//Debug.Log("FindDbufferRTs : " + fieldInfo_m_RTs);
dbufferRTs = fieldInfo_m_RTs.GetValue(m_DbufferManager) as RTHandle[];
}
}
if (dbufferRTs != null)
{
dbufferNormalMaskRTI = new RenderTargetIdentifier[2];
dbufferNormalMaskRTI[0] = dbufferRTs[DBUFFER_NORMALS].nameID;
dbufferNormalMaskRTI[1] = dbufferRTs[DBUFFER_MASK].nameID;
if (dbufferRTs != null)
{
dbufferNormalMaskRTI = new RenderTargetIdentifier[2];
dbufferNormalMaskRTI[0] = dbufferRTs[DBUFFER_NORMALS].nameID;
dbufferNormalMaskRTI[1] = dbufferRTs[DBUFFER_MASK].nameID;
}
else
{
dbufferNormalMaskRTI = null;
}
else
static bool EnsureMaterial(ref Material material, string shaderName)
dbufferNormalMaskRTI = null;
}
}
if (material != null && material.shader == null)
material = null;
static bool EnsureMaterial(ref Material material, string shaderName)
{
if (material != null && material.shader == null)
material = null;
if (material == null)
material = CoreUtils.CreateEngineMaterial(shaderName);
if (material == null)
material = CoreUtils.CreateEngineMaterial(shaderName);
return (material != null);
}
return (material != null);
}
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
base.Setup(renderContext, cmd);
base.name = "NormalBufferBlurPass";
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
base.Setup(renderContext, cmd);
base.name = "NormalBufferBlurPass";
FindDbufferRTs(RenderPipelineManager.currentPipeline as HDRenderPipeline);
FindDbufferRTs(RenderPipelineManager.currentPipeline as HDRenderPipeline);
EnsureMaterial(ref passMaterial, NAME_SHADER);
if (passMaterial != null)
{
passMaterial.SetInt("_StencilBit", (int)UserStencilUsage.UserBit0);
}
EnsureMaterial(ref passMaterial, NAME_SHADER);
if (passMaterial != null)
{
passMaterial.SetInt("_StencilBit", (int)UserStencilUsage.UserBit0);
if (NAME_PASS_REPLACE_TAG == null)
{
NAME_PASS_REPLACE_TAG = new ShaderTagId[NAME_PASS_REPLACE.Length];
for (int i = 0; i != NAME_PASS_REPLACE_TAG.Length; i++)
{
NAME_PASS_REPLACE_TAG[i] = new ShaderTagId(NAME_PASS_REPLACE[i]);
}
}
if (NAME_PASS_REPLACE_TAG == null)
protected override void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResults)
NAME_PASS_REPLACE_TAG = new ShaderTagId[NAME_PASS_REPLACE.Length];
for (int i = 0; i != NAME_PASS_REPLACE_TAG.Length; i++)
{
NAME_PASS_REPLACE_TAG[i] = new ShaderTagId(NAME_PASS_REPLACE[i]);
}
Profiler.BeginSample("NormalBufferBlurPass");
ExecuteNormalBufferBlur(renderContext, cmd, hdCamera, cullingResults);
Profiler.EndSample();
}
protected override void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResults)
{
Profiler.BeginSample("NormalBufferBlurPass");
ExecuteNormalBufferBlur(renderContext, cmd, hdCamera, cullingResults);
Profiler.EndSample();
}
void ExecuteNormalBufferBlur(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResults)
{
if (!EnsureMaterial(ref passMaterial, NAME_SHADER))
return;
void ExecuteNormalBufferBlur(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResults)
{
if (!EnsureMaterial(ref passMaterial, NAME_SHADER))
return;
if (layerMask == 0)
return;
if (layerMask == 0)
return;
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals))
return;
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals))
return;
RTHandle cameraColor;
RTHandle cameraDepth;
GetCameraBuffers(out cameraColor, out cameraDepth);
RTHandle cameraColor;
RTHandle cameraDepth;
GetCameraBuffers(out cameraColor, out cameraDepth);
int bufferW = cameraColor.rt.width;
int bufferH = cameraColor.rt.height;
int bufferW = cameraColor.rt.width;
int bufferH = cameraColor.rt.height;
// allocate temporary buffers
cmd.GetTemporaryRT(rtRegions, bufferW, bufferH, (int)DepthBits.None, FilterMode.Point, RenderTextureFormat.R8, RenderTextureReadWrite.Linear, 1, false);
cmd.GetTemporaryRT(rtDecoded, bufferW, bufferH, (int)DepthBits.None, FilterMode.Point, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1, false);
// allocate temporary buffers
cmd.GetTemporaryRT(rtRegions, bufferW, bufferH, (int)DepthBits.None, FilterMode.Point, RenderTextureFormat.R8, RenderTextureReadWrite.Linear, 1, false);
cmd.GetTemporaryRT(rtDecoded, bufferW, bufferH, (int)DepthBits.None, FilterMode.Point, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1, false);
// render decals to mark blur regions
CoreUtils.SetRenderTarget(cmd,
rtRegions, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
cameraDepth, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store,
ClearFlag.Color, Color.white
);
CoreUtils.SetViewport(cmd, cameraDepth);
// render decals to mark blur regions
CoreUtils.SetRenderTarget(cmd,
rtRegions, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
cameraDepth, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store,
ClearFlag.Color, Color.white
);
CoreUtils.SetViewport(cmd, cameraDepth);
RendererListDesc renderListDesc = new RendererListDesc(NAME_PASS_REPLACE_TAG, cullingResults, hdCamera.camera)
{
rendererConfiguration = PerObjectData.None,
renderQueueRange = GetRenderQueueRange(queue),
sortingCriteria = SortingCriteria.None,
layerMask = layerMask,
overrideMaterial = passMaterial,
overrideMaterialPassIndex = PASS_MARK,
stateBlock = null,
excludeObjectMotionVectors = false,
};
RendererListDesc renderListDesc = new RendererListDesc(NAME_PASS_REPLACE_TAG, cullingResults, hdCamera.camera)
{
rendererConfiguration = PerObjectData.None,
renderQueueRange = GetRenderQueueRange(queue),
sortingCriteria = SortingCriteria.None,
layerMask = layerMask,
overrideMaterial = passMaterial,
overrideMaterialPassIndex = PASS_MARK,
stateBlock = null,
excludeObjectMotionVectors = false,
};
HDUtils.DrawRendererList(renderContext, cmd, RendererList.Create(renderListDesc));
// decode normal buffer in marked regions
CoreUtils.SetRenderTarget(cmd,
rtDecoded, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
cameraDepth, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare,
ClearFlag.None
);
CoreUtils.SetViewport(cmd, cameraDepth);
cmd.SetRandomWriteTarget(2, GetNormalBuffer());
cmd.DrawProcedural(Matrix4x4.identity, passMaterial, PASS_DECODE, MeshTopology.Triangles, 3, 1);
cmd.ClearRandomWriteTargets();
// blur and re-encode normals in marked regions
cmd.SetGlobalTexture(rtRegions, rtRegions);
cmd.SetGlobalTexture(rtDecoded, rtDecoded);
HDUtils.DrawRendererList(renderContext, cmd, RendererList.Create(renderListDesc));
if (dbufferNormalMaskRTI != null)
{
CoreUtils.SetRenderTarget(cmd,
dbufferNormalMaskRTI,
cameraDepth,
ClearFlag.None);
CoreUtils.SetViewport(cmd, cameraDepth);
cmd.SetRandomWriteTarget(2, GetNormalBuffer());
cmd.DrawProcedural(Matrix4x4.identity, passMaterial, PASS_BLUR_AND_ENCODE_AND_DECAL, MeshTopology.Triangles, 3, 1);
cmd.ClearRandomWriteTargets();
}
else
{
// decode normal buffer in marked regions
cameraDepth, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store,
rtDecoded, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
cameraDepth, RenderBufferLoadAction.Load, RenderBufferStoreAction.DontCare,
cmd.DrawProcedural(Matrix4x4.identity, passMaterial, PASS_BLUR_AND_ENCODE, MeshTopology.Triangles, 3, 1);
cmd.DrawProcedural(Matrix4x4.identity, passMaterial, PASS_DECODE, MeshTopology.Triangles, 3, 1);
// blur and re-encode normals in marked regions
cmd.SetGlobalTexture(rtRegions, rtRegions);
cmd.SetGlobalTexture(rtDecoded, rtDecoded);
if (dbufferNormalMaskRTI != null)
{
CoreUtils.SetRenderTarget(cmd,
dbufferNormalMaskRTI,
cameraDepth,
ClearFlag.None);
CoreUtils.SetViewport(cmd, cameraDepth);
cmd.SetRandomWriteTarget(2, GetNormalBuffer());
cmd.DrawProcedural(Matrix4x4.identity, passMaterial, PASS_BLUR_AND_ENCODE_AND_DECAL, MeshTopology.Triangles, 3, 1);
cmd.ClearRandomWriteTargets();
}
else
{
CoreUtils.SetRenderTarget(cmd,
cameraDepth, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store,
ClearFlag.None
);
CoreUtils.SetViewport(cmd, cameraDepth);
cmd.SetRandomWriteTarget(2, GetNormalBuffer());
cmd.DrawProcedural(Matrix4x4.identity, passMaterial, PASS_BLUR_AND_ENCODE, MeshTopology.Triangles, 3, 1);
cmd.ClearRandomWriteTargets();
}
// free temporary buffers
cmd.ReleaseTemporaryRT(rtRegions);
cmd.ReleaseTemporaryRT(rtDecoded);
// free temporary buffers
cmd.ReleaseTemporaryRT(rtRegions);
cmd.ReleaseTemporaryRT(rtDecoded);
}
protected override void Cleanup()
{
base.Cleanup();
protected override void Cleanup()
{
base.Cleanup();
}
}
}

354
Runtime/SkinAttachment.cs


public ulong checksum1 = 0;
[Header("Debug options")]
[Range(0, 6)]
public int debugIndex = 0;
public bool debugIndexEnabled = false;
public bool debugBounds = false;
public bool showBounds = false;
public bool showIslands = false;
public bool showRootLines = false;
private const int debugColorsSize = 7;
private static Color[] debugColors = new Color[debugColorsSize] { Color.red, Color.green, Color.blue, Color.cyan, Color.magenta, Color.yellow, Color.white };
private static SkinAttachmentData debugData;
[Header("Runtime options")]
public bool forceRecalculateBounds;

[NonSerialized] public Transform skinningBone;
[NonSerialized] public Matrix4x4 skinningBoneBindPose;
[NonSerialized] public Matrix4x4 skinningBoneBindPoseInverse;
public Matrix4x4 GetWorldToLocalSkinning()
{
if (skinningBone != null)
return (skinningBoneBindPoseInverse * skinningBone.worldToLocalMatrix);
else
return (this.transform.worldToLocalMatrix);
}
public Matrix4x4 GetLocalSkinningToWorld()
{
if (skinningBone != null)
return (skinningBone.localToWorldMatrix * skinningBoneBindPose);
else
return (this.transform.localToWorldMatrix);
}
void DiscoverSkinningBone()
{

if (isActiveAndEnabled == false)
return;
if (target == null)
return;
if (attached)
DrawGizmosAttached();
else
DrawGizmosDetached();
}
var targetMeshInfo = target.GetCachedMeshInfo();
if (targetMeshInfo.valid == false)
return;
void DrawGizmosAttached()
{
if (attachmentType != AttachmentType.Transform)
{
if (meshInstance == null)
return;
//TODO get rid of duplicate code
Gizmos.matrix = this.transform.localToWorldMatrix;
if (attached)
{
if (attachmentType != AttachmentType.Transform && debugBounds)
if (showBounds)
Gizmos.matrix = this.transform.localToWorldMatrix;
Gizmos.color = Color.white;
}
}
void DrawGizmosDetached()
{
if (target == null)
return;
var targetMeshInfo = target.GetCachedMeshInfo();
if (targetMeshInfo.valid == false)
}
var targetPosition = target.transform.InverseTransformPoint(this.transform.position);
// draw sphere with radius to closest vertex
if (targetMeshInfo.meshVertexBSP.FindNearest(ref closestDist, ref closestNode, ref targetPosition))
var targetLocalPos = target.transform.InverseTransformPoint(this.transform.position);
if (targetMeshInfo.meshVertexBSP.FindNearest(ref closestDist, ref closestNode, ref targetLocalPos))
var r = targetPosition - target.meshBuffers.vertexPositions[closestNode];
var r = targetLocalPos - target.meshBuffers.vertexPositions[closestNode];
Gizmos.DrawSphere(targetPosition, Mathf.Sqrt(closestDist));
Gizmos.DrawSphere(targetLocalPos, Mathf.Sqrt(closestDist));
Gizmos.DrawLine(targetPosition, target.meshBuffers.vertexPositions[closestNode]);
Gizmos.DrawLine(targetLocalPos, target.meshBuffers.vertexPositions[closestNode]);
target.meshBuffers.DrawTriangles(targetMeshInfo.meshAdjacency.vertexTriangles[closestNode]);
target.meshBuffers.DrawGizmoTriangles(targetMeshInfo.meshAdjacency.vertexTriangles[closestNode]);
return;
if (meshBuffers == null)
else
}
if (skinningBone != null)
Gizmos.matrix = skinningBone.localToWorldMatrix * skinningBoneBindPose;
else
Gizmos.matrix = this.transform.localToWorldMatrix;
if (meshInstance == null)
return;
var subjectPositions = meshBuffers.vertexPositions;
if (attachmentType == AttachmentType.Mesh)
{
var colorArray = new Color[] { Color.red, Color.green, Color.blue, Color.cyan, Color.magenta, Color.yellow, Color.white };
var colorIndex = -1;
if (skinningBone != null)
Gizmos.matrix = skinningBone.localToWorldMatrix * skinningBoneBindPose;
else
Gizmos.matrix = this.transform.localToWorldMatrix;
var positions = meshBuffers.vertexPositions;
for (int island = 0; island != meshIslands.islandCount; island++)
if (showIslands)
colorIndex++;
colorIndex %= colorArray.Length;
if (colorIndex != debugIndex && debugIndexEnabled)
continue;
Gizmos.color = Color.Lerp(Color.clear, colorArray[colorIndex], 0.3f);
foreach (var i in meshIslands.islandVertices[island])
for (int island = 0; island != meshIslands.islandCount; island++)
foreach (var j in meshAdjacency.vertexVertices[i])
Gizmos.color = Color.Lerp(Color.clear, debugColors[island % debugColors.Length], 0.3f);
foreach (var i in meshIslands.islandVertices[island])
Gizmos.DrawLine(positions[i], positions[j]);
foreach (var j in meshAdjacency.vertexVertices[i])
{
Gizmos.DrawLine(subjectPositions[i], subjectPositions[j]);
}
return;
}
if (attachmentType == AttachmentType.MeshRoots)
{
var colorArray = new Color[] { Color.red, Color.green, Color.blue, Color.cyan, Color.magenta, Color.yellow, Color.white };
var colorIndex = -1;
var positions = meshBuffers.vertexPositions;
var targetPositions = new Vector3[positions.Length];
Matrix4x4 targetToWorld = Matrix4x4.TRS(target.transform.position, target.transform.rotation, Vector3.one);
Matrix4x4 subjectToTarget;
Matrix4x4 targetToSubject;
if (showRootLines)
if (skinningBone != null)
if (debugData == null)
subjectToTarget = target.transform.worldToLocalMatrix * (skinningBone.localToWorldMatrix * skinningBoneBindPose);
targetToSubject = (skinningBoneBindPoseInverse * skinningBone.worldToLocalMatrix) * targetToWorld;
debugData = SkinAttachmentData.CreateInstance<SkinAttachmentData>();
debugData.hideFlags = HideFlags.HideAndDontSave;
subjectToTarget = target.transform.worldToLocalMatrix * this.transform.localToWorldMatrix;
targetToSubject = this.transform.worldToLocalMatrix * targetToWorld;
debugData.Clear();
}
for (int i = 0; i != positions.Length; i++)
{
targetPositions[i] = subjectToTarget.MultiplyPoint3x4(positions[i]);
}
int dryRunPoseCount = -1;
int dryRunItemCount = -1;
for (int island = 0; island != meshIslands.islandCount; island++)
{
colorIndex++;
colorIndex %= colorArray.Length;
if (colorIndex != debugIndex && debugIndexEnabled)
continue;
Gizmos.color = colorArray[colorIndex];
// draw the faces
foreach (int i in meshIslands.islandVertices[island])
SkinAttachmentDataBuilder.BuildDataAttachSubject(ref debugData, target.transform, target.GetCachedMeshInfo(), this, dryRun: true, ref dryRunPoseCount, ref dryRunItemCount);
foreach (int j in meshAdjacency.vertexVertices[i])
{
Gizmos.DrawLine(positions[i], positions[j]);
}
ArrayUtils.ResizeCheckedIfLessThan(ref debugData.pose, dryRunPoseCount);
ArrayUtils.ResizeCheckedIfLessThan(ref debugData.item, dryRunItemCount);
// draw root-lines
unsafe
{
var rootIdx = new UnsafeArrayInt(positions.Length);
var rootDir = new UnsafeArrayVector3(positions.Length);
var rootGen = new UnsafeArrayInt(positions.Length);
var visitor = new UnsafeBFS(positions.Length);
visitor.Clear();
SkinAttachmentDataBuilder.BuildDataAttachSubject(ref debugData, target.transform, target.GetCachedMeshInfo(), this, dryRun: false, ref dryRunPoseCount, ref dryRunItemCount);
// find island roots
{
int rootCount = 0;
Matrix4x4 targetToWorld = Matrix4x4.TRS(target.transform.position, target.transform.rotation, Vector3.one);
// NOTE: targetToWorld specifically excludes scale, since source data (BakeMesh) is already scaled
var bestDist0 = float.PositiveInfinity;
var bestNode0 = -1;
var bestVert0 = -1;
Matrix4x4 targetToSubject;
{
if (skinningBone != null)
targetToSubject = (skinningBoneBindPoseInverse * skinningBone.worldToLocalMatrix) * targetToWorld;
else
targetToSubject = this.transform.worldToLocalMatrix * targetToWorld;
}
var bestDist1 = float.PositiveInfinity;
var bestNode1 = -1;
var bestVert1 = -1;
Gizmos.color = Color.white;
foreach (var i in meshIslands.islandVertices[island])
{
var targetDist = float.PositiveInfinity;
var targetNode = -1;
if (targetMeshInfo.meshVertexBSP.FindNearest(ref targetDist, ref targetNode, ref targetPositions[i]))
{
// found a root if one or more neighbouring vertices are below
var bestDist = float.PositiveInfinity;
var bestNode = -1;
foreach (var j in meshAdjacency.vertexVertices[i])
{
var targetDelta = targetPositions[j] - target.meshBuffers.vertexPositions[targetNode];
var targetNormalDist = Vector3.Dot(targetDelta, target.meshBuffers.vertexNormals[targetNode]);
if (targetNormalDist < 0.0f)
{
var d = Vector3.SqrMagnitude(targetDelta);
if (d < bestDist)
{
bestDist = d;
bestNode = j;
}
}
}
if (bestNode != -1)
{
visitor.Ignore(i);
rootIdx.val[i] = targetNode;
rootDir.val[i] = Vector3.Normalize(targetPositions[bestNode] - targetPositions[i]);
rootGen.val[i] = 0;
rootCount++;
}
else
{
rootIdx.val[i] = -1;
rootGen.val[i] = -1;
// see if node qualifies as second choice root
var targetDelta = targetPositions[i] - target.meshBuffers.vertexPositions[targetNode];
var targetNormalDist = Mathf.Abs(Vector3.Dot(targetDelta, target.meshBuffers.vertexNormals[targetNode]));
if (targetNormalDist < bestDist0)
{
bestDist1 = bestDist0;
bestNode1 = bestNode0;
bestVert1 = bestVert0;
bestDist0 = targetNormalDist;
bestNode0 = targetNode;
bestVert0 = i;
}
else if (targetNormalDist < bestDist1)
{
bestDist1 = targetNormalDist;
bestNode1 = targetNode;
bestVert1 = i;
}
}
}
}
if (rootCount < 2 && bestVert0 != -1)
{
visitor.Ignore(bestVert0);
rootIdx.val[bestVert0] = bestNode0;
rootDir.val[bestVert0] = Vector3.Normalize(target.meshBuffers.vertexPositions[bestNode0] - targetPositions[bestVert0]);
rootGen.val[bestVert0] = 0;
rootCount++;
if (rootCount < 2 && bestVert1 != -1)
{
visitor.Ignore(bestVert1);
rootIdx.val[bestVert1] = bestNode1;
rootDir.val[bestVert1] = Vector3.Normalize(target.meshBuffers.vertexPositions[bestNode1] - targetPositions[bestVert1]);
rootGen.val[bestVert1] = 0;
rootCount++;
}
}
}
// find boundary
foreach (var i in meshIslands.islandVertices[island])
{
if (rootIdx.val[i] != -1)
continue;
foreach (var j in meshAdjacency.vertexVertices[i])
{
if (rootIdx.val[j] != -1)
{
visitor.Insert(i);
break;
}
}
}
// propagate roots
while (visitor.MoveNext())
{
var i = visitor.position;
var bestDist = float.PositiveInfinity;
var bestNode = -1;
foreach (var j in meshAdjacency.vertexVertices[i])
{
if (rootIdx.val[j] != -1)
{
var d = -Vector3.Dot(rootDir.val[j], Vector3.Normalize(targetPositions[j] - targetPositions[i]));
if (d < bestDist)
{
bestDist = d;
bestNode = j;
}
}
else
{
visitor.Insert(j);
}
}
rootIdx.val[i] = rootIdx.val[bestNode];
rootDir.val[i] = Vector3.Normalize(targetPositions[bestNode] - targetPositions[i]);
rootGen.val[i] = rootGen.val[bestNode] + 1;
Gizmos.color = colorArray[rootGen.val[i] % colorArray.Length];
Gizmos.DrawSphere(positions[bestNode], 0.0002f);
Gizmos.DrawSphere(0.5f * (positions[i] + positions[bestNode]), 0.0001f);
}
// draw roots
foreach (var i in meshIslands.islandVertices[island])
{
var root = rootIdx.val[i];
if (root < 0)
{
Debug.Log("i " + i + " has rootIdx " + root);
Gizmos.DrawLine(positions[i], positions[i] + Vector3.up);
}
Gizmos.DrawLine(positions[i], targetToSubject.MultiplyPoint3x4(target.meshBuffers.vertexPositions[root]));
}
// dispose
visitor.Dispose();
rootGen.Dispose();
rootDir.Dispose();
rootIdx.Dispose();
for (int i = 0; i != meshBuffers.vertexCount; i++)
{
Vector3 rootOffset = targetToSubject.MultiplyVector(-debugData.item[i].targetOffset);
Gizmos.DrawRay(subjectPositions[i], rootOffset);
//-------------
return;
}
}
#endif

277
Runtime/SkinAttachmentDataBuilder.cs


public static unsafe void BuildDataAttachToVertex(SkinAttachmentData attachData, int* attachmentIndex, int* attachmentCount, in MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetOffsets, Vector3* targetNormals, int* targetVertices, int targetCount)
{
var poseIndex = attachData.poseCount;
var descIndex = attachData.itemCount;
var itemIndex = attachData.itemCount;
fixed (SkinAttachmentItem* desc = attachData.item)
fixed (SkinAttachmentItem* item = attachData.item)
{
for (int i = 0; i != targetCount; i++)
{

Debug.LogError("no valid poses for target vertex " + i + ", aborting");
poseIndex = attachData.poseCount;
descIndex = attachData.itemCount;
itemIndex = attachData.itemCount;
desc[descIndex].poseIndex = poseIndex;
desc[descIndex].poseCount = poseCount;
desc[descIndex].baseVertex = targetVertices[i];
desc[descIndex].baseNormal = meshInfo.meshBuffers.vertexNormals[targetVertices[i]];
desc[descIndex].targetNormal = targetNormals[i];
desc[descIndex].targetOffset = targetOffsets[i];
item[itemIndex].poseIndex = poseIndex;
item[itemIndex].poseCount = poseCount;
item[itemIndex].baseVertex = targetVertices[i];
item[itemIndex].baseNormal = meshInfo.meshBuffers.vertexNormals[targetVertices[i]];
item[itemIndex].targetNormal = targetNormals[i];
item[itemIndex].targetOffset = targetOffsets[i];
descIndex += 1;
itemIndex += 1;
*attachmentIndex = descIndex > attachData.itemCount ? attachData.itemCount : -1;
*attachmentCount = descIndex - attachData.itemCount;
*attachmentIndex = itemIndex > attachData.itemCount ? attachData.itemCount : -1;
*attachmentCount = itemIndex - attachData.itemCount;
attachData.itemCount = descIndex;
attachData.itemCount = itemIndex;
}
public static unsafe void BuildDataAttachToClosestVertex(SkinAttachmentData attachData, int* attachmentIndex, int* attachmentCount, in MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetNormals, int targetCount)

targetVertices.val[i] = meshInfo.meshVertexBSP.FindNearest(ref targetPositions[i]);
}
CountDataAttachToVertex(ref poseCount, ref itemCount, meshInfo, targetPositions, targetOffsets.val, targetNormals, targetVertices.val, targetCount);
}
}
public static void BuildDataAttachSubject(ref SkinAttachmentData attachData, Transform target, in MeshInfo meshInfo, SkinAttachment subject, bool dryRun, ref int dryRunPoseCount, ref int dryRunItemCount)
{
Matrix4x4 subjectToTarget;
{
if (subject.skinningBone != null)
subjectToTarget = target.transform.worldToLocalMatrix * (subject.skinningBone.localToWorldMatrix * subject.skinningBoneBindPose);
else
subjectToTarget = target.transform.worldToLocalMatrix * subject.transform.localToWorldMatrix;
}
switch (subject.attachmentType)
{
case SkinAttachment.AttachmentType.Transform:
unsafe
{
var targetPosition = subjectToTarget.MultiplyPoint3x4(Vector3.zero);
var targetNormal = subjectToTarget.MultiplyVector(Vector3.up);
fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
if (dryRun)
CountDataAttachToClosestVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, &targetPosition, &targetNormal, 1);
else
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, &targetPosition, &targetNormal, 1);
}
}
break;
case SkinAttachment.AttachmentType.Mesh:
unsafe
{
if (subject.meshInstance == null)
break;
var subjectVertexCount = subject.meshBuffers.vertexCount;
var subjectPositions = subject.meshBuffers.vertexPositions;
var subjectNormals = subject.meshBuffers.vertexNormals;
using (var targetPositions = new UnsafeArrayVector3(subjectVertexCount))
using (var targetNormals = new UnsafeArrayVector3(subjectVertexCount))
{
for (int i = 0; i != subjectVertexCount; i++)
{
targetPositions.val[i] = subjectToTarget.MultiplyPoint3x4(subjectPositions[i]);
targetNormals.val[i] = subjectToTarget.MultiplyVector(subjectNormals[i]);
}
fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
if (dryRun)
CountDataAttachToClosestVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
else
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
}
}
}
break;
case SkinAttachment.AttachmentType.MeshRoots:
unsafe
{
if (subject.meshInstance == null)
break;
var subjectVertexCount = subject.meshBuffers.vertexCount;
var subjectPositions = subject.meshBuffers.vertexPositions;
var subjectNormals = subject.meshBuffers.vertexPositions;
using (var targetPositions = new UnsafeArrayVector3(subjectVertexCount))
using (var targetNormals = new UnsafeArrayVector3(subjectVertexCount))
using (var targetOffsets = new UnsafeArrayVector3(subjectVertexCount))
using (var targetVertices = new UnsafeArrayInt(subjectVertexCount))
using (var rootIdx = new UnsafeArrayInt(subjectVertexCount))
using (var rootDir = new UnsafeArrayVector3(subjectVertexCount))
using (var rootGen = new UnsafeArrayInt(subjectVertexCount))
using (var visitor = new UnsafeBFS(subjectVertexCount))
{
for (int i = 0; i != subjectVertexCount; i++)
{
targetPositions.val[i] = subjectToTarget.MultiplyPoint3x4(subjectPositions[i]);
targetNormals.val[i] = subjectToTarget.MultiplyVector(subjectNormals[i]);
targetOffsets.val[i] = Vector3.zero;
}
visitor.Clear();
// find island roots
for (int island = 0; island != subject.meshIslands.islandCount; island++)
{
int rootCount = 0;
var bestDist0 = float.PositiveInfinity;
var bestNode0 = -1;
var bestVert0 = -1;
var bestDist1 = float.PositiveInfinity;
var bestNode1 = -1;
var bestVert1 = -1;
foreach (var i in subject.meshIslands.islandVertices[island])
{
var targetDist = float.PositiveInfinity;
var targetNode = -1;
if (meshInfo.meshVertexBSP.FindNearest(ref targetDist, ref targetNode, ref targetPositions.val[i]))
{
// found a root if one or more neighbouring vertices are below
var bestDist = float.PositiveInfinity;
var bestNode = -1;
foreach (var j in subject.meshAdjacency.vertexVertices[i])
{
var targetDelta = targetPositions.val[j] - meshInfo.meshBuffers.vertexPositions[targetNode];
var targetNormalDist = Vector3.Dot(targetDelta, meshInfo.meshBuffers.vertexNormals[targetNode]);
if (targetNormalDist < 0.0f)
{
var d = Vector3.SqrMagnitude(targetDelta);
if (d < bestDist)
{
bestDist = d;
bestNode = j;
}
}
}
if (bestNode != -1)
{
visitor.Ignore(i);
rootIdx.val[i] = targetNode;
rootDir.val[i] = Vector3.Normalize(targetPositions.val[bestNode] - targetPositions.val[i]);
rootGen.val[i] = 0;
rootCount++;
}
else
{
rootIdx.val[i] = -1;
rootGen.val[i] = -1;
// see if node qualifies as second choice root
var targetDelta = targetPositions.val[i] - meshInfo.meshBuffers.vertexPositions[targetNode];
var targetNormalDist = Mathf.Abs(Vector3.Dot(targetDelta, meshInfo.meshBuffers.vertexNormals[targetNode]));
if (targetNormalDist < bestDist0)
{
bestDist1 = bestDist0;
bestNode1 = bestNode0;
bestVert1 = bestVert0;
bestDist0 = targetNormalDist;
bestNode0 = targetNode;
bestVert0 = i;
}
else if (targetNormalDist < bestDist1)
{
bestDist1 = targetNormalDist;
bestNode1 = targetNode;
bestVert1 = i;
}
}
}
}
if (rootCount < 2 && bestVert0 != -1)
{
visitor.Ignore(bestVert0);
rootIdx.val[bestVert0] = bestNode0;
rootDir.val[bestVert0] = Vector3.Normalize(meshInfo.meshBuffers.vertexPositions[bestNode0] - targetPositions.val[bestVert0]);
rootGen.val[bestVert0] = 0;
rootCount++;
if (rootCount < 2 && bestVert1 != -1)
{
visitor.Ignore(bestVert1);
rootIdx.val[bestVert1] = bestNode1;
rootDir.val[bestVert1] = Vector3.Normalize(meshInfo.meshBuffers.vertexPositions[bestNode1] - targetPositions.val[bestVert1]);
rootGen.val[bestVert1] = 0;
rootCount++;
}
}
}
// find boundaries
for (int i = 0; i != subjectVertexCount; i++)
{
if (rootIdx.val[i] != -1)
continue;
foreach (var j in subject.meshAdjacency.vertexVertices[i])
{
if (rootIdx.val[j] != -1)
{
visitor.Insert(i);
break;
}
}
}
// propagate roots
while (visitor.MoveNext())
{
var i = visitor.position;
var bestDist = float.PositiveInfinity;
var bestNode = -1;
foreach (var j in subject.meshAdjacency.vertexVertices[i])
{
if (rootIdx.val[j] != -1)
{
var d = -Vector3.Dot(rootDir.val[j], Vector3.Normalize(targetPositions.val[j] - targetPositions.val[i]));
if (d < bestDist)
{
bestDist = d;
bestNode = j;
}
}
else
{
visitor.Insert(j);
}
}
rootIdx.val[i] = rootIdx.val[bestNode];
rootDir.val[i] = Vector3.Normalize(targetPositions.val[bestNode] - targetPositions.val[i]);
rootGen.val[i] = rootGen.val[bestNode] + 1;
targetOffsets.val[i] = targetPositions.val[i] - targetPositions.val[bestNode];
targetPositions.val[i] = targetPositions.val[bestNode];
}
// copy to target vertices
for (int i = 0; i != subjectVertexCount; i++)
{
targetVertices.val[i] = rootIdx.val[i];
}
fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
if (dryRun)
CountDataAttachToVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
else
BuildDataAttachToVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
}
}
}
break;
}
}
}

309
Runtime/SkinAttachmentTarget.cs


//#define SMR_BAKEMESH_SKIPCALCBOUNDS
using System;
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using UnityEngine;

if (subjects[i].attachmentMode == SkinAttachment.AttachmentMode.BuildPoses)
{
subjects[i].RevertVertexData();
CommitSubject(ref meshInfo, subjects[i], dryRun: true, ref dryRunPoseCount, ref dryRunItemCount);
BuildDataAttachSubject(ref attachData, transform, meshInfo, subjects[i], dryRun: true, ref dryRunPoseCount, ref dryRunItemCount);
}
}

{
if (subjects[i].attachmentMode == SkinAttachment.AttachmentMode.BuildPoses)
{
CommitSubject(ref meshInfo, subjects[i], dryRun: false, ref dryRunPoseCount, ref dryRunPoseCount);
BuildDataAttachSubject(ref attachData, transform, meshInfo, subjects[i], dryRun: false, ref dryRunPoseCount, ref dryRunPoseCount);
}
}

}
}
void CommitSubject(ref MeshInfo meshInfo, SkinAttachment subject, bool dryRun, ref int dryRunPoseCount, ref int dryRunItemCount)
{
Profiler.BeginSample("attach-subj");
Matrix4x4 subjectToTarget;
{
if (subject.skinningBone != null)
subjectToTarget = this.transform.worldToLocalMatrix * (subject.skinningBone.localToWorldMatrix * subject.skinningBoneBindPose);
else
subjectToTarget = this.transform.worldToLocalMatrix * subject.transform.localToWorldMatrix;
}
switch (subject.attachmentType)
{
case SkinAttachment.AttachmentType.Transform:
unsafe
{
var targetPosition = subjectToTarget.MultiplyPoint3x4(Vector3.zero);
var targetNormal = subjectToTarget.MultiplyVector(Vector3.up);
fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
if (dryRun)
CountDataAttachToClosestVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, &targetPosition, &targetNormal, 1);
else
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, &targetPosition, &targetNormal, 1);
}
}
break;
case SkinAttachment.AttachmentType.Mesh:
unsafe
{
if (subject.meshInstance == null)
break;
var subjectVertexCount = subject.meshBuffers.vertexCount;
var subjectPositions = subject.meshBuffers.vertexPositions;
var subjectNormals = subject.meshBuffers.vertexNormals;
using (var targetPositions = new UnsafeArrayVector3(subjectVertexCount))
using (var targetNormals = new UnsafeArrayVector3(subjectVertexCount))
{
for (int i = 0; i != subjectVertexCount; i++)
{
targetPositions.val[i] = subjectToTarget.MultiplyPoint3x4(subjectPositions[i]);
targetNormals.val[i] = subjectToTarget.MultiplyVector(subjectNormals[i]);
}
fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
if (dryRun)
CountDataAttachToClosestVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
else
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
}
}
}
break;
case SkinAttachment.AttachmentType.MeshRoots:
unsafe
{
if (subject.meshInstance == null)
break;
var subjectVertexCount = subject.meshBuffers.vertexCount;
var subjectPositions = subject.meshBuffers.vertexPositions;
var subjectNormals = subject.meshBuffers.vertexPositions;
using (var targetPositions = new UnsafeArrayVector3(subjectVertexCount))
using (var targetNormals = new UnsafeArrayVector3(subjectVertexCount))
using (var targetOffsets = new UnsafeArrayVector3(subjectVertexCount))
using (var targetVertices = new UnsafeArrayInt(subjectVertexCount))
using (var rootIdx = new UnsafeArrayInt(subjectVertexCount))
using (var rootDir = new UnsafeArrayVector3(subjectVertexCount))
using (var rootGen = new UnsafeArrayInt(subjectVertexCount))
using (var visitor = new UnsafeBFS(subjectVertexCount))
{
for (int i = 0; i != subjectVertexCount; i++)
{
targetPositions.val[i] = subjectToTarget.MultiplyPoint3x4(subjectPositions[i]);
targetNormals.val[i] = subjectToTarget.MultiplyVector(subjectNormals[i]);
targetOffsets.val[i] = Vector3.zero;
}
visitor.Clear();
// find island roots
for (int island = 0; island != subject.meshIslands.islandCount; island++)
{
int rootCount = 0;
var bestDist0 = float.PositiveInfinity;
var bestNode0 = -1;
var bestVert0 = -1;
var bestDist1 = float.PositiveInfinity;
var bestNode1 = -1;
var bestVert1 = -1;
foreach (var i in subject.meshIslands.islandVertices[island])
{
var targetDist = float.PositiveInfinity;
var targetNode = -1;
if (meshInfo.meshVertexBSP.FindNearest(ref targetDist, ref targetNode, ref targetPositions.val[i]))
{
// found a root if one or more neighbouring vertices are below
var bestDist = float.PositiveInfinity;
var bestNode = -1;
foreach (var j in subject.meshAdjacency.vertexVertices[i])
{
var targetDelta = targetPositions.val[j] - meshInfo.meshBuffers.vertexPositions[targetNode];
var targetNormalDist = Vector3.Dot(targetDelta, meshInfo.meshBuffers.vertexNormals[targetNode]);
if (targetNormalDist < 0.0f)
{
var d = Vector3.SqrMagnitude(targetDelta);
if (d < bestDist)
{
bestDist = d;
bestNode = j;
}
}
}
if (bestNode != -1)
{
visitor.Ignore(i);
rootIdx.val[i] = targetNode;
rootDir.val[i] = Vector3.Normalize(targetPositions.val[bestNode] - targetPositions.val[i]);
rootGen.val[i] = 0;
rootCount++;
}
else
{
rootIdx.val[i] = -1;
rootGen.val[i] = -1;
// see if node qualifies as second choice root
var targetDelta = targetPositions.val[i] - meshInfo.meshBuffers.vertexPositions[targetNode];
var targetNormalDist = Mathf.Abs(Vector3.Dot(targetDelta, meshInfo.meshBuffers.vertexNormals[targetNode]));
if (targetNormalDist < bestDist0)
{
bestDist1 = bestDist0;
bestNode1 = bestNode0;
bestVert1 = bestVert0;
bestDist0 = targetNormalDist;
bestNode0 = targetNode;
bestVert0 = i;
}
else if (targetNormalDist < bestDist1)
{
bestDist1 = targetNormalDist;
bestNode1 = targetNode;
bestVert1 = i;
}
}
}
}
if (rootCount < 2 && bestVert0 != -1)
{
visitor.Ignore(bestVert0);
rootIdx.val[bestVert0] = bestNode0;
rootDir.val[bestVert0] = Vector3.Normalize(meshInfo.meshBuffers.vertexPositions[bestNode0] - targetPositions.val[bestVert0]);
rootGen.val[bestVert0] = 0;
rootCount++;
if (rootCount < 2 && bestVert1 != -1)
{
visitor.Ignore(bestVert1);
rootIdx.val[bestVert1] = bestNode1;
rootDir.val[bestVert1] = Vector3.Normalize(meshInfo.meshBuffers.vertexPositions[bestNode1] - targetPositions.val[bestVert1]);
rootGen.val[bestVert1] = 0;
rootCount++;
}
}
}
// find boundaries
for (int i = 0; i != subjectVertexCount; i++)
{
if (rootIdx.val[i] != -1)
continue;
foreach (var j in subject.meshAdjacency.vertexVertices[i])
{
if (rootIdx.val[j] != -1)
{
visitor.Insert(i);
break;
}
}
}
// propagate roots
while (visitor.MoveNext())
{
var i = visitor.position;
var bestDist = float.PositiveInfinity;
var bestNode = -1;
foreach (var j in subject.meshAdjacency.vertexVertices[i])
{
if (rootIdx.val[j] != -1)
{
var d = -Vector3.Dot(rootDir.val[j], Vector3.Normalize(targetPositions.val[j] - targetPositions.val[i]));
if (d < bestDist)
{
bestDist = d;
bestNode = j;
}
}
else
{
visitor.Insert(j);
}
}
rootIdx.val[i] = rootIdx.val[bestNode];
rootDir.val[i] = Vector3.Normalize(targetPositions.val[bestNode] - targetPositions.val[i]);
rootGen.val[i] = rootGen.val[bestNode] + 1;
targetOffsets.val[i] = targetPositions.val[i] - targetPositions.val[bestNode];
targetPositions.val[i] = targetPositions.val[bestNode];
}
// copy to target vertices
for (int i = 0; i != subjectVertexCount; i++)
{
targetVertices.val[i] = rootIdx.val[i];
}
fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
if (dryRun)
CountDataAttachToVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
else
BuildDataAttachToVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
}
}
}
break;
}
Profiler.EndSample();
}
//---------
// Resolve
void ResolveSubjects()
{
if (attachData == null)

ArrayUtils.ResizeChecked(ref stagingJobs, subjects.Count);
ArrayUtils.ResizeChecked(ref stagingData, subjects.Count * 2);
ArrayUtils.ResizeChecked(ref stagingPins, subjects.Count * 2 + stagingPinsSourceDataCount);
GCHandle attachDataPosePin = GCHandle.Alloc(attachData.pose, GCHandleType.Pinned);
GCHandle attachDataItemPin = GCHandle.Alloc(attachData.item, GCHandleType.Pinned);
stagingPins[stagingPinsSourceDataOffset + 0] = GCHandle.Alloc(meshBuffers.vertexPositions, GCHandleType.Pinned);
stagingPins[stagingPinsSourceDataOffset + 1] = GCHandle.Alloc(meshBuffers.vertexTangents, GCHandleType.Pinned);

subject.meshInstance.SilentlySetVertices(stagingData[indexPos]);
subject.meshInstance.SilentlySetNormals(stagingData[indexNrm]);
//Profiler.BeginSample("recalc-bounds");
//subject.meshInstance.RecalculateBounds();
//Profiler.EndSample();
Profiler.BeginSample("conservative-bounds");
{
//Debug.Log("targetMeshWorldBoundsCenter = " + targetMeshWorldBoundsCenter.ToString("G4") + " (from meshBakedOrAsset = " + meshBakedOrAsset.ToString() + ")");

{
stagingPins[stagingPinsSourceDataOffset + i].Free();
}
attachDataPosePin.Free();
attachDataItemPin.Free();
Profiler.EndSample();
}

[BurstCompile(FloatMode = FloatMode.Fast)]
unsafe struct ResolveJob : IJobParallelFor
{
[NativeDisableUnsafePtrRestriction] public Vector3* meshPositions;
[NativeDisableUnsafePtrRestriction] public Vector3* meshNormals;
[NativeDisableUnsafePtrRestriction] public SkinAttachmentItem* attachItem;
[NativeDisableUnsafePtrRestriction] public SkinAttachmentPose* attachPose;
[NativeDisableUnsafePtrRestriction] public Vector3* resolvedPositions;
[NativeDisableUnsafePtrRestriction] public Vector3* resolvedNormals;
[NativeDisableUnsafePtrRestriction, NoAlias] public Vector3* meshPositions;
[NativeDisableUnsafePtrRestriction, NoAlias] public Vector3* meshNormals;
[NativeDisableUnsafePtrRestriction, NoAlias] public SkinAttachmentItem* attachItem;
[NativeDisableUnsafePtrRestriction, NoAlias] public SkinAttachmentPose* attachPose;
[NativeDisableUnsafePtrRestriction, NoAlias] public Vector3* resolvedPositions;
[NativeDisableUnsafePtrRestriction, NoAlias] public Vector3* resolvedNormals;
public Matrix4x4 resolveTransform;

//TODO this is still too slow, speed it up
//TODO this needs optimization
SkinAttachmentItem desc = attachItem[attachmentIndex + i];
SkinAttachmentItem item = attachItem[attachmentIndex + i];
var poseIndex0 = desc.poseIndex;
var poseIndexN = desc.poseIndex + desc.poseCount;
var poseIndex0 = item.poseIndex;
var poseIndexN = item.poseIndex + item.poseCount;
for (int poseIndex = poseIndex0; poseIndex != poseIndexN; poseIndex++)
{

targetWeights += /*pose.area*/triangleArea;
}
var targetNormalRot = Quaternion.FromToRotation(desc.baseNormal, meshNormals[desc.baseVertex]);
var targetNormal = targetNormalRot * desc.targetNormal;
var targetOffset = targetNormalRot * desc.targetOffset;
var targetNormalRot = Quaternion.FromToRotation(item.baseNormal, meshNormals[item.baseVertex]);
var targetNormal = targetNormalRot * item.targetNormal;
var targetOffset = targetNormalRot * item.targetOffset;
resolvedPositions[i] = resolveTransform.MultiplyPoint3x4(targetBlended / targetWeights + targetOffset);
resolvedNormals[i] = resolveTransform.MultiplyVector(targetNormal);

//--------
// Gizmos
//PACKAGETODO move these to SkinAttachmentTargetEditor
public void OnDrawGizmos()
public void OnDrawGizmosSelected()
{
var activeGO = UnityEditor.Selection.activeGameObject;
if (activeGO == null)

17
Runtime/SkinDeformationRenderer.cs


private Vector3[] blendedPositions;
private Vector3[] blendedNormals;
[Header("Stream options")]
public bool renderAlbedo;
public bool renderFittedWeights;
[Range(1.0f, 10.0f)]

[Space]
[Header("Runtime options")]
[Space]
[Header("Blendshape overrides")]
public bool muteFacialRig = false;
[TextArea(1, 20)]
public string muteFacialRigExclude = "";

smrProps = new MaterialPropertyBlock();
#if UNITY_EDITOR
if (enabledInstances.Contains(this) == false)
enabledInstances.Add(this);
if (SkinDeformationRenderer.enabledInstances.Contains(this) == false)
SkinDeformationRenderer.enabledInstances.Add(this);
#if UNITY_EDITOR
SkinDeformationRenderer.enabledInstances.Remove(this);
#endif
#if UNITY_EDITOR
enabledInstances.Remove(this);
#endif
}
void OnDestroy()

24
Runtime/SnappersHeadRenderer.cs


[EnumFlag]
public SnappersHeadDefinition.Warnings warnings;
[Header("Activation Masks")]
[Header("Activation masks")]
public Texture2D mask1;
public Texture2D mask2;
public Texture2D mask3;

public Texture2D mask11;
public Texture2D mask12;
[Header("Activation Maps")]
[Header("Activation maps")]
public Texture2D albedo1;
public Texture2D albedo2;
public Texture2D albedo3;

SnappersHeadDefinition.ApplyControllers(ref headInstance);
SnappersHeadDefinition.ApplyBlendShapes(ref headInstance, smr);
SnappersHeadDefinition.ApplyShaderParam(ref headInstance, smrProps);
/*
SnappersHeadDefinition.UpdateInstanceData(ref headData, headDefinition, smr);
if (injectFittedWeights)
{
var skinDeform = GetComponent<SkinDeformationRenderer>();
if (skinDeform != null && skinDeform.fittedWeightsAvailable)
{
var fittedWeights = skinDeform.fittedWeights;
var inputIndices = headData.blendShapeIndices;
var inputWeights = headData.blendShapeWeights;
for (int i = 0; i != headData.blendShapeIndices.Length; i++)
{
inputWeights[i] = Mathf.Clamp01(Mathf.Max(injectFittedWeightsScale * fittedWeights[inputIndices[i]], inputWeights[i]));
}
}
}
SnappersHeadDefinition.UpdateMaskParams(ref headData, headDefinition);
SnappersHeadDefinition.UpdatePropertyBlock(smrProps, headData);
*/
}
else
{

正在加载...
取消
保存