private void UpdateVertices(float currentTime) { var bodyMesh = _bodyMesh; var bodyAvatar = _bodyAvatar; var bodyVertices = _bodyVertices; var headMesh = _headMesh; var headAvatar = _headAvatar; var origBodyVertices = _originalBodyVertices; var headVertices = _headVertices; var origHeadVertices = _originalHeadVertices; var keyFrames = _animation.KeyFrames; #if !STATIC_POSE_DEBUG var animatedBoneCount = _animation.BoneCount; var firstKeyFrameIndex = -1; var lastFirstKeyFrameIndex = 0; for (var i = 0; i < keyFrames.Count; i += animatedBoneCount) { //if (keyFrames[i].Time >= currentTime) { if (keyFrames[i].FrameIndex > _lastFrameIndex) { firstKeyFrameIndex = lastFirstKeyFrameIndex; break; } lastFirstKeyFrameIndex = i; } if (firstKeyFrameIndex < 0) { // We are at the end of the whole animation. return; } for (var i = firstKeyFrameIndex; i < firstKeyFrameIndex + animatedBoneCount; ++i) { var frame = keyFrames[i]; var altPath = frame.Path.Contains("BODY_SCALE/") ? frame.Path.Replace("BODY_SCALE/", string.Empty) : frame.Path; var bone = _bodyBoneList.FirstOrDefault(b => b.Path == altPath); if (bone == null) { throw new ApplicationException($"Invalid bone path: {altPath}"); } BoneNode transferredBone = null; foreach (var kv in BoneAttachmentMap) { if (kv.Key == altPath) { transferredBone = _headBoneList.SingleOrDefault(b => b.Path == kv.Value); if (transferredBone == null) { throw new ArgumentException(); } break; } } if (frame.HasPositions) { var x = frame.PositionX.Value; var y = frame.PositionY.Value; var z = frame.PositionZ.Value; var t = new Vector3(x, y, z); t = t.FixCoordSystem(); bone.LocalPosition = t; //if (transferredBone != null) { // transferredBone.LocalPosition = t; //} } if (frame.HasRotations) { var q = UnityRotation.EulerDeg(frame.AngleX.Value, frame.AngleY.Value, frame.AngleZ.Value); q = q.FixCoordSystem(); bone.LocalRotation = q; if (transferredBone != null) { transferredBone.LocalRotation = q; } } } #endif foreach (var bone in _bodyBoneList) { bone.UpdateTransform(); } foreach (var bone in _headBoneList) { bone.UpdateTransform(); } UpdateVertInternal(origBodyVertices, bodyVertices, bodyAvatar, bodyMesh, _bodyBoneList); UpdateVertInternal(origHeadVertices, headVertices, headAvatar, headMesh, _headBoneList); void UpdateVertInternal(PosNorm[] origVertices, PosNorm[] vertices, Avatar avatar, Mesh mesh, IReadOnlyList <BoneNode> boneList) { var vertexCount = vertices.Length; for (var i = 0; i < vertexCount; ++i) { var vertex = origVertices[i]; var skin = mesh.Skin[i]; var m = Matrix4.Zero; var activeSkinCount = 0; float totalWeight = 0; for (var j = 0; j < 4; ++j) { if (skin[j].Weight <= 0) { continue; } ++activeSkinCount; var boneNameHash = mesh.BoneNameHashes[skin[j].BoneIndex]; var boneIndex = avatar.FindBoneIndexByNameHash(boneNameHash); var transform = boneList[boneIndex].SkinMatrix; m = m + transform * skin[j].Weight; totalWeight += skin[j].Weight; } if (activeSkinCount == 0) { #if DEBUG Debug.Print("Warning: one skin is not bound to bones."); #endif continue; } #if DEBUG if (Math.Abs(totalWeight - 1.0f) > 0.00001f) { Debug.Print("Warning: weights do not sum up."); } #endif #if !NO_TRANSFORM_MESH vertex.Position = Vector3.TransformPosition(vertex.Position, m); vertex.Normal = Vector3.TransformNormal(vertex.Normal, m); #endif vertices[i] = vertex; } } ++_lastFrameIndex; }