diff --git a/packages/dev/core/src/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.ts b/packages/dev/core/src/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.ts
index 68de8555ec8..7315b66b95f 100644
--- a/packages/dev/core/src/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.ts
+++ b/packages/dev/core/src/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.ts
@@ -85,10 +85,10 @@ export class FlowGraphJsonPointerParserBlock
Animation[] {
- const accessorContainer = this.templateComponent.getAccessor(this.config.pathConverter, context);
+ const accessor = this.templateComponent.getAccessor(this.config.pathConverter, context);
return (keys: any[], fps: number, animationType: number, easingFunction?: EasingFunction) => {
const animations: Animation[] = [];
// make sure keys are of the right type (in case of float3 color/vector)
- const type = accessorContainer.info.type;
+ const type = accessor.info.type;
if (type.startsWith("Color")) {
keys = keys.map((key) => {
return {
@@ -137,8 +137,8 @@ export class FlowGraphJsonPointerParserBlock
{
- const name = accessorContainer.info.getPropertyName?.[index](accessorContainer.object) || "Animation-interpolation-" + index;
+ accessor.info.interpolation?.forEach((info, index) => {
+ const name = accessor.info.getPropertyName?.[index](accessor.object) || "Animation-interpolation-" + index;
// generate the keys based on interpolation info
let newKeys: any[] = keys;
if (animationType !== info.type) {
@@ -150,7 +150,7 @@ export class FlowGraphJsonPointerParserBlock
{
/**
* The original object.
*/
object: O;
+ /**
+ * The index of the array in question when applicable.
+ */
+ index?: number;
/**
* Information about the object.
*/
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_lights_image_based.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_lights_image_based.ts
index 8ce46393e5f..fa18bed7683 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_lights_image_based.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/EXT_lights_image_based.ts
@@ -73,9 +73,7 @@ export class EXT_lights_image_based implements IGLTFLoaderExtension {
}
}
- /**
- * @internal
- */
+ /** @internal */
// eslint-disable-next-line no-restricted-syntax
public loadSceneAsync(context: string, scene: IScene): Nullable> {
return GLTFLoader.LoadExtensionAsync(context, scene, this.name, async (extensionContext, extension) => {
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts
index 085cff13007..be2d7e0c4fe 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts
@@ -5,7 +5,7 @@ import type { ICamera, IKHRLightsPunctual_Light, IMaterial } from "../glTFLoader
import type { IAnimatable } from "core/Animations/animatable.interface";
import { AnimationPropertyInfo } from "../glTFLoaderAnimation";
import { Color3 } from "core/Maths/math.color";
-import { SetInterpolationForKey } from "./objectModelMapping";
+import { AddInterpolation } from "./objectModelMapping";
function getColor3(_target: any, source: Float32Array, offset: number, scale: number): Color3 {
return Color3.FromArray(source, offset).scale(scale);
@@ -73,256 +73,237 @@ class LightAnimationPropertyInfo extends AnimationPropertyInfo {
}
}
-SetInterpolationForKey("/cameras/{}/orthographic/xmag", [
+AddInterpolation("/cameras/{}/orthographic/xmag", [
new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "orthoLeft", getMinusFloat, () => 1),
new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "orthoRight", getNextFloat, () => 1),
]);
-SetInterpolationForKey("/cameras/{}/orthographic/ymag", [
+AddInterpolation("/cameras/{}/orthographic/ymag", [
new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "orthoBottom", getMinusFloat, () => 1),
new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "orthoTop", getNextFloat, () => 1),
]);
-SetInterpolationForKey("/cameras/{}/orthographic/zfar", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "maxZ", getFloat, () => 1)]);
-SetInterpolationForKey("/cameras/{}/orthographic/znear", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "minZ", getFloat, () => 1)]);
+AddInterpolation("/cameras/{}/orthographic/zfar", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "maxZ", getFloat, () => 1)]);
+AddInterpolation("/cameras/{}/orthographic/znear", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "minZ", getFloat, () => 1)]);
-SetInterpolationForKey("/cameras/{}/perspective/yfov", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "fov", getFloat, () => 1)]);
-SetInterpolationForKey("/cameras/{}/perspective/zfar", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "maxZ", getFloat, () => 1)]);
-SetInterpolationForKey("/cameras/{}/perspective/znear", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "minZ", getFloat, () => 1)]);
+AddInterpolation("/cameras/{}/perspective/yfov", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "fov", getFloat, () => 1)]);
+AddInterpolation("/cameras/{}/perspective/zfar", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "maxZ", getFloat, () => 1)]);
+AddInterpolation("/cameras/{}/perspective/znear", [new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "minZ", getFloat, () => 1)]);
// add interpolation to the materials mapping
-SetInterpolationForKey("/materials/{}/pbrMetallicRoughness/baseColorFactor", [
+AddInterpolation("/materials/{}/pbrMetallicRoughness/baseColorFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "albedoColor", getColor3, () => 4),
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "alpha", getAlpha, () => 4),
]);
-SetInterpolationForKey("/materials/{}/pbrMetallicRoughness/metallicFactor", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "metallic", getFloat, () => 1)]);
-SetInterpolationForKey("/materials/{}/pbrMetallicRoughness/metallicFactor", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "roughness", getFloat, () => 1)]);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/metallicFactor", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "metallic", getFloat, () => 1)]);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/roughnessFactor", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "roughness", getFloat, () => 1)]);
const baseColorTextureInterpolation = getTextureTransformTree("albedoTexture");
-SetInterpolationForKey("/materials/{}/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/scale", baseColorTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/offset", baseColorTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/rotation", baseColorTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/scale", baseColorTextureInterpolation.scale);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/offset", baseColorTextureInterpolation.offset);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/rotation", baseColorTextureInterpolation.rotation);
const metallicRoughnessTextureInterpolation = getTextureTransformTree("metallicTexture");
-SetInterpolationForKey("//materials/{}/pbrMetallicRoughness/metallicRoughnessTexture/scale", metallicRoughnessTextureInterpolation.scale);
-SetInterpolationForKey("//materials/{}/pbrMetallicRoughness/metallicRoughnessTexture/offset", metallicRoughnessTextureInterpolation.offset);
-SetInterpolationForKey("//materials/{}/pbrMetallicRoughness/metallicRoughnessTexture/rotation", metallicRoughnessTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/metallicRoughnessTexture/extensions/KHR_texture_transform/scale", metallicRoughnessTextureInterpolation.scale);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/metallicRoughnessTexture/extensions/KHR_texture_transform/offset", metallicRoughnessTextureInterpolation.offset);
+AddInterpolation("/materials/{}/pbrMetallicRoughness/metallicRoughnessTexture/extensions/KHR_texture_transform/rotation", metallicRoughnessTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/emissiveFactor", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "emissiveColor", getColor3, () => 3)]);
+AddInterpolation("/materials/{}/emissiveFactor", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "emissiveColor", getColor3, () => 3)]);
const normalTextureInterpolation = getTextureTransformTree("bumpTexture");
-SetInterpolationForKey("/materials/{}/normalTexture/scale", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "bumpTexture.level", getFloat, () => 1)]);
+AddInterpolation("/materials/{}/normalTexture/scale", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "bumpTexture.level", getFloat, () => 1)]);
-SetInterpolationForKey("/materials/{}/normalTexture/extensions/KHR_texture_transform/scale", normalTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/normalTexture/extensions/KHR_texture_transform/offset", normalTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/normalTexture/extensions/KHR_texture_transform/rotation", normalTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/normalTexture/extensions/KHR_texture_transform/scale", normalTextureInterpolation.scale);
+AddInterpolation("/materials/{}/normalTexture/extensions/KHR_texture_transform/offset", normalTextureInterpolation.offset);
+AddInterpolation("/materials/{}/normalTexture/extensions/KHR_texture_transform/rotation", normalTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/occlusionTexture/strength", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "ambientTextureStrength", getFloat, () => 1)]);
+AddInterpolation("/materials/{}/occlusionTexture/strength", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "ambientTextureStrength", getFloat, () => 1)]);
const occlusionTextureInterpolation = getTextureTransformTree("ambientTexture");
-SetInterpolationForKey("/materials/{}/occlusionTexture/extensions/KHR_texture_transform/scale", occlusionTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/occlusionTexture/extensions/KHR_texture_transform/offset", occlusionTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/occlusionTexture/extensions/KHR_texture_transform/rotation", occlusionTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/occlusionTexture/extensions/KHR_texture_transform/scale", occlusionTextureInterpolation.scale);
+AddInterpolation("/materials/{}/occlusionTexture/extensions/KHR_texture_transform/offset", occlusionTextureInterpolation.offset);
+AddInterpolation("/materials/{}/occlusionTexture/extensions/KHR_texture_transform/rotation", occlusionTextureInterpolation.rotation);
const emissiveTextureInterpolation = getTextureTransformTree("emissiveTexture");
-SetInterpolationForKey("/materials/{}/emissiveTexture/extensions/KHR_texture_transform/scale", emissiveTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/emissiveTexture/extensions/KHR_texture_transform/offset", emissiveTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/emissiveTexture/extensions/KHR_texture_transform/rotation", emissiveTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/emissiveTexture/extensions/KHR_texture_transform/scale", emissiveTextureInterpolation.scale);
+AddInterpolation("/materials/{}/emissiveTexture/extensions/KHR_texture_transform/offset", emissiveTextureInterpolation.offset);
+AddInterpolation("/materials/{}/emissiveTexture/extensions/KHR_texture_transform/rotation", emissiveTextureInterpolation.rotation);
// materials extensions
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyStrength", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyStrength", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "anisotropy.intensity", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyRotation", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyRotation", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "anisotropy.angle", getFloat, () => 1),
]);
const anisotropyTextureInterpolation = getTextureTransformTree("anisotropy.texture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyTexture/extensions/KHR_texture_transform/scale", anisotropyTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyTexture/extensions/KHR_texture_transform/offset", anisotropyTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyTexture/extensions/KHR_texture_transform/rotation", anisotropyTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyTexture/extensions/KHR_texture_transform/scale", anisotropyTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyTexture/extensions/KHR_texture_transform/offset", anisotropyTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_anisotropy/anisotropyTexture/extensions/KHR_texture_transform/rotation", anisotropyTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "clearCoat.intensity", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatRoughnessFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatRoughnessFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "clearCoat.roughness", getFloat, () => 1),
]);
const clearcoatTextureInterpolation = getTextureTransformTree("clearCoat.texture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatTexture/extensions/KHR_texture_transform/scale", clearcoatTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatTexture/extensions/KHR_texture_transform/offset", clearcoatTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatTexture/extensions/KHR_texture_transform/rotation", clearcoatTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatTexture/extensions/KHR_texture_transform/scale", clearcoatTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatTexture/extensions/KHR_texture_transform/offset", clearcoatTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatTexture/extensions/KHR_texture_transform/rotation", clearcoatTextureInterpolation.rotation);
const clearcoatNormalTextureInterpolation = getTextureTransformTree("clearCoat.bumpTexture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/scale", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/scale", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "clearCoat.bumpTexture.level", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/extensions/KHR_texture_transform/scale", clearcoatNormalTextureInterpolation.scale);
-SetInterpolationForKey(
- "/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/extensions/KHR_texture_transform/offset",
- clearcoatNormalTextureInterpolation.offset
-);
-SetInterpolationForKey(
- "/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/extensions/KHR_texture_transform/rotation",
- clearcoatNormalTextureInterpolation.rotation
-);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/extensions/KHR_texture_transform/scale", clearcoatNormalTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/extensions/KHR_texture_transform/offset", clearcoatNormalTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatNormalTexture/extensions/KHR_texture_transform/rotation", clearcoatNormalTextureInterpolation.rotation);
const clearcoatRoughnessTextureInterpolation = getTextureTransformTree("clearCoat.textureRoughness");
-SetInterpolationForKey(
- "/materials/{}/extensions/KHR_materials_clearcoat/clearcoatRoughnessTexture/extensions/KHR_texture_transform/scale",
- clearcoatRoughnessTextureInterpolation.scale
-);
-SetInterpolationForKey(
+AddInterpolation("/materials/{}/extensions/KHR_materials_clearcoat/clearcoatRoughnessTexture/extensions/KHR_texture_transform/scale", clearcoatRoughnessTextureInterpolation.scale);
+AddInterpolation(
"/materials/{}/extensions/KHR_materials_clearcoat/clearcoatRoughnessTexture/extensions/KHR_texture_transform/offset",
clearcoatRoughnessTextureInterpolation.offset
);
-SetInterpolationForKey(
+AddInterpolation(
"/materials/{}/extensions/KHR_materials_clearcoat/clearcoatRoughnessTexture/extensions/KHR_texture_transform/rotation",
clearcoatRoughnessTextureInterpolation.rotation
);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_dispersion/dispersionFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_dispersion/dispersionFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "subSurface.dispersion", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_emissive_strength/emissiveStrength", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_emissive_strength/emissiveStrength", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "emissiveIntensity", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_ior/ior", [
- new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "indexOfRefraction", getFloat, () => 1),
-]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_ior/ior", [new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "indexOfRefraction", getFloat, () => 1)]);
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "iridescence.intensity", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceIor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceIor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "iridescence.indexOfRefraction", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessMinimum", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessMinimum", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "iridescence.minimumThickness", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessMaximum", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessMaximum", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "iridescence.maximumThickness", getFloat, () => 1),
]);
const iridescenceTextureInterpolation = getTextureTransformTree("iridescence.texture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceTexture/extensions/KHR_texture_transform/scale", iridescenceTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceTexture/extensions/KHR_texture_transform/offset", iridescenceTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_iridescence/iridescenceTexture/extensions/KHR_texture_transform/rotation", iridescenceTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceTexture/extensions/KHR_texture_transform/scale", iridescenceTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceTexture/extensions/KHR_texture_transform/offset", iridescenceTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_iridescence/iridescenceTexture/extensions/KHR_texture_transform/rotation", iridescenceTextureInterpolation.rotation);
const iridescenceThicknessTextureInterpolation = getTextureTransformTree("iridescence.thicknessTexture");
-SetInterpolationForKey(
+AddInterpolation(
"/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessTexture/extensions/KHR_texture_transform/scale",
iridescenceThicknessTextureInterpolation.scale
);
-SetInterpolationForKey(
+AddInterpolation(
"/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessTexture/extensions/KHR_texture_transform/offset",
iridescenceThicknessTextureInterpolation.offset
);
-SetInterpolationForKey(
+AddInterpolation(
"/materials/{}/extensions/KHR_materials_iridescence/iridescenceThicknessTexture/extensions/KHR_texture_transform/rotation",
iridescenceThicknessTextureInterpolation.rotation
);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenColorFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenColorFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "sheen.color", getColor3, () => 3),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "sheen.roughness", getFloat, () => 1),
]);
const sheenTextureInterpolation = getTextureTransformTree("sheen.texture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenColorTexture/extensions/KHR_texture_transform/scale", sheenTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenColorTexture/extensions/KHR_texture_transform/offset", sheenTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenColorTexture/extensions/KHR_texture_transform/rotation", sheenTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenColorTexture/extensions/KHR_texture_transform/scale", sheenTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenColorTexture/extensions/KHR_texture_transform/offset", sheenTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenColorTexture/extensions/KHR_texture_transform/rotation", sheenTextureInterpolation.rotation);
const sheenRoughnessTextureInterpolation = getTextureTransformTree("sheen.textureRoughness");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessTexture/extensions/KHR_texture_transform/scale", sheenRoughnessTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessTexture/extensions/KHR_texture_transform/offset", sheenRoughnessTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessTexture/extensions/KHR_texture_transform/rotation", sheenRoughnessTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessTexture/extensions/KHR_texture_transform/scale", sheenRoughnessTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessTexture/extensions/KHR_texture_transform/offset", sheenRoughnessTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_sheen/sheenRoughnessTexture/extensions/KHR_texture_transform/rotation", sheenRoughnessTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "metallicF0Factor", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularColorFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularColorFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "metallicReflectanceColor", getColor3, () => 3),
]);
const specularTextureInterpolation = getTextureTransformTree("metallicReflectanceTexture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularTexture/extensions/KHR_texture_transform/scale", specularTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularTexture/extensions/KHR_texture_transform/offset", specularTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularTexture/extensions/KHR_texture_transform/rotation", specularTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularTexture/extensions/KHR_texture_transform/scale", specularTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularTexture/extensions/KHR_texture_transform/offset", specularTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularTexture/extensions/KHR_texture_transform/rotation", specularTextureInterpolation.rotation);
const specularColorTextureInterpolation = getTextureTransformTree("reflectanceTexture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularColorTexture/extensions/KHR_texture_transform/scale", specularColorTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_specular/specularColorTexture/extensions/KHR_texture_transform/offset", specularColorTextureInterpolation.offset);
-SetInterpolationForKey(
- "/materials/{}/extensions/KHR_materials_specular/specularColorTexture/extensions/KHR_texture_transform/rotation",
- specularColorTextureInterpolation.rotation
-);
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularColorTexture/extensions/KHR_texture_transform/scale", specularColorTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularColorTexture/extensions/KHR_texture_transform/offset", specularColorTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_specular/specularColorTexture/extensions/KHR_texture_transform/rotation", specularColorTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_transmission/transmissionFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_transmission/transmissionFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "subSurface.refractionIntensity", getFloat, () => 1),
]);
const transmissionTextureInterpolation = getTextureTransformTree("subSurface.refractionIntensityTexture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_transmission/transmissionTexture/extensions/KHR_texture_transform/scale", transmissionTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_transmission/transmissionTexture/extensions/KHR_texture_transform/offset", transmissionTextureInterpolation.offset);
-SetInterpolationForKey(
- "/materials/{}/extensions/KHR_materials_transmission/transmissionTexture/extensions/KHR_texture_transform/rotation",
- transmissionTextureInterpolation.rotation
-);
+AddInterpolation("/materials/{}/extensions/KHR_materials_transmission/transmissionTexture/extensions/KHR_texture_transform/scale", transmissionTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_transmission/transmissionTexture/extensions/KHR_texture_transform/offset", transmissionTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_transmission/transmissionTexture/extensions/KHR_texture_transform/rotation", transmissionTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_volume/attenuationColor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_volume/attenuationColor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "subSurface.tintColor", getColor3, () => 3),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_volume/attenuationDistance", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_volume/attenuationDistance", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "subSurface.tintColorAtDistance", getFloat, () => 1),
]);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_volume/thicknessFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_volume/thicknessFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "subSurface.maximumThickness", getFloat, () => 1),
]);
const thicknessTextureInterpolation = getTextureTransformTree("subSurface.thicknessTexture");
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_volume/thicknessTexture/extensions/KHR_texture_transform/scale", thicknessTextureInterpolation.scale);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_volume/thicknessTexture/extensions/KHR_texture_transform/offset", thicknessTextureInterpolation.offset);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_volume/thicknessTexture/extensions/KHR_texture_transform/rotation", thicknessTextureInterpolation.rotation);
+AddInterpolation("/materials/{}/extensions/KHR_materials_volume/thicknessTexture/extensions/KHR_texture_transform/scale", thicknessTextureInterpolation.scale);
+AddInterpolation("/materials/{}/extensions/KHR_materials_volume/thicknessTexture/extensions/KHR_texture_transform/offset", thicknessTextureInterpolation.offset);
+AddInterpolation("/materials/{}/extensions/KHR_materials_volume/thicknessTexture/extensions/KHR_texture_transform/rotation", thicknessTextureInterpolation.rotation);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "subSurface.translucencyIntensity", getFloat, () => 1),
]);
const diffuseTransmissionTextureInterpolation = getTextureTransformTree("subSurface.translucencyIntensityTexture");
-SetInterpolationForKey(
- "materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionTexture/extensions/KHR_texture_transform/scale",
+AddInterpolation(
+ "/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionTexture/extensions/KHR_texture_transform/scale",
diffuseTransmissionTextureInterpolation.scale
);
-SetInterpolationForKey(
- "materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionTexture/extensions/KHR_texture_transform/offset",
+AddInterpolation(
+ "/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionTexture/extensions/KHR_texture_transform/offset",
diffuseTransmissionTextureInterpolation.offset
);
-SetInterpolationForKey(
- "materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionTexture/extensions/KHR_texture_transform/rotation",
+AddInterpolation(
+ "/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionTexture/extensions/KHR_texture_transform/rotation",
diffuseTransmissionTextureInterpolation.rotation
);
-SetInterpolationForKey("/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorFactor", [
+AddInterpolation("/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorFactor", [
new MaterialAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "subSurface.translucencyColor", getColor3, () => 3),
]);
const diffuseTransmissionColorTextureInterpolation = getTextureTransformTree("subSurface.translucencyColorTexture");
-SetInterpolationForKey(
- "materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture/extensions/KHR_texture_transform/scale",
+AddInterpolation(
+ "/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture/extensions/KHR_texture_transform/scale",
diffuseTransmissionColorTextureInterpolation.scale
);
-SetInterpolationForKey(
- "materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture/extensions/KHR_texture_transform/offset",
+AddInterpolation(
+ "/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture/extensions/KHR_texture_transform/offset",
diffuseTransmissionColorTextureInterpolation.offset
);
-SetInterpolationForKey(
- "materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture/extensions/KHR_texture_transform/rotation",
+AddInterpolation(
+ "/materials/{}/extensions/KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture/extensions/KHR_texture_transform/rotation",
diffuseTransmissionColorTextureInterpolation.rotation
);
-SetInterpolationForKey("/extensions/KHR_lights_punctual/lights/{}/color", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "diffuse", getColor3, () => 3)]);
-SetInterpolationForKey("/extensions/KHR_lights_punctual/lights/{}/intensity", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "intensity", getFloat, () => 1)]);
-SetInterpolationForKey("/extensions/KHR_lights_punctual/lights/{}/range", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "range", getFloat, () => 1)]);
-SetInterpolationForKey("/extensions/KHR_lights_punctual/lights/{}/spot/innerConeAngle", [
+AddInterpolation("/extensions/KHR_lights_punctual/lights/{}/color", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "diffuse", getColor3, () => 3)]);
+AddInterpolation("/extensions/KHR_lights_punctual/lights/{}/intensity", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "intensity", getFloat, () => 1)]);
+AddInterpolation("/extensions/KHR_lights_punctual/lights/{}/range", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "range", getFloat, () => 1)]);
+AddInterpolation("/extensions/KHR_lights_punctual/lights/{}/spot/innerConeAngle", [
new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "innerAngle", getFloatBy2, () => 1),
]);
-SetInterpolationForKey("/extensions/KHR_lights_punctual/lights/{}/spot/outerConeAngle", [
- new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "angle", getFloatBy2, () => 1),
-]);
+AddInterpolation("/extensions/KHR_lights_punctual/lights/{}/spot/outerConeAngle", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "angle", getFloatBy2, () => 1)]);
-SetInterpolationForKey("/nodes/{}/extensions/EXT_lights_ies/color", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "diffuse", getColor3, () => 3)]);
-SetInterpolationForKey("/nodes/{}/extensions/EXT_lights_ies/multiplier", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "intensity", getFloat, () => 1)]);
+AddInterpolation("/nodes/{}/extensions/EXT_lights_ies/color", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "diffuse", getColor3, () => 3)]);
+AddInterpolation("/nodes/{}/extensions/EXT_lights_ies/multiplier", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "intensity", getFloat, () => 1)]);
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.ts
index 730df0b8374..37f0399290d 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.ts
@@ -97,26 +97,29 @@ export class KHR_animation_pointer implements IGLTFLoaderExtension {
throw new Error(`${extensionContext}: Pointer is missing`);
}
+ let obj: { object: any; info: any };
try {
- const obj = this._pathToObjectConverter.convert(pointer);
- if (!obj.info.interpolation) {
- throw new Error(`${extensionContext}/pointer: Interpolation is missing`);
- }
- return this._loader._loadAnimationChannelFromTargetInfoAsync(
- context,
- animationContext,
- animation,
- channel,
- {
- object: obj.object,
- info: obj.info.interpolation,
- },
- onLoad
- );
+ obj = this._pathToObjectConverter.convert(pointer);
} catch (e) {
Logger.Warn(`${extensionContext}/pointer: Invalid pointer (${pointer}) skipped`);
return null;
}
+
+ if (!obj.info.interpolation) {
+ throw new Error(`${extensionContext}/pointer: Interpolation is missing`);
+ }
+
+ return this._loader._loadAnimationChannelFromTargetInfoAsync(
+ context,
+ animationContext,
+ animation,
+ channel,
+ {
+ object: obj.object,
+ info: obj.info.interpolation,
+ },
+ onLoad
+ );
}
}
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_interactivity.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_interactivity.ts
index 308095d9ae6..1b7a2ffadc5 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_interactivity.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_interactivity.ts
@@ -1,17 +1,16 @@
/* eslint-disable @typescript-eslint/naming-convention */
-import type { IKHRInteractivity } from "babylonjs-gltf2interface";
import type { GLTFLoader } from "../glTFLoader";
import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
import { FlowGraphCoordinator } from "core/FlowGraph/flowGraphCoordinator";
import { ParseFlowGraphAsync } from "core/FlowGraph/flowGraphParser";
import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
import type { GLTFPathToObjectConverter } from "./gltfPathToObjectConverter";
-import { AddObjectAccessorToKey, GetPathToObjectConverter } from "./objectModelMapping";
+import { AddObjectAccessor, SetTargetObject, GetPathToObjectConverter } from "./objectModelMapping";
import { InteractivityGraphToFlowGraphParser } from "./KHR_interactivity/interactivityGraphParser";
import { addToBlockFactory } from "core/FlowGraph/Blocks/flowGraphBlockFactory";
import { Quaternion, Vector3 } from "core/Maths/math.vector";
-import type { Scene } from "core/scene";
-import type { IAnimation } from "../glTFLoaderInterfaces";
+import type { IAnimation, IScene, IKHRInteractivity } from "../glTFLoaderInterfaces";
+import type { Nullable } from "core/types";
const NAME = "KHR_interactivity";
@@ -39,144 +38,165 @@ export class KHR_interactivity implements IGLTFLoaderExtension {
*/
public enabled: boolean;
- private _pathConverter?: GLTFPathToObjectConverter;
+ private readonly _pathConverter: GLTFPathToObjectConverter;
+
+ private _loader?: GLTFLoader;
+ private _coordinator?: FlowGraphCoordinator;
/**
* @internal
* @param _loader
*/
- constructor(private _loader: GLTFLoader) {
+ constructor(_loader: GLTFLoader) {
+ this._loader = _loader;
this.enabled = this._loader.isExtensionUsed(NAME);
this._pathConverter = GetPathToObjectConverter(this._loader.gltf);
// avoid starting animations automatically.
_loader._skipStartAnimationStep = true;
- // Update object model with new pointers
-
- const scene = _loader.babylonScene;
- if (scene) {
- _AddInteractivityObjectModel(scene);
+ // Give the interactivity object a reference to the scene.
+ const interactivity = this._loader.gltf.extensions?.KHR_interactivity as IKHRInteractivity;
+ if (interactivity) {
+ interactivity._babylonScene = _loader.babylonScene;
}
}
public dispose() {
- (this._loader as any) = null;
- delete this._pathConverter;
+ delete this._loader;
+ delete this._coordinator;
}
- // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/no-misused-promises
- public async onReady(): Promise {
- if (!this._loader.babylonScene || !this._pathConverter) {
- return;
+ /** @internal */
+ public onReady(): void {
+ if (this._coordinator) {
+ this._coordinator.start();
}
- const scene = this._loader.babylonScene;
- const interactivityDefinition = this._loader.gltf.extensions?.KHR_interactivity as IKHRInteractivity;
- if (!interactivityDefinition) {
- // This can technically throw, but it's not a critical error
- return;
+ }
+
+ /** @internal */
+ // eslint-disable-next-line no-restricted-syntax
+ public loadSceneAsync(context: string, scene: IScene): Nullable> {
+ if (!this._loader) {
+ return null;
}
- const coordinator = new FlowGraphCoordinator({ scene });
- coordinator.dispatchEventsSynchronously = false; // glTF interactivity dispatches events asynchronously
- const graphs = interactivityDefinition.graphs.map((graph) => {
- const parser = new InteractivityGraphToFlowGraphParser(graph, this._loader.gltf, this._loader.parent.targetFps);
- return parser.serializeToFlowGraph();
- });
- // parse each graph async
- await Promise.all(graphs.map(async (graph) => await ParseFlowGraphAsync(graph, { coordinator, pathConverter: this._pathConverter })));
+ return this._loader.loadSceneAsync(context, scene).then(() => {
+ if (!this._loader) {
+ return;
+ }
+
+ const scene = this._loader.babylonScene;
+ const gltf = this._loader.gltf;
+ const targetFps = this._loader.parent.targetFps;
+ const interactivityDefinition = gltf.extensions?.KHR_interactivity as IKHRInteractivity;
+ if (!interactivityDefinition) {
+ // This can technically throw, but it's not a critical error
+ return;
+ }
- coordinator.start();
+ const coordinator = new FlowGraphCoordinator({ scene });
+ coordinator.dispatchEventsSynchronously = false; // glTF interactivity dispatches events asynchronously
+
+ const graphs = interactivityDefinition.graphs.map((graph) => {
+ const parser = new InteractivityGraphToFlowGraphParser(graph, gltf, targetFps);
+ return parser.serializeToFlowGraph();
+ });
+
+ return Promise.all(graphs.map((graph) => ParseFlowGraphAsync(graph, { coordinator, pathConverter: this._pathConverter }))).then(() => {
+ this._coordinator = coordinator;
+ });
+ });
}
}
-/**
- * @internal
- * populates the object model with the interactivity extension
- */
-export function _AddInteractivityObjectModel(scene: Scene) {
- // Note - all of those are read-only, as per the specs!
-
- // active camera rotation
- AddObjectAccessorToKey("/extensions/KHR_interactivity/?/activeCamera/rotation", {
- get: () => {
- if (!scene.activeCamera) {
- return new Quaternion(NaN, NaN, NaN, NaN);
- }
- const quat = Quaternion.FromRotationMatrix(scene.activeCamera.getWorldMatrix()).normalize();
- if (!scene.useRightHandedSystem) {
- quat.w *= -1; // glTF uses right-handed system, while babylon uses left-handed
- quat.x *= -1; // glTF uses right-handed system, while babylon uses left-handed
- }
- return quat;
- },
- type: "Quaternion",
- getTarget: () => scene.activeCamera,
- });
- // activeCamera position
- AddObjectAccessorToKey("/extensions/KHR_interactivity/?/activeCamera/position", {
- get: () => {
- if (!scene.activeCamera) {
- return new Vector3(NaN, NaN, NaN);
- }
- const pos = scene.activeCamera.getWorldMatrix().getTranslation(); // not global position
- if (!scene.useRightHandedSystem) {
- pos.x *= -1; // glTF uses right-handed system, while babylon uses left-handed
- }
- return pos;
- },
- type: "Vector3",
- getTarget: () => scene.activeCamera,
- });
-
- // /animations/{} pointers:
- AddObjectAccessorToKey("/animations/{}/extensions/KHR_interactivity/isPlaying", {
- get: (animation: IAnimation) => {
- return animation._babylonAnimationGroup?.isPlaying ?? false;
- },
- type: "boolean",
- getTarget: (animation: IAnimation) => {
- return animation._babylonAnimationGroup;
- },
- });
- AddObjectAccessorToKey("/animations/{}/extensions/KHR_interactivity/minTime", {
- get: (animation: IAnimation) => {
- return (animation._babylonAnimationGroup?.from ?? 0) / 60; // fixed factor for duration-to-frames conversion
- },
- type: "number",
- getTarget: (animation: IAnimation) => {
- return animation._babylonAnimationGroup;
- },
- });
- AddObjectAccessorToKey("/animations/{}/extensions/KHR_interactivity/maxTime", {
- get: (animation: IAnimation) => {
- return (animation._babylonAnimationGroup?.to ?? 0) / 60; // fixed factor for duration-to-frames conversion
- },
- type: "number",
- getTarget: (animation: IAnimation) => {
- return animation._babylonAnimationGroup;
- },
- });
- // playhead
- AddObjectAccessorToKey("/animations/{}/extensions/KHR_interactivity/playhead", {
- get: (animation: IAnimation) => {
- return (animation._babylonAnimationGroup?.getCurrentFrame() ?? 0) / 60; // fixed factor for duration-to-frames conversion
- },
- type: "number",
- getTarget: (animation: IAnimation) => {
- return animation._babylonAnimationGroup;
- },
- });
- //virtualPlayhead - TODO, do we support this property in our animations? getCurrentFrame is the only method we have for this.
- AddObjectAccessorToKey("/animations/{}/extensions/KHR_interactivity/virtualPlayhead", {
- get: (animation: IAnimation) => {
- return (animation._babylonAnimationGroup?.getCurrentFrame() ?? 0) / 60; // fixed factor for duration-to-frames conversion
- },
- type: "number",
- getTarget: (animation: IAnimation) => {
- return animation._babylonAnimationGroup;
- },
- });
-}
+// Add object accessors to object model.
+// Note - all of those are read-only, as per the specs!
+
+// Add a target object for the extension for access to scene properties
+SetTargetObject("/extensions/KHR_interactivity");
+
+// active camera rotation
+AddObjectAccessor("/extensions/KHR_interactivity/activeCamera/rotation", {
+ get: (interactivity: IKHRInteractivity) => {
+ const scene = interactivity._babylonScene!;
+ if (!scene.activeCamera) {
+ return new Quaternion(NaN, NaN, NaN, NaN);
+ }
+ const quat = Quaternion.FromRotationMatrix(scene.activeCamera.getWorldMatrix()).normalize();
+ if (!scene.useRightHandedSystem) {
+ quat.w *= -1; // glTF uses right-handed system, while babylon uses left-handed
+ quat.x *= -1; // glTF uses right-handed system, while babylon uses left-handed
+ }
+ return quat;
+ },
+ type: "Quaternion",
+ getTarget: (interactivity: IKHRInteractivity) => interactivity._babylonScene!.activeCamera,
+});
+// activeCamera position
+AddObjectAccessor("/extensions/KHR_interactivity/activeCamera/position", {
+ get: (interactivity: IKHRInteractivity) => {
+ const scene = interactivity._babylonScene!;
+ if (!scene.activeCamera) {
+ return new Vector3(NaN, NaN, NaN);
+ }
+ const pos = scene.activeCamera.getWorldMatrix().getTranslation(); // not global position
+ if (!scene.useRightHandedSystem) {
+ pos.x *= -1; // glTF uses right-handed system, while babylon uses left-handed
+ }
+ return pos;
+ },
+ type: "Vector3",
+ getTarget: (interactivity: IKHRInteractivity) => interactivity._babylonScene!.activeCamera,
+});
+
+// /animations/{} pointers:
+AddObjectAccessor("/animations/{}/extensions/KHR_interactivity/isPlaying", {
+ get: (animation: IAnimation) => {
+ return animation._babylonAnimationGroup?.isPlaying ?? false;
+ },
+ type: "boolean",
+ getTarget: (animation: IAnimation) => {
+ return animation._babylonAnimationGroup;
+ },
+});
+AddObjectAccessor("/animations/{}/extensions/KHR_interactivity/minTime", {
+ get: (animation: IAnimation) => {
+ return (animation._babylonAnimationGroup?.from ?? 0) / 60; // fixed factor for duration-to-frames conversion
+ },
+ type: "number",
+ getTarget: (animation: IAnimation) => {
+ return animation._babylonAnimationGroup;
+ },
+});
+AddObjectAccessor("/animations/{}/extensions/KHR_interactivity/maxTime", {
+ get: (animation: IAnimation) => {
+ return (animation._babylonAnimationGroup?.to ?? 0) / 60; // fixed factor for duration-to-frames conversion
+ },
+ type: "number",
+ getTarget: (animation: IAnimation) => {
+ return animation._babylonAnimationGroup;
+ },
+});
+// playhead
+AddObjectAccessor("/animations/{}/extensions/KHR_interactivity/playhead", {
+ get: (animation: IAnimation) => {
+ return (animation._babylonAnimationGroup?.getCurrentFrame() ?? 0) / 60; // fixed factor for duration-to-frames conversion
+ },
+ type: "number",
+ getTarget: (animation: IAnimation) => {
+ return animation._babylonAnimationGroup;
+ },
+});
+// virtualPlayhead - TODO, do we support this property in our animations? getCurrentFrame is the only method we have for this.
+AddObjectAccessor("/animations/{}/extensions/KHR_interactivity/virtualPlayhead", {
+ get: (animation: IAnimation) => {
+ return (animation._babylonAnimationGroup?.getCurrentFrame() ?? 0) / 60; // fixed factor for duration-to-frames conversion
+ },
+ type: "number",
+ getTarget: (animation: IAnimation) => {
+ return animation._babylonAnimationGroup;
+ },
+});
// Register flow graph blocks. Do it here so they are available when the extension is enabled.
addToBlockFactory(NAME, "FlowGraphGLTFDataProvider", async () => {
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_variants.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_variants.ts
index a18f3d9594b..d0a90256bb8 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_variants.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_materials_variants.ts
@@ -249,9 +249,7 @@ export class KHR_materials_variants implements IGLTFLoaderExtension {
}
}
- /**
- * @internal
- */
+ /** @internal */
// eslint-disable-next-line no-restricted-syntax
public _loadMeshPrimitiveAsync(
context: string,
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_hoverability.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_hoverability.ts
index 0e5ef9c3af4..f1fc8ee168d 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_hoverability.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_hoverability.ts
@@ -4,7 +4,7 @@ import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
import { addNewInteractivityFlowGraphMapping } from "./KHR_interactivity/declarationMapper";
import type { INode } from "../glTFLoaderInterfaces";
-import { AddObjectAccessorToKey } from "./objectModelMapping";
+import { AddObjectAccessor } from "./objectModelMapping";
const NAME = "KHR_node_hoverability";
@@ -156,7 +156,7 @@ addNewInteractivityFlowGraphMapping("event/onHoverOut", NAME, {
},
});
-AddObjectAccessorToKey("/nodes/{}/extensions/KHR_node_hoverability/hoverable", {
+AddObjectAccessor("/nodes/{}/extensions/KHR_node_hoverability/hoverable", {
get: (node: INode) => {
const tn = node._babylonTransformNode as any;
if (tn && tn.pointerOverDisableMeshTesting !== undefined) {
@@ -191,16 +191,14 @@ export class KHR_node_hoverability implements IGLTFLoaderExtension {
private _loader: GLTFLoader;
- /**
- * @internal
- */
+ /** @internal */
constructor(loader: GLTFLoader) {
this._loader = loader;
this.enabled = loader.isExtensionUsed(NAME);
}
- // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-misused-promises
- public async onReady(): Promise {
+ /** @internal */
+ public onReady(): void {
this._loader.gltf.nodes?.forEach((node) => {
// default is true, so only apply if false
if (node.extensions?.KHR_node_hoverability && node.extensions?.KHR_node_hoverability.hoverable === false) {
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_selectability.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_selectability.ts
index 80caea0758b..8de6906f4a9 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_selectability.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_selectability.ts
@@ -4,7 +4,7 @@ import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
import { addNewInteractivityFlowGraphMapping } from "./KHR_interactivity/declarationMapper";
import type { INode } from "../glTFLoaderInterfaces";
-import { AddObjectAccessorToKey } from "./objectModelMapping";
+import { AddObjectAccessor } from "./objectModelMapping";
const NAME = "KHR_node_selectability";
@@ -90,7 +90,7 @@ addNewInteractivityFlowGraphMapping("event/onSelect", NAME, {
});
// object model extension for selectable
-AddObjectAccessorToKey("/nodes/{}/extensions/KHR_node_selectability/selectable", {
+AddObjectAccessor("/nodes/{}/extensions/KHR_node_selectability/selectable", {
get: (node: INode) => {
const tn = node._babylonTransformNode as any;
if (tn && tn.isPickable !== undefined) {
@@ -124,16 +124,14 @@ export class KHR_node_selectability implements IGLTFLoaderExtension {
private _loader: GLTFLoader;
- /**
- * @internal
- */
+ /** @internal */
constructor(loader: GLTFLoader) {
this._loader = loader;
this.enabled = loader.isExtensionUsed(NAME);
}
- // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-misused-promises
- public async onReady(): Promise {
+ /** @internal */
+ public onReady(): void {
this._loader.gltf.nodes?.forEach((node) => {
if (node.extensions?.KHR_node_selectability && node.extensions?.KHR_node_selectability.selectable === false) {
node._babylonTransformNode?.getChildMeshes().forEach((mesh) => {
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts
index fc57756d63d..e4823df069d 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts
@@ -3,7 +3,7 @@ import type { GLTFLoader } from "../glTFLoader";
import type { IGLTFLoaderExtension } from "../glTFLoaderExtension";
import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry";
import type { INode } from "../glTFLoaderInterfaces";
-import { AddObjectAccessorToKey } from "./objectModelMapping";
+import { AddObjectAccessor } from "./objectModelMapping";
const NAME = "KHR_node_visibility";
@@ -19,7 +19,7 @@ declare module "../../glTFFileLoader" {
}
// object model extension for visibility
-AddObjectAccessorToKey("/nodes/{}/extensions/KHR_node_visibility/visible", {
+AddObjectAccessor("/nodes/{}/extensions/KHR_node_visibility/visible", {
get: (node: INode) => {
const tn = node._babylonTransformNode as any;
if (tn && tn.isVisible !== undefined) {
@@ -59,16 +59,14 @@ export class KHR_node_visibility implements IGLTFLoaderExtension {
private _loader: GLTFLoader;
- /**
- * @internal
- */
+ /** @internal */
constructor(loader: GLTFLoader) {
this._loader = loader;
this.enabled = loader.isExtensionUsed(NAME);
}
- // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-misused-promises
- public async onReady(): Promise {
+ /** @internal */
+ public onReady(): void {
this._loader.gltf.nodes?.forEach((node) => {
node._primitiveBabylonMeshes?.forEach((mesh) => {
mesh.inheritVisibility = true;
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/gltfPathToObjectConverter.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/gltfPathToObjectConverter.ts
index 7766a216fdb..915be0e2475 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/gltfPathToObjectConverter.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/gltfPathToObjectConverter.ts
@@ -2,20 +2,6 @@ import type { IObjectInfo, IPathToObjectConverter } from "core/ObjectModel/objec
import type { IGLTF } from "../glTFLoaderInterfaces";
import type { IObjectAccessor } from "core/FlowGraph/typeDefinitions";
-/**
- * Adding an exception here will break traversing through the glTF object tree.
- * This is used for properties that might not be in the glTF object model, but are optional and have a default value.
- * For example, the path /nodes/\{\}/extensions/KHR_node_visibility/visible is optional - the object can be deferred without the object fully existing.
- */
-export const OptionalPathExceptionsList: {
- regex: RegExp;
-}[] = [
- {
- // get the node as object when reading an extension
- regex: new RegExp(`^/nodes/\\d+/extensions/`),
- },
-];
-
/**
* A converter that takes a glTF Object Model JSON Pointer
* and transforms it into an ObjectAccessorContainer, allowing
@@ -42,7 +28,7 @@ export class GLTFPathToObjectConverter implements
*
* Examples:
* - "/nodes/0/rotation"
- * - "/nodes.length"
+ * - "/nodes.length"
* - "/materials/2/emissiveFactor"
* - "/materials/2/pbrMetallicRoughness/baseColorFactor"
* - "/materials/2/extensions/KHR_materials_emissive_strength/emissiveStrength"
@@ -61,51 +47,40 @@ export class GLTFPathToObjectConverter implements
const parts = path.split("/");
parts.shift();
- //if the last part has ".length" in it, separate that as an extra part
- if (parts[parts.length - 1].includes(".length")) {
+ // If the last part ends with `.length`, separate that as an extra part
+ if (parts[parts.length - 1].endsWith(".length")) {
const lastPart = parts[parts.length - 1];
const split = lastPart.split(".");
parts.pop();
parts.push(...split);
}
- let ignoreObjectTree = false;
+ let index: number | undefined = undefined;
for (const part of parts) {
- const isLength = part === "length";
- if (isLength && !infoTree.__array__) {
- throw new Error(`Path ${path} is invalid`);
- }
- if (infoTree.__ignoreObjectTree__) {
- ignoreObjectTree = true;
- }
- if (infoTree.__array__ && !isLength) {
- infoTree = infoTree.__array__;
- } else {
+ if (infoTree[part]) {
infoTree = infoTree[part];
- if (!infoTree) {
- throw new Error(`Path ${path} is invalid`);
+ } else if (infoTree["{}"]) {
+ infoTree = infoTree["{}"];
+ if (target) {
+ index = parseInt(part, 10);
}
+ } else {
+ throw new Error(`Path ${path} is invalid`);
}
- if (!ignoreObjectTree) {
- if (objectTree === undefined) {
- // check if the path is in the exception list. If it is, break and return the last object that was found
- const exception = OptionalPathExceptionsList.find((e) => e.regex.test(path));
- if (!exception) {
- throw new Error(`Path ${path} is invalid`);
- }
- } else if (!isLength) {
- objectTree = objectTree?.[part];
- }
+
+ if (!target) {
+ objectTree = objectTree[part];
}
- if (infoTree.__target__ || isLength) {
+ if (infoTree.__target__) {
target = objectTree;
}
}
return {
object: target,
+ index: index,
info: infoTree,
};
}
diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts
index e47b3443384..0b96fa5083a 100644
--- a/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts
+++ b/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts
@@ -25,17 +25,17 @@ export interface IGLTFObjectModelTree {
extensions: IGLTFObjectModelTreeExtensionsObject;
animations: {
length: IObjectAccessor;
- __array__: {};
+ "{}": {};
};
meshes: {
length: IObjectAccessor;
- __array__: {};
+ "{}": {};
};
}
export interface IGLTFObjectModelTreeNodesObject {
length: IObjectAccessor;
- __array__: {
+ "{}": {
__target__: boolean;
translation: IObjectAccessor;
rotation: IObjectAccessor;
@@ -44,7 +44,7 @@ export interface IGLTFObjectModelTreeNodesObject;
weights: {
length: IObjectAccessor;
- __array__: { __target__: boolean } & IObjectAccessor;
+ "{}": IObjectAccessor;
} & IObjectAccessor;
extensions: {
EXT_lights_ies?: {
@@ -56,7 +56,7 @@ export interface IGLTFObjectModelTreeNodesObject;
@@ -74,7 +74,7 @@ export interface IGLTFObjectModelTreeCamerasObject {
}
export interface IGLTFObjectModelTreeMaterialsObject {
- __array__: {
+ "{}": {
__target__: boolean;
pbrMetallicRoughness: {
baseColorFactor: IObjectAccessor;
@@ -240,7 +240,7 @@ export interface IGLTFObjectModelTreeExtensionsObject {
KHR_lights_punctual: {
lights: {
length: IObjectAccessor;
- __array__: {
+ "{}": {
__target__: boolean;
color: IObjectAccessor;
intensity: IObjectAccessor;
@@ -259,7 +259,7 @@ export interface IGLTFObjectModelTreeExtensionsObject {
};
EXT_lights_image_based: {
lights: {
- __array__: {
+ "{}": {
__target__: boolean;
intensity: IObjectAccessor;
rotation: IObjectAccessor;
@@ -276,7 +276,7 @@ const nodesTree: IGLTFObjectModelTreeNodesObject = {
getTarget: (nodes: INode[]) => nodes.map((node) => node._babylonTransformNode!),
getPropertyName: [() => "length"],
},
- __array__: {
+ "{}": {
__target__: true,
translation: {
type: "Vector3",
@@ -304,21 +304,33 @@ const nodesTree: IGLTFObjectModelTreeNodesObject = {
type: "number",
get: (node: INode) => node._numMorphTargets,
getTarget: (node: INode) => node._babylonTransformNode,
- getPropertyName: [() => "influence"],
},
- __array__: {
- __target__: true,
+ "{}": {
type: "number",
- get: (node: INode, index?: number) => (index !== undefined ? node._primitiveBabylonMeshes?.[0].morphTargetManager?.getTarget(index).influence : undefined),
- // set: (value: number, node: INode, index?: number) => node._babylonTransformNode?.getMorphTargetManager()?.getTarget(index)?.setInfluence(value),
+ get: (node: INode, arrayIndex?: number) => node._primitiveBabylonMeshes![0].morphTargetManager!.getTarget(arrayIndex!).influence,
+ set: (value: number, node: INode, arrayIndex?: number) => {
+ for (const primitive of node._primitiveBabylonMeshes!) {
+ const target = primitive.morphTargetManager!.getTarget(arrayIndex!);
+ if (target) {
+ target.influence = value;
+ }
+ }
+ },
getTarget: (node: INode) => node._babylonTransformNode,
- getPropertyName: [() => "influence"],
},
type: "number[]",
- get: (node: INode, index?: number) => [0], // TODO: get the weights correctly
- // set: (value: number, node: INode, index?: number) => node._babylonTransformNode?.getMorphTargetManager()?.getTarget(index)?.setInfluence(value),
+ get: (node: INode) => Array.from({ length: node._numMorphTargets! }, (_, index) => node._primitiveBabylonMeshes![0].morphTargetManager!.getTarget(index).influence!),
+ set: (value: number[], node: INode) => {
+ for (const primitive of node._primitiveBabylonMeshes!) {
+ for (let i = 0; i < value.length; i++) {
+ const target = primitive.morphTargetManager!.getTarget(i);
+ if (target) {
+ target.influence = value[i];
+ }
+ }
+ }
+ },
getTarget: (node: INode) => node._babylonTransformNode,
- getPropertyName: [() => "influence"],
},
// readonly!
matrix: {
@@ -397,7 +409,7 @@ const animationsTree = {
getTarget: (animations: IAnimation[]) => animations.map((animation) => animation._babylonAnimationGroup!),
getPropertyName: [() => "length"],
},
- __array__: {},
+ "{}": {},
};
const meshesTree = {
@@ -407,11 +419,11 @@ const meshesTree = {
getTarget: (meshes: IMesh[]) => meshes.map((mesh) => mesh.primitives[0]._instanceData?.babylonSourceMesh),
getPropertyName: [() => "length"],
},
- __array__: {},
+ "{}": {},
};
const camerasTree: IGLTFObjectModelTreeCamerasObject = {
- __array__: {
+ "{}": {
__target__: true,
orthographic: {
xmag: {
@@ -509,7 +521,7 @@ const camerasTree: IGLTFObjectModelTreeCamerasObject = {
};
const materialsTree: IGLTFObjectModelTreeMaterialsObject = {
- __array__: {
+ "{}": {
__target__: true,
emissiveFactor: {
type: "Color3",
@@ -861,7 +873,7 @@ const extensionsTree: IGLTFObjectModelTreeExtensionsObject = {
getTarget: (lights: IKHRLightsPunctual_Light[]) => lights.map((light) => light._babylonLight!),
getPropertyName: [(_lights: IKHRLightsPunctual_Light[]) => "length"],
},
- __array__: {
+ "{}": {
__target__: true,
color: {
type: "Color3",
@@ -921,7 +933,7 @@ const extensionsTree: IGLTFObjectModelTreeExtensionsObject = {
getTarget: (lights) => lights.map((light) => light._babylonTexture!),
getPropertyName: [(_lights) => "length"],
},
- __array__: {
+ "{}": {
__target__: true,
intensity: {
type: "number",
@@ -1018,6 +1030,40 @@ const objectModelMapping: IGLTFObjectModelTree = {
meshes: meshesTree,
};
+function GetMapping(path: string): any {
+ if (!path.startsWith("/")) {
+ throw new Error(`Path "${path}" must start with a slash (/)`);
+ }
+
+ const parts = path.split("/");
+ let current = objectModelMapping as any;
+ for (let index = 1; index < parts.length; index++) {
+ current = current[parts[index]];
+ }
+
+ return current;
+}
+
+function EnsureMapping(path: string): any {
+ if (!path.startsWith("/")) {
+ throw new Error(`Path "${path}" must start with a slash (/)`);
+ }
+
+ const keyParts = path.split("/");
+ let current = objectModelMapping as any;
+ for (let index = 1; index < keyParts.length; index++) {
+ const key = keyParts[index];
+ current[key] ||= {};
+ current = current[key];
+ }
+
+ return current;
+}
+
+function IsObjectAccessor(current: any): current is IObjectAccessor {
+ return current && current.type && current.get;
+}
+
/**
* get a path-to-object converter for the given glTF tree
* @param gltf the glTF tree to use
@@ -1028,81 +1074,53 @@ export function GetPathToObjectConverter(gltf: IGLTF) {
}
/**
- * This function will return the object accessor for the given key in the object model
- * If the key is not found, it will return undefined
- * @param key the key to get the mapping for, for example /materials/\{\}/emissiveFactor
+ * This function will return the object accessor for the given path in the object model
+ * @param path the path for the object accessor
* @returns an object accessor for the given key, or undefined if the key is not found
*/
-export function GetMappingForKey(key: string): IObjectAccessor | undefined {
- // replace every `{}` in key with __array__ to match the object model
- const keyParts = key.split("/").map((part) => part.replace(/{}/g, "__array__"));
- let current = objectModelMapping as any;
- for (const part of keyParts) {
- // make sure part is not empty
- if (!part) {
- continue;
- }
- current = current[part];
- }
- // validate that current is an object accessor
- if (current && current.type && current.get) {
- return current;
- }
- return undefined;
+export function GetObjectAccessor(path: string): IObjectAccessor | undefined {
+ const current = GetMapping(path);
+ return IsObjectAccessor(current) ? current : undefined;
}
/**
- * Set interpolation for a specific key in the object model
- * @param key the key to set, for example /materials/\{\}/emissiveFactor
- * @param interpolation the interpolation elements array
+ * This will set a new target object in the object model at the given path.
+ * @param path the path to set as the target object.
*/
-export function SetInterpolationForKey(key: string, interpolation?: IInterpolationPropertyInfo[]): void {
- // replace every `{}` in key with __array__ to match the object model
- const keyParts = key.split("/").map((part) => part.replace(/{}/g, "__array__"));
- let current = objectModelMapping as any;
- for (const part of keyParts) {
- // make sure part is not empty
- if (!part) {
- continue;
- }
- current = current[part];
- }
- // validate that the current object is an object accessor
- if (current && current.type && current.get) {
- (current as IObjectAccessor).interpolation = interpolation;
- }
+export function SetTargetObject(path: string): void {
+ const current = EnsureMapping(path);
+ current.__target__ = true;
}
/**
- * This will ad a new object accessor in the object model at the given key.
- * Note that this will NOT change the typescript types. To do that you will need to change the interface itself (extending it in the module that uses it)
- * @param key the key to add the object accessor at. For example /cameras/\{\}/perspective/aspectRatio
+ * This will set a new object accessor in the object model at the given path.
+ * @param path the path for the object accessor
* @param accessor the object accessor to add
*/
-export function AddObjectAccessorToKey(
- key: string,
- accessor: IObjectAccessor
-): void {
- // replace every `{}` in key with __array__ to match the object model
- const keyParts = key.split("/").map((part) => part.replace(/{}/g, "__array__"));
- let current = objectModelMapping as any;
- for (const part of keyParts) {
- // make sure part is not empty
- if (!part) {
- continue;
- }
- if (!current[part]) {
- if (part === "?") {
- current.__ignoreObjectTree__ = true;
- continue;
- }
- current[part] = {};
- // if the part is __array__ then add the __target__ property
- if (part === "__array__") {
- current[part].__target__ = true;
- }
- }
- current = current[part];
+export function AddObjectAccessor(path: string, accessor: IObjectAccessor): void {
+ const current = EnsureMapping(path);
+ if (IsObjectAccessor(current)) {
+ throw new Error(`Path "${path}" already points to a valid object accessor.`);
}
Object.assign(current, accessor);
}
+
+/**
+ * Set the interpolation for a object accessor in the object model
+ * @param path the object accessor path for the interpolation
+ * @param interpolation the interpolation elements array
+ */
+export function AddInterpolation(path: string, interpolation: IInterpolationPropertyInfo[]): void {
+ const current = EnsureMapping(path);
+
+ // TODO: don't throw for now because we don't have object accessors for all the extensions yet
+ // if (!IsObjectAccessor(current)) {
+ // throw new Error(`Path "${path}" does not point to a valid object accessor.`);
+ // }
+
+ if (current.interpolation) {
+ throw new Error(`Path "${path}" already has an interpolation defined.`);
+ }
+
+ current.interpolation = interpolation;
+}
diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts
index b199e919678..593656d08e7 100644
--- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts
+++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts
@@ -80,7 +80,7 @@ import type { IObjectInfo } from "core/ObjectModel/objectModelInterfaces";
import { registeredGLTFExtensions, registerGLTFExtension, unregisterGLTFExtension } from "./glTFLoaderExtensionRegistry";
import type { GLTFExtensionFactory } from "./glTFLoaderExtensionRegistry";
import type { IInterpolationPropertyInfo } from "core/FlowGraph/typeDefinitions";
-import { GetMappingForKey } from "./Extensions/objectModelMapping";
+import { GetObjectAccessor } from "./Extensions/objectModelMapping";
import { deepMerge } from "core/Misc/deepMerger";
import { GetTypedArrayConstructor } from "core/Buffers/bufferUtils";
@@ -1724,19 +1724,19 @@ export class GLTFLoader implements IGLTFLoader {
let properties: IInterpolationPropertyInfo[];
switch (channelTargetPath) {
case AnimationChannelTargetPath.TRANSLATION: {
- properties = GetMappingForKey("/nodes/{}/translation")?.interpolation!;
+ properties = GetObjectAccessor("/nodes/{}/translation")?.interpolation!;
break;
}
case AnimationChannelTargetPath.ROTATION: {
- properties = GetMappingForKey("/nodes/{}/rotation")?.interpolation!;
+ properties = GetObjectAccessor("/nodes/{}/rotation")?.interpolation!;
break;
}
case AnimationChannelTargetPath.SCALE: {
- properties = GetMappingForKey("/nodes/{}/scale")?.interpolation!;
+ properties = GetObjectAccessor("/nodes/{}/scale")?.interpolation!;
break;
}
case AnimationChannelTargetPath.WEIGHTS: {
- properties = GetMappingForKey("/nodes/{}/weights")?.interpolation!;
+ properties = GetObjectAccessor("/nodes/{}/weights")?.interpolation!;
break;
}
default: {
diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoaderAnimation.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoaderAnimation.ts
index a9bc6e02e5c..a32d5fc556a 100644
--- a/packages/dev/loaders/src/glTF/2.0/glTFLoaderAnimation.ts
+++ b/packages/dev/loaders/src/glTF/2.0/glTFLoaderAnimation.ts
@@ -2,7 +2,7 @@ import { Animation } from "core/Animations/animation";
import { Quaternion, Vector3 } from "core/Maths/math.vector";
import type { INode } from "./glTFLoaderInterfaces";
import type { IAnimatable } from "core/Animations/animatable.interface";
-import { SetInterpolationForKey } from "./Extensions/objectModelMapping";
+import { AddInterpolation } from "./Extensions/objectModelMapping";
/** @internal */
export type GetValueFn = (target: any, source: Float32Array, offset: number, scale: number) => any;
@@ -93,7 +93,7 @@ export class WeightAnimationPropertyInfo extends AnimationPropertyInfo {
}
}
-SetInterpolationForKey("/nodes/{}/translation", [new TransformNodeAnimationPropertyInfo(Animation.ANIMATIONTYPE_VECTOR3, "position", getVector3, () => 3)]);
-SetInterpolationForKey("/nodes/{}/rotation", [new TransformNodeAnimationPropertyInfo(Animation.ANIMATIONTYPE_QUATERNION, "rotationQuaternion", getQuaternion, () => 4)]);
-SetInterpolationForKey("/nodes/{}/scale", [new TransformNodeAnimationPropertyInfo(Animation.ANIMATIONTYPE_VECTOR3, "scaling", getVector3, () => 3)]);
-SetInterpolationForKey("/nodes/{}/weights", [new WeightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "influence", getWeights, (target) => target._numMorphTargets!)]);
+AddInterpolation("/nodes/{}/translation", [new TransformNodeAnimationPropertyInfo(Animation.ANIMATIONTYPE_VECTOR3, "position", getVector3, () => 3)]);
+AddInterpolation("/nodes/{}/rotation", [new TransformNodeAnimationPropertyInfo(Animation.ANIMATIONTYPE_QUATERNION, "rotationQuaternion", getQuaternion, () => 4)]);
+AddInterpolation("/nodes/{}/scale", [new TransformNodeAnimationPropertyInfo(Animation.ANIMATIONTYPE_VECTOR3, "scaling", getVector3, () => 3)]);
+AddInterpolation("/nodes/{}/weights", [new WeightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "influence", getWeights, (target) => target._numMorphTargets!)]);
diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoaderInterfaces.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoaderInterfaces.ts
index d120662d5dd..7e85d864145 100644
--- a/packages/dev/loaders/src/glTF/2.0/glTFLoaderInterfaces.ts
+++ b/packages/dev/loaders/src/glTF/2.0/glTFLoaderInterfaces.ts
@@ -7,6 +7,7 @@ import type { AbstractMesh } from "core/Meshes/abstractMesh";
import type { Mesh } from "core/Meshes/mesh";
import type { Camera } from "core/Cameras/camera";
import type { Light } from "core/Lights/light";
+import type { Scene } from "core/scene";
import type * as GLTF2 from "babylonjs-gltf2interface";
@@ -312,3 +313,9 @@ export interface IEXTLightsIES_Light extends GLTF2.IEXTLightsIES_Light, IArrayIt
/** @hidden */
_babylonLight?: Light;
}
+
+/** @internal */
+export interface IKHRInteractivity extends GLTF2.IKHRInteractivity {
+ /** @hidden */
+ _babylonScene?: Scene;
+}
diff --git a/packages/dev/loaders/test/unit/Interactivity/objectModel.test.ts b/packages/dev/loaders/test/unit/Interactivity/objectModel.test.ts
index aa591176698..75339380c82 100644
--- a/packages/dev/loaders/test/unit/Interactivity/objectModel.test.ts
+++ b/packages/dev/loaders/test/unit/Interactivity/objectModel.test.ts
@@ -8,7 +8,7 @@ import { ParseFlowGraphAsync } from "core/FlowGraph";
import { InteractivityGraphToFlowGraphParser } from "loaders/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser";
import "loaders/glTF/2.0/glTFLoaderAnimation";
import "loaders/glTF/2.0/Extensions/KHR_animation_pointer.data";
-import { _AddInteractivityObjectModel } from "loaders/glTF/2.0/Extensions/KHR_interactivity";
+import "loaders/glTF/2.0/Extensions/KHR_interactivity";
import { GetPathToObjectConverter } from "loaders/glTF/2.0/Extensions/objectModelMapping";
import { IKHRInteractivity_Declaration, IKHRInteractivity_Graph, IKHRInteractivity_Node, IKHRInteractivity_Type, IKHRInteractivity_Variable } from "babylonjs-gltf2interface";
import { Mesh } from "core/Meshes/mesh";
@@ -72,7 +72,6 @@ describe("glTF interactivity Object Model", () => {
new ArcRotateCamera("", Math.PI / 2, Math.PI / 2, 4, new Vector3(0, 0, 0));
log.mockClear();
errorLog.mockClear();
- _AddInteractivityObjectModel(scene);
renderInterval = setInterval(() => scene?.render(), 16);
});
@@ -169,7 +168,9 @@ describe("glTF interactivity Object Model", () => {
await generateSimpleNodeGraph(
{
extensions: {
- KHR_interactivity: {},
+ KHR_interactivity: {
+ _babylonScene: scene,
+ },
},
},
[{ op: "pointer/get" }, { op: "flow/log", extension: "BABYLON" }],
@@ -206,7 +207,9 @@ describe("glTF interactivity Object Model", () => {
await generateSimpleNodeGraph(
{
extensions: {
- KHR_interactivity: {},
+ KHR_interactivity: {
+ _babylonScene: scene,
+ },
},
},
[{ op: "pointer/get" }, { op: "flow/log", extension: "BABYLON" }],
diff --git a/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts b/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts
index 6578b6e423b..11b00761207 100644
--- a/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts
+++ b/packages/public/glTF2Interface/babylon.glTF2Interface.d.ts
@@ -691,7 +691,7 @@ declare module BABYLON.GLTF2 {
*/
mode?: MeshPrimitiveMode;
/**
- * An array of Morph Targets, each Morph Target is a dictionary mapping attributes (only POSITION, NORMAL, and TANGENT supported) to their deviations in the Morph Target
+ * An array of morph targets, each morph target is a dictionary mapping attributes (only POSITION, NORMAL, and TANGENT supported) to their deviations in the morph target
*/
targets?: {
[name: string]: number;
diff --git a/packages/tools/sandbox/src/sandbox.tsx b/packages/tools/sandbox/src/sandbox.tsx
index d39f4591015..7fc149353dc 100644
--- a/packages/tools/sandbox/src/sandbox.tsx
+++ b/packages/tools/sandbox/src/sandbox.tsx
@@ -93,7 +93,7 @@ export class Sandbox extends React.Component<
this._globalState.showDebugLayer();
}
- this.setState({ errorMessage: error.message ? `${error.message} Check the developer console.` : "Unable to load scene. Check the developer console." });
+ this.setState({ errorMessage: error.message ? error.message : "Unable to load scene. Check the developer console." });
this._engine && this._engine.hideLoadingUI();