Fix the bug of animation playback for multiple same type components under an Entity (#2095)

* fix: multi subMesh animation bug
This commit is contained in:
luzhuang
2024-05-13 14:07:19 +08:00
committed by GitHub
parent 288c64d12b
commit 1bf6822210
5 changed files with 122 additions and 7 deletions

View File

@@ -0,0 +1,108 @@
/**
* @title Animation MultiSubMeshBlendShape
* @category Animation
*/
import {
Animator,
Camera,
DirectLight,
Logger,
SkinnedMeshRenderer,
SystemInfo,
Vector3,
WebGLEngine,
GLTFResource,
Keyframe,
AnimatorController,
AnimatorControllerLayer,
AnimatorStateMachine,
AnimationClip,
AnimationFloatArrayCurve
} from "@galacean/engine";
import { initScreenshot, updateForE2E } from "./.mockForE2E";
Logger.enable();
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.width = window.innerWidth * SystemInfo.devicePixelRatio;
engine.canvas.height = window.innerHeight * SystemInfo.devicePixelRatio;
const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();
// camera
const cameraEntity = rootEntity.createChild("camera_node");
cameraEntity.transform.position = new Vector3(0, 1.5, 1);
const camera = cameraEntity.addComponent(Camera);
const lightNode = rootEntity.createChild("light_node");
lightNode.addComponent(DirectLight).intensity = 1.0;
lightNode.transform.lookAt(new Vector3(0, 0, 1));
lightNode.transform.rotate(new Vector3(-45, -135, 0));
engine.resourceManager
.load<GLTFResource>(
"https://mdn.alipayobjects.com/oasis_be/afts/file/A*M_orSIoXP-QAAAAAAAAAAAAADkp5AQ/258To52bs_01.glb"
)
.then((asset) => {
const { defaultSceneRoot } = asset;
rootEntity.addChild(defaultSceneRoot);
const entity = defaultSceneRoot;
defaultSceneRoot.transform.rotation = new Vector3(-90, -0, 0);
const animator = entity.addComponent(Animator);
animator.animatorController = new AnimatorController();
const layer = new AnimatorControllerLayer("base");
animator.animatorController.addLayer(layer);
const stateMachine = (layer.stateMachine = new AnimatorStateMachine());
const state = stateMachine.addState("blendShape");
const clip = (state.clip = new AnimationClip("blendShape"));
//custom blendShape curve
const blendShapeCurve = new AnimationFloatArrayCurve();
let key1 = new Keyframe<Float32Array>();
key1.time = 0;
let array1 = new Float32Array(52);
for (let i = 0; i < array1.length; i++) {
array1[i] = 0;
if (i == 8) {
array1[i] = 0;
}
}
key1.value = array1;
let key2 = new Keyframe<Float32Array>();
key2.time = 0.5;
let array2 = new Float32Array(52);
for (let i = 0; i < array2.length; i++) {
array2[i] = 0;
if (i == 8) {
array2[i] = 1;
}
}
key2.value = array2;
let key3 = new Keyframe<Float32Array>();
key3.time = 1;
let array3 = new Float32Array(52);
for (let i = 0; i < array3.length; i++) {
array3[i] = 0;
if (i == 8) {
array3[i] = 0;
}
}
key3.value = array3;
blendShapeCurve.addKey(key1);
blendShapeCurve.addKey(key2);
blendShapeCurve.addKey(key3);
const skinMeshRenders = entity.getComponentsIncludeChildren<SkinnedMeshRenderer>(SkinnedMeshRenderer, []);
for (let i = 0, n = skinMeshRenders.length; i < n; i++) {
clip.addCurveBinding("", SkinnedMeshRenderer, i, "blendShapeWeights", blendShapeCurve);
}
animator.play("blendShape");
updateForE2E(engine, 500);
initScreenshot(engine, camera);
});
});

View File

@@ -30,6 +30,11 @@ export const E2E_CONFIG = {
caseFileName: "animator-customBlendShape",
threshold: 0.1
},
multiSubMeshBlendShape: {
category: "Animator",
caseFileName: "animator-multiSubMeshBlendShape",
threshold: 0.1
},
event: {
category: "Animator",
caseFileName: "animator-event",

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2e3237691c33d1fb0ca40b8d3076a87f29d4f1887ae6852cb3c256fe7605d91
size 80713

View File

@@ -300,7 +300,6 @@ export class Animator extends Component {
const { relativePath } = curve;
const targetEntity = curve.relativePath === "" ? entity : entity.findByPath(curve.relativePath);
if (targetEntity) {
const propertyPath = `${curve.typeIndex}.` + curve.property;
const component =
curve.typeIndex > 0
? targetEntity.getComponents(curve.type, AnimationCurveOwner._components)[curve.typeIndex]
@@ -311,7 +310,7 @@ export class Animator extends Component {
}
const { property } = curve;
const { instanceId } = targetEntity;
const { instanceId } = component;
// Get owner
const propertyOwners = (curveOwnerPool[instanceId] ||= <Record<string, AnimationCurveOwner<KeyframeValueType>>>(
Object.create(null)
@@ -322,7 +321,7 @@ export class Animator extends Component {
const layerPropertyOwners = (layerCurveOwnerPool[instanceId] ||= <Record<string, AnimationCurveLayerOwner>>(
Object.create(null)
));
const layerOwner = (layerPropertyOwners[propertyPath] ||= curve._createCurveLayerOwner(owner));
const layerOwner = (layerPropertyOwners[property] ||= curve._createCurveLayerOwner(owner));
if (mask && mask.pathMasks.length) {
layerOwner.isActive = mask.getPathMask(relativePath)?.active ?? true;

View File

@@ -265,10 +265,10 @@ describe("Animator test", function () {
);
let layerData = animator["_animatorLayersData"][1];
const layerCurveOwner = layerData.curveOwnerPool[targetEntity.instanceId]["0.rotationQuaternion"];
const parentLayerCurveOwner = layerData.curveOwnerPool[parentEntity.instanceId]["0.rotationQuaternion"];
const layerCurveOwner = layerData.curveOwnerPool[targetEntity.transform.instanceId]["rotationQuaternion"];
const parentLayerCurveOwner = layerData.curveOwnerPool[parentEntity.transform.instanceId]["rotationQuaternion"];
let childLayerCurveOwner = layerData.curveOwnerPool[childEntity.instanceId]["0.rotationQuaternion"];
let childLayerCurveOwner = layerData.curveOwnerPool[childEntity.transform.instanceId]["rotationQuaternion"];
expect(layerCurveOwner.isActive).to.eq(false);
expect(parentLayerCurveOwner.isActive).to.eq(true);
@@ -279,7 +279,7 @@ describe("Animator test", function () {
animator.animatorController.addLayer(additiveLayer);
animator.play("Run", 1);
layerData = animator["_animatorLayersData"][1];
childLayerCurveOwner = layerData.curveOwnerPool[childEntity.instanceId]["0.rotationQuaternion"];
childLayerCurveOwner = layerData.curveOwnerPool[childEntity.transform.instanceId]["rotationQuaternion"];
expect(childLayerCurveOwner.isActive).to.eq(true);
});