UNPKG

@cesium/engine

Version:

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

250 lines (216 loc) 7.62 kB
import AttributeType from "../AttributeType.js"; import combine from "../../Core/combine.js"; import defined from "../../Core/defined.js"; import ShaderDestination from "../../Renderer/ShaderDestination.js"; import MorphTargetsStageVS from "../../Shaders/Model/MorphTargetsStageVS.js"; import VertexAttributeSemantic from "../VertexAttributeSemantic.js"; /** * The morph targets pipeline stage processes the morph targets and weights of a primitive. * * @namespace MorphTargetsPipelineStage * * @private */ const MorphTargetsPipelineStage = { name: "MorphTargetsPipelineStage", // Helps with debugging FUNCTION_ID_GET_MORPHED_POSITION: "getMorphedPosition", FUNCTION_SIGNATURE_GET_MORPHED_POSITION: "vec3 getMorphedPosition(in vec3 position)", FUNCTION_ID_GET_MORPHED_NORMAL: "getMorphedNormal", FUNCTION_SIGNATURE_GET_MORPHED_NORMAL: "vec3 getMorphedNormal(in vec3 normal)", FUNCTION_ID_GET_MORPHED_TANGENT: "getMorphedTangent", FUNCTION_SIGNATURE_GET_MORPHED_TANGENT: "vec3 getMorphedTangent(in vec3 tangent)", }; /** * This pipeline stage processes the morph targets and weights of a primitive, * adding the relevant attribute declarations and functions to the shaders. * * Processes a primitive. This stage modifies the following parts of the render resources: * <ul> * <li> adds attribute declarations for the morph targets in the vertex shader * <li> adds the uniform declaration for the morph weights in the vertex shader * <li> adds functions to apply the morphs in the vertex shader * </ul> * * @param {PrimitiveRenderResources} renderResources The render resources for this primitive. * @param {ModelComponents.Primitive} primitive The primitive. * * @private */ MorphTargetsPipelineStage.process = function (renderResources, primitive) { const shaderBuilder = renderResources.shaderBuilder; shaderBuilder.addDefine( "HAS_MORPH_TARGETS", undefined, ShaderDestination.VERTEX, ); addGetMorphedAttributeFunctionDeclarations(shaderBuilder); const morphTargetsLength = primitive.morphTargets.length; for (let i = 0; i < morphTargetsLength; i++) { const attributes = primitive.morphTargets[i].attributes; const attributesLength = attributes.length; for (let j = 0; j < attributesLength; j++) { const attribute = attributes[j]; const semantic = attribute.semantic; // Cesium only supports morph targets for positions, normals, and tangents if ( semantic !== VertexAttributeSemantic.POSITION && semantic !== VertexAttributeSemantic.NORMAL && semantic !== VertexAttributeSemantic.TANGENT ) { continue; } processMorphTargetAttribute( renderResources, attribute, renderResources.attributeIndex, i, ); renderResources.attributeIndex++; } } addGetMorphedAttributeFunctionReturns(shaderBuilder); const weights = renderResources.runtimeNode.morphWeights; const weightsLength = weights.length; shaderBuilder.addUniform( "float", `u_morphWeights[${weightsLength}]`, ShaderDestination.VERTEX, ); shaderBuilder.addVertexLines(MorphTargetsStageVS); const uniformMap = { u_morphWeights: function () { return renderResources.runtimeNode.morphWeights; }, }; renderResources.uniformMap = combine(uniformMap, renderResources.uniformMap); }; const scratchAttributeInfo = { attributeString: undefined, functionId: undefined, }; function processMorphTargetAttribute( renderResources, attribute, attributeIndex, morphTargetIndex, ) { const shaderBuilder = renderResources.shaderBuilder; addMorphTargetAttributeToRenderResources( renderResources, attribute, attributeIndex, ); const attributeInfo = getMorphTargetAttributeInfo( attribute, scratchAttributeInfo, ); addMorphTargetAttributeDeclarationAndFunctionLine( shaderBuilder, attributeInfo, morphTargetIndex, ); } function addMorphTargetAttributeToRenderResources( renderResources, attribute, attributeIndex, ) { const vertexAttribute = { index: attributeIndex, value: defined(attribute.buffer) ? undefined : attribute.constant, vertexBuffer: attribute.buffer, componentsPerAttribute: AttributeType.getNumberOfComponents(attribute.type), componentDatatype: attribute.componentDatatype, offsetInBytes: attribute.byteOffset, strideInBytes: attribute.byteStride, normalize: attribute.normalized, }; renderResources.attributes.push(vertexAttribute); } function getMorphTargetAttributeInfo(attribute, result) { const semantic = attribute.semantic; switch (semantic) { case VertexAttributeSemantic.POSITION: result.attributeString = "Position"; result.functionId = MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_POSITION; break; case VertexAttributeSemantic.NORMAL: result.attributeString = "Normal"; result.functionId = MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_NORMAL; break; case VertexAttributeSemantic.TANGENT: result.attributeString = "Tangent"; result.functionId = MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_TANGENT; break; default: break; } return result; } function addMorphTargetAttributeDeclarationAndFunctionLine( shaderBuilder, attributeInfo, morphTargetIndex, ) { const attributeString = attributeInfo.attributeString; const attributeName = `a_target${attributeString}_${morphTargetIndex}`; const line = `morphed${attributeString} += u_morphWeights[${morphTargetIndex}] * a_target${attributeString}_${morphTargetIndex};`; shaderBuilder.addAttribute("vec3", attributeName); shaderBuilder.addFunctionLines(attributeInfo.functionId, [line]); } function addGetMorphedAttributeFunctionDeclarations(shaderBuilder) { shaderBuilder.addFunction( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_POSITION, MorphTargetsPipelineStage.FUNCTION_SIGNATURE_GET_MORPHED_POSITION, ShaderDestination.VERTEX, ); const positionLine = "vec3 morphedPosition = position;"; shaderBuilder.addFunctionLines( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_POSITION, [positionLine], ); shaderBuilder.addFunction( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_NORMAL, MorphTargetsPipelineStage.FUNCTION_SIGNATURE_GET_MORPHED_NORMAL, ShaderDestination.VERTEX, ); const normalLine = "vec3 morphedNormal = normal;"; shaderBuilder.addFunctionLines( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_NORMAL, [normalLine], ); shaderBuilder.addFunction( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_TANGENT, MorphTargetsPipelineStage.FUNCTION_SIGNATURE_GET_MORPHED_TANGENT, ShaderDestination.VERTEX, ); const tangentLine = "vec3 morphedTangent = tangent;"; shaderBuilder.addFunctionLines( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_TANGENT, [tangentLine], ); } function addGetMorphedAttributeFunctionReturns(shaderBuilder) { const positionLine = "return morphedPosition;"; shaderBuilder.addFunctionLines( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_POSITION, [positionLine], ); const normalLine = "return morphedNormal;"; shaderBuilder.addFunctionLines( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_NORMAL, [normalLine], ); const tangentLine = "return morphedTangent;"; shaderBuilder.addFunctionLines( MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_TANGENT, [tangentLine], ); } export default MorphTargetsPipelineStage;