Netcode Bootstrap
This commit is contained in:
@@ -0,0 +1,600 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using FixedStringName = Unity.Collections.FixedString512Bytes;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Unity.Assertions;
|
||||
using Unity.Mathematics;
|
||||
using Rukhanka.Toolbox;
|
||||
using Hash128 = Unity.Entities.Hash128;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Hybrid
|
||||
{
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[TemporaryBakingType]
|
||||
internal struct BoneEntitiesToRemove : IBufferElementData
|
||||
{
|
||||
public Entity boneEntity;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[TemporaryBakingType]
|
||||
internal struct BoneEntityRef: IBufferElementData
|
||||
{
|
||||
public Entity boneEntity;
|
||||
public int rigBoneIndex;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal class InternalSkeletonBone
|
||||
{
|
||||
public Transform boneTransform;
|
||||
public string name;
|
||||
public string parentName;
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public Vector3 scale;
|
||||
}
|
||||
|
||||
//=================================================================================================================//
|
||||
|
||||
public partial class RigDefinitionBaker: Baker<RigDefinitionAuthoring>
|
||||
{
|
||||
static FieldInfo parentBoneNameField;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static RigDefinitionBaker()
|
||||
{
|
||||
parentBoneNameField = typeof(SkeletonBone).GetField("parentName", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public override void Bake(RigDefinitionAuthoring a)
|
||||
{
|
||||
var e = GetEntity(TransformUsageFlags.Dynamic);
|
||||
|
||||
var animator = GetComponent<Animator>();
|
||||
if (a.rigConfigSource == RigDefinitionAuthoring.RigConfigSource.FromAnimator)
|
||||
{
|
||||
Assert.IsNotNull(animator, "Rig is configured to use parameters from Unity.Animator, but no one found. Please switch to manual configuration mode, or attach Animator to the authoring GameObject.");
|
||||
a.avatar = animator.avatar;
|
||||
a.animationCulling = animator.cullingMode != AnimatorCullingMode.AlwaysAnimate;
|
||||
a.applyRootMotion = animator.applyRootMotion;
|
||||
}
|
||||
|
||||
DependsOn(a.avatar);
|
||||
|
||||
AddBuffer<AnimationToProcessComponent>(e);
|
||||
AddComponent<GPURigFrameOffsetsComponent>(e);
|
||||
CreateRigDefinitionFromRigAuthoring(e, a);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InternalSkeletonBone CreateSkeletonBoneFromTransform(Transform t, string parentName)
|
||||
{
|
||||
var bone = new InternalSkeletonBone();
|
||||
bone.boneTransform = t;
|
||||
bone.name = t.name;
|
||||
bone.position = t.localPosition;
|
||||
bone.rotation = t.localRotation;
|
||||
bone.scale = t.localScale;
|
||||
bone.parentName = parentName;
|
||||
return bone;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TransformHierarchyWalk(Transform parent, List<InternalSkeletonBone> sb)
|
||||
{
|
||||
for (int i = 0; i < parent.childCount; ++i)
|
||||
{
|
||||
var c = parent.GetChild(i);
|
||||
var ct = c.transform;
|
||||
var bone = CreateSkeletonBoneFromTransform(ct, parent.name);
|
||||
sb.Add(bone);
|
||||
|
||||
TransformHierarchyWalk(ct, sb);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
List<InternalSkeletonBone> CreateAvatarFromObjectHierarchy(GameObject root)
|
||||
{
|
||||
// Manually fill all bone transforms
|
||||
var sb = new List<InternalSkeletonBone>();
|
||||
var rootBone = CreateSkeletonBoneFromTransform(root.transform, "");
|
||||
sb.Add(rootBone);
|
||||
|
||||
TransformHierarchyWalk(root.transform, sb);
|
||||
return sb;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int GetRigRootBoneIndex(Avatar avatar, List<InternalSkeletonBone> rigBones)
|
||||
{
|
||||
if (avatar == null)
|
||||
return 0;
|
||||
|
||||
var rootBoneName = avatar.GetRootMotionNodeName();
|
||||
if (avatar.isHuman)
|
||||
{
|
||||
var hd = avatar.humanDescription;
|
||||
var humanBoneIndexInDesc = Array.FindIndex(hd.human, x => x.humanName == "Hips");
|
||||
rootBoneName = hd.human[humanBoneIndexInDesc].boneName;
|
||||
}
|
||||
var rv = rigBones.FindIndex(x => x.name == rootBoneName);
|
||||
return math.max(rv, 0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int DeepestHierarchyBoneCount(in BlobBuilderArray<RigBoneInfo> rigBones)
|
||||
{
|
||||
var rv = 0;
|
||||
for (var i = 0; i < rigBones.Length; ++i)
|
||||
{
|
||||
var numBonesInHierarchy = 1;
|
||||
var curBoneIndex = rigBones[i].parentBoneIndex;
|
||||
while (curBoneIndex >= 0)
|
||||
{
|
||||
curBoneIndex = rigBones[curBoneIndex].parentBoneIndex;
|
||||
++numBonesInHierarchy;
|
||||
}
|
||||
rv = math.max(rv, numBonesInHierarchy);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool IsBoneInOptimizationMask(string skeletonBonesPath, AvatarMask mask)
|
||||
{
|
||||
if (mask == null)
|
||||
return true;
|
||||
|
||||
for (var i = 0; i < mask.transformCount; ++i)
|
||||
{
|
||||
var maskPath = mask.GetTransformPath(i);
|
||||
var pathActive = mask.GetTransformActive(i);
|
||||
if (maskPath == skeletonBonesPath)
|
||||
return pathActive;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
string[] MakeSkeletonBonesFullPaths(SkeletonBone[] skeletonBones)
|
||||
{
|
||||
var rv = new string[skeletonBones.Length];
|
||||
if (skeletonBones.Length == 0)
|
||||
return rv;
|
||||
|
||||
// First bone need to be empty, because it contains root transform name, but avatar masks have it empty string
|
||||
rv[0] = "";
|
||||
for (var i = 1; i < skeletonBones.Length; ++i)
|
||||
{
|
||||
var sb = skeletonBones[i];
|
||||
var parentName = (string)parentBoneNameField.GetValue(sb);
|
||||
var parentIndex = Array.FindIndex(skeletonBones, 0, i, x => x.name == parentName);
|
||||
var fullName = sb.name;
|
||||
if (parentIndex > 0)
|
||||
fullName = rv[parentIndex] + "/" + sb.name;
|
||||
rv[i] = fullName;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
List<InternalSkeletonBone> CreateInternalRigRepresentation(Avatar avatar, RigDefinitionAuthoring rigDef)
|
||||
{
|
||||
if (avatar == null)
|
||||
{
|
||||
return CreateAvatarFromObjectHierarchy(rigDef.gameObject);
|
||||
}
|
||||
|
||||
var skeleton = avatar.humanDescription.skeleton;
|
||||
|
||||
// Validate avatar optimization mask
|
||||
var rigOptimizationMask = rigDef.avatarOptimizationMask;
|
||||
if (rigOptimizationMask != null)
|
||||
{
|
||||
if (rigOptimizationMask.transformCount != skeleton.Length)
|
||||
{
|
||||
Debug.LogWarning($"'{rigOptimizationMask.name}' bone count ({rigOptimizationMask.transformCount}) does not match rig avatar '{avatar.name}' bone count ({skeleton.Length}). Avatar mask was created for different avatar and ignored.");
|
||||
rigOptimizationMask = null;
|
||||
}
|
||||
}
|
||||
|
||||
var skeletonBonesFullPaths = MakeSkeletonBonesFullPaths(skeleton);
|
||||
|
||||
var rv = new List<InternalSkeletonBone>();
|
||||
for (var i = 0; i < skeleton.Length; ++i)
|
||||
{
|
||||
var boneIsObjectRoot = i == 0;
|
||||
var sb = skeleton[i];
|
||||
|
||||
if (!IsBoneInOptimizationMask(skeletonBonesFullPaths[i], rigOptimizationMask))
|
||||
continue;
|
||||
|
||||
var isb = new InternalSkeletonBone()
|
||||
{
|
||||
boneTransform = boneIsObjectRoot ? rigDef.transform : TransformUtils.FindChildRecursively(rigDef.transform, sb.name),
|
||||
name = sb.name,
|
||||
position = sb.position,
|
||||
rotation = sb.rotation,
|
||||
scale = sb.scale,
|
||||
parentName = (string)parentBoneNameField.GetValue(sb)
|
||||
};
|
||||
rv.Add(isb);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateRigDefinitionFromRigAuthoring(Entity rigEntity, RigDefinitionAuthoring rigDef)
|
||||
{
|
||||
var avatar = rigDef.avatar;
|
||||
|
||||
var skeletonBones = CreateInternalRigRepresentation(avatar, rigDef);
|
||||
if (skeletonBones.Count == 0)
|
||||
{
|
||||
Debug.LogError($"Unity avatar '{avatar.name}' setup is incorrect. Follow <a href=\"https://docs.rukhanka.com/getting_started#rig-definition\">documentation</a> about avatar setup process please.");
|
||||
return;
|
||||
}
|
||||
|
||||
var rv = new RigDefinitionComponent();
|
||||
rv.applyRootMotion = rigDef.applyRootMotion;
|
||||
|
||||
var rigBlobHash = rigDef.CalculateRigHash();
|
||||
var rigBlobExist = TryGetBlobAssetReference<RigDefinitionBlob>(rigBlobHash, out var rigBlob);
|
||||
if (!rigBlobExist)
|
||||
{
|
||||
rigBlob = CreateRigBlob(avatar, rigDef, skeletonBones, rigBlobHash);
|
||||
AddBlobAssetWithCustomHash(ref rigBlob, rigBlobHash);
|
||||
}
|
||||
|
||||
rv.rigBlob = rigBlob;
|
||||
AddComponent(rigEntity, rv);
|
||||
AddBuffer<RootMotionAnimationStateComponent>(rigEntity);
|
||||
var rmvc = new RootMotionVelocityComponent()
|
||||
{
|
||||
worldVelocity = float3.zero,
|
||||
deltaPos = float3.zero,
|
||||
deltaRot = quaternion.identity,
|
||||
removeBuiltinEntityMovement = rigDef.rootMotionMode == RigDefinitionAuthoring.RootMotionMode.DisableBuiltinMovement
|
||||
};
|
||||
AddComponent(rigEntity, rmvc);
|
||||
|
||||
if (rigDef.hasAnimationEvents)
|
||||
{
|
||||
AddBuffer<AnimationEventComponent>(rigEntity);
|
||||
AddBuffer<PreviousProcessedAnimationComponent>(rigEntity);
|
||||
}
|
||||
|
||||
if (rigDef.animationCulling)
|
||||
{
|
||||
AddComponent<CullAnimationsTag>(rigEntity);
|
||||
}
|
||||
|
||||
var isGPUAnimator = rigDef.animationEngine == RigDefinitionAuthoring.AnimationEngine.GPU;
|
||||
AddComponent<GPUAnimationEngineTag>(rigEntity);
|
||||
SetComponentEnabled<GPUAnimationEngineTag>(rigEntity, isGPUAnimator);
|
||||
|
||||
ProcessBoneStrippingMask(rigEntity, rigDef, skeletonBones);
|
||||
CreateBoneEntityRefs(rigEntity, skeletonBones, rigDef);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateBoneEntityRefs(Entity e, List<InternalSkeletonBone> skeletonBones, RigDefinitionAuthoring rigDef)
|
||||
{
|
||||
var transformFlags = TransformUsageFlags.Dynamic;
|
||||
var manualBoneStripping = rigDef.boneEntityStrippingMode == RigDefinitionAuthoring.BoneEntityStrippingMode.Manual;
|
||||
|
||||
var boneEntityRefArr = AddBuffer<BoneEntityRef>(e);
|
||||
for (var i = 0; i < skeletonBones.Count; ++i)
|
||||
{
|
||||
var boneTransformFlags = transformFlags | (manualBoneStripping && i != 0 ? TransformUsageFlags.WorldSpace : 0);
|
||||
var skeletonBone = skeletonBones[i];
|
||||
var boneEntity = GetEntityForBone(skeletonBone.boneTransform, boneTransformFlags, rigDef);
|
||||
boneEntityRefArr.Add(new BoneEntityRef() {boneEntity = boneEntity, rigBoneIndex = i});
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CheckForDuplicatedBones(ref RigDefinitionBlob rdb)
|
||||
{
|
||||
var duplicateBoneChecker = new NativeHashSet<uint>(rdb.bones.Length, Allocator.Temp);
|
||||
for (var i = 0; i < rdb.bones.Length; ++i)
|
||||
{
|
||||
ref var bone = ref rdb.bones[i];
|
||||
if (!duplicateBoneChecker.Add(bone.hash))
|
||||
{
|
||||
#if RUKHANKA_DEBUG_INFO
|
||||
Debug.LogError($"RigDefinitionBaker: Duplicate bone with name '{bone.name.ToString()}' in rig '{rdb.name.ToString()}'! This is not allowed!");
|
||||
#else
|
||||
Debug.LogError($"RigDefinitionBaker: Duplicate bone with hash '{bone.hash}' in rig '{rdb.hash}'! This is not allowed! Enable 'RUKHANKA_DEBUG_INFO' to see bone names.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BlobAssetReference<RigDefinitionBlob> CreateRigBlob(Avatar avatar, RigDefinitionAuthoring rigDef, List<InternalSkeletonBone> skeletonBones, Hash128 rigHash)
|
||||
{
|
||||
#if RUKHANKA_DEBUG_INFO
|
||||
var startTimeMarker = Time.realtimeSinceStartupAsDouble;
|
||||
#endif
|
||||
|
||||
var bb = new BlobBuilder(Allocator.Temp);
|
||||
ref var c = ref bb.ConstructRoot<RigDefinitionBlob>();
|
||||
c.hash = rigHash;
|
||||
c.rootBoneIndex = GetRigRootBoneIndex(avatar, skeletonBones);
|
||||
|
||||
#if RUKHANKA_DEBUG_INFO
|
||||
var rigName = rigDef.gameObject.name;
|
||||
if (rigName.Length > 0)
|
||||
bb.AllocateString(ref c.name, rigName);
|
||||
#endif
|
||||
|
||||
var bonesArrayBlob = bb.Allocate(ref c.bones, skeletonBones.Count);
|
||||
for (int i = 0; i < skeletonBones.Count; ++i)
|
||||
{
|
||||
ref var boneBlob = ref bonesArrayBlob[i];
|
||||
CreateRigBoneBlob(bb, ref boneBlob, skeletonBones, i);
|
||||
}
|
||||
|
||||
var rigIsHuman = avatar != null && avatar.isHuman;
|
||||
if (rigIsHuman)
|
||||
{
|
||||
CreateHumanoidData(bb, ref c, bonesArrayBlob, avatar, skeletonBones);
|
||||
}
|
||||
|
||||
|
||||
#if RUKHANKA_DEBUG_INFO
|
||||
var dt = Time.realtimeSinceStartupAsDouble - startTimeMarker;
|
||||
c.bakingTime = (float)dt;
|
||||
#endif
|
||||
|
||||
var rv = bb.CreateBlobAssetReference<RigDefinitionBlob>(Allocator.Persistent);
|
||||
CheckForDuplicatedBones(ref rv.Value);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateHumanoidData(BlobBuilder bb, ref RigDefinitionBlob rdb, BlobBuilderArray<RigBoneInfo> bonesArr, Avatar avatar, List<InternalSkeletonBone> skeletonBones)
|
||||
{
|
||||
ref var hdb = ref bb.Allocate(ref rdb.humanData);
|
||||
var humanToRigArr = bb.Allocate(ref hdb.humanBoneToSkeletonBoneIndices, (int)HumanBodyBones.LastBone);
|
||||
var humanRotArr = bb.Allocate(ref hdb.humanRotData, skeletonBones.Count);
|
||||
//var mirroredIndicesArr = bb.Allocate(ref hdb.mirroredBoneIndices, skeletonBones.Count);
|
||||
|
||||
for (int j = 0; j < humanToRigArr.Length; ++j)
|
||||
humanToRigArr[j] = -1;
|
||||
|
||||
for (int l = 0; l < humanRotArr.Length; ++l)
|
||||
{
|
||||
ref var hrd = ref humanRotArr[l];
|
||||
|
||||
var humanRigIndex = CreateHumanoidBoneRotationData(ref hrd, avatar, skeletonBones[l].name);
|
||||
if (humanRigIndex >= 0)
|
||||
{
|
||||
humanToRigArr[humanRigIndex] = l;
|
||||
// Make muscle neutral ref pose
|
||||
ref var rbi = ref bonesArr[l];
|
||||
rbi.refPose.rot = math.mul(hrd.preRot, hrd.postRot);
|
||||
// Set human body part for this bone
|
||||
rbi.humanBodyPart = humanPartToAvatarMaskPartRemapTable[humanRigIndex];
|
||||
}
|
||||
}
|
||||
|
||||
//CreateHumanoidMirrorData(humanToRigArr, mirroredIndicesArr);
|
||||
SetHumanBodyBodyPartForNonAssignedBones(bonesArr, skeletonBones);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AvatarMaskBodyPart GetAvatarMaskBodyPartFromParent(int boneIndex, BlobBuilderArray<RigBoneInfo> bonesArr)
|
||||
{
|
||||
if (boneIndex < 0)
|
||||
return (AvatarMaskBodyPart)(-1);
|
||||
|
||||
ref var rb = ref bonesArr[boneIndex];
|
||||
if (rb.humanBodyPart >= 0)
|
||||
return rb.humanBodyPart;
|
||||
|
||||
return GetAvatarMaskBodyPartFromParent(rb.parentBoneIndex, bonesArr);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateHumanoidMirrorData(BlobBuilderArray<int> humanToRigArr, BlobBuilderArray<int> mirroredIndicesArr)
|
||||
{
|
||||
for (var i = 0; i < mirroredIndicesArr.Length; ++i)
|
||||
mirroredIndicesArr[i] = i;
|
||||
|
||||
for (var i = 0; i < humanToRigArr.Length; ++i)
|
||||
{
|
||||
ref var v = ref humanToRigArr[i];
|
||||
var mirroredPart = humanoidMirrorTable[i];
|
||||
mirroredIndicesArr[v] = humanToRigArr[(int)mirroredPart];
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SetHumanBodyBodyPartForNonAssignedBones(BlobBuilderArray<RigBoneInfo> bonesArr, List<InternalSkeletonBone> skeletonBones)
|
||||
{
|
||||
// Root bone is a special case
|
||||
bonesArr[0].humanBodyPart = AvatarMaskBodyPart.Root;
|
||||
|
||||
// For other bones search for parent with body part is set and set it to the same value
|
||||
for (int i = 1; i < bonesArr.Length; ++i)
|
||||
{
|
||||
// Override human body part if explicitly specified
|
||||
var t = skeletonBones[i].boneTransform;
|
||||
HumanBodyPartOverrideAuthoring hbpo = null;
|
||||
if (t != null)
|
||||
hbpo = t.GetComponent<HumanBodyPartOverrideAuthoring>();
|
||||
var humanBodyPart = hbpo != null ? hbpo.humanBodyPart : GetAvatarMaskBodyPartFromParent(i, bonesArr);
|
||||
bonesArr[i].humanBodyPart = humanBodyPart;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int CreateHumanoidBoneRotationData(ref HumanRotationData hrd, Avatar a, string boneName)
|
||||
{
|
||||
hrd = HumanRotationData.Identity();
|
||||
|
||||
var hd = a.humanDescription;
|
||||
var humanBoneInSkeletonIndex = Array.FindIndex(hd.human, x => x.boneName == boneName);
|
||||
if (humanBoneInSkeletonIndex < 0)
|
||||
return -1;
|
||||
|
||||
var humanBones = HumanTrait.BoneName;
|
||||
var humanBoneDef = hd.human[humanBoneInSkeletonIndex];
|
||||
var humanBoneId = Array.FindIndex(humanBones, x => x == humanBoneDef.humanName);
|
||||
Debug.Assert(humanBoneId >= 0);
|
||||
|
||||
hrd.preRot = a.GetPreRotation(humanBoneId);
|
||||
hrd.postRot = math.inverse(a.GetPostRotation(humanBoneId));
|
||||
hrd.sign = a.GetLimitSign(humanBoneId);
|
||||
|
||||
var minA = humanBoneDef.limit.min;
|
||||
var maxA = humanBoneDef.limit.max;
|
||||
if (humanBoneDef.limit.useDefaultValues)
|
||||
{
|
||||
minA.x = HumanTrait.GetMuscleDefaultMin(HumanTrait.MuscleFromBone(humanBoneId, 0));
|
||||
minA.y = HumanTrait.GetMuscleDefaultMin(HumanTrait.MuscleFromBone(humanBoneId, 1));
|
||||
minA.z = HumanTrait.GetMuscleDefaultMin(HumanTrait.MuscleFromBone(humanBoneId, 2));
|
||||
|
||||
maxA.x = HumanTrait.GetMuscleDefaultMax(HumanTrait.MuscleFromBone(humanBoneId, 0));
|
||||
maxA.y = HumanTrait.GetMuscleDefaultMax(HumanTrait.MuscleFromBone(humanBoneId, 1));
|
||||
maxA.z = HumanTrait.GetMuscleDefaultMax(HumanTrait.MuscleFromBone(humanBoneId, 2));
|
||||
}
|
||||
hrd.minMuscleAngles = math.radians(minA);
|
||||
hrd.maxMuscleAngles = math.radians(maxA);
|
||||
|
||||
return humanBoneId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe Entity GetEntityForBone(Transform t, TransformUsageFlags boneFlags, RigDefinitionAuthoring rigDef)
|
||||
{
|
||||
// Hierarchy root should be always included
|
||||
if (t == rigDef.transform)
|
||||
return GetEntity(t, boneFlags);
|
||||
|
||||
if (t == null || t.GetComponent<SkinnedMeshRenderer>() != null)
|
||||
return Entity.Null;
|
||||
|
||||
var automaticBoneStripping = rigDef.boneEntityStrippingMode == RigDefinitionAuthoring.BoneEntityStrippingMode.Automatic;
|
||||
var rv = automaticBoneStripping ? _State.BakedEntityData->GetEntity(t) : GetEntity(t, boneFlags);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateRigBoneBlob(BlobBuilder bb, ref RigBoneInfo rbi, List<InternalSkeletonBone> skeletonBones, int boneIndex)
|
||||
{
|
||||
var boneIsObjectRoot = boneIndex == 0;
|
||||
var skeletonBone = skeletonBones[boneIndex];
|
||||
|
||||
var name = skeletonBone.name;
|
||||
// Special handling of hierarchy root
|
||||
if (boneIsObjectRoot)
|
||||
{
|
||||
name = SpecialBones.UnnamedRootBoneName;
|
||||
}
|
||||
|
||||
var boneName = new FixedStringName(name);
|
||||
var boneHash = boneName.CalculateHash32();
|
||||
rbi.hash = boneHash;
|
||||
rbi.refPose = CreateBoneTransformFromSkeletonBone(skeletonBone);
|
||||
rbi.humanBodyPart = (AvatarMaskBodyPart)(-1);
|
||||
var parentBoneIndex = skeletonBones.FindIndex(x => x.name == skeletonBone.parentName);
|
||||
rbi.parentBoneIndex = parentBoneIndex;
|
||||
|
||||
#if RUKHANKA_DEBUG_INFO
|
||||
if (name.Length > 0)
|
||||
bb.AllocateString(ref rbi.name, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoneTransform CreateBoneTransformFromSkeletonBone(InternalSkeletonBone skeletonBone)
|
||||
{
|
||||
var pose = new BoneTransform()
|
||||
{
|
||||
pos = skeletonBone.position,
|
||||
rot = skeletonBone.rotation,
|
||||
scale = skeletonBone.scale,
|
||||
};
|
||||
|
||||
if (skeletonBone.boneTransform != null)
|
||||
{
|
||||
pose = new BoneTransform()
|
||||
{
|
||||
pos = skeletonBone.boneTransform.localPosition,
|
||||
rot = skeletonBone.boneTransform.localRotation,
|
||||
scale = skeletonBone.boneTransform.localScale,
|
||||
};
|
||||
}
|
||||
return pose;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ProcessBoneStrippingMask(Entity rigEntity, RigDefinitionAuthoring rda, List<InternalSkeletonBone> rigBones)
|
||||
{
|
||||
// Bone stripping mask is processed only in "Manual" stripping mode
|
||||
if (rda.boneEntityStrippingMode != RigDefinitionAuthoring.BoneEntityStrippingMode.Manual || rda.boneStrippingMask == null)
|
||||
return;
|
||||
|
||||
var m = rda.boneStrippingMask;
|
||||
var bonesToRemove = AddBuffer<BoneEntitiesToRemove>(rigEntity);
|
||||
|
||||
for (int i = 0; i < m.transformCount; ++i)
|
||||
{
|
||||
var isActive = m.GetTransformActive(i);
|
||||
if (isActive) continue;
|
||||
|
||||
var path = m.GetTransformPath(i);
|
||||
var boneIndex = 0;
|
||||
for (; boneIndex < rigBones.Count && !path.EndsWith(rigBones[boneIndex].name); ++boneIndex) { }
|
||||
|
||||
if (boneIndex < rigBones.Count)
|
||||
{
|
||||
var boneEntity = GetEntity(rigBones[boneIndex].boneTransform, TransformUsageFlags.None);
|
||||
bonesToRemove.Add(new BoneEntitiesToRemove() { boneEntity = boneEntity });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user