Skip to content

Commit 5b9baaf

Browse files
authored
Merge pull request #10479 from CesiumGS/model-experimental-articulations
Add support for `AGI_articulations` to `ModelExperimental`
2 parents 2dc38a2 + 3370a94 commit 5b9baaf

15 files changed

+1734
-21
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Added `modelUpAxis` and `modelForwardAxis` constructor options to `Cesium3DTileset` [#10439](https://github.com/CesiumGS/cesium/pull/10439)
1616
- Added `heightReference` to `ModelExperimental`. [#10448](https://github.com/CesiumGS/cesium/pull/10448)
1717
- Added `silhouetteSize` and `silhouetteColor` to `ModelExperimental`. [#10457](https://github.com/CesiumGS/cesium/pull/10457)
18+
- Added support for `AGI_articulations` to `ModelExperimental`. [#10479](https://github.com/CesiumGS/cesium/pull/10479)
1819

1920
##### Fixes :wrench:
2021

Source/Core/ArticulationStageType.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* An enum describing the type of motion that is defined by an articulation stage
3+
* in the AGI_articulations extension.
4+
*
5+
* @alias {ArticulationStageType}
6+
* @enum {String}
7+
*
8+
* @private
9+
*/
10+
const ArticulationStageType = {
11+
XTRANSLATE: "xTranslate",
12+
YTRANSLATE: "yTranslate",
13+
ZTRANSLATE: "zTranslate",
14+
XROTATE: "xRotate",
15+
YROTATE: "yRotate",
16+
ZROTATE: "zRotate",
17+
XSCALE: "xScale",
18+
YSCALE: "yScale",
19+
ZSCALE: "zScale",
20+
UNIFORMSCALE: "uniformScale",
21+
};
22+
23+
export default Object.freeze(ArticulationStageType);

Source/Scene/GltfLoader.js

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
import arrayFill from "../Core/arrayFill.js";
2+
import ArticulationStageType from "../Core/ArticulationStageType.js";
3+
import AttributeType from "./AttributeType.js";
4+
import Axis from "./Axis.js";
25
import Cartesian3 from "../Core/Cartesian3.js";
36
import Cartesian4 from "../Core/Cartesian4.js";
47
import Check from "../Core/Check.js";
58
import ComponentDatatype from "../Core/ComponentDatatype.js";
69
import Credit from "../Core/Credit.js";
710
import defaultValue from "../Core/defaultValue.js";
811
import defined from "../Core/defined.js";
9-
import InterpolationType from "../Core/InterpolationType.js";
1012
import FeatureDetection from "../Core/FeatureDetection.js";
11-
import Matrix4 from "../Core/Matrix4.js";
12-
import Quaternion from "../Core/Quaternion.js";
13-
import Sampler from "../Renderer/Sampler.js";
1413
import getAccessorByteStride from "./GltfPipeline/getAccessorByteStride.js";
1514
import getComponentReader from "./GltfPipeline/getComponentReader.js";
16-
import numberOfComponentsForType from "./GltfPipeline/numberOfComponentsForType.js";
17-
import AttributeType from "./AttributeType.js";
18-
import Axis from "./Axis.js";
19-
import GltfStructuralMetadataLoader from "./GltfStructuralMetadataLoader.js";
2015
import GltfLoaderUtil from "./GltfLoaderUtil.js";
16+
import GltfStructuralMetadataLoader from "./GltfStructuralMetadataLoader.js";
2117
import InstanceAttributeSemantic from "./InstanceAttributeSemantic.js";
18+
import InterpolationType from "../Core/InterpolationType.js";
19+
import Matrix4 from "../Core/Matrix4.js";
2220
import ModelComponents from "./ModelComponents.js";
21+
import numberOfComponentsForType from "./GltfPipeline/numberOfComponentsForType.js";
22+
import Quaternion from "../Core/Quaternion.js";
2323
import ResourceCache from "./ResourceCache.js";
2424
import ResourceLoader from "./ResourceLoader.js";
25+
import Sampler from "../Renderer/Sampler.js";
2526
import SupportedImageFormats from "./SupportedImageFormats.js";
2627
import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
2728

@@ -40,6 +41,8 @@ const AnimationSampler = ModelComponents.AnimationSampler;
4041
const AnimationTarget = ModelComponents.AnimationTarget;
4142
const AnimationChannel = ModelComponents.AnimationChannel;
4243
const Animation = ModelComponents.Animation;
44+
const ArticulationStage = ModelComponents.ArticulationStage;
45+
const Articulation = ModelComponents.Articulation;
4346
const Asset = ModelComponents.Asset;
4447
const Scene = ModelComponents.Scene;
4548
const Components = ModelComponents.Components;
@@ -1570,11 +1573,16 @@ function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) {
15701573
defaultValue.EMPTY_OBJECT
15711574
);
15721575
const instancingExtension = nodeExtensions.EXT_mesh_gpu_instancing;
1576+
const articulationsExtension = nodeExtensions.AGI_articulations;
15731577

15741578
if (defined(instancingExtension)) {
15751579
node.instances = loadInstances(loader, gltf, nodeExtensions, frameState);
15761580
}
15771581

1582+
if (defined(articulationsExtension)) {
1583+
node.articulationName = articulationsExtension.articulationName;
1584+
}
1585+
15781586
const meshId = gltfNode.mesh;
15791587
if (defined(meshId)) {
15801588
const mesh = gltf.meshes[meshId];
@@ -1813,6 +1821,61 @@ function loadAnimations(loader, gltf, nodes) {
18131821
return animations;
18141822
}
18151823

1824+
function loadArticulationStage(gltfStage) {
1825+
const stage = new ArticulationStage();
1826+
stage.name = gltfStage.name;
1827+
1828+
const type = gltfStage.type.toUpperCase();
1829+
stage.type = ArticulationStageType[type];
1830+
1831+
stage.minimumValue = gltfStage.minimumValue;
1832+
stage.maximumValue = gltfStage.maximumValue;
1833+
stage.initialValue = gltfStage.initialValue;
1834+
1835+
return stage;
1836+
}
1837+
1838+
function loadArticulation(gltfArticulation) {
1839+
const articulation = new Articulation();
1840+
articulation.name = gltfArticulation.name;
1841+
1842+
const gltfStages = gltfArticulation.stages;
1843+
const gltfStagesLength = gltfStages.length;
1844+
1845+
const stages = new Array(gltfStagesLength);
1846+
for (let i = 0; i < gltfStagesLength; i++) {
1847+
const stage = loadArticulationStage(gltfStages[i]);
1848+
stages[i] = stage;
1849+
}
1850+
1851+
articulation.stages = stages;
1852+
1853+
return articulation;
1854+
}
1855+
1856+
function loadArticulations(gltf) {
1857+
const extensions = defaultValue(gltf.extensions, defaultValue.EMPTY_OBJECT);
1858+
const articulationsExtension = extensions.AGI_articulations;
1859+
1860+
if (!defined(articulationsExtension)) {
1861+
return [];
1862+
}
1863+
1864+
const gltfArticulations = articulationsExtension.articulations;
1865+
if (!defined(gltfArticulations)) {
1866+
return [];
1867+
}
1868+
1869+
const gltfArticulationsLength = gltfArticulations.length;
1870+
const articulations = new Array(gltfArticulationsLength);
1871+
for (let i = 0; i < gltfArticulationsLength; i++) {
1872+
const articulation = loadArticulation(gltfArticulations[i]);
1873+
articulations[i] = articulation;
1874+
}
1875+
1876+
return articulations;
1877+
}
1878+
18161879
function getSceneNodeIds(gltf) {
18171880
let nodesIds;
18181881
if (defined(gltf.scenes) && defined(gltf.scene)) {
@@ -1864,6 +1927,7 @@ function parse(
18641927
const nodes = loadNodes(loader, gltf, supportedImageFormats, frameState);
18651928
const skins = loadSkins(loader, gltf, nodes);
18661929
const animations = loadAnimations(loader, gltf, nodes);
1930+
const articulations = loadArticulations(gltf);
18671931
const scene = loadScene(gltf, nodes);
18681932

18691933
const components = new Components();
@@ -1881,6 +1945,7 @@ function parse(
18811945
components.nodes = nodes;
18821946
components.skins = skins;
18831947
components.animations = animations;
1948+
components.articulations = articulations;
18841949
components.upAxis = loader._upAxis;
18851950
components.forwardAxis = loader._forwardAxis;
18861951

Source/Scene/ModelComponents.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,15 @@ function Node() {
794794
* @private
795795
*/
796796
this.morphWeights = [];
797+
798+
/**
799+
* The name of the articulation affecting this node, as defined by the
800+
* AGI_articulations extension.
801+
*
802+
* @type {String}
803+
* @private
804+
*/
805+
this.articulationName = undefined;
797806
}
798807

799808
/**
@@ -951,6 +960,84 @@ function Animation() {
951960
this.channels = [];
952961
}
953962

963+
/**
964+
* An articulation stage belonging to an articulation from the
965+
* AGI_articulations extension.
966+
*
967+
* @alias {ModelComponents.ArticulationStage}
968+
* @constructor
969+
*
970+
* @private
971+
*/
972+
function ArticulationStage() {
973+
/**
974+
* The name of the articulation stage.
975+
*
976+
* @type {String}
977+
* @private
978+
*/
979+
this.name = undefined;
980+
981+
/**
982+
* The type of the articulation stage, defined by the type of motion it modifies.
983+
*
984+
* @type {ArticulationStageType}
985+
* @private
986+
*/
987+
this.type = undefined;
988+
989+
/**
990+
* The minimum value for the range of motion of this articulation stage.
991+
*
992+
* @type {Number}
993+
* @private
994+
*/
995+
this.minimumValue = undefined;
996+
997+
/**
998+
* The maximum value for the range of motion of this articulation stage.
999+
*
1000+
* @type {Number}
1001+
* @private
1002+
*/
1003+
this.maximumValue = undefined;
1004+
1005+
/**
1006+
* The initial value for this articulation stage.
1007+
*
1008+
* @type {Number}
1009+
* @private
1010+
*/
1011+
this.initialValue = undefined;
1012+
}
1013+
1014+
/**
1015+
* An articulation for the model, as defined by the AGI_articulations extension.
1016+
*
1017+
* @alias {ModelComponents.Articulation}
1018+
* @constructor
1019+
*
1020+
* @private
1021+
*/
1022+
function Articulation() {
1023+
/**
1024+
* The name of the articulation.
1025+
*
1026+
* @type {String}
1027+
* @private
1028+
*/
1029+
this.name = undefined;
1030+
1031+
/**
1032+
* The stages belonging to this articulation. The stages are applied to
1033+
* the model in order of appearance.
1034+
*
1035+
* @type {ModelComponents.ArticulationStage[]}
1036+
* @private
1037+
*/
1038+
this.stages = [];
1039+
}
1040+
9541041
/**
9551042
* The asset of the model.
9561043
*
@@ -1015,6 +1102,13 @@ function Components() {
10151102
*/
10161103
this.animations = [];
10171104

1105+
/**
1106+
* All articulations in the model as defined by the AGI_articulations extension.
1107+
*
1108+
* @type {ModelComponents.Articulation[]}
1109+
*/
1110+
this.articulations = [];
1111+
10181112
/**
10191113
* Structural metadata containing the schema, property tables, property
10201114
* textures and property mappings
@@ -1360,6 +1454,8 @@ ModelComponents.AnimationSampler = AnimationSampler;
13601454
ModelComponents.AnimationTarget = AnimationTarget;
13611455
ModelComponents.AnimationChannel = AnimationChannel;
13621456
ModelComponents.Animation = Animation;
1457+
ModelComponents.ArticulationStage = ArticulationStage;
1458+
ModelComponents.Articulation = Articulation;
13631459
ModelComponents.Asset = Asset;
13641460
ModelComponents.Components = Components;
13651461
ModelComponents.TextureReader = TextureReader;

Source/Scene/ModelExperimental/ModelExperimental.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,57 @@ Object.defineProperties(ModelExperimental.prototype, {
12941294
},
12951295
});
12961296

1297+
/**
1298+
* Sets the current value of an articulation stage. After setting one or
1299+
* multiple stage values, call ModelExperimental.applyArticulations() to
1300+
* cause the node matrices to be recalculated.
1301+
*
1302+
* @param {String} articulationStageKey The name of the articulation, a space, and the name of the stage.
1303+
* @param {Number} value The numeric value of this stage of the articulation.
1304+
*
1305+
* @exception {DeveloperError} The model is not loaded. Use ModelExperimental.readyPromise or wait for ModelExperimental.ready to be true.
1306+
*
1307+
* @see ModelExperimental#applyArticulations
1308+
*
1309+
* @example
1310+
* // Sets the value of the stage named "MoveX" belonging to the articulation named "SampleArticulation"
1311+
* model.setArticulationStage("SampleArticulation MoveX", 50.0);
1312+
*/
1313+
ModelExperimental.prototype.setArticulationStage = function (
1314+
articulationStageKey,
1315+
value
1316+
) {
1317+
//>>includeStart('debug', pragmas.debug);
1318+
Check.typeOf.number("value", value);
1319+
if (!this._ready) {
1320+
throw new DeveloperError(
1321+
"The model is not loaded. Use ModelExperimental.readyPromise or wait for ModelExperimental.ready to be true."
1322+
);
1323+
}
1324+
//>>includeEnd('debug');
1325+
1326+
this._sceneGraph.setArticulationStage(articulationStageKey, value);
1327+
};
1328+
1329+
/**
1330+
* Applies any modified articulation stages to the matrix of each node that
1331+
* participates in any articulation. Note that this will overwrite any node
1332+
* transformations on participating nodes.
1333+
*
1334+
* @exception {DeveloperError} The model is not loaded. Use ModelExperimental.readyPromise or wait for ModelExperimental.ready to be true.
1335+
*/
1336+
ModelExperimental.prototype.applyArticulations = function () {
1337+
//>>includeStart('debug', pragmas.debug);
1338+
if (!this._ready) {
1339+
throw new DeveloperError(
1340+
"The model is not loaded. Use ModelExperimental.readyPromise or wait for ModelExperimental.ready to be true."
1341+
);
1342+
}
1343+
//>>includeEnd('debug');
1344+
1345+
this._sceneGraph.applyArticulations();
1346+
};
1347+
12971348
/**
12981349
* Resets the draw commands for this model.
12991350
*

0 commit comments

Comments
 (0)