You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1355 lines
40 KiB
JavaScript
1355 lines
40 KiB
JavaScript
import BoundingSphere from "../Core/BoundingSphere.js";
|
|
import Cartesian2 from "../Core/Cartesian2.js";
|
|
import Cartesian3 from "../Core/Cartesian3.js";
|
|
import Cartesian4 from "../Core/Cartesian4.js";
|
|
import clone from "../Core/clone.js";
|
|
import defined from "../Core/defined.js";
|
|
import Matrix2 from "../Core/Matrix2.js";
|
|
import Matrix3 from "../Core/Matrix3.js";
|
|
import Matrix4 from "../Core/Matrix4.js";
|
|
import Quaternion from "../Core/Quaternion.js";
|
|
import RuntimeError from "../Core/RuntimeError.js";
|
|
import WebGLConstants from "../Core/WebGLConstants.js";
|
|
import ShaderSource from "../Renderer/ShaderSource.js";
|
|
import addToArray from "../ThirdParty/GltfPipeline/addToArray.js";
|
|
import ForEach from "../ThirdParty/GltfPipeline/ForEach.js";
|
|
import hasExtension from "../ThirdParty/GltfPipeline/hasExtension.js";
|
|
import AttributeType from "./AttributeType.js";
|
|
import Axis from "./Axis.js";
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
var ModelUtility = {};
|
|
|
|
/**
|
|
* Updates the model's forward axis if the model is not a 2.0 model.
|
|
*
|
|
* @param {Object} model The model to update.
|
|
*/
|
|
ModelUtility.updateForwardAxis = function (model) {
|
|
var cachedSourceVersion = model.gltf.extras.sourceVersion;
|
|
|
|
if (
|
|
(defined(cachedSourceVersion) && cachedSourceVersion !== "2.0") ||
|
|
ModelUtility.getAssetVersion(model.gltf) !== "2.0"
|
|
) {
|
|
model._gltfForwardAxis = Axis.X;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Gets the string representing the glTF asset version.
|
|
*
|
|
* @param {Object} gltf A javascript object containing a glTF asset.
|
|
* @returns {String} The glTF asset version string.
|
|
*/
|
|
ModelUtility.getAssetVersion = function (gltf) {
|
|
// In glTF 1.0 it was valid to omit the version number.
|
|
if (!defined(gltf.asset) || !defined(gltf.asset.version)) {
|
|
return "1.0";
|
|
}
|
|
|
|
return gltf.asset.version;
|
|
};
|
|
|
|
/**
|
|
* Splits primitive materials with values incompatible for generating techniques.
|
|
*
|
|
* @param {Object} gltf A javascript object containing a glTF asset.
|
|
* @returns {Object} The glTF asset with modified materials.
|
|
*/
|
|
ModelUtility.splitIncompatibleMaterials = function (gltf) {
|
|
var accessors = gltf.accessors;
|
|
var materials = gltf.materials;
|
|
var primitiveInfoByMaterial = {};
|
|
ForEach.mesh(gltf, function (mesh) {
|
|
ForEach.meshPrimitive(mesh, function (primitive) {
|
|
var materialIndex = primitive.material;
|
|
var material = materials[materialIndex];
|
|
|
|
var jointAccessorId = primitive.attributes.JOINTS_0;
|
|
var componentType;
|
|
var accessorType;
|
|
if (defined(jointAccessorId)) {
|
|
var jointAccessor = accessors[jointAccessorId];
|
|
componentType = jointAccessor.componentType;
|
|
accessorType = jointAccessor.type;
|
|
}
|
|
var isSkinned = defined(jointAccessorId) && accessorType === "VEC4";
|
|
var hasVertexColors = defined(primitive.attributes.COLOR_0);
|
|
var hasMorphTargets = defined(primitive.targets);
|
|
var hasNormals = defined(primitive.attributes.NORMAL);
|
|
var hasTangents = defined(primitive.attributes.TANGENT);
|
|
var hasTexCoords = defined(primitive.attributes.TEXCOORD_0);
|
|
var hasTexCoord1 =
|
|
hasTexCoords && defined(primitive.attributes.TEXCOORD_1);
|
|
var hasOutline =
|
|
defined(primitive.extensions) &&
|
|
defined(primitive.extensions.CESIUM_primitive_outline);
|
|
|
|
var primitiveInfo = primitiveInfoByMaterial[materialIndex];
|
|
if (!defined(primitiveInfo)) {
|
|
primitiveInfoByMaterial[materialIndex] = {
|
|
skinning: {
|
|
skinned: isSkinned,
|
|
componentType: componentType,
|
|
},
|
|
hasVertexColors: hasVertexColors,
|
|
hasMorphTargets: hasMorphTargets,
|
|
hasNormals: hasNormals,
|
|
hasTangents: hasTangents,
|
|
hasTexCoords: hasTexCoords,
|
|
hasTexCoord1: hasTexCoord1,
|
|
hasOutline: hasOutline,
|
|
};
|
|
} else if (
|
|
primitiveInfo.skinning.skinned !== isSkinned ||
|
|
primitiveInfo.hasVertexColors !== hasVertexColors ||
|
|
primitiveInfo.hasMorphTargets !== hasMorphTargets ||
|
|
primitiveInfo.hasNormals !== hasNormals ||
|
|
primitiveInfo.hasTangents !== hasTangents ||
|
|
primitiveInfo.hasTexCoords !== hasTexCoords ||
|
|
primitiveInfo.hasTexCoord1 !== hasTexCoord1 ||
|
|
primitiveInfo.hasOutline !== hasOutline
|
|
) {
|
|
// This primitive uses the same material as another one that either:
|
|
// * Isn't skinned
|
|
// * Uses a different type to store joints and weights
|
|
// * Doesn't have vertex colors, morph targets, normals, tangents, or texCoords
|
|
// * Doesn't have a CESIUM_primitive_outline extension.
|
|
var clonedMaterial = clone(material, true);
|
|
// Split this off as a separate material
|
|
materialIndex = addToArray(materials, clonedMaterial);
|
|
primitive.material = materialIndex;
|
|
primitiveInfoByMaterial[materialIndex] = {
|
|
skinning: {
|
|
skinned: isSkinned,
|
|
componentType: componentType,
|
|
},
|
|
hasVertexColors: hasVertexColors,
|
|
hasMorphTargets: hasMorphTargets,
|
|
hasNormals: hasNormals,
|
|
hasTangents: hasTangents,
|
|
hasTexCoords: hasTexCoords,
|
|
hasTexCoord1: hasTexCoord1,
|
|
hasOutline: hasOutline,
|
|
};
|
|
}
|
|
});
|
|
});
|
|
|
|
return primitiveInfoByMaterial;
|
|
};
|
|
|
|
ModelUtility.getShaderVariable = function (type) {
|
|
if (type === "SCALAR") {
|
|
return "float";
|
|
}
|
|
return type.toLowerCase();
|
|
};
|
|
|
|
ModelUtility.ModelState = {
|
|
NEEDS_LOAD: 0,
|
|
LOADING: 1,
|
|
LOADED: 2, // Renderable, but textures can still be pending when incrementallyLoadTextures is true.
|
|
FAILED: 3,
|
|
};
|
|
|
|
ModelUtility.getFailedLoadFunction = function (model, type, path) {
|
|
return function (error) {
|
|
model._state = ModelUtility.ModelState.FAILED;
|
|
var message = "Failed to load " + type + ": " + path;
|
|
if (defined(error)) {
|
|
message += "\n" + error.message;
|
|
}
|
|
model._readyPromise.reject(new RuntimeError(message));
|
|
};
|
|
};
|
|
|
|
ModelUtility.parseBuffers = function (model, bufferLoad) {
|
|
var loadResources = model._loadResources;
|
|
ForEach.buffer(model.gltf, function (buffer, bufferViewId) {
|
|
if (defined(buffer.extras._pipeline.source)) {
|
|
loadResources.buffers[bufferViewId] = buffer.extras._pipeline.source;
|
|
} else if (defined(bufferLoad)) {
|
|
var bufferResource = model._resource.getDerivedResource({
|
|
url: buffer.uri,
|
|
});
|
|
++loadResources.pendingBufferLoads;
|
|
bufferResource
|
|
.fetchArrayBuffer()
|
|
.then(bufferLoad(model, bufferViewId))
|
|
.otherwise(
|
|
ModelUtility.getFailedLoadFunction(
|
|
model,
|
|
"buffer",
|
|
bufferResource.url
|
|
)
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
var aMinScratch = new Cartesian3();
|
|
var aMaxScratch = new Cartesian3();
|
|
|
|
ModelUtility.computeBoundingSphere = function (model) {
|
|
var gltf = model.gltf;
|
|
var gltfNodes = gltf.nodes;
|
|
var gltfMeshes = gltf.meshes;
|
|
var rootNodes = gltf.scenes[gltf.scene].nodes;
|
|
var rootNodesLength = rootNodes.length;
|
|
|
|
var nodeStack = [];
|
|
|
|
var min = new Cartesian3(
|
|
Number.MAX_VALUE,
|
|
Number.MAX_VALUE,
|
|
Number.MAX_VALUE
|
|
);
|
|
var max = new Cartesian3(
|
|
-Number.MAX_VALUE,
|
|
-Number.MAX_VALUE,
|
|
-Number.MAX_VALUE
|
|
);
|
|
|
|
for (var i = 0; i < rootNodesLength; ++i) {
|
|
var n = gltfNodes[rootNodes[i]];
|
|
n._transformToRoot = ModelUtility.getTransform(n);
|
|
nodeStack.push(n);
|
|
|
|
while (nodeStack.length > 0) {
|
|
n = nodeStack.pop();
|
|
var transformToRoot = n._transformToRoot;
|
|
|
|
var meshId = n.mesh;
|
|
if (defined(meshId)) {
|
|
var mesh = gltfMeshes[meshId];
|
|
var primitives = mesh.primitives;
|
|
var primitivesLength = primitives.length;
|
|
for (var m = 0; m < primitivesLength; ++m) {
|
|
var positionAccessor = primitives[m].attributes.POSITION;
|
|
if (defined(positionAccessor)) {
|
|
var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
|
|
if (defined(minMax.min) && defined(minMax.max)) {
|
|
var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch);
|
|
var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch);
|
|
|
|
Matrix4.multiplyByPoint(transformToRoot, aMin, aMin);
|
|
Matrix4.multiplyByPoint(transformToRoot, aMax, aMax);
|
|
Cartesian3.minimumByComponent(min, aMin, min);
|
|
Cartesian3.maximumByComponent(max, aMax, max);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var children = n.children;
|
|
if (defined(children)) {
|
|
var childrenLength = children.length;
|
|
for (var k = 0; k < childrenLength; ++k) {
|
|
var child = gltfNodes[children[k]];
|
|
child._transformToRoot = ModelUtility.getTransform(child);
|
|
Matrix4.multiplyTransformation(
|
|
transformToRoot,
|
|
child._transformToRoot,
|
|
child._transformToRoot
|
|
);
|
|
nodeStack.push(child);
|
|
}
|
|
}
|
|
delete n._transformToRoot;
|
|
}
|
|
}
|
|
|
|
var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
|
|
if (model._forwardAxis === Axis.Z) {
|
|
// glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
|
|
BoundingSphere.transformWithoutScale(
|
|
boundingSphere,
|
|
Axis.Z_UP_TO_X_UP,
|
|
boundingSphere
|
|
);
|
|
}
|
|
if (model._upAxis === Axis.Y) {
|
|
BoundingSphere.transformWithoutScale(
|
|
boundingSphere,
|
|
Axis.Y_UP_TO_Z_UP,
|
|
boundingSphere
|
|
);
|
|
} else if (model._upAxis === Axis.X) {
|
|
BoundingSphere.transformWithoutScale(
|
|
boundingSphere,
|
|
Axis.X_UP_TO_Z_UP,
|
|
boundingSphere
|
|
);
|
|
}
|
|
return boundingSphere;
|
|
};
|
|
|
|
function techniqueAttributeForSemantic(technique, semantic) {
|
|
return ForEach.techniqueAttribute(technique, function (
|
|
attribute,
|
|
attributeName
|
|
) {
|
|
if (attribute.semantic === semantic) {
|
|
return attributeName;
|
|
}
|
|
});
|
|
}
|
|
|
|
function ensureSemanticExistenceForPrimitive(gltf, primitive) {
|
|
var accessors = gltf.accessors;
|
|
var materials = gltf.materials;
|
|
var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
|
|
|
|
var techniques = techniquesWebgl.techniques;
|
|
var programs = techniquesWebgl.programs;
|
|
var shaders = techniquesWebgl.shaders;
|
|
var targets = primitive.targets;
|
|
|
|
var attributes = primitive.attributes;
|
|
for (var target in targets) {
|
|
if (targets.hasOwnProperty(target)) {
|
|
var targetAttributes = targets[target];
|
|
for (var attribute in targetAttributes) {
|
|
if (attribute !== "extras") {
|
|
attributes[attribute + "_" + target] = targetAttributes[attribute];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var material = materials[primitive.material];
|
|
var technique =
|
|
techniques[material.extensions.KHR_techniques_webgl.technique];
|
|
var program = programs[technique.program];
|
|
var vertexShader = shaders[program.vertexShader];
|
|
|
|
for (var semantic in attributes) {
|
|
if (attributes.hasOwnProperty(semantic)) {
|
|
if (!defined(techniqueAttributeForSemantic(technique, semantic))) {
|
|
var accessorId = attributes[semantic];
|
|
var accessor = accessors[accessorId];
|
|
var lowerCase = semantic.toLowerCase();
|
|
if (lowerCase.charAt(0) === "_") {
|
|
lowerCase = lowerCase.slice(1);
|
|
}
|
|
var attributeName = "a_" + lowerCase;
|
|
technique.attributes[attributeName] = {
|
|
semantic: semantic,
|
|
type: accessor.componentType,
|
|
};
|
|
var pipelineExtras = vertexShader.extras._pipeline;
|
|
var shaderText = pipelineExtras.source;
|
|
shaderText =
|
|
"attribute " +
|
|
ModelUtility.getShaderVariable(accessor.type) +
|
|
" " +
|
|
attributeName +
|
|
";\n" +
|
|
shaderText;
|
|
pipelineExtras.source = shaderText;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ensures all attributes present on the primitive are present in the technique and
|
|
* vertex shader.
|
|
*
|
|
* @param {Object} gltf A javascript object containing a glTF asset.
|
|
* @returns {Object} The glTF asset, including any additional attributes.
|
|
*/
|
|
ModelUtility.ensureSemanticExistence = function (gltf) {
|
|
ForEach.mesh(gltf, function (mesh) {
|
|
ForEach.meshPrimitive(mesh, function (primitive) {
|
|
ensureSemanticExistenceForPrimitive(gltf, primitive);
|
|
});
|
|
});
|
|
|
|
return gltf;
|
|
};
|
|
|
|
/**
|
|
* Creates attribute location for all attributes required by a technique.
|
|
*
|
|
* @param {Object} technique A glTF KHR_techniques_webgl technique object.
|
|
* @param {Object} precreatedAttributes A dictionary object of pre-created attributes for which to also create locations.
|
|
* @returns {Object} A dictionary object containing attribute names and their locations.
|
|
*/
|
|
ModelUtility.createAttributeLocations = function (
|
|
technique,
|
|
precreatedAttributes
|
|
) {
|
|
var attributeLocations = {};
|
|
var hasIndex0 = false;
|
|
var i = 1;
|
|
|
|
ForEach.techniqueAttribute(technique, function (attribute, attributeName) {
|
|
// Set the position attribute to the 0th index. In some WebGL implementations the shader
|
|
// will not work correctly if the 0th attribute is not active. For example, some glTF models
|
|
// list the normal attribute first but derived shaders like the cast-shadows shader do not use
|
|
// the normal attribute.
|
|
if (/pos/i.test(attributeName) && !hasIndex0) {
|
|
attributeLocations[attributeName] = 0;
|
|
hasIndex0 = true;
|
|
} else {
|
|
attributeLocations[attributeName] = i++;
|
|
}
|
|
});
|
|
|
|
if (defined(precreatedAttributes)) {
|
|
for (var attributeName in precreatedAttributes) {
|
|
if (precreatedAttributes.hasOwnProperty(attributeName)) {
|
|
attributeLocations[attributeName] = i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return attributeLocations;
|
|
};
|
|
|
|
ModelUtility.getAccessorMinMax = function (gltf, accessorId) {
|
|
var accessor = gltf.accessors[accessorId];
|
|
var extensions = accessor.extensions;
|
|
var accessorMin = accessor.min;
|
|
var accessorMax = accessor.max;
|
|
// If this accessor is quantized, we should use the decoded min and max
|
|
if (defined(extensions)) {
|
|
var quantizedAttributes = extensions.WEB3D_quantized_attributes;
|
|
if (defined(quantizedAttributes)) {
|
|
accessorMin = quantizedAttributes.decodedMin;
|
|
accessorMax = quantizedAttributes.decodedMax;
|
|
}
|
|
}
|
|
return {
|
|
min: accessorMin,
|
|
max: accessorMax,
|
|
};
|
|
};
|
|
|
|
function getTechniqueAttributeOrUniformFunction(
|
|
gltf,
|
|
technique,
|
|
semantic,
|
|
ignoreNodes
|
|
) {
|
|
if (hasExtension(gltf, "KHR_techniques_webgl")) {
|
|
return function (attributeOrUniform, attributeOrUniformName) {
|
|
if (
|
|
attributeOrUniform.semantic === semantic &&
|
|
(!ignoreNodes || !defined(attributeOrUniform.node))
|
|
) {
|
|
return attributeOrUniformName;
|
|
}
|
|
};
|
|
}
|
|
|
|
return function (parameterName, attributeOrUniformName) {
|
|
var attributeOrUniform = technique.parameters[parameterName];
|
|
if (
|
|
attributeOrUniform.semantic === semantic &&
|
|
(!ignoreNodes || !defined(attributeOrUniform.node))
|
|
) {
|
|
return attributeOrUniformName;
|
|
}
|
|
};
|
|
}
|
|
|
|
ModelUtility.getAttributeOrUniformBySemantic = function (
|
|
gltf,
|
|
semantic,
|
|
programId,
|
|
ignoreNodes
|
|
) {
|
|
return ForEach.technique(gltf, function (technique) {
|
|
if (defined(programId) && technique.program !== programId) {
|
|
return;
|
|
}
|
|
|
|
var value = ForEach.techniqueAttribute(
|
|
technique,
|
|
getTechniqueAttributeOrUniformFunction(
|
|
gltf,
|
|
technique,
|
|
semantic,
|
|
ignoreNodes
|
|
)
|
|
);
|
|
|
|
if (defined(value)) {
|
|
return value;
|
|
}
|
|
|
|
return ForEach.techniqueUniform(
|
|
technique,
|
|
getTechniqueAttributeOrUniformFunction(
|
|
gltf,
|
|
technique,
|
|
semantic,
|
|
ignoreNodes
|
|
)
|
|
);
|
|
});
|
|
};
|
|
|
|
ModelUtility.getDiffuseAttributeOrUniform = function (gltf, programId) {
|
|
var diffuseUniformName = ModelUtility.getAttributeOrUniformBySemantic(
|
|
gltf,
|
|
"COLOR_0",
|
|
programId
|
|
);
|
|
if (!defined(diffuseUniformName)) {
|
|
diffuseUniformName = ModelUtility.getAttributeOrUniformBySemantic(
|
|
gltf,
|
|
"_3DTILESDIFFUSE",
|
|
programId
|
|
);
|
|
}
|
|
return diffuseUniformName;
|
|
};
|
|
|
|
var nodeTranslationScratch = new Cartesian3();
|
|
var nodeQuaternionScratch = new Quaternion();
|
|
var nodeScaleScratch = new Cartesian3();
|
|
|
|
ModelUtility.getTransform = function (node, result) {
|
|
if (defined(node.matrix)) {
|
|
return Matrix4.fromColumnMajorArray(node.matrix, result);
|
|
}
|
|
|
|
return Matrix4.fromTranslationQuaternionRotationScale(
|
|
Cartesian3.fromArray(node.translation, 0, nodeTranslationScratch),
|
|
Quaternion.unpack(node.rotation, 0, nodeQuaternionScratch),
|
|
Cartesian3.fromArray(node.scale, 0, nodeScaleScratch),
|
|
result
|
|
);
|
|
};
|
|
|
|
ModelUtility.getUsedExtensions = function (gltf) {
|
|
var extensionsUsed = gltf.extensionsUsed;
|
|
var cachedExtensionsUsed = {};
|
|
|
|
if (defined(extensionsUsed)) {
|
|
var extensionsUsedLength = extensionsUsed.length;
|
|
for (var i = 0; i < extensionsUsedLength; i++) {
|
|
var extension = extensionsUsed[i];
|
|
cachedExtensionsUsed[extension] = true;
|
|
}
|
|
}
|
|
return cachedExtensionsUsed;
|
|
};
|
|
|
|
ModelUtility.getRequiredExtensions = function (gltf) {
|
|
var extensionsRequired = gltf.extensionsRequired;
|
|
var cachedExtensionsRequired = {};
|
|
|
|
if (defined(extensionsRequired)) {
|
|
var extensionsRequiredLength = extensionsRequired.length;
|
|
for (var i = 0; i < extensionsRequiredLength; i++) {
|
|
var extension = extensionsRequired[i];
|
|
cachedExtensionsRequired[extension] = true;
|
|
}
|
|
}
|
|
|
|
return cachedExtensionsRequired;
|
|
};
|
|
|
|
ModelUtility.supportedExtensions = {
|
|
AGI_articulations: true,
|
|
CESIUM_RTC: true,
|
|
EXT_texture_webp: true,
|
|
KHR_blend: true,
|
|
KHR_binary_glTF: true,
|
|
KHR_draco_mesh_compression: true,
|
|
KHR_materials_common: true,
|
|
KHR_techniques_webgl: true,
|
|
KHR_materials_unlit: true,
|
|
KHR_materials_pbrSpecularGlossiness: true,
|
|
KHR_texture_transform: true,
|
|
WEB3D_quantized_attributes: true,
|
|
};
|
|
|
|
ModelUtility.checkSupportedExtensions = function (
|
|
extensionsRequired,
|
|
browserSupportsWebp
|
|
) {
|
|
for (var extension in extensionsRequired) {
|
|
if (extensionsRequired.hasOwnProperty(extension)) {
|
|
if (!ModelUtility.supportedExtensions[extension]) {
|
|
throw new RuntimeError("Unsupported glTF Extension: " + extension);
|
|
}
|
|
|
|
if (extension === "EXT_texture_webp" && browserSupportsWebp === false) {
|
|
throw new RuntimeError(
|
|
"Loaded model requires WebP but browser does not support it."
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ModelUtility.checkSupportedGlExtensions = function (extensionsUsed, context) {
|
|
if (defined(extensionsUsed)) {
|
|
var glExtensionsUsedLength = extensionsUsed.length;
|
|
for (var i = 0; i < glExtensionsUsedLength; i++) {
|
|
var extension = extensionsUsed[i];
|
|
if (extension !== "OES_element_index_uint") {
|
|
throw new RuntimeError("Unsupported WebGL Extension: " + extension);
|
|
} else if (!context.elementIndexUint) {
|
|
throw new RuntimeError(
|
|
"OES_element_index_uint WebGL extension is not enabled."
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function replaceAllButFirstInString(string, find, replace) {
|
|
// Limit search to strings that are not a subset of other tokens.
|
|
find += "(?!\\w)";
|
|
find = new RegExp(find, "g");
|
|
|
|
var index = string.search(find);
|
|
return string.replace(find, function (match, offset) {
|
|
return index === offset ? match : replace;
|
|
});
|
|
}
|
|
|
|
function getQuantizedAttributes(gltf, accessorId) {
|
|
var accessor = gltf.accessors[accessorId];
|
|
var extensions = accessor.extensions;
|
|
if (defined(extensions)) {
|
|
return extensions.WEB3D_quantized_attributes;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function getAttributeVariableName(gltf, primitive, attributeSemantic) {
|
|
var materialId = primitive.material;
|
|
var material = gltf.materials[materialId];
|
|
|
|
if (
|
|
!hasExtension(gltf, "KHR_techniques_webgl") ||
|
|
!defined(material.extensions) ||
|
|
!defined(material.extensions.KHR_techniques_webgl)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
var techniqueId = material.extensions.KHR_techniques_webgl.technique;
|
|
var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
|
|
var technique = techniquesWebgl.techniques[techniqueId];
|
|
return ForEach.techniqueAttribute(technique, function (
|
|
attribute,
|
|
attributeName
|
|
) {
|
|
var semantic = attribute.semantic;
|
|
if (semantic === attributeSemantic) {
|
|
return attributeName;
|
|
}
|
|
});
|
|
}
|
|
|
|
ModelUtility.modifyShaderForDracoQuantizedAttributes = function (
|
|
gltf,
|
|
primitive,
|
|
shader,
|
|
decodedAttributes
|
|
) {
|
|
var quantizedUniforms = {};
|
|
for (var attributeSemantic in decodedAttributes) {
|
|
if (decodedAttributes.hasOwnProperty(attributeSemantic)) {
|
|
var attribute = decodedAttributes[attributeSemantic];
|
|
var quantization = attribute.quantization;
|
|
if (!defined(quantization)) {
|
|
continue;
|
|
}
|
|
|
|
var attributeVarName = getAttributeVariableName(
|
|
gltf,
|
|
primitive,
|
|
attributeSemantic
|
|
);
|
|
|
|
if (attributeSemantic.charAt(0) === "_") {
|
|
attributeSemantic = attributeSemantic.substring(1);
|
|
}
|
|
var decodeUniformVarName =
|
|
"gltf_u_dec_" + attributeSemantic.toLowerCase();
|
|
|
|
if (!defined(quantizedUniforms[decodeUniformVarName])) {
|
|
var newMain = "gltf_decoded_" + attributeSemantic;
|
|
var decodedAttributeVarName = attributeVarName.replace(
|
|
"a_",
|
|
"gltf_a_dec_"
|
|
);
|
|
var size = attribute.componentsPerAttribute;
|
|
|
|
// replace usages of the original attribute with the decoded version, but not the declaration
|
|
shader = replaceAllButFirstInString(
|
|
shader,
|
|
attributeVarName,
|
|
decodedAttributeVarName
|
|
);
|
|
|
|
// declare decoded attribute
|
|
var variableType;
|
|
if (quantization.octEncoded) {
|
|
variableType = "vec3";
|
|
} else if (size > 1) {
|
|
variableType = "vec" + size;
|
|
} else {
|
|
variableType = "float";
|
|
}
|
|
shader = variableType + " " + decodedAttributeVarName + ";\n" + shader;
|
|
|
|
// The gltf 2.0 COLOR_0 vertex attribute can be VEC4 or VEC3
|
|
var vec3Color = size === 3 && attributeSemantic === "COLOR_0";
|
|
if (vec3Color) {
|
|
shader = replaceAllButFirstInString(
|
|
shader,
|
|
decodedAttributeVarName,
|
|
"vec4(" + decodedAttributeVarName + ", 1.0)"
|
|
);
|
|
}
|
|
|
|
// splice decode function into the shader
|
|
var decode = "";
|
|
if (quantization.octEncoded) {
|
|
var decodeUniformVarNameRangeConstant =
|
|
decodeUniformVarName + "_rangeConstant";
|
|
shader =
|
|
"uniform float " +
|
|
decodeUniformVarNameRangeConstant +
|
|
";\n" +
|
|
shader;
|
|
decode =
|
|
"\n" +
|
|
"void main() {\n" +
|
|
// Draco oct-encoding decodes to zxy order
|
|
" " +
|
|
decodedAttributeVarName +
|
|
" = czm_octDecode(" +
|
|
attributeVarName +
|
|
".xy, " +
|
|
decodeUniformVarNameRangeConstant +
|
|
").zxy;\n" +
|
|
" " +
|
|
newMain +
|
|
"();\n" +
|
|
"}\n";
|
|
} else {
|
|
var decodeUniformVarNameNormConstant =
|
|
decodeUniformVarName + "_normConstant";
|
|
var decodeUniformVarNameMin = decodeUniformVarName + "_min";
|
|
shader =
|
|
"uniform float " +
|
|
decodeUniformVarNameNormConstant +
|
|
";\n" +
|
|
"uniform " +
|
|
variableType +
|
|
" " +
|
|
decodeUniformVarNameMin +
|
|
";\n" +
|
|
shader;
|
|
var attributeVarAccess = vec3Color ? ".xyz" : "";
|
|
decode =
|
|
"\n" +
|
|
"void main() {\n" +
|
|
" " +
|
|
decodedAttributeVarName +
|
|
" = " +
|
|
decodeUniformVarNameMin +
|
|
" + " +
|
|
attributeVarName +
|
|
attributeVarAccess +
|
|
" * " +
|
|
decodeUniformVarNameNormConstant +
|
|
";\n" +
|
|
" " +
|
|
newMain +
|
|
"();\n" +
|
|
"}\n";
|
|
}
|
|
|
|
shader = ShaderSource.replaceMain(shader, newMain);
|
|
shader += decode;
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
shader: shader,
|
|
};
|
|
};
|
|
|
|
ModelUtility.modifyShaderForQuantizedAttributes = function (
|
|
gltf,
|
|
primitive,
|
|
shader
|
|
) {
|
|
var quantizedUniforms = {};
|
|
var attributes = primitive.attributes;
|
|
for (var attributeSemantic in attributes) {
|
|
if (attributes.hasOwnProperty(attributeSemantic)) {
|
|
var attributeVarName = getAttributeVariableName(
|
|
gltf,
|
|
primitive,
|
|
attributeSemantic
|
|
);
|
|
var accessorId = primitive.attributes[attributeSemantic];
|
|
|
|
if (attributeSemantic.charAt(0) === "_") {
|
|
attributeSemantic = attributeSemantic.substring(1);
|
|
}
|
|
var decodeUniformVarName =
|
|
"gltf_u_dec_" + attributeSemantic.toLowerCase();
|
|
|
|
var decodeUniformVarNameScale = decodeUniformVarName + "_scale";
|
|
var decodeUniformVarNameTranslate = decodeUniformVarName + "_translate";
|
|
if (
|
|
!defined(quantizedUniforms[decodeUniformVarName]) &&
|
|
!defined(quantizedUniforms[decodeUniformVarNameScale])
|
|
) {
|
|
var quantizedAttributes = getQuantizedAttributes(gltf, accessorId);
|
|
if (defined(quantizedAttributes)) {
|
|
var decodeMatrix = quantizedAttributes.decodeMatrix;
|
|
var newMain = "gltf_decoded_" + attributeSemantic;
|
|
var decodedAttributeVarName = attributeVarName.replace(
|
|
"a_",
|
|
"gltf_a_dec_"
|
|
);
|
|
var size = Math.floor(Math.sqrt(decodeMatrix.length));
|
|
|
|
// replace usages of the original attribute with the decoded version, but not the declaration
|
|
shader = replaceAllButFirstInString(
|
|
shader,
|
|
attributeVarName,
|
|
decodedAttributeVarName
|
|
);
|
|
// declare decoded attribute
|
|
var variableType;
|
|
if (size > 2) {
|
|
variableType = "vec" + (size - 1);
|
|
} else {
|
|
variableType = "float";
|
|
}
|
|
shader =
|
|
variableType + " " + decodedAttributeVarName + ";\n" + shader;
|
|
// splice decode function into the shader - attributes are pre-multiplied with the decode matrix
|
|
// uniform in the shader (32-bit floating point)
|
|
var decode = "";
|
|
if (size === 5) {
|
|
// separate scale and translate since glsl doesn't have mat5
|
|
shader =
|
|
"uniform mat4 " + decodeUniformVarNameScale + ";\n" + shader;
|
|
shader =
|
|
"uniform vec4 " + decodeUniformVarNameTranslate + ";\n" + shader;
|
|
decode =
|
|
"\n" +
|
|
"void main() {\n" +
|
|
" " +
|
|
decodedAttributeVarName +
|
|
" = " +
|
|
decodeUniformVarNameScale +
|
|
" * " +
|
|
attributeVarName +
|
|
" + " +
|
|
decodeUniformVarNameTranslate +
|
|
";\n" +
|
|
" " +
|
|
newMain +
|
|
"();\n" +
|
|
"}\n";
|
|
|
|
quantizedUniforms[decodeUniformVarNameScale] = { mat: 4 };
|
|
quantizedUniforms[decodeUniformVarNameTranslate] = { vec: 4 };
|
|
} else {
|
|
shader =
|
|
"uniform mat" +
|
|
size +
|
|
" " +
|
|
decodeUniformVarName +
|
|
";\n" +
|
|
shader;
|
|
decode =
|
|
"\n" +
|
|
"void main() {\n" +
|
|
" " +
|
|
decodedAttributeVarName +
|
|
" = " +
|
|
variableType +
|
|
"(" +
|
|
decodeUniformVarName +
|
|
" * vec" +
|
|
size +
|
|
"(" +
|
|
attributeVarName +
|
|
",1.0));\n" +
|
|
" " +
|
|
newMain +
|
|
"();\n" +
|
|
"}\n";
|
|
|
|
quantizedUniforms[decodeUniformVarName] = { mat: size };
|
|
}
|
|
shader = ShaderSource.replaceMain(shader, newMain);
|
|
shader += decode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
shader: shader,
|
|
uniforms: quantizedUniforms,
|
|
};
|
|
};
|
|
|
|
function getScalarUniformFunction(value) {
|
|
var that = {
|
|
value: value,
|
|
clone: function (source, result) {
|
|
return source;
|
|
},
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
function getVec2UniformFunction(value) {
|
|
var that = {
|
|
value: Cartesian2.fromArray(value),
|
|
clone: Cartesian2.clone,
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
function getVec3UniformFunction(value) {
|
|
var that = {
|
|
value: Cartesian3.fromArray(value),
|
|
clone: Cartesian3.clone,
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
function getVec4UniformFunction(value) {
|
|
var that = {
|
|
value: Cartesian4.fromArray(value),
|
|
clone: Cartesian4.clone,
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
function getMat2UniformFunction(value) {
|
|
var that = {
|
|
value: Matrix2.fromColumnMajorArray(value),
|
|
clone: Matrix2.clone,
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
function getMat3UniformFunction(value) {
|
|
var that = {
|
|
value: Matrix3.fromColumnMajorArray(value),
|
|
clone: Matrix3.clone,
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
function getMat4UniformFunction(value) {
|
|
var that = {
|
|
value: Matrix4.fromColumnMajorArray(value),
|
|
clone: Matrix4.clone,
|
|
func: function () {
|
|
return that.value;
|
|
},
|
|
};
|
|
return that;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
function DelayLoadedTextureUniform(value, textures, defaultTexture) {
|
|
this._value = undefined;
|
|
this._textureId = value.index;
|
|
this._textures = textures;
|
|
this._defaultTexture = defaultTexture;
|
|
}
|
|
|
|
Object.defineProperties(DelayLoadedTextureUniform.prototype, {
|
|
value: {
|
|
get: function () {
|
|
// Use the default texture (1x1 white) until the model's texture is loaded
|
|
if (!defined(this._value)) {
|
|
var texture = this._textures[this._textureId];
|
|
if (defined(texture)) {
|
|
this._value = texture;
|
|
} else {
|
|
return this._defaultTexture;
|
|
}
|
|
}
|
|
|
|
return this._value;
|
|
},
|
|
set: function (value) {
|
|
this._value = value;
|
|
},
|
|
},
|
|
});
|
|
|
|
DelayLoadedTextureUniform.prototype.clone = function (source) {
|
|
return source;
|
|
};
|
|
|
|
DelayLoadedTextureUniform.prototype.func = undefined;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
function getTextureUniformFunction(value, textures, defaultTexture) {
|
|
var uniform = new DelayLoadedTextureUniform(value, textures, defaultTexture);
|
|
// Define function here to access closure since 'this' can't be
|
|
// used when the Renderer sets uniforms.
|
|
uniform.func = function () {
|
|
return uniform.value;
|
|
};
|
|
return uniform;
|
|
}
|
|
|
|
var gltfUniformFunctions = {};
|
|
gltfUniformFunctions[WebGLConstants.FLOAT] = getScalarUniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.FLOAT_VEC2] = getVec2UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.FLOAT_VEC3] = getVec3UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.FLOAT_VEC4] = getVec4UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.INT] = getScalarUniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.INT_VEC2] = getVec2UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.INT_VEC3] = getVec3UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.INT_VEC4] = getVec4UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.BOOL] = getScalarUniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.BOOL_VEC2] = getVec2UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.BOOL_VEC3] = getVec3UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.BOOL_VEC4] = getVec4UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.FLOAT_MAT2] = getMat2UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.FLOAT_MAT3] = getMat3UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.FLOAT_MAT4] = getMat4UniformFunction;
|
|
gltfUniformFunctions[WebGLConstants.SAMPLER_2D] = getTextureUniformFunction;
|
|
// GLTF_SPEC: Support SAMPLER_CUBE. https://github.com/KhronosGroup/glTF/issues/40
|
|
|
|
ModelUtility.createUniformFunction = function (
|
|
type,
|
|
value,
|
|
textures,
|
|
defaultTexture
|
|
) {
|
|
return gltfUniformFunctions[type](value, textures, defaultTexture);
|
|
};
|
|
|
|
function scaleFromMatrix5Array(matrix) {
|
|
return [
|
|
matrix[0],
|
|
matrix[1],
|
|
matrix[2],
|
|
matrix[3],
|
|
matrix[5],
|
|
matrix[6],
|
|
matrix[7],
|
|
matrix[8],
|
|
matrix[10],
|
|
matrix[11],
|
|
matrix[12],
|
|
matrix[13],
|
|
matrix[15],
|
|
matrix[16],
|
|
matrix[17],
|
|
matrix[18],
|
|
];
|
|
}
|
|
|
|
function translateFromMatrix5Array(matrix) {
|
|
return [matrix[20], matrix[21], matrix[22], matrix[23]];
|
|
}
|
|
|
|
ModelUtility.createUniformsForDracoQuantizedAttributes = function (
|
|
decodedAttributes
|
|
) {
|
|
var uniformMap = {};
|
|
for (var attribute in decodedAttributes) {
|
|
if (decodedAttributes.hasOwnProperty(attribute)) {
|
|
var decodedData = decodedAttributes[attribute];
|
|
var quantization = decodedData.quantization;
|
|
|
|
if (!defined(quantization)) {
|
|
continue;
|
|
}
|
|
|
|
if (attribute.charAt(0) === "_") {
|
|
attribute = attribute.substring(1);
|
|
}
|
|
|
|
var uniformVarName = "gltf_u_dec_" + attribute.toLowerCase();
|
|
|
|
if (quantization.octEncoded) {
|
|
var uniformVarNameRangeConstant = uniformVarName + "_rangeConstant";
|
|
var rangeConstant = (1 << quantization.quantizationBits) - 1.0;
|
|
uniformMap[uniformVarNameRangeConstant] = getScalarUniformFunction(
|
|
rangeConstant
|
|
).func;
|
|
continue;
|
|
}
|
|
|
|
var uniformVarNameNormConstant = uniformVarName + "_normConstant";
|
|
var normConstant =
|
|
quantization.range / (1 << quantization.quantizationBits);
|
|
uniformMap[uniformVarNameNormConstant] = getScalarUniformFunction(
|
|
normConstant
|
|
).func;
|
|
|
|
var uniformVarNameMin = uniformVarName + "_min";
|
|
switch (decodedData.componentsPerAttribute) {
|
|
case 1:
|
|
uniformMap[uniformVarNameMin] = getScalarUniformFunction(
|
|
quantization.minValues
|
|
).func;
|
|
break;
|
|
case 2:
|
|
uniformMap[uniformVarNameMin] = getVec2UniformFunction(
|
|
quantization.minValues
|
|
).func;
|
|
break;
|
|
case 3:
|
|
uniformMap[uniformVarNameMin] = getVec3UniformFunction(
|
|
quantization.minValues
|
|
).func;
|
|
break;
|
|
case 4:
|
|
uniformMap[uniformVarNameMin] = getVec4UniformFunction(
|
|
quantization.minValues
|
|
).func;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return uniformMap;
|
|
};
|
|
|
|
ModelUtility.createUniformsForQuantizedAttributes = function (
|
|
gltf,
|
|
primitive,
|
|
quantizedUniforms
|
|
) {
|
|
var accessors = gltf.accessors;
|
|
var setUniforms = {};
|
|
var uniformMap = {};
|
|
|
|
var attributes = primitive.attributes;
|
|
for (var attribute in attributes) {
|
|
if (attributes.hasOwnProperty(attribute)) {
|
|
var accessorId = attributes[attribute];
|
|
var a = accessors[accessorId];
|
|
var extensions = a.extensions;
|
|
|
|
if (attribute.charAt(0) === "_") {
|
|
attribute = attribute.substring(1);
|
|
}
|
|
|
|
if (defined(extensions)) {
|
|
var quantizedAttributes = extensions.WEB3D_quantized_attributes;
|
|
if (defined(quantizedAttributes)) {
|
|
var decodeMatrix = quantizedAttributes.decodeMatrix;
|
|
var uniformVariable = "gltf_u_dec_" + attribute.toLowerCase();
|
|
|
|
switch (a.type) {
|
|
case AttributeType.SCALAR:
|
|
uniformMap[uniformVariable] = getMat2UniformFunction(
|
|
decodeMatrix
|
|
).func;
|
|
setUniforms[uniformVariable] = true;
|
|
break;
|
|
case AttributeType.VEC2:
|
|
uniformMap[uniformVariable] = getMat3UniformFunction(
|
|
decodeMatrix
|
|
).func;
|
|
setUniforms[uniformVariable] = true;
|
|
break;
|
|
case AttributeType.VEC3:
|
|
uniformMap[uniformVariable] = getMat4UniformFunction(
|
|
decodeMatrix
|
|
).func;
|
|
setUniforms[uniformVariable] = true;
|
|
break;
|
|
case AttributeType.VEC4:
|
|
// VEC4 attributes are split into scale and translate because there is no mat5 in GLSL
|
|
var uniformVariableScale = uniformVariable + "_scale";
|
|
var uniformVariableTranslate = uniformVariable + "_translate";
|
|
uniformMap[uniformVariableScale] = getMat4UniformFunction(
|
|
scaleFromMatrix5Array(decodeMatrix)
|
|
).func;
|
|
uniformMap[uniformVariableTranslate] = getVec4UniformFunction(
|
|
translateFromMatrix5Array(decodeMatrix)
|
|
).func;
|
|
setUniforms[uniformVariableScale] = true;
|
|
setUniforms[uniformVariableTranslate] = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there are any unset quantized uniforms in this program, they should be set to the identity
|
|
for (var quantizedUniform in quantizedUniforms) {
|
|
if (quantizedUniforms.hasOwnProperty(quantizedUniform)) {
|
|
if (!setUniforms[quantizedUniform]) {
|
|
var properties = quantizedUniforms[quantizedUniform];
|
|
if (defined(properties.mat)) {
|
|
if (properties.mat === 2) {
|
|
uniformMap[quantizedUniform] = getMat2UniformFunction(
|
|
Matrix2.IDENTITY
|
|
).func;
|
|
} else if (properties.mat === 3) {
|
|
uniformMap[quantizedUniform] = getMat3UniformFunction(
|
|
Matrix3.IDENTITY
|
|
).func;
|
|
} else if (properties.mat === 4) {
|
|
uniformMap[quantizedUniform] = getMat4UniformFunction(
|
|
Matrix4.IDENTITY
|
|
).func;
|
|
}
|
|
}
|
|
if (defined(properties.vec)) {
|
|
if (properties.vec === 4) {
|
|
uniformMap[quantizedUniform] = getVec4UniformFunction([
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
]).func;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return uniformMap;
|
|
};
|
|
|
|
// This doesn't support LOCAL, which we could add if it is ever used.
|
|
var scratchTranslationRtc = new Cartesian3();
|
|
var gltfSemanticUniforms = {
|
|
MODEL: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.model;
|
|
};
|
|
},
|
|
VIEW: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.view;
|
|
};
|
|
},
|
|
PROJECTION: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.projection;
|
|
};
|
|
},
|
|
MODELVIEW: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.modelView;
|
|
};
|
|
},
|
|
CESIUM_RTC_MODELVIEW: function (uniformState, model) {
|
|
// CESIUM_RTC extension
|
|
var mvRtc = new Matrix4();
|
|
return function () {
|
|
if (defined(model._rtcCenter)) {
|
|
Matrix4.getTranslation(uniformState.model, scratchTranslationRtc);
|
|
Cartesian3.add(
|
|
scratchTranslationRtc,
|
|
model._rtcCenter,
|
|
scratchTranslationRtc
|
|
);
|
|
Matrix4.multiplyByPoint(
|
|
uniformState.view,
|
|
scratchTranslationRtc,
|
|
scratchTranslationRtc
|
|
);
|
|
return Matrix4.setTranslation(
|
|
uniformState.modelView,
|
|
scratchTranslationRtc,
|
|
mvRtc
|
|
);
|
|
}
|
|
return uniformState.modelView;
|
|
};
|
|
},
|
|
MODELVIEWPROJECTION: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.modelViewProjection;
|
|
};
|
|
},
|
|
MODELINVERSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.inverseModel;
|
|
};
|
|
},
|
|
VIEWINVERSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.inverseView;
|
|
};
|
|
},
|
|
PROJECTIONINVERSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.inverseProjection;
|
|
};
|
|
},
|
|
MODELVIEWINVERSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.inverseModelView;
|
|
};
|
|
},
|
|
MODELVIEWPROJECTIONINVERSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.inverseModelViewProjection;
|
|
};
|
|
},
|
|
MODELINVERSETRANSPOSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.inverseTransposeModel;
|
|
};
|
|
},
|
|
MODELVIEWINVERSETRANSPOSE: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.normal;
|
|
};
|
|
},
|
|
VIEWPORT: function (uniformState, model) {
|
|
return function () {
|
|
return uniformState.viewportCartesian4;
|
|
};
|
|
},
|
|
// JOINTMATRIX created in createCommand()
|
|
};
|
|
|
|
ModelUtility.getGltfSemanticUniforms = function () {
|
|
return gltfSemanticUniforms;
|
|
};
|
|
export default ModelUtility;
|