UNPKG

@cesium/engine

Version:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.

119 lines (99 loc) 3.92 kB
import combine from "../../Core/combine.js"; import ShaderDestination from "../../Renderer/ShaderDestination.js"; import SkinningStageVS from "../../Shaders/Model/SkinningStageVS.js"; import VertexAttributeSemantic from "../VertexAttributeSemantic.js"; /** * The skinning pipeline stage processes the joint matrices of a skinned primitive. * * @namespace SkinningPipelineStage * * @private */ const SkinningPipelineStage = { name: "SkinningPipelineStage", // Helps with debugging FUNCTION_ID_GET_SKINNING_MATRIX: "getSkinningMatrix", FUNCTION_SIGNATURE_GET_SKINNING_MATRIX: "mat4 getSkinningMatrix()", }; /** * This pipeline stage processes the joint matrices of a skinned primitive, adding * the relevant functions and uniforms to the shaders. The joint and weight attributes * themselves are processed in the geometry pipeline stage. * * Processes a primitive. This stage modifies the following parts of the render resources: * <ul> * <li> adds the uniform declaration for the joint matrices in the vertex shader</li> * <li> adds the function to compute the skinning matrix in the vertex shader</li> * </ul> * * @param {PrimitiveRenderResources} renderResources The render resources for this primitive. * @param {ModelComponents.Primitive} primitive The primitive. * @private */ SkinningPipelineStage.process = function (renderResources, primitive) { const shaderBuilder = renderResources.shaderBuilder; shaderBuilder.addDefine("HAS_SKINNING", undefined, ShaderDestination.VERTEX); addGetSkinningMatrixFunction(shaderBuilder, primitive); const runtimeNode = renderResources.runtimeNode; const jointMatrices = runtimeNode.computedJointMatrices; shaderBuilder.addUniform( "mat4", `u_jointMatrices[${jointMatrices.length}]`, ShaderDestination.VERTEX, ); shaderBuilder.addVertexLines(SkinningStageVS); const uniformMap = { u_jointMatrices: function () { return runtimeNode.computedJointMatrices; }, }; renderResources.uniformMap = combine(uniformMap, renderResources.uniformMap); }; function getMaximumAttributeSetIndex(primitive) { let setIndex = -1; const attributes = primitive.attributes; const length = attributes.length; for (let i = 0; i < length; i++) { const attribute = attributes[i]; const isJointsOrWeights = attribute.semantic === VertexAttributeSemantic.JOINTS || attribute.semantic === VertexAttributeSemantic.WEIGHTS; if (!isJointsOrWeights) { continue; } setIndex = Math.max(setIndex, attribute.setIndex); } return setIndex; } function addGetSkinningMatrixFunction(shaderBuilder, primitive) { shaderBuilder.addFunction( SkinningPipelineStage.FUNCTION_ID_GET_SKINNING_MATRIX, SkinningPipelineStage.FUNCTION_SIGNATURE_GET_SKINNING_MATRIX, ShaderDestination.VERTEX, ); const initialLine = "mat4 skinnedMatrix = mat4(0);"; shaderBuilder.addFunctionLines( SkinningPipelineStage.FUNCTION_ID_GET_SKINNING_MATRIX, [initialLine], ); let setIndex; let componentIndex; const componentStrings = ["x", "y", "z", "w"]; const maximumSetIndex = getMaximumAttributeSetIndex(primitive); for (setIndex = 0; setIndex <= maximumSetIndex; setIndex++) { for (componentIndex = 0; componentIndex <= 3; componentIndex++) { const component = componentStrings[componentIndex]; // Example: skinnedMatrix += a_weights_0.x * u_jointMatrices[int(a_joints_0.x)]; const line = `skinnedMatrix += a_weights_${setIndex}.${component} * u_jointMatrices[int(a_joints_${setIndex}.${component})];`; shaderBuilder.addFunctionLines( SkinningPipelineStage.FUNCTION_ID_GET_SKINNING_MATRIX, [line], ); } } const returnLine = "return skinnedMatrix;"; shaderBuilder.addFunctionLines( SkinningPipelineStage.FUNCTION_ID_GET_SKINNING_MATRIX, [returnLine], ); } export default SkinningPipelineStage;