Skip to content

Commit

Permalink
Pose Spaces
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
Trainguy9512 committed Mar 5, 2024
1 parent 66ae30e commit bc33920
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 174 deletions.
Expand Up @@ -199,6 +199,9 @@ protected AnimationPose<FPPlayerLocators> calculatePose() {
AnimationPose<FPPlayerLocators> pose = sampleAnimationState(IDLE_SEQUENCE_PLAYER);

pose = dampenArmRotation(pose);

pose.convertSpaceLocalToEntity();
pose.convertSpaceEntityToLocal();
return pose;
}

Expand All @@ -215,11 +218,11 @@ private AnimationPose<FPPlayerLocators> dampenArmRotation(AnimationPose<FPPlayer
FPPlayerLocators.armBuffer,
pose.getJointPoseCopy(FPPlayerLocators.armBuffer).rotate(
new Vector3f(
(dampenedCameraRotationX - cameraRotationX) * -0.005F,
(dampenedCameraRotationX - cameraRotationX) * 0.008F,
(dampenedCameraRotationY - cameraRotationY) * 0.005F,
0
(dampenedCameraRotationY - cameraRotationY) * 0.003F
),
false
AnimationPose.Space.ENTITY
));
return pose;
}
Expand Down Expand Up @@ -322,7 +325,7 @@ public void tick(LivingEntity livingEntity, AnimationDataContainer entityAnimati
dampenedCameraRotation = targetRotation;
} else {
// Lerp the dampened camera rotation towards the normal camera rotation
dampenedCameraRotation.lerp(targetRotation, 0.3F);
dampenedCameraRotation.lerp(targetRotation, 0.5F);
}
setEntityAnimationVariable(DAMPENED_CAMERA_ROTATION_X, dampenedCameraRotation.x());
setEntityAnimationVariable(DAMPENED_CAMERA_ROTATION_Y, dampenedCameraRotation.y());
Expand Down
Expand Up @@ -2,6 +2,7 @@

import com.google.common.collect.Maps;
import com.mojang.blaze3d.vertex.PoseStack;
import com.trainguy9512.animationoverhaul.AnimationOverhaulMain;
import com.trainguy9512.animationoverhaul.util.animation.LocatorSkeleton;
import com.trainguy9512.animationoverhaul.util.time.Easing;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -15,6 +16,7 @@ public class AnimationPose<L extends Enum<L>> {

private final LocatorSkeleton<L> locatorSkeleton;
private final HashMap<Enum<L>, JointPose> pose;
private Space poseSpace = Space.LOCAL;

private AnimationPose(LocatorSkeleton<L> locatorSkeleton){
this.locatorSkeleton = locatorSkeleton;
Expand All @@ -28,6 +30,7 @@ private AnimationPose(LocatorSkeleton<L> locatorSkeleton){
public AnimationPose(AnimationPose<L> animationPose){
this.locatorSkeleton = animationPose.locatorSkeleton;
this.pose = new HashMap<>(animationPose.pose);
this.poseSpace = animationPose.poseSpace;
}

public static <L extends Enum<L>> AnimationPose<L> of(LocatorSkeleton<L> locatorSkeleton){
Expand Down Expand Up @@ -75,110 +78,59 @@ public void subtractPose(AnimationPose animationPose){
*/

public AnimationPose<L> getConvertedFromLocalToWorld(){
AnimationPose<L> animationPose = new AnimationPose<L>(this);
//ArrayList<Quaternionf> rotationStack = new ArrayList<>();



animationPose.transformChildren(this.getSkeleton().getRootLocator(), new PoseStack());
//animationPose.transformChildren(this.getSkeleton().getRootLocator(), this.getJointPoseCopy(this.getSkeleton().getRootLocator()).getTransformCopy());

//HashMap<Enum<L>, Matrix4fStack> matrixStackSet = Maps.newHashMap();
//ArrayList<Matrix4f> rootMatrixStack = new ArrayList<>();
//Matrix4f rootMatrix = new Matrix4f();

//Enum<L> 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<L> parent, Matrix4f parentTransform){
JointPose parentJointPose = new JointPose(this.getJointPoseCopy(parent));
public void setPoseSpace(Space poseSpace){
this.poseSpace = poseSpace;
}


for (Enum<L> 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<L> convertSpaceLocalToEntity(){
if(this.getPoseSpace() == Space.LOCAL){
this.setPoseSpace(Space.ENTITY);
this.convertChildrenSpaceLocalToEntity(this.getSkeleton().getRootLocator(), new PoseStack());
}
return this;
}



private void transformChildren(Enum<L> parent, PoseStack poseStack){
private void convertChildrenSpaceLocalToEntity(Enum<L> 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<L> 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<L> 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<L> parent, Matrix4f parentMatrix){
JointPose parentJointPose = this.getJointPoseCopy(parent);

/*
this.setLocatorPose(child, getLocatorPose(child)
//.translate(childPose.getTranslation(), true)
//.rotate(childPose.getRotation(), true)
);
*/
for (Enum<L> 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<L> animationPose, float alpha, Easing easing){
Expand Down Expand Up @@ -284,4 +236,9 @@ public static <L extends Enum<L>> AnimationPose<L> fromChannelTimeline(LocatorSk
}
return animationPose;
}

public enum Space {
ENTITY,
LOCAL
}
}
Expand Up @@ -23,7 +23,7 @@ public void setPose(AnimationPose<L> animationPose){
public AnimationPose<L> 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){
Expand Down
Expand Up @@ -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());
Expand All @@ -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;
}

Expand Down

0 comments on commit bc33920

Please sign in to comment.