UNPKG

cesium

Version:

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

249 lines (216 loc) 7.79 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/ModelExperimental/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 = {}; MorphTargetsPipelineStage.name = "MorphTargetsPipelineStage"; // Helps with debugging MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_POSITION = "getMorphedPosition"; MorphTargetsPipelineStage.FUNCTION_SIGNATURE_GET_MORPHED_POSITION = "vec3 getMorphedPosition(in vec3 position)"; MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_NORMAL = "getMorphedNormal"; MorphTargetsPipelineStage.FUNCTION_SIGNATURE_GET_MORPHED_NORMAL = "vec3 getMorphedNormal(in vec3 normal)"; MorphTargetsPipelineStage.FUNCTION_ID_GET_MORPHED_TANGENT = "getMorphedTangent"; MorphTargetsPipelineStage.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;