cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
187 lines (164 loc) • 5.98 kB
JavaScript
import defaultValue from "../../Core/defaultValue.js";
import defined from "../../Core/defined.js";
import ShaderDestination from "../../Renderer/ShaderDestination.js";
import SelectedFeatureIdStageCommon from "../../Shaders/ModelExperimental/SelectedFeatureIdStageCommon.js";
import ModelComponents from "../ModelComponents.js";
import ModelExperimentalUtility from "./ModelExperimentalUtility.js";
/**
* The selected feature ID pipeline stage is responsible for handling the
* set of feature IDs selected for styling/picking.
*
* @namespace SelectedFeatureIdPipelineStage
* @private
*/
const SelectedFeatureIdPipelineStage = {};
SelectedFeatureIdPipelineStage.name = "SelectedFeatureIdPipelineStage"; // Helps with debugging
SelectedFeatureIdPipelineStage.STRUCT_ID_SELECTED_FEATURE = "SelectedFeature";
SelectedFeatureIdPipelineStage.STRUCT_NAME_SELECTED_FEATURE = "SelectedFeature";
SelectedFeatureIdPipelineStage.FUNCTION_ID_FEATURE_VARYINGS_VS =
"updateFeatureStructVS";
SelectedFeatureIdPipelineStage.FUNCTION_ID_FEATURE_VARYINGS_FS =
"updateFeatureStructFS";
SelectedFeatureIdPipelineStage.FUNCTION_SIGNATURE_UPDATE_FEATURE =
"void updateFeatureStruct(inout SelectedFeature feature)";
/**
* Process a primitive. This modifies the following parts of the render resources:
* <ul>
* <li>sets the defines for the feature ID attribute to use for styling/picking</li>
* <li>adds fields to the SelectedFeature struct in the shader</li>
* </ul>
*
* @param {PrimitiveRenderResources} renderResources The render resources for this primitive.
* @param {ModelComponents.Primitive} primitive The primitive.
* @param {FrameState} frameState The frame state.
*/
SelectedFeatureIdPipelineStage.process = function (
renderResources,
primitive,
frameState
) {
const shaderBuilder = renderResources.shaderBuilder;
renderResources.hasPropertyTable = true;
const model = renderResources.model;
const node = renderResources.runtimeNode.node;
const selectedFeatureIds = getSelectedFeatureIds(model, node, primitive);
const shaderDestination = selectedFeatureIds.shaderDestination;
shaderBuilder.addDefine(
"HAS_SELECTED_FEATURE_ID",
undefined,
shaderDestination
);
// Add a define to insert the variable to use.
// Example: #define SELECTED_FEATURE_ID featureId_1
// This corresponds to featureIds.featureId_1
shaderBuilder.addDefine(
"SELECTED_FEATURE_ID",
selectedFeatureIds.variableName,
shaderDestination
);
// Add a define to the shader to distinguish feature ID attributes from
// textures. This is needed for determining where to filter features
// by pass type.
shaderBuilder.addDefine(
selectedFeatureIds.featureIdDefine,
undefined,
shaderDestination
);
updateFeatureStruct(shaderBuilder);
const nullFeatureId = selectedFeatureIds.featureIds.nullFeatureId;
const uniformMap = renderResources.uniformMap;
if (defined(nullFeatureId)) {
shaderBuilder.addDefine(
"HAS_NULL_FEATURE_ID",
undefined,
shaderDestination
);
shaderBuilder.addUniform("int", "model_nullFeatureId", shaderDestination);
uniformMap.model_nullFeatureId = function () {
return nullFeatureId;
};
}
if (selectedFeatureIds.shaderDestination === ShaderDestination.BOTH) {
shaderBuilder.addVertexLines([SelectedFeatureIdStageCommon]);
}
shaderBuilder.addFragmentLines([SelectedFeatureIdStageCommon]);
};
function getFeatureIdDefine(featureIds) {
if (featureIds instanceof ModelComponents.FeatureIdTexture) {
return "HAS_SELECTED_FEATURE_ID_TEXTURE";
}
return "HAS_SELECTED_FEATURE_ID_ATTRIBUTE";
}
function getShaderDestination(featureIds) {
// Feature ID textures are only supported in the fragment shader.
if (featureIds instanceof ModelComponents.FeatureIdTexture) {
return ShaderDestination.FRAGMENT;
}
return ShaderDestination.BOTH;
}
function getSelectedFeatureIds(model, node, primitive) {
let variableName;
let featureIds;
// Check instances first, as this is the most specific type of
// feature ID
if (defined(node.instances)) {
featureIds = ModelExperimentalUtility.getFeatureIdsByLabel(
node.instances.featureIds,
model.instanceFeatureIdLabel
);
if (defined(featureIds)) {
// Either label could be used here, but prefer label as it may be more
// meaningful when debugging
variableName = defaultValue(featureIds.label, featureIds.positionalLabel);
return {
featureIds: featureIds,
variableName: variableName,
shaderDestination: getShaderDestination(featureIds),
featureIdDefine: getFeatureIdDefine(featureIds),
};
}
}
featureIds = ModelExperimentalUtility.getFeatureIdsByLabel(
primitive.featureIds,
model.featureIdLabel
);
// again, prefer label for being more descriptive
variableName = defaultValue(featureIds.label, featureIds.positionalLabel);
return {
featureIds: featureIds,
variableName: variableName,
shaderDestination: getShaderDestination(featureIds),
featureIdDefine: getFeatureIdDefine(featureIds),
};
}
/**
* Populate the "SelectedFeature" struct in the shaders that holds information about the "active" (used for picking/styling) feature.
* The struct is always added to the shader by the GeometryPipelineStage (required for compilation). The SelectedFeature struct looks
* as follows:
*
* struct SelectedFeature {
* int id;
* vec2 st;
* vec4 color;
* }
*
* @private
*/
function updateFeatureStruct(shaderBuilder) {
shaderBuilder.addStructField(
SelectedFeatureIdPipelineStage.STRUCT_ID_SELECTED_FEATURE,
"int",
"id"
);
shaderBuilder.addStructField(
SelectedFeatureIdPipelineStage.STRUCT_ID_SELECTED_FEATURE,
"vec2",
"st"
);
shaderBuilder.addStructField(
SelectedFeatureIdPipelineStage.STRUCT_ID_SELECTED_FEATURE,
"vec4",
"color"
);
}
export default SelectedFeatureIdPipelineStage;