import BoundingSphere from "../../Core/BoundingSphere.js";
|
import Cartesian3 from "../../Core/Cartesian3.js";
|
import defined from "../../Core/defined.js";
|
import Matrix4 from "../../Core/Matrix4.js";
|
import Quaternion from "../../Core/Quaternion.js";
|
import RuntimeError from "../../Core/RuntimeError.js";
|
import Axis from "../Axis.js";
|
import AttributeType from "../AttributeType.js";
|
import VertexAttributeSemantic from "../VertexAttributeSemantic.js";
|
|
/**
|
* Utility functions for {@link ModelExperimental}.
|
*
|
* @private
|
*/
|
export default function ModelExperimentalUtility() {}
|
|
/**
|
* Create a function for reporting when a model fails to load
|
*
|
* @param {ModelExperimental} model The model to report about
|
* @param {String} type The type of object to report about
|
* @param {String} path The URI of the model file
|
* @return {Function} An error function that throws an error for the failed model
|
*
|
* @private
|
*/
|
ModelExperimentalUtility.getFailedLoadFunction = function (model, type, path) {
|
return function (error) {
|
var message = "Failed to load " + type + ": " + path;
|
if (defined(error)) {
|
message += "\n" + error.message;
|
}
|
model._readyPromise.reject(new RuntimeError(message));
|
};
|
};
|
|
/**
|
* Get a transformation matrix from a node in the model.
|
*
|
* @param {ModelComponents.Node} node The node components
|
* @return {Matrix4} The computed transformation matrix. If no transformation matrix or parameters are specified, this will be the identity matrix.
|
*
|
* @private
|
*/
|
ModelExperimentalUtility.getNodeTransform = function (node) {
|
if (defined(node.matrix)) {
|
return node.matrix;
|
}
|
|
return Matrix4.fromTranslationQuaternionRotationScale(
|
defined(node.translation) ? node.translation : Cartesian3.ZERO,
|
defined(node.rotation) ? node.rotation : Quaternion.IDENTITY,
|
defined(node.scale) ? node.scale : Cartesian3.ONE
|
);
|
};
|
|
/**
|
* Find an attribute by semantic such as POSITION or TANGENT.
|
*
|
* @param {ModelComponents.Primitive|ModelComponents.Instances} object The primitive components or instances object
|
* @param {VertexAttributeSemantic|InstanceAttributeSemantic} semantic The semantic to search for
|
* @param {Number} setIndex The set index of the semantic. May be undefined for some semantics (POSITION, NORMAL, TRANSLATION, ROTATION, for example)
|
* @return {ModelComponents.Attribute} The selected attribute, or undefined if not found.
|
*
|
* @private
|
*/
|
ModelExperimentalUtility.getAttributeBySemantic = function (
|
object,
|
semantic,
|
setIndex
|
) {
|
var attributes = object.attributes;
|
var attributesLength = attributes.length;
|
for (var i = 0; i < attributesLength; ++i) {
|
var attribute = attributes[i];
|
var matchesSetIndex = defined(setIndex)
|
? attribute.setIndex === setIndex
|
: true;
|
if (attribute.semantic === semantic && matchesSetIndex) {
|
return attribute;
|
}
|
}
|
};
|
|
ModelExperimentalUtility.hasQuantizedAttributes = function (attributes) {
|
if (!defined(attributes)) {
|
return false;
|
}
|
|
for (var i = 0; i < attributes.length; i++) {
|
var attribute = attributes[i];
|
if (defined(attribute.quantization)) {
|
return true;
|
}
|
}
|
return false;
|
};
|
|
/**
|
* @param {ModelComponents.Attribute} attribute
|
*
|
* @private
|
*/
|
ModelExperimentalUtility.getAttributeInfo = function (attribute) {
|
var semantic = attribute.semantic;
|
var setIndex = attribute.setIndex;
|
|
var variableName;
|
var hasSemantic = false;
|
if (defined(semantic)) {
|
variableName = VertexAttributeSemantic.getVariableName(semantic, setIndex);
|
hasSemantic = true;
|
} else {
|
variableName = attribute.name;
|
// According to the glTF 2.0 spec, custom attributes must be prepended with
|
// an underscore.
|
variableName = variableName.replace(/^_/, "");
|
variableName = variableName.toLowerCase();
|
}
|
|
var attributeType = attribute.type;
|
var glslType = AttributeType.getGlslType(attributeType);
|
|
var isQuantized = defined(attribute.quantization);
|
var quantizedGlslType;
|
if (isQuantized) {
|
quantizedGlslType = AttributeType.getGlslType(attribute.quantization.type);
|
}
|
|
return {
|
attribute: attribute,
|
isQuantized: isQuantized,
|
variableName: variableName,
|
hasSemantic: hasSemantic,
|
glslType: glslType,
|
quantizedGlslType: quantizedGlslType,
|
};
|
};
|
|
var cartesianMaxScratch = new Cartesian3();
|
var cartesianMinScratch = new Cartesian3();
|
/**
|
* Create a bounding sphere from a primitive's POSITION attribute and model
|
* matrix.
|
*
|
* @param {ModelComponents.Primitive} primitive The primitive components.
|
* @param {Matrix4} modelMatrix The primitive's model matrix.
|
* @param {Cartesian3} [instancingTranslationMax] The component-wise maximum value of the instancing translation attribute.
|
* @param {Cartesian3} [instancingTranslationMin] The component-wise minimum value of the instancing translation attribute.
|
*/
|
ModelExperimentalUtility.createBoundingSphere = function (
|
primitive,
|
modelMatrix,
|
instancingTranslationMax,
|
instancingTranslationMin
|
) {
|
var positionGltfAttribute = ModelExperimentalUtility.getAttributeBySemantic(
|
primitive,
|
"POSITION"
|
);
|
|
var positionMax = positionGltfAttribute.max;
|
var positionMin = positionGltfAttribute.min;
|
|
var boundingSphere;
|
if (defined(instancingTranslationMax) && defined(instancingTranslationMin)) {
|
var computedMin = Cartesian3.add(
|
positionMin,
|
instancingTranslationMin,
|
cartesianMinScratch
|
);
|
var computedMax = Cartesian3.add(
|
positionMax,
|
instancingTranslationMax,
|
cartesianMaxScratch
|
);
|
boundingSphere = BoundingSphere.fromCornerPoints(computedMin, computedMax);
|
} else {
|
boundingSphere = BoundingSphere.fromCornerPoints(positionMin, positionMax);
|
}
|
|
BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere);
|
return boundingSphere;
|
};
|
|
/**
|
* Model matrices in a model file (e.g. glTF) are typically in a different
|
* coordinate system, such as with y-up instead of z-up. This method adjusts
|
* the matrix so z is up, x is forward.
|
*
|
* @param {Matrix4} modelMatrix The original model matrix. This will be updated in place
|
* @param {Axis} upAxis The original up direction
|
* @param {Axis} forwardAxis The original forward direction
|
*
|
* @private
|
*/
|
ModelExperimentalUtility.correctModelMatrix = function (
|
modelMatrix,
|
upAxis,
|
forwardAxis
|
) {
|
if (upAxis === Axis.Y) {
|
Matrix4.multiplyTransformation(modelMatrix, Axis.Y_UP_TO_Z_UP, modelMatrix);
|
} else if (upAxis === Axis.X) {
|
Matrix4.multiplyTransformation(modelMatrix, Axis.X_UP_TO_Z_UP, modelMatrix);
|
}
|
|
if (forwardAxis === Axis.Z) {
|
// glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
|
Matrix4.multiplyTransformation(modelMatrix, Axis.Z_UP_TO_X_UP, modelMatrix);
|
}
|
};
|