浏览代码

add various improvements to frame fitting (target asset with different vertex count, threaded obj import, custom reference frame), add support for multiple face materials

/main
Lasse Jon Fuglsang Pedersen 4 年前
当前提交
57aba62d
共有 11 个文件被更改,包括 673 次插入238 次删除
  1. 2
      Editor/SkinAttachmentTargetEditor.cs
  2. 376
      Editor/SkinDeformationClipEditor.cs
  3. 10
      Editor/SkinDeformationClipRegions.cs
  4. 74
      Editor/SnappersHeadRendererEditor.cs
  5. 58
      Runtime/SkinDeformationClip.cs
  6. 18
      Runtime/SnappersHeadDefinition.cs
  7. 293
      Runtime/SnappersHeadRenderer.cs
  8. 50
      Runtime/Utility/NativeMesh.cs
  9. 10
      Runtime/Utility/NativeMeshObjLoader.cs
  10. 9
      Runtime/BinaryAsset.cs
  11. 11
      Runtime/BinaryAsset.cs.meta

2
Editor/SkinAttachmentTargetEditor.cs


for (int i = 0; i != driver.subjects.Count; i++)
{
var attachment = driver.subjects[i];
if (attachment == null)
continue;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.ObjectField(attachment, typeof(SkinAttachment), false);

376
Editor/SkinDeformationClipEditor.cs


using System.Linq;
using UnityEngine;
using UnityEditor;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
namespace Unity.DemoTeam.DigitalHuman
{

void FittedIndices_SetFromTargetMesh(object userData)
{
var clip = userData as SkinDeformationClip;
var iarr = SkinDeformationFitting.GetBlendShapeIndices(clip.importSettings.transferTarget);
var iarr = SkinDeformationFitting.GetBlendShapeIndices(clip.settings.transferTarget);
clip.importSettings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
clip.settings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
}
void FittedIndices_SetPrecomputed(object userData)

0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317
};
clip.importSettings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
clip.settings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
}
void FittedIndices_SetPrecomputedWrinkles(object userData)

1,14,15,44,48,51,54,59,62,67,72,80,85,87,89,91,93,95,97,110,113,116,118,119,121,123,126,129,132,135,138,141,144,147,150,158,163,181,183,184,187,191,194,197,200,207,209,219,221,227,229,230,231,232,233,235,237,240,241,250,251,252,253,254,255,256,257,258,259,264,265,290,291,292,293,294,295
};
clip.importSettings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
clip.settings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
var istr = clip.importSettings.fittedIndices;
var istr = clip.settings.fittedIndices;
clip.importSettings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
clip.settings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
var istr = clip.importSettings.fittedIndices;
var istr = clip.settings.fittedIndices;
iarr = SkinDeformationFitting.ComputeLinearlyIndependentBlendShapeIndices(clip.importSettings.transferTarget, iarr);
iarr = SkinDeformationFitting.ComputeLinearlyIndependentBlendShapeIndices(clip.settings.transferTarget, iarr);
if (iarr == null)
{

clip.importSettings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
clip.settings.fittedIndices = String.Join(",", iarr.Select(i => i.ToString()).ToArray());
}
void OnDisable()

{
SkinDeformationClip clip = (SkinDeformationClip)target;
if (clip.importSettings.solveRegionPreview)
if (clip.settings.solveRegionPreview)
SkinDeformationClipRegions.Enable(clip);
else
SkinDeformationClipRegions.Disable();

return indices;
}
static void AssertClipSources(SkinDeformationClip clip)
{
//TODO validation
}
static SharedJobData sharedJobData;
struct SharedJobData
{
public string[] paths;
public NativeMeshObjLoader.VertexAttribs vertexAttribs;
public NativeMeshObjLoader.VertexOrder vertexOrder;
public NativeMeshSOA[] result;
public bool[] resultTouched;
}
struct ObjLoaderJob : IJobParallelFor
{
public void Execute(int i)
{
sharedJobData.resultTouched[i] = true;
using (var sourceObj_i = NativeMeshObjLoader.Parse(sharedJobData.paths[i], Allocator.Temp, sharedJobData.vertexAttribs, sharedJobData.vertexOrder))
{
sharedJobData.result[i].CopyFrom(sourceObj_i);
}
}
}
var sourceObjsPreloaded = null as NativeMeshSOA[];
try
{
var progressTitle = "Importing '" + clip.name + "'";

var sourceObjPaths = null as string[];
var sourceMeshAssets = null as Mesh[];
var sourceAlbedoAssets = null as Texture2D[];
var referenceObjPath = clip.settings.referenceObjPath;
var referenceMeshAsset = clip.settings.referenceMeshAsset;
var referenceIsFirstFrame = clip.settings.referenceIsFirstFrame;
int frameFaceIndicesCount = 0;
var useExternalLoader = (clip.importSettings.readFrom == SkinDeformationClip.InputType.ExternalObj);
var useExternalLoader = (clip.settings.sourceFrom == SkinDeformationClip.SourceType.ExternalObj);
sourceObjPaths = GetFilesAtPath(clip.importSettings.externalObjPath, clip.importSettings.externalObjPattern);
Debug.Assert(sourceObjPaths.Length > 0, "source .obj count == 0 (check import settings)");
sourceObjPaths = GetFilesAtPath(clip.settings.externalObjPath, clip.settings.externalObjPattern);
Debug.Assert(sourceObjPaths.Length > 0, "source obj count == 0 (check import settings)");
if (referenceIsFirstFrame)
{
referenceObjPath = sourceObjPaths[0];
sourceObjPaths = sourceObjPaths.Skip(1).ToArray();
}
using (var nativeMesh = NativeMeshObjLoader.Parse(sourceObjPaths[0]))
using (var nativeMesh = NativeMeshObjLoader.Parse(referenceObjPath))
frameFaceIndicesCount = nativeMesh.faceIndicesCount;
}
if (clip.settings.externalObjPreloadThreaded)
{
sharedJobData.paths = sourceObjPaths;
sharedJobData.vertexAttribs = NativeMeshObjLoader.VertexAttribs.Position;// ignored for now
sharedJobData.vertexOrder = NativeMeshObjLoader.VertexOrder.ByDefinition;
sharedJobData.result = new NativeMeshSOA[sourceObjPaths.Length];
sharedJobData.resultTouched = new bool[sourceObjPaths.Length];
for (int i = 0; i != sharedJobData.result.Length; i++)
{
sharedJobData.result[i].Allocate(frameVertexCount, frameFaceIndicesCount, Allocator.Persistent);
}
unsafe
{
fixed (bool* resultTouched = sharedJobData.resultTouched)
{
var jobDef = new ObjLoaderJob();
var job = jobDef.Schedule(sourceObjPaths.Length, 1);
JobHandle.ScheduleBatchedJobs();
while (true)
{
int numTotal = sourceObjPaths.Length;
int numTouched = 0;
for (int i = 0; i != numTotal; i++)
{
if (resultTouched[i])
{
numTouched++;
}
}
EditorUtility.DisplayProgressBar(progressTitle, "Loading assets (" + numTouched + " / " + numTotal + ")", (progressIndex - 1 + ((float)numTouched / numTotal)) / progressCount);
if (job.IsCompleted)
break;
}
job.Complete();
}
}
sourceObjsPreloaded = sharedJobData.result;
sourceMeshAssets = GetAssetsAtPath<Mesh>(clip.importSettings.meshAssetPath, clip.importSettings.meshAssetPrefix);
Debug.Assert(sourceMeshAssets.Length > 0, "mesh count == 0 (check import settings)");
sourceMeshAssets = GetAssetsAtPath<Mesh>(clip.settings.meshAssetFolder, clip.settings.meshAssetPrefix);
Debug.Assert(sourceMeshAssets.Length > 0, "source mesh count == 0 (check import settings)");
sourceAlbedoAssets = GetAssetsAtPath<Texture2D>(clip.importSettings.albedoAssetPath, clip.importSettings.albedoAssetPrefix);
sourceAlbedoAssets = GetAssetsAtPath<Texture2D>(clip.settings.albedoAssetFolder, clip.settings.albedoAssetPrefix);
Debug.LogWarning("mesh asset count != albedo asset count: skipping albedos");
Debug.LogWarning("source albedo count != mesh count (SKIPPING albedo assets)");
}
if (referenceIsFirstFrame)
{
referenceMeshAsset = sourceMeshAssets[0];
sourceMeshAssets = sourceMeshAssets.Skip(1).ToArray();
if (sourceAlbedoAssets != null)
sourceAlbedoAssets = sourceAlbedoAssets.Skip(1).ToArray();
Debug.Assert(referenceMeshAsset != null);
frameVertexCount = sourceMeshAssets[0].vertexCount;
frameVertexCount = referenceMeshAsset.vertexCount;
Debug.Log("frameCount: " + frameCount);
Debug.Log("frameVertexCount: " + frameVertexCount);
int frameFittedWeightsCount = 0;// modified later
var frames = new SkinDeformation[frameCount];

MeshBuffers buffersFrame0 = new MeshBuffers(frameVertexCount);
MeshBuffers buffersFrameX = new MeshBuffers(frameVertexCount);
MeshBuffers buffersTarget = buffersFrame0;
if (clip.importSettings.transferTarget != null)
{
buffersTarget = new MeshBuffers(clip.importSettings.transferTarget);
}
MeshBuffers meshBuffers = new MeshBuffers(frameVertexCount);
MeshBuffers meshBuffersReference = new MeshBuffers(frameVertexCount);
MeshAdjacency weldedAdjacency = new MeshAdjacency(buffersTarget, clip.importSettings.solveWelded);
MeshAdjacency weldedAdjacency = new MeshAdjacency(meshBuffersReference, clip.settings.solveWelded);
var sourceRotation = Quaternion.Euler(clip.importSettings.applyRotation);
var sourceScale = clip.importSettings.applyScale;
var sourceRotation = Quaternion.Euler(clip.settings.applyRotation);
var sourceScale = clip.settings.applyScaling;
using (var nativeMesh = NativeMeshObjLoader.Parse(sourceObjPaths[0]))
using (var referenceObj = NativeMeshObjLoader.Parse(referenceObjPath))
buffersFrame0.LoadFrom(nativeMesh);
buffersFrame0.ApplyRotation(sourceRotation);
buffersFrame0.ApplyScale(sourceScale);
meshBuffersReference.LoadFrom(referenceObj);
meshBuffersReference.ApplyRotation(sourceRotation);
meshBuffersReference.ApplyScale(sourceScale);
buffersFrame0.LoadFrom(sourceMeshAssets[0]);
buffersFrame0.ApplyRotation(sourceRotation);
buffersFrame0.ApplyScale(sourceScale);
meshBuffersReference.LoadFrom(referenceMeshAsset);
meshBuffersReference.ApplyRotation(sourceRotation);
meshBuffersReference.ApplyScale(sourceScale);
var denoiseIndices = ResolveIndexArrayFromVertexSelectionArray(clip.importSettings.denoiseRegions, weldedAdjacency);
var denoiseFactor = clip.importSettings.denoiseStrength;
var denoiseIndices = ResolveIndexArrayFromVertexSelectionArray(clip.settings.denoiseRegions, weldedAdjacency);
var denoiseFactor = clip.settings.denoiseStrength;
var transplantIndices = ResolveIndexArrayFromVertexSelectionArray(clip.importSettings.transplantRegions, weldedAdjacency);
var transplantFactor = clip.importSettings.transplantStrength;
var transplantSource = clip.importSettings.transferTarget;
if (transplantFactor < float.Epsilon || transplantSource == null)
var transplantIndices = ResolveIndexArrayFromVertexSelectionArray(clip.settings.transplantRegions, weldedAdjacency);
var transplantFactor = clip.settings.transplantStrength;
if (transplantFactor < float.Epsilon)
transplantIndices = new int[0];
#if SOLVE_FULL_LAPLACIAN

#endif
#if SOLVE_FULL_LAPLACIAN
var meshLaplacianTransform = null as MeshLaplacianTransform;
var laplacianTransform = null as MeshLaplacianTransform;
var meshLaplacianTransform = null as MeshLaplacianTransformROI;
var laplacianTransform = null as MeshLaplacianTransformROI;
var transplantBuffers = new MeshBuffers(frameVertexCount);
var transplantLaplacian = new MeshLaplacian();
var meshLaplacianReference = new MeshLaplacian();
meshLaplacianTransform = new MeshLaplacianTransform(weldedAdjacency, laplacianConstraintIndices);
laplacianTransform = new MeshLaplacianTransform(weldedAdjacency, laplacianConstraintIndices);
meshLaplacianTransform = new MeshLaplacianTransformROI(weldedAdjacency, laplacianROIIndices, 0);
laplacianTransform = new MeshLaplacianTransformROI(weldedAdjacency, laplacianROIIndices, 0);
denoiseIndices[i] = meshLaplacianTransform.internalFromExternal[denoiseIndices[i]];
denoiseIndices[i] = laplacianTransform.internalFromExternal[denoiseIndices[i]];
transplantIndices[i] = meshLaplacianTransform.internalFromExternal[transplantIndices[i]];
transplantIndices[i] = laplacianTransform.internalFromExternal[transplantIndices[i]];
meshLaplacianTransform.ComputeMeshLaplacian(meshLaplacianDenoised, buffersFrame0);
if (transplantIndices.Length > 0 && transplantSource != null)
{
transplantBuffers.LoadFrom(transplantSource);
meshLaplacianTransform.ComputeMeshLaplacian(transplantLaplacian, transplantBuffers);
}
laplacianTransform.ComputeMeshLaplacian(meshLaplacianDenoised, meshBuffersReference);
laplacianTransform.ComputeMeshLaplacian(meshLaplacianReference, meshBuffersReference);
EditorUtility.DisplayProgressBar(progressTitle, "Importing frames", (progressIndex - 1 + ((float)i / frameCount)) / progressCount);
EditorUtility.DisplayProgressBar(progressTitle, "Importing frames (" + (i + 1) + " / " + frameCount + ")", (progressIndex - 1 + ((float)i / frameCount)) / progressCount);
using (var nativeMesh = NativeMeshObjLoader.Parse(sourceObjPaths[i]))
if (clip.settings.externalObjPreloadThreaded)
buffersFrameX.LoadFrom(nativeMesh);
buffersFrameX.ApplyRotation(sourceRotation);
buffersFrameX.ApplyScale(sourceScale);
meshBuffers.LoadFrom(sourceObjsPreloaded[i]);
}
else using (var sourceObj_i = NativeMeshObjLoader.Parse(sourceObjPaths[i]))
{
meshBuffers.LoadFrom(sourceObj_i);
meshBuffers.ApplyRotation(sourceRotation);
meshBuffers.ApplyScale(sourceScale);
buffersFrameX.LoadFrom(sourceMeshAssets[i]);
buffersFrameX.ApplyRotation(sourceRotation);
buffersFrameX.ApplyScale(sourceScale);
meshBuffers.LoadFrom(sourceMeshAssets[i]);
meshBuffers.ApplyRotation(sourceRotation);
meshBuffers.ApplyScale(sourceScale);
}
if (meshBuffers.vertexCount != frameVertexCount)
{
Debug.LogWarning("frame " + i + " has " + meshBuffers.vertexCount + " vertices (expected " + frameVertexCount + ")");
meshLaplacianTransform.ComputeMeshLaplacian(meshLaplacian, buffersFrameX);
laplacianTransform.ComputeMeshLaplacian(meshLaplacian, meshBuffers);
double historyFactor = denoiseFactor;
foreach (int j in denoiseIndices)

foreach (int j in transplantIndices)
{
meshLaplacian.vertexDifferentialX[j] = transplantFactor * transplantLaplacian.vertexDifferentialX[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialX[j];
meshLaplacian.vertexDifferentialY[j] = transplantFactor * transplantLaplacian.vertexDifferentialY[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialY[j];
meshLaplacian.vertexDifferentialZ[j] = transplantFactor * transplantLaplacian.vertexDifferentialZ[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialZ[j];
meshLaplacian.vertexDifferentialX[j] = transplantFactor * meshLaplacianReference.vertexDifferentialX[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialX[j];
meshLaplacian.vertexDifferentialY[j] = transplantFactor * meshLaplacianReference.vertexDifferentialY[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialY[j];
meshLaplacian.vertexDifferentialZ[j] = transplantFactor * meshLaplacianReference.vertexDifferentialZ[j] + (1.0 - transplantFactor) * meshLaplacian.vertexDifferentialZ[j];
meshLaplacianTransform.ResolveMeshBuffers(buffersFrameX, meshLaplacian);
laplacianTransform.ResolveMeshBuffers(meshBuffers, meshLaplacian);
buffersFrameX.RecalculateNormals(weldedAdjacency);
buffersFrameX.ApplyWeldedChanges(weldedAdjacency);
meshBuffers.RecalculateNormals(weldedAdjacency);
meshBuffers.ApplyWeldedChanges(weldedAdjacency);
frames[i].SetAlbedo((sourceAlbedoAssets != null) ? sourceAlbedoAssets[i] : null);
frames[i].SetDeltas(buffersFrame0, buffersFrameX);
var targetVertexCount = buffersFrame0.vertexCount;
if (targetVertexCount != buffersFrameX.vertexCount)
{
Debug.LogWarning("frame " + i + " has different vertexCount (" + buffersFrameX.vertexCount + " vs " + targetVertexCount + " in frame 0)");
}
frames[i].SetAlbedo(sourceAlbedoAssets != null ? sourceAlbedoAssets[i] : null);
frames[i].SetDeltas(meshBuffersReference, meshBuffers);
}
for (int i = 0; i != subframeCount; i++)

subframes[i].fractionHi = 1.0f;
}
if (clip.importSettings.keyframes)
if (clip.settings.keyframes)
ImportFrameIntervalsFromCSV(clip.importSettings.keyframesCSV, frameCount - 1, ref subframeCount, ref subframes);
ImportFrameIntervalsFromCSV(clip.settings.keyframesCSV, frameCount - 1, ref subframeCount, ref subframes);
EditorUtility.DisplayProgressBar(progressTitle, "Retargeting frames", progressIndex++ / progressCount);
EditorUtility.DisplayProgressBar(progressTitle, "Transferring frames", progressIndex++ / progressCount);
if (clip.settings.transferTarget != null)
var targetBuffers = new MeshBuffers(clip.settings.transferTarget);
var targetVertexCount = targetBuffers.vertexCount;
var targetVertexResolve = new int[targetVertexCount];
Debug.LogFormat("transferMode: {0}", clip.settings.transferMode);
Debug.LogFormat("targetVertexCount: {0}", targetVertexCount);
switch (clip.settings.transferMode)
{
case SkinDeformationClip.ImportSettings.TransferMode.ByVertexIndex:
{
Debug.Assert(frameVertexCount == targetVertexCount, "target vertex count does not match reference vertex count");
for (int i = 0; i != targetVertexCount; i++)
{
targetVertexResolve[i] = i;
}
}
break;
case SkinDeformationClip.ImportSettings.TransferMode.ByVertexPosition:
{
var referenceBSP = new KdTree3(meshBuffersReference.vertexPositions, meshBuffersReference.vertexCount);
var referenceDelta2Max = 0.0f;
var referenceDelta2Count = 0;
var referenceDelta2Threshold = 1e-10f;
for (int i = 0; i != targetVertexCount; i++)
{
targetVertexResolve[i] = referenceBSP.FindNearest(ref targetBuffers.vertexPositions[i]);
}
for (int i = 0; i != targetVertexCount; i++)
{
Vector3 posTarget = targetBuffers.vertexPositions[i];
Vector3 posReference = meshBuffersReference.vertexPositions[targetVertexResolve[i]];
var delta2 = Vector3.SqrMagnitude(posTarget - posReference);
if (delta2 > referenceDelta2Threshold)
{
referenceDelta2Max = Mathf.Max(delta2, referenceDelta2Max);
referenceDelta2Count++;
}
}
if (referenceDelta2Count > 0)
{
Debug.LogWarning("some (" + referenceDelta2Count + ") target vertices were far from reference (max delta: " + referenceDelta2Max + ")");
}
}
break;
}
var targetDeltaPositions = new Vector3[targetVertexCount];
var targetDeltaNormals = new Vector3[targetVertexCount];
for (int frameIndex = 0; frameIndex != frameCount; frameIndex++)
{
EditorUtility.DisplayProgressBar(progressTitle, "Transferring frames (" + (frameIndex + 1) + " / " + frameCount + ")", (progressIndex - 1 + ((float)frameIndex / frameCount)) / progressCount);
for (int i = 0; i != targetVertexCount; i++)
{
int j = targetVertexResolve[i];// reference index
targetDeltaPositions[i] = frames[frameIndex].deltaPositions[j];
targetDeltaNormals[i] = frames[frameIndex].deltaNormals[j];
}
ArrayUtils.ResizeChecked(ref frames[frameIndex].deltaPositions, targetVertexCount);
ArrayUtils.ResizeChecked(ref frames[frameIndex].deltaNormals, targetVertexCount);
ArrayUtils.CopyChecked(targetDeltaPositions, ref frames[frameIndex].deltaPositions, targetVertexCount);
ArrayUtils.CopyChecked(targetDeltaNormals, ref frames[frameIndex].deltaNormals, targetVertexCount);
}
frameVertexCount = targetVertexCount;
/*
switch (clip.importSettings.transferMode)
{
case SkinDeformationClip.TransferMode.PassThrough:

}
break;
}
*/
if (clip.settings.transferTarget != null)
if (clip.importSettings.fitToBlendShapes)
frameFittedWeightsCount = clip.importSettings.transferTarget.blendShapeCount;
if (clip.settings.fitToBlendShapes)
frameFittedWeightsCount = clip.settings.transferTarget.blendShapeCount;
else
frameFittedWeightsCount = 0;

if (frameFittedWeightsCount > 0)
{
var blendShapeIndicesCommaSep = clip.importSettings.fittedIndices;
var blendShapeIndicesCommaSep = clip.settings.fittedIndices;
SkinDeformationFitting.FitFramesToBlendShapes(frames, clip.importSettings.transferTarget, blendShapeIndices, clip.importSettings.fittingMethod, clip.importSettings.fittingParam);
SkinDeformationFitting.FitFramesToBlendShapes(frames, clip.settings.transferTarget, blendShapeIndices, clip.settings.fittingMethod, clip.settings.fittingParam);
else
{
for (int i = 0; i != frameCount; i++)
frames[i].fittedWeights = new float[0];
}
clip.lastImport = clip.importSettings.Clone();
clip.settingsLastImported = clip.settings.Clone();
clip.frameCount = frameCount;
clip.frameVertexCount = frameVertexCount;
clip.frameFittedWeightsCount = frameFittedWeightsCount;

}
finally
{
if (sourceObjsPreloaded != null)
{
for (int i = 0; i != sourceObjsPreloaded.Length; i++)
{
sourceObjsPreloaded[i].Dispose();
}
sourceObjsPreloaded = null;
}
EditorUtility.ClearProgressBar();
}
}

10
Editor/SkinDeformationClipRegions.cs


if (Event.current.type != EventType.Repaint)
return;
var mesh = clip.importSettings.transferTarget;
var mesh = clip.settings.transferTarget;
var updateDenoiseIndices = !CompareTextAssetArrays(activeDenoiseIndices, clip.importSettings.denoiseRegions);
var updateTransplantIndices = !CompareTextAssetArrays(activeTransplantIndices, clip.importSettings.transplantRegions);
var updateDenoiseIndices = !CompareTextAssetArrays(activeDenoiseIndices, clip.settings.denoiseRegions);
var updateTransplantIndices = !CompareTextAssetArrays(activeTransplantIndices, clip.settings.transplantRegions);
foreach (var deformationRenderer in SkinDeformationRenderer.enabledInstances)
{

if (updateDenoiseIndices)
{
updateDenoiseIndices = false;
activeDenoiseIndices = clip.importSettings.denoiseRegions.Clone() as TextAsset[];
activeDenoiseIndices = clip.settings.denoiseRegions.Clone() as TextAsset[];
pairedDenoiseIndices = BuildPairsFromIndices(targetMeshInfo.meshAdjacency, SkinDeformationClipEditor.ResolveIndexArrayFromVertexSelectionArray(activeDenoiseIndices));
}

activeTransplantIndices = clip.importSettings.transplantRegions.Clone() as TextAsset[];
activeTransplantIndices = clip.settings.transplantRegions.Clone() as TextAsset[];
pairedTransplantIndices = BuildPairsFromIndices(targetMeshInfo.meshAdjacency, SkinDeformationClipEditor.ResolveIndexArrayFromVertexSelectionArray(activeTransplantIndices));
}

74
Editor/SnappersHeadRendererEditor.cs


if (shr == null)
return;
if (GUILayout.Button("Create Texture Array Assets"))
EditorGUILayout.HelpBox("Remember to build texture arrays after assigning or updating textures in the material setup section.", MessageType.Info);
if (GUILayout.Button("Build texture arrays"))
CreateTextureArrayAssets(shr);
BuildTextureArrays(shr);
EditorGUILayout.Space();
static void CreateTextureArrayAssets(SnappersHeadRenderer shr)
static void BuildTextureArrays(SnappersHeadRenderer shr)
var inputMask = new Texture2D[] { shr.mask1, shr.mask2, shr.mask3, shr.mask4, shr.mask5, shr.mask6, shr.mask7, shr.mask8, shr.mask9, shr.mask10, shr.mask11, shr.mask12 };
var inputAlbedo = new Texture2D[] { shr.albedo1, shr.albedo2, shr.albedo3, shr.albedo4 };
var inputNormal = new Texture2D[] { shr.normal1, shr.normal2, shr.normal3, shr.normal4 };
var inputCavity = new Texture2D[] { shr.cavity1, shr.cavity2, shr.cavity3, shr.cavity4 };
var textureSets = shr.materials;
if (textureSets == null)
return;
var assetPath = shr.arrayAssetPath.Trim('/');
var assetPathMask = assetPath + "/_Tex2DArray_Mask.asset";
var assetPathAlbedo = assetPath + "/_Tex2DArray_Albedo.asset";
var assetPathNormal = assetPath + "/_Tex2DArray_Normal.asset";
var assetPathCavity = assetPath + "/_Tex2DArray_Cavity.asset";
for (int i = 0; i != textureSets.Length; i++)
{
ref var ts = ref textureSets[i];
shr.arrayMask = CreateTextureArrayAsset(inputMask, linear: true, assetPathMask);
shr.arrayAlbedo = CreateTextureArrayAsset(inputAlbedo, linear: false, assetPathAlbedo);
shr.arrayNormal = CreateTextureArrayAsset(inputNormal, linear: true, assetPathNormal);
shr.arrayCavity = CreateTextureArrayAsset(inputCavity, linear: true, assetPathCavity);
var inputMask = new Texture2D[] { ts.mask1, ts.mask2, ts.mask3, ts.mask4, ts.mask5, ts.mask6, ts.mask7, ts.mask8, ts.mask9, ts.mask10, ts.mask11, ts.mask12 };
var inputAlbedo = new Texture2D[] { ts.albedo1, ts.albedo2, ts.albedo3, ts.albedo4 };
var inputNormal = new Texture2D[] { ts.normal1, ts.normal2, ts.normal3, ts.normal4 };
var inputCavity = new Texture2D[] { ts.cavity1, ts.cavity2, ts.cavity3, ts.cavity4 };
ts.maskArray = CreateTextureArrayAsset(inputMask, linear: true);
ts.albedoArray = CreateTextureArrayAsset(inputAlbedo, linear: false);
ts.normalArray = CreateTextureArrayAsset(inputNormal, linear: true);
ts.cavityArray = CreateTextureArrayAsset(inputCavity, linear: true);
}
static Texture2DArray CreateTextureArrayAsset(Texture2D[] slices, bool linear)
{
var first = System.Array.Find(slices, e => e != null);
if (first == null)
return null;
var path = AssetDatabase.GetAssetPath(first);
var lastDot = path.LastIndexOf('.');
if (lastDot > path.LastIndexOf('/'))
{
path = path.Substring(0, lastDot) + "_array.asset";
}
else
{
path = path + "_array.asset";
}
return CreateTextureArrayAsset(slices, linear, path);
}
var array = new Texture2DArray(slices[0].width, slices[0].height, slices.Length, slices[0].format, true, linear);
var first = System.Array.Find(slices, e => e != null);
if (first == null)
return null;
var array = new Texture2DArray(first.width, first.height, slices.Length, first.format, true, linear);
if (slices.Length > 0 && slices[0] != null)
if (slices.Length > 0)
array.wrapMode = slices[0].wrapMode;
array.anisoLevel = slices[0].anisoLevel;
array.filterMode = slices[0].filterMode;
array.wrapMode = first.wrapMode;
array.anisoLevel = first.anisoLevel;
array.filterMode = first.filterMode;
}
for (int i = 0; i != slices.Length; i++)

58
Runtime/SkinDeformationClip.cs


using System;
using System.IO;
using UnityEngine;
using UnityEngine.Serialization;
using Unity.DemoTeam.Attributes;
#if UNITY_EDITOR
using UnityEditor;

}
//--- import settings begin ---
public enum TransferMode
{
PassThrough,
PassThroughWithFirstFrameDelta,
}
public enum InputType
public enum SourceType
{
ExternalObj,
ProjectAssets,

public class ImportSettings
{
[Header("Sequence")]
public InputType readFrom = InputType.ExternalObj;
[VisibleIf("readFrom", InputType.ExternalObj)] public string externalObjPath;
[VisibleIf("readFrom", InputType.ExternalObj)] public string externalObjPattern = "*.obj";
[VisibleIf("readFrom", InputType.ProjectAssets)] public string meshAssetPath;
[VisibleIf("readFrom", InputType.ProjectAssets)] public string meshAssetPrefix;
[VisibleIf("readFrom", InputType.ProjectAssets)] public string albedoAssetPath;
[VisibleIf("readFrom", InputType.ProjectAssets)] public string albedoAssetPrefix;
[Header("Source sequence")]
[FormerlySerializedAs("readFrom")] public SourceType sourceFrom = SourceType.ExternalObj;
[FormerlySerializedAs("externalObjPath")]
[VisibleIf("sourceFrom", SourceType.ExternalObj)] public string externalObjPath;
[FormerlySerializedAs("externalObjPattern")]
[VisibleIf("sourceFrom", SourceType.ExternalObj)] public string externalObjPattern = "*.obj";
[VisibleIf("sourceFrom", SourceType.ExternalObj)] public bool externalObjPreloadThreaded = true;
[VisibleIf("sourceFrom", SourceType.ProjectAssets)] public string meshAssetFolder;
[VisibleIf("sourceFrom", SourceType.ProjectAssets)] public string meshAssetPrefix;
[VisibleIf("sourceFrom", SourceType.ProjectAssets)] public string albedoAssetFolder;
[VisibleIf("sourceFrom", SourceType.ProjectAssets)] public string albedoAssetPrefix;
[Tooltip("Enable this to treat the imported frames as keyframes")]
[Header("Mesh transform")]
[Header("Source reference")]
public bool referenceIsFirstFrame;
[VisibleIf("sourceFrom", SourceType.ExternalObj)] public string referenceObjPath;
[VisibleIf("sourceFrom", SourceType.ProjectAssets)] public Mesh referenceMeshAsset;
[Header("Frame transform")]
public float applyScale = 1.0f;
public float applyScaling = 0.01f;
[Header("Mesh processing")]
[Header("Frame processing")]
[Tooltip("Regions are specified in text files. Each file should contain an array of vertex indices on the form: [i, j, k, ...]")]
public TextAsset[] denoiseRegions;
[Range(0.0f, 1.0f)]

public bool solveWelded = true;
[Header("Frame transfer")]
public TransferMode transferMode = TransferMode.ByVertexIndex;
public TransferMode transferMode;
public enum TransferMode
{
ByVertexIndex,
ByVertexPosition,
}
[Header("Frame fitting")]
public bool fitToBlendShapes = false;

var c = this.MemberwiseClone() as ImportSettings;
c.externalObjPath = c.externalObjPath.Clone() as string;
c.externalObjPattern = c.externalObjPattern.Clone() as string;
c.meshAssetPath = c.meshAssetPath.Clone() as string;
c.meshAssetFolder = c.meshAssetFolder.Clone() as string;
c.albedoAssetPath = c.albedoAssetPath.Clone() as string;
c.albedoAssetFolder = c.albedoAssetFolder.Clone() as string;
c.referenceObjPath = c.referenceObjPath.Clone() as string;
c.denoiseRegions = c.denoiseRegions.Clone() as TextAsset[];
c.transplantRegions = c.transplantRegions.Clone() as TextAsset[];
c.fittedIndices = c.fittedIndices.Clone() as string;

[ReadOnly]
public ImportSettings lastImport = new ImportSettings();
public ImportSettings importSettings = new ImportSettings();
[FormerlySerializedAs("lastImport")]
public ImportSettings settingsLastImported = new ImportSettings();
[FormerlySerializedAs("importSettings")]
public ImportSettings settings = new ImportSettings();
//--- import settings end ---
//--- frame data serialization begin ---

18
Runtime/SnappersHeadDefinition.cs


public InstanceData CreateInstanceData<NamedControllers, NamedBlendShapes>(Mesh sourceMesh, Transform sourceRig, Warnings warnings) where NamedControllers : struct where NamedBlendShapes : struct
{
var meshName = sourceMesh.name;
if (meshName.EndsWith(MeshInstanceBehaviour.meshInstanceSuffix))
meshName = meshName.Substring(0, meshName.IndexOf(MeshInstanceBehaviour.meshInstanceSuffix));
var blendShapePrefix = meshName + "_blendShape.";
var blendShapePrefix = "";
if (sourceMesh.blendShapeCount > 0)
{
var firstBlendShapeName = sourceMesh.GetBlendShapeName(0);
var firstBlendShapeDelim = firstBlendShapeName.IndexOf('.');
if (firstBlendShapeDelim != -1)
{
blendShapePrefix = firstBlendShapeName.Substring(0, firstBlendShapeDelim + 1);
}
}
var controllerPrefix = string.Empty;
var controllerNames = typeof(NamedControllers).GetFields();

else if (warnings.HasFlag(Warnings.MissingBlendShapes))
Debug.LogWarningFormat("rig definition {0} targets blend shape not present in linked mesh: {1}", this.name, blendShapePrefix + blendShapeNames[i].Name);
}
//Debug.LogFormat("{0} discovered blendShapeIndices: {1}", this.name, string.Join(",", instanceData.blendShapeIndices));
return instanceData;
}

293
Runtime/SnappersHeadRenderer.cs


//#define _SNAPPERS_TEXTURE_ARRAYS
using System;
using UnityEngine;
using UnityEngine.Serialization;
using Unity.DemoTeam.Attributes;

private SkinnedMeshRenderer smr;
private MaterialPropertyBlock smrProps;
[Header("Facial Rig")]
[Header("Facial rig")]
public SnappersHeadDefinition headDefinition;
public SnappersHeadDefinition headDefinition;
[FormerlySerializedAs("headController")]
public Transform headControllers;
[EnumFlag]
public SnappersHeadDefinition.Warnings warnings;
[FormerlySerializedAs("headController")] public Transform headControllers;
[EnumFlag] public SnappersHeadDefinition.Warnings warnings;
[Header("Material setup")]
public TextureSet[] materials = new TextureSet[0];
[Header("Activation masks")]
public Texture2D mask1;
public Texture2D mask2;
public Texture2D mask3;
public Texture2D mask4;
public Texture2D mask5;
public Texture2D mask6;
public Texture2D mask7;
public Texture2D mask8;
public Texture2D mask9;
public Texture2D mask10;
public Texture2D mask11;
public Texture2D mask12;
[Serializable]
public struct TextureSet
{
[Header("Identifier")]
public int materialIndex;
public MaterialPropertyBlock materialProps;
[Header("Activation maps")]
public Texture2D albedo1;
public Texture2D albedo2;
public Texture2D albedo3;
public Texture2D albedo4;
[Space]
public Texture2D normal1;
public Texture2D normal2;
public Texture2D normal3;
public Texture2D normal4;
[Space]
public Texture2D cavity1;
public Texture2D cavity2;
public Texture2D cavity3;
public Texture2D cavity4;
[Header("Activation masks")]
public Texture2D mask1;
public Texture2D mask2;
public Texture2D mask3;
public Texture2D mask4;
public Texture2D mask5;
public Texture2D mask6;
public Texture2D mask7;
public Texture2D mask8;
public Texture2D mask9;
public Texture2D mask10;
public Texture2D mask11;
public Texture2D mask12;
#if _SNAPPERS_TEXTURE_ARRAYS
public Texture2DArray maskArray;
#endif
[Header("Activation maps")]
public Texture2D albedo1;
public Texture2D albedo2;
public Texture2D albedo3;
public Texture2D albedo4;
#if _SNAPPERS_TEXTURE_ARRAYS
public Texture2DArray albedoArray;
#endif
[Space]
public Texture2D normal1;
public Texture2D normal2;
public Texture2D normal3;
public Texture2D normal4;
#if _SNAPPERS_TEXTURE_ARRAYS
public Texture2DArray normalArray;
#endif
[Space]
public Texture2D cavity1;
public Texture2D cavity2;
public Texture2D cavity3;
public Texture2D cavity4;
#if _SNAPPERS_TEXTURE_ARRAYS
public Texture2DArray cavityArray;
#endif
public void ApplyTextureSet()
{
public string arrayAssetPath = "Assets/Characters/Gawain/Face/Snappers";
public Texture2DArray arrayMask;
public Texture2DArray arrayAlbedo;
public Texture2DArray arrayNormal;
public Texture2DArray arrayCavity;
SetTextureChecked(materialProps, "_SnappersMask", maskArray);
SetTextureChecked(materialProps, "_SnappersAlbedo", albedoArray);
SetTextureChecked(materialProps, "_SnappersNormal", normalArray);
SetTextureChecked(materialProps, "_SnappersCavity", cavityArray);
#else
SetTextureChecked(materialProps, "_SnappersMask1", mask1);
SetTextureChecked(materialProps, "_SnappersMask2", mask2);
SetTextureChecked(materialProps, "_SnappersMask3", mask3);
SetTextureChecked(materialProps, "_SnappersMask4", mask4);
SetTextureChecked(materialProps, "_SnappersMask5", mask5);
SetTextureChecked(materialProps, "_SnappersMask6", mask6);
SetTextureChecked(materialProps, "_SnappersMask7", mask7);
SetTextureChecked(materialProps, "_SnappersMask8", mask8);
SetTextureChecked(materialProps, "_SnappersMask9", mask9);
SetTextureChecked(materialProps, "_SnappersMask10", mask10);
SetTextureChecked(materialProps, "_SnappersMask11", mask11);
SetTextureChecked(materialProps, "_SnappersMask12", mask12);
SetTextureChecked(materialProps, "_SnappersAlbedo1", albedo1);
SetTextureChecked(materialProps, "_SnappersAlbedo2", albedo2);
SetTextureChecked(materialProps, "_SnappersAlbedo3", albedo3);
SetTextureChecked(materialProps, "_SnappersAlbedo4", albedo4);
SetTextureChecked(materialProps, "_SnappersNormal1", normal1);
SetTextureChecked(materialProps, "_SnappersNormal2", normal2);
SetTextureChecked(materialProps, "_SnappersNormal3", normal3);
SetTextureChecked(materialProps, "_SnappersNormal4", normal4);
SetTextureChecked(materialProps, "_SnappersCavity1", cavity1);
SetTextureChecked(materialProps, "_SnappersCavity2", cavity2);
SetTextureChecked(materialProps, "_SnappersCavity3", cavity3);
SetTextureChecked(materialProps, "_SnappersCavity4", cavity4);
}
}
[Header("-> SkinDeformationRenderer (if avail.)")]
public bool injectFittedWeights;

#region Deprecated material setup
[HideInInspector, SerializeField] private Texture2D mask1;
[HideInInspector, SerializeField] private Texture2D mask2;
[HideInInspector, SerializeField] private Texture2D mask3;
[HideInInspector, SerializeField] private Texture2D mask4;
[HideInInspector, SerializeField] private Texture2D mask5;
[HideInInspector, SerializeField] private Texture2D mask6;
[HideInInspector, SerializeField] private Texture2D mask7;
[HideInInspector, SerializeField] private Texture2D mask8;
[HideInInspector, SerializeField] private Texture2D mask9;
[HideInInspector, SerializeField] private Texture2D mask10;
[HideInInspector, SerializeField] private Texture2D mask11;
[HideInInspector, SerializeField] private Texture2D mask12;
[HideInInspector, SerializeField] private Texture2D albedo1;
[HideInInspector, SerializeField] private Texture2D albedo2;
[HideInInspector, SerializeField] private Texture2D albedo3;
[HideInInspector, SerializeField] private Texture2D albedo4;
[HideInInspector, SerializeField] private Texture2D normal1;
[HideInInspector, SerializeField] private Texture2D normal2;
[HideInInspector, SerializeField] private Texture2D normal3;
[HideInInspector, SerializeField] private Texture2D normal4;
[HideInInspector, SerializeField] private Texture2D cavity1;
[HideInInspector, SerializeField] private Texture2D cavity2;
[HideInInspector, SerializeField] private Texture2D cavity3;
[HideInInspector, SerializeField] private Texture2D cavity4;
bool TransferMaterial(ref Texture2D src, ref Texture2D dst)
{
dst = src;
src = null;
return (dst != null);
}
#endregion
#region Deprecated material transfer
if (materials.Length == 0)
{
var setPopulated = false;
var set = new TextureSet();
set.materialIndex = 0;
setPopulated |= TransferMaterial(ref mask1, ref set.mask1);
setPopulated |= TransferMaterial(ref mask2, ref set.mask2);
setPopulated |= TransferMaterial(ref mask3, ref set.mask3);
setPopulated |= TransferMaterial(ref mask4, ref set.mask4);
setPopulated |= TransferMaterial(ref mask5, ref set.mask5);
setPopulated |= TransferMaterial(ref mask6, ref set.mask6);
setPopulated |= TransferMaterial(ref mask7, ref set.mask7);
setPopulated |= TransferMaterial(ref mask8, ref set.mask8);
setPopulated |= TransferMaterial(ref mask9, ref set.mask9);
setPopulated |= TransferMaterial(ref mask10, ref set.mask10);
setPopulated |= TransferMaterial(ref mask11, ref set.mask11);
setPopulated |= TransferMaterial(ref mask12, ref set.mask12);
setPopulated |= TransferMaterial(ref albedo1, ref set.albedo1);
setPopulated |= TransferMaterial(ref albedo2, ref set.albedo2);
setPopulated |= TransferMaterial(ref albedo3, ref set.albedo3);
setPopulated |= TransferMaterial(ref albedo4, ref set.albedo4);
setPopulated |= TransferMaterial(ref normal1, ref set.normal1);
setPopulated |= TransferMaterial(ref normal2, ref set.normal2);
setPopulated |= TransferMaterial(ref normal3, ref set.normal3);
setPopulated |= TransferMaterial(ref normal4, ref set.normal4);
setPopulated |= TransferMaterial(ref cavity1, ref set.cavity1);
setPopulated |= TransferMaterial(ref cavity2, ref set.cavity2);
setPopulated |= TransferMaterial(ref cavity3, ref set.cavity3);
setPopulated |= TransferMaterial(ref cavity4, ref set.cavity4);
if (setPopulated)
{
materials = new TextureSet[1];
materials[0] = set;
}
}
#endregion
smrProps = new MaterialPropertyBlock();
for (int i = 0; i != materials.Length; i++)
{
if (materials[i].materialProps == null)
materials[i].materialProps = new MaterialPropertyBlock();
}
if (smrProps == null)
smrProps = new MaterialPropertyBlock();
smr.GetPropertyBlock(smrProps);
FetchPropertyBlocks();
SnappersHeadDefinition.ApplyShaderParam(ref headInstance, smrProps);
for (int i = 0; i != materials.Length; i++)
{
SnappersHeadDefinition.ApplyShaderParam(ref headInstance, materials[i].materialProps);
}
smr.SetPropertyBlock(smrProps);
ApplyPropertyBlocks();
}
void FetchPropertyBlocks()
{
for (int i = 0; i != materials.Length; i++)
{
if (materials[i].materialProps == null)
materials[i].materialProps = new MaterialPropertyBlock();
smr.GetPropertyBlock(materials[i].materialProps, materials[i].materialIndex);
}
}
void ApplyPropertyBlocks()
{
for (int i = 0; i != materials.Length; i++)
{
smr.SetPropertyBlock(materials[i].materialProps, materials[i].materialIndex);
}
if (smrProps == null)
smrProps = new MaterialPropertyBlock();
smr.GetPropertyBlock(smrProps);
FetchPropertyBlocks();
{
if (headDefinition != null)
{

SnappersHeadDefinition.ApplyControllers(ref headInstance);
SnappersHeadDefinition.ApplyBlendShapes(ref headInstance, smr);
SnappersHeadDefinition.ApplyShaderParam(ref headInstance, smrProps);
SnappersHeadDefinition.ApplyShaderParam(ref headInstance, smrProps);
#if _SNAPPERS_TEXTURE_ARRAYS
SetTextureChecked(smrProps, "_SnappersMask", arrayMask);
SetTextureChecked(smrProps, "_SnappersAlbedo", arrayAlbedo);
SetTextureChecked(smrProps, "_SnappersNormal", arrayNormal);
SetTextureChecked(smrProps, "_SnappersCavity", arrayCavity);
#else
SetTextureChecked(smrProps, "_SnappersMask1", mask1);
SetTextureChecked(smrProps, "_SnappersMask2", mask2);
SetTextureChecked(smrProps, "_SnappersMask3", mask3);
SetTextureChecked(smrProps, "_SnappersMask4", mask4);
SetTextureChecked(smrProps, "_SnappersMask5", mask5);
SetTextureChecked(smrProps, "_SnappersMask6", mask6);
SetTextureChecked(smrProps, "_SnappersMask7", mask7);
SetTextureChecked(smrProps, "_SnappersMask8", mask8);
SetTextureChecked(smrProps, "_SnappersMask9", mask9);
SetTextureChecked(smrProps, "_SnappersMask10", mask10);
SetTextureChecked(smrProps, "_SnappersMask11", mask11);
SetTextureChecked(smrProps, "_SnappersMask12", mask12);
SetTextureChecked(smrProps, "_SnappersAlbedo1", albedo1);
SetTextureChecked(smrProps, "_SnappersAlbedo2", albedo2);
SetTextureChecked(smrProps, "_SnappersAlbedo3", albedo3);
SetTextureChecked(smrProps, "_SnappersAlbedo4", albedo4);
SetTextureChecked(smrProps, "_SnappersNormal1", normal1);
SetTextureChecked(smrProps, "_SnappersNormal2", normal2);
SetTextureChecked(smrProps, "_SnappersNormal3", normal3);
SetTextureChecked(smrProps, "_SnappersNormal4", normal4);
SetTextureChecked(smrProps, "_SnappersCavity1", cavity1);
SetTextureChecked(smrProps, "_SnappersCavity2", cavity2);
SetTextureChecked(smrProps, "_SnappersCavity3", cavity3);
SetTextureChecked(smrProps, "_SnappersCavity4", cavity4);
#endif
for (int i = 0; i != materials.Length; i++)
{
SnappersHeadDefinition.ApplyShaderParam(ref headInstance, materials[i].materialProps);
materials[i].ApplyTextureSet();
}
smr.SetPropertyBlock(smrProps);
ApplyPropertyBlocks();
}
static void SetTextureChecked(MaterialPropertyBlock props, string textureId, Texture texture)

50
Runtime/Utility/NativeMesh.cs


faceIndices.Dispose();
faceIndicesCount = 0;
}
public NativeMeshSOA(NativeMeshSOA other, Allocator allocator)
{
vertexPositions = new NativeArray<Vector3>(other.vertexPositions, allocator);
vertexTexCoords = new NativeArray<Vector2>(other.vertexTexCoords, allocator);
vertexNormals = new NativeArray<Vector3>(other.vertexNormals, allocator);
vertexCount = other.vertexCount;
faceIndices = new NativeArray<int>(other.faceIndices, allocator);
faceIndicesCount = other.faceIndicesCount;
}
public void Allocate(int vertexCount, int faceIndicesCount, Allocator allocator)
{
this.vertexPositions = new NativeArray<Vector3>(vertexCount, allocator);
this.vertexTexCoords = new NativeArray<Vector2>(vertexCount, allocator);
this.vertexNormals = new NativeArray<Vector3>(vertexCount, allocator);
this.vertexCount = vertexCount;
this.faceIndices = new NativeArray<int>(faceIndicesCount, allocator);
this.faceIndicesCount = faceIndicesCount;
}
public void CopyFrom(NativeMeshSOA other)
{
Debug.Assert(other.vertexCount == this.vertexCount);
Debug.Assert(other.faceIndicesCount == this.faceIndicesCount);
this.vertexPositions.CopyFrom(other.vertexPositions);
this.vertexTexCoords.CopyFrom(other.vertexTexCoords);
this.vertexNormals.CopyFrom(other.vertexNormals);
this.vertexCount = other.vertexCount;
this.faceIndices.CopyFrom(other.faceIndices);
this.faceIndicesCount = other.faceIndicesCount;
}
public void CopyTo(NativeMeshSOA other)
{
Debug.Assert(other.vertexCount == this.vertexCount);
Debug.Assert(other.faceIndicesCount == this.faceIndicesCount);
other.vertexPositions.CopyFrom(this.vertexPositions);
other.vertexTexCoords.CopyFrom(this.vertexTexCoords);
other.vertexNormals.CopyFrom(this.vertexNormals);
other.vertexCount = this.vertexCount;
other.faceIndices.CopyFrom(this.faceIndices);
other.faceIndicesCount = this.faceIndicesCount;
}
}
}

10
Runtime/Utility/NativeMeshObjLoader.cs


public InputVertex v2;
}
public unsafe static NativeMeshSOA Parse(string path, VertexAttribs vertexAttribs = VertexAttribs.Position, VertexOrder vertexOrder = VertexOrder.ByDefinition)
public unsafe static NativeMeshSOA Parse(string path, Allocator outputAllocator = Allocator.Persistent, VertexAttribs vertexAttribs = VertexAttribs.Position, VertexOrder vertexOrder = VertexOrder.ByDefinition)
{
#if VERBOSE
Debug.LogFormat("trying {0}", path);

// copy to container
NativeMeshSOA mesh = new NativeMeshSOA()
{
vertexPositions = new NativeArray<Vector3>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexTexCoords = new NativeArray<Vector2>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexNormals = new NativeArray<Vector3>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexPositions = new NativeArray<Vector3>(numOutputVertices, outputAllocator, NativeArrayOptions.UninitializedMemory),
vertexTexCoords = new NativeArray<Vector2>(numOutputVertices, outputAllocator, NativeArrayOptions.UninitializedMemory),
vertexNormals = new NativeArray<Vector3>(numOutputVertices, outputAllocator, NativeArrayOptions.UninitializedMemory),
faceIndices = new NativeArray<int>(numOutputIndices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
faceIndices = new NativeArray<int>(numOutputIndices, outputAllocator, NativeArrayOptions.UninitializedMemory),
faceIndicesCount = numOutputIndices,
};

9
Runtime/BinaryAsset.cs


using UnityEngine;
namespace Unity.DemoTeam.DigitalHuman
{
[PreferBinarySerialization]
public sealed class BinaryAsset : ScriptableObject
{
}
}

11
Runtime/BinaryAsset.cs.meta


fileFormatVersion: 2
guid: 656a0d83bce955941aa12f067f991806
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存