From bc33920f30a55ed8dcb5a4024f10f53cc655276e Mon Sep 17 00:00:00 2001 From: James Pelter Date: Tue, 5 Mar 2024 02:04:19 -0600 Subject: [PATCH] Pose Spaces - Standardized the difference between local and world poses and laid down the groundwork for replacing boolean parameter 'localSpace' with an enum that contains values for Local and Entity spaces. - Renamed usage of world space transformations to entity, as technically world space transformations before didn't actually transform stuff relative to the game world, but rather the entity. So actual world-space transformations are needed, this supports the addition of an extra transformation space - In addition for animation poses being able to be converted from Local to Entity, they can now be converted from Entity to Local, so that entity space transformations can be done and inserted in between instances of local space transformations, similar to that of Unreal's convert space nodes. - Added a variable to animation poses, for keeping track of the current space in order to prevent double-conversions. Also allows for every animation pose to always be converted to World prior to mixins. --- .../entity/FirstPersonPlayerAnimator.java | 11 +- .../animation/pose/AnimationPose.java | 125 ++++++------------ .../animation/pose/BakedAnimationPose.java | 2 +- .../animation/pose/JointPose.java | 103 +++------------ 4 files changed, 67 insertions(+), 174 deletions(-) diff --git a/src/main/java/com/trainguy9512/animationoverhaul/animation/entity/FirstPersonPlayerAnimator.java b/src/main/java/com/trainguy9512/animationoverhaul/animation/entity/FirstPersonPlayerAnimator.java index 4e09af5..1ad7330 100644 --- a/src/main/java/com/trainguy9512/animationoverhaul/animation/entity/FirstPersonPlayerAnimator.java +++ b/src/main/java/com/trainguy9512/animationoverhaul/animation/entity/FirstPersonPlayerAnimator.java @@ -199,6 +199,9 @@ protected AnimationPose calculatePose() { AnimationPose pose = sampleAnimationState(IDLE_SEQUENCE_PLAYER); pose = dampenArmRotation(pose); + + pose.convertSpaceLocalToEntity(); + pose.convertSpaceEntityToLocal(); return pose; } @@ -215,11 +218,11 @@ private AnimationPose dampenArmRotation(AnimationPose> { private final LocatorSkeleton locatorSkeleton; private final HashMap, JointPose> pose; + private Space poseSpace = Space.LOCAL; private AnimationPose(LocatorSkeleton locatorSkeleton){ this.locatorSkeleton = locatorSkeleton; @@ -28,6 +30,7 @@ private AnimationPose(LocatorSkeleton locatorSkeleton){ public AnimationPose(AnimationPose animationPose){ this.locatorSkeleton = animationPose.locatorSkeleton; this.pose = new HashMap<>(animationPose.pose); + this.poseSpace = animationPose.poseSpace; } public static > AnimationPose of(LocatorSkeleton locatorSkeleton){ @@ -75,110 +78,59 @@ public void subtractPose(AnimationPose animationPose){ */ - public AnimationPose getConvertedFromLocalToWorld(){ - AnimationPose animationPose = new AnimationPose(this); - //ArrayList rotationStack = new ArrayList<>(); - - - - animationPose.transformChildren(this.getSkeleton().getRootLocator(), new PoseStack()); - //animationPose.transformChildren(this.getSkeleton().getRootLocator(), this.getJointPoseCopy(this.getSkeleton().getRootLocator()).getTransformCopy()); - - //HashMap, Matrix4fStack> matrixStackSet = Maps.newHashMap(); - //ArrayList rootMatrixStack = new ArrayList<>(); - //Matrix4f rootMatrix = new Matrix4f(); - - //Enum enumm = this.locatorSkeleton.getLocatorChildren(this.locatorSkeleton.getRootLocator()).get(1); - //animationPose.setLocatorPose(enumm, animationPose.getLocatorPose(enumm).rotate(new Vector3f(Mth.PI, 0, 0), false)); - - //animationPose.transformChildren(this.getSkeleton().getRootLocator(), rootMatrixStack, this.getCopy(), 200); - - return animationPose; + public Space getPoseSpace(){ + return this.poseSpace; } - private void transformChildren(Enum parent, Matrix4f parentTransform){ - JointPose parentJointPose = new JointPose(this.getJointPoseCopy(parent)); + public void setPoseSpace(Space poseSpace){ + this.poseSpace = poseSpace; + } - for (Enum child : this.getSkeleton().getLocatorChildren(parent)){ - JointPose childJointPose = new JointPose(this.getJointPoseCopy(child)); - Matrix4f multipliedChildTransform = childJointPose.getTransformCopy().mul(parentTransform); - this.setJointPose(child, childJointPose.setTransform(multipliedChildTransform)); - - transformChildren(child, new Matrix4f(childJointPose.getTransformCopy())); + // Local to World + public AnimationPose convertSpaceLocalToEntity(){ + if(this.getPoseSpace() == Space.LOCAL){ + this.setPoseSpace(Space.ENTITY); + this.convertChildrenSpaceLocalToEntity(this.getSkeleton().getRootLocator(), new PoseStack()); } + return this; } - - - private void transformChildren(Enum parent, PoseStack poseStack){ + private void convertChildrenSpaceLocalToEntity(Enum parent, PoseStack poseStack){ JointPose localParentJointPose = new JointPose(this.getJointPoseCopy(parent)); + poseStack.pushPose(); poseStack.mulPoseMatrix(localParentJointPose.getTransformCopy()); - - - //poseStack.translate(localParentJointPose.getTranslation().x(), localParentJointPose.getTranslation().y(), localParentJointPose.getTranslation().z()); - //poseStack.mulPose(localParentJointPose.getRotation()); - for (Enum child : this.getSkeleton().getLocatorChildren(parent)){ + convertChildrenSpaceLocalToEntity(child, poseStack); + } + this.setJointPose(parent, localParentJointPose.setTransform(new Matrix4f(poseStack.last().pose()))); + poseStack.popPose(); + } - //Quaternionf composedRotation = new Quaternionf(); - /* - for(Quaternionf childRotation : rotationStack){ - newChildPose.rotate(childRotation, false); - } - - */ - //this.setLocatorPose(child, newWorldChildPose); - - - - /* - PoseStack poseStack = new PoseStack(); - parentPose.transformPoseStack(poseStack, 1); - poseStack.pushPose(); - childPose.transformPoseStack(poseStack, 1); - - Matrix4f pose = poseStack.last().pose(); - Quaternionf rotation = pose.getNormalizedRotation(new Quaternionf()); - this.setLocatorPose(child, MutablePartPose.fromTranslationAndRotation( - pose.m30(), - pose.m31(), - pose.m32(), - rotation - )); - - poseStack.popPose(); - */ - //Quaternionf childRotation = childPose.getCopy().getRotation(); - - - /* - for(Quaternionf rotation : rotationStack){ - childRotation.mul(rotation, childRotation); - } - - */ - //MutablePartPose transformedPose = parentPose.getCopy(); - //transformedPose.translate(childPose.getTranslation(), true); - //transformedPose.rotate(childPose.getRotation(), true); + // World to Local + public AnimationPose convertSpaceEntityToLocal(){ + if(this.getPoseSpace() == Space.ENTITY){ + this.setPoseSpace(Space.LOCAL); + this.convertChildrenSpaceEntityToLocal(this.getSkeleton().getRootLocator(), new Matrix4f()); + } + return this; + } - transformChildren(child, poseStack); + private void convertChildrenSpaceEntityToLocal(Enum parent, Matrix4f parentMatrix){ + JointPose parentJointPose = this.getJointPoseCopy(parent); - /* - this.setLocatorPose(child, getLocatorPose(child) - //.translate(childPose.getTranslation(), true) - //.rotate(childPose.getRotation(), true) - ); - */ + for (Enum child : this.getSkeleton().getLocatorChildren(parent)){ + convertChildrenSpaceEntityToLocal(child, parentJointPose.getTransformCopy()); } - this.setJointPose(parent, localParentJointPose.setTransform(new Matrix4f(poseStack.last().pose()))); - poseStack.popPose(); + + parentJointPose.transform(parentMatrix.invert(), Space.LOCAL); + this.setJointPose(parent, parentJointPose); } public void blend(AnimationPose animationPose, float alpha, Easing easing){ @@ -284,4 +236,9 @@ public static > AnimationPose fromChannelTimeline(LocatorSk } return animationPose; } + + public enum Space { + ENTITY, + LOCAL + } } diff --git a/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/BakedAnimationPose.java b/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/BakedAnimationPose.java index c7a0427..3ba6a28 100644 --- a/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/BakedAnimationPose.java +++ b/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/BakedAnimationPose.java @@ -23,7 +23,7 @@ public void setPose(AnimationPose animationPose){ public AnimationPose getBlendedPose(float partialTicks){ // uncomment this for debugging //partialTicks = 1; - return this.poseOld.getBlendedLinear(this.pose, partialTicks).getConvertedFromLocalToWorld(); + return this.poseOld.getBlendedLinear(this.pose, partialTicks).convertSpaceLocalToEntity(); } public void bakeToModelParts(ModelPart rootModelPart, float partialTicks){ diff --git a/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/JointPose.java b/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/JointPose.java index dbd731e..013cc83 100644 --- a/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/JointPose.java +++ b/src/main/java/com/trainguy9512/animationoverhaul/animation/pose/JointPose.java @@ -129,9 +129,17 @@ public PartPose asPartPose(){ //TODO: Use TranslateLocal Matrix4F - public JointPose translate(Vector3f translation, boolean localSpace){ + public JointPose transform(Matrix4f transform, AnimationPose.Space space){ + switch (space){ + case ENTITY -> this.getTransformReference().mul(transform); + case LOCAL -> this.getTransformReference().mulLocal(transform); + } + return this; + } + + public JointPose translate(Vector3f translation, AnimationPose.Space space){ if(translation.x() != 0 || translation.y() != 0 || translation.z() != 0){ - if(localSpace){ + if(space == AnimationPose.Space.LOCAL){ translation.rotateZ(this.getEulerRotationZYX().z()); translation.rotateY(this.getEulerRotationZYX().y()); translation.rotateX(this.getEulerRotationZYX().x()); @@ -143,103 +151,28 @@ public JointPose translate(Vector3f translation, boolean localSpace){ return this; } - public JointPose rotate(Quaternionf rotation, boolean localSpace){ - if(localSpace){ - - /* - Vector3f eulerRotation = this.getEulerRotation(); - rotation.rotateX(eulerRotation.x()); - rotation.rotateY(eulerRotation.y()); - rotation.rotateZ(eulerRotation.z()); - - */ - - - - - /* - Vector3f eulerRotation = rotation.getEulerAnglesXYZ(new Vector3f()); - - - PoseStack poseStack = new PoseStack(); - poseStack.pushPose(); - poseStack.setIdentity(); - poseStack.mulPose(this.rotation); - - poseStack.pushPose(); - poseStack.mulPose(rotation); - - - this.rotation = poseStack.last().pose().getNormalizedRotation(new Quaternionf()); - - poseStack.popPose(); - poseStack.popPose(); - - */ - - - - - - //Quaternionf newRotation = new Quaternionf(rotation.x(), rotation.y(), rotation.z(), rotation.w()).normalize(); - //Quaternionf oldRotation = new Quaternionf(this.rotation.x(), this.rotation.y(), this.rotation.z(), this.rotation.w()).normalize(); - - //newRotation.rotateXYZ(this.getRotation().x(), this.getEulerRotation().y(), this.getEulerRotation().z()); - - - - //this.rotation.normalize(); - - + public JointPose rotate(Quaternionf rotation, AnimationPose.Space space){ + if(space == AnimationPose.Space.LOCAL){ this.getTransformReference().rotateLocal(rotation); - - //rotation.mul(this.rotation, this.rotation); - //this.rotation = newRotation.mul(oldRotation); - - - //this.rotation = rotation.mul(this.rotation); - - /* - rotation.rotateX(this.getEulerRotation().x()); - rotation.rotateY(this.getEulerRotation().y()); - rotation.rotateZ(this.getEulerRotation().z()); - this.rotation = rotation; - */ - - - - - /* - Vector3f rotationOriginal = this.getEulerRotation(); - Vector3f rotationAdded = rotation.getEulerAnglesXYZ(new Vector3f()); - rotationOriginal.add(rotationAdded); - this.setEulerRotation(rotationOriginal); - - */ } else { this.getTransformReference().rotate(rotation); - - //Vector3f rotationOriginal = this.rotation.getEulerAnglesXYZ(new Vector3f()); - //Vector3f rotationAdded = rotation.getEulerAnglesZYX(new Vector3f()); - //this.rotation.mul(new Quaternionf().rotationZYX(rotationAdded.z(), rotationAdded.y(), rotationAdded.x())); - } return this; } - public JointPose rotate(Vector3f rotation, boolean localSpace){ - return this.rotate(new Quaternionf().rotationXYZ(rotation.x(), rotation.y(), rotation.z()), localSpace); + public JointPose rotate(Vector3f rotation, AnimationPose.Space space){ + return this.rotate(new Quaternionf().rotationXYZ(rotation.x(), rotation.y(), rotation.z()), space); } public JointPose multiplyPose(JointPose partPose){ - this.translate(partPose.getTranslation(), false); - this.rotate(partPose.getRotation(), false); + this.translate(partPose.getTranslation(), AnimationPose.Space.ENTITY); + this.rotate(partPose.getRotation(), AnimationPose.Space.ENTITY); return this; } public JointPose inverseMultiplyPose(JointPose partPose){ - this.translate(partPose.getTranslation().negate(), false); - this.rotate(partPose.getRotation().invert(), false); + this.translate(partPose.getTranslation().negate(), AnimationPose.Space.ENTITY); + this.rotate(partPose.getRotation().invert(), AnimationPose.Space.ENTITY); return this; }