Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enables coloring of ModelExperimental #9881

Merged
merged 14 commits into from
Oct 22, 2021
Merged
74 changes: 74 additions & 0 deletions Source/Scene/ModelExperimental/ModelColorStage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import ColorBlendMode from "../ColorBlendMode.js";
import combine from "../../Core/combine.js";
import ModelColorStageFS from "../../Shaders/ModelExperimental/ModelColorStageFS.js";
import Pass from "../../Renderer/Pass.js";
import ShaderDestination from "../../Renderer/ShaderDestination.js";

/**
* The model color pipeline stage is responsible for handling the application of a static color to the model.
*/
var ModelColorStage = {};

ModelColorStage.COLOR_UNIFORM_NAME = "model_color";
ModelColorStage.COLOR_BLEND_UNIFORM_NAME = "model_colorBlend";

/**
* Process a model. This modifies the following parts of the render resources:
*
* <ul>
* <li>adds a define to the fragment shader to indicate that the model has a color</li>
* <li>adds a function to the fragment shader to apply the color to the model's base color</li>
* <li>adds the uniforms for the fragment shader for the model's color and blending properties</li>
* <li>updates the pass type in the render resources based on translucency of the model's color</li>
*</ul>
*
* @param {ModelRenderResources} renderResources
* @param {ModelExperimental} model
* @param {FrameState} frameState
sanjeetsuhag marked this conversation as resolved.
Show resolved Hide resolved
*/
ModelColorStage.process = function (renderResources, model, frameState) {
var shaderBuilder = renderResources.shaderBuilder;

shaderBuilder.addDefine(
"HAS_MODEL_COLOR",
undefined,
ShaderDestination.FRAGMENT
);
shaderBuilder.addFragmentLines([ModelColorStageFS]);

var stageUniforms = {};

// Pass the model's color as a uniform. Set the pass type to translucent, if needed.
var color = model.color;
if (color.alpha > 0.0 && color.alpha < 1.0) {
renderResources.alphaOptions.pass = Pass.TRANSLUCENT;
}
shaderBuilder.addUniform(
"vec4",
ModelColorStage.COLOR_UNIFORM_NAME,
ShaderDestination.FRAGMENT
);
stageUniforms[ModelColorStage.COLOR_UNIFORM_NAME] = function () {
return model.color;
};

// Create a colorBlend from the model's colorBlendMode and colorBlendAmount and pass it as a uniform.
shaderBuilder.addUniform(
"float",
ModelColorStage.COLOR_BLEND_UNIFORM_NAME,
ShaderDestination.FRAGMENT
);
stageUniforms[ModelColorStage.COLOR_BLEND_UNIFORM_NAME] = function () {
return ColorBlendMode.getColorBlend(
model.colorBlendMode,
model.colorBlendAmount
);
};

renderResources.uniformMap = combine(
stageUniforms,
renderResources.uniformMap
);
};

export default ModelColorStage;
88 changes: 88 additions & 0 deletions Source/Scene/ModelExperimental/ModelExperimental.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Check from "../../Core/Check.js";
import ColorBlendMode from "../ColorBlendMode.js";
import defined from "../../Core/defined.js";
import defaultValue from "../../Core/defaultValue.js";
import DeveloperError from "../../Core/DeveloperError.js";
Expand All @@ -12,6 +13,7 @@ import destroyObject from "../../Core/destroyObject.js";
import Matrix4 from "../../Core/Matrix4.js";
import ModelFeatureTable from "./ModelFeatureTable.js";
import B3dmLoader from "./B3dmLoader.js";
import Color from "../../Core/Color.js";

/**
* A 3D model. This is a new architecture that is more decoupled than the older {@link Model}. This class is still experimental.
Expand All @@ -33,6 +35,9 @@ import B3dmLoader from "./B3dmLoader.js";
* @param {CustomShader} [options.customShader] A custom shader. This will add user-defined GLSL code to the vertex and fragment shaders.
* @param {Cesium3DTileContent} [options.content] The tile content this model belongs to. This property will be undefined if model is not loaded as part of a tileset.
* @param {Boolean} [options.show=true] Whether or not to render the model.
* @param {Color} [options.color] A color that blends with the model's rendered color.
* @param {ColorBlendMode} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] Defines how the color blends with the model.
* @param {Number} [options.colorBlendAmount=0.5] Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
* @param {Number} [options.featureIdAttributeIndex=0] The index of the feature ID attribute to use for picking features per-instance or per-primitive.
* @param {Number} [options.featureIdTextureIndex=0] The index of the feature ID texture to use for picking features per-primitive.
*
Expand Down Expand Up @@ -70,6 +75,14 @@ export default function ModelExperimental(options) {

this._texturesLoaded = false;

var color = options.color;
this._color = defaultValue(color) ? Color.clone(color) : undefined;
this._colorBlendMode = defaultValue(
options.colorBlendMode,
ColorBlendMode.HIGHLIGHT
);
this._colorBlendAmount = defaultValue(options.colorBlendAmount, 0.5);

this._cull = defaultValue(options.cull, true);
this._opaquePass = defaultValue(options.opaquePass, Pass.OPAQUE);
this._allowPicking = defaultValue(options.allowPicking, true);
Expand Down Expand Up @@ -351,6 +364,65 @@ Object.defineProperties(ModelExperimental.prototype, {
},
},

/**
* The color to blend with the model's rendered color.
*
* @memberof ModelExperimental.prototype
*
* @type {Color}
*
* @private
*/
color: {
get: function () {
return this._color;
},
set: function (value) {
if (!Color.equals(this._color, value)) {
this.resetDrawCommands();
}
this._color = value;
},
},

/**
* Defines how the color blends with the model.
*
* @memberof ModelExperimental.prototype
*
* @type {ColorBlendMode}
* @default ColorBlendMode.HIGHLIGHT
*
* @private
*/
colorBlendMode: {
get: function () {
return this._colorBlendMode;
},
set: function (value) {
this._colorBlendMode = value;
},
},

/**
* Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
*
* @memberof ModelExperimental.prototype
*
* @type {Number}
* @default 0.5
*
* @private
*/
colorBlendAmount: {
get: function () {
return this._colorBlendAmount;
},
set: function (value) {
this._colorBlendAmount = value;
},
},

/**
* Gets the model's bounding sphere.
*
Expand Down Expand Up @@ -471,6 +543,16 @@ Object.defineProperties(ModelExperimental.prototype, {
},
});

/**
* Resets the draw commands for this model.
*
* @private
*/
ModelExperimental.prototype.resetDrawCommands = function () {
this._drawCommandsBuilt = false;
this._sceneGraph._drawCommands = [];
};

/**
* Called when {@link Viewer} or {@link CesiumWidget} render the scene to
* get the draw commands needed to render this primitive.
Expand Down Expand Up @@ -601,6 +683,9 @@ ModelExperimental.prototype.destroy = function () {
* @param {CustomShader} [options.customShader] A custom shader. This will add user-defined GLSL code to the vertex and fragment shaders.
* @param {Cesium3DTileContent} [options.content] The tile content this model belongs to. This property will be undefined if model is not loaded as part of a tileset.
* @param {Boolean} [options.show=true] Whether or not to render the model.
* @param {Color} [options.color] A color that blends with the model's rendered color.
* @param {ColorBlendMode} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] Defines how the color blends with the model.
* @param {Number} [options.colorBlendAmount=0.5] Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
* @param {Number} [options.featureIdAttributeIndex=0] The index of the feature ID attribute to use for picking features per-instance or per-primitive.
* @param {Number} [options.featureIdTextureIndex=0] The index of the feature ID texture to use for picking features per-primitive.
*
Expand Down Expand Up @@ -651,6 +736,9 @@ ModelExperimental.fromGltf = function (options) {
customShader: options.customShader,
content: options.content,
show: options.show,
color: options.color,
colorBlendAmount: options.colorBlendAmount,
colorBlendMode: options.colorBlendMode,
featureIdAttributeIndex: options.featureIdAttributeIndex,
featureIdTextureIndex: options.featureIdTextureIndex,
};
Expand Down
12 changes: 12 additions & 0 deletions Source/Scene/ModelExperimental/ModelExperimentalSceneGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Check from "../../Core/Check.js";
import defaultValue from "../../Core/defaultValue.js";
import defined from "../../Core/defined.js";
import Matrix4 from "../../Core/Matrix4.js";
import ModelColorStage from "./ModelColorStage.js";
import ModelExperimentalPrimitive from "./ModelExperimentalPrimitive.js";
import ModelExperimentalNode from "./ModelExperimentalNode.js";
import ModelExperimentalUtility from "./ModelExperimentalUtility.js";
Expand Down Expand Up @@ -192,7 +193,18 @@ ModelExperimentalSceneGraph.prototype.buildDrawCommands = function (
) {
var modelRenderResources = new ModelRenderResources(this._model);

this._pipelineStages = [];
var model = this._model;
if (defined(model.color)) {
this._pipelineStages.push(ModelColorStage);
}

var i, j, k;
for (i = 0; i < this._pipelineStages.length; i++) {
var modelPipelineStage = this._pipelineStages[i];
modelPipelineStage.process(modelRenderResources, model, frameState);
}

for (i = 0; i < this._runtimeNodes.length; i++) {
var runtimeNode = this._runtimeNodes[i];

Expand Down
22 changes: 22 additions & 0 deletions Source/Scene/ModelExperimental/ModelRenderResources.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Check from "../../Core/Check.js";
import ModelAlphaOptions from "./ModelAlphaOptions.js";
import ShaderBuilder from "../../Renderer/ShaderBuilder.js";

/**
Expand Down Expand Up @@ -34,4 +35,25 @@ export default function ModelRenderResources(model) {
* @private
*/
this.model = model;

/**
* A dictionary mapping uniform name to functions that return the uniform
* values.
*
* @type {Object.<String, Function>}
* @readonly
*
* @private
*/
this.uniformMap = {};

/**
* Options for configuring the alpha stage such as pass and alpha mode.
*
* @type {ModelAlphaOptions}
* @readonly
*
* @private
*/
this.alphaOptions = new ModelAlphaOptions();
}
24 changes: 24 additions & 0 deletions Source/Scene/ModelExperimental/NodeRenderResources.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Check from "../../Core/Check.js";
import clone from "../../Core/clone.js";

/**
* A model is made up of one or more nodes in the scene graph. Some details
Expand Down Expand Up @@ -40,6 +41,29 @@ export default function NodeRenderResources(modelRenderResources, runtimeNode) {
*/
this.shaderBuilder = modelRenderResources.shaderBuilder.clone();

/**
* A dictionary mapping uniform name to functions that return the uniform
* values. Inherited from the model render resources.
*
* @type {Object.<String, Function>}
*
* @readonly
*
* @private
*/
this.uniformMap = clone(modelRenderResources.uniformMap);

/**
* Options for configuring the alpha stage such as pass and alpha mode. Inherited from the model
* render resources.
*
* @type {ModelAlphaOptions}
* @readonly
*
* @private
*/
this.alphaOptions = clone(modelRenderResources.alphaOptions);

// other properties
/**
* A reference to the runtime node
Expand Down
44 changes: 24 additions & 20 deletions Source/Scene/ModelExperimental/PrimitiveRenderResources.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Check from "../../Core/Check.js";
import clone from "../../Core/clone.js";
import defined from "../../Core/defined.js";
import BlendingState from "../BlendingState.js";
import DepthFunction from "../DepthFunction.js";
import ModelAlphaOptions from "./ModelAlphaOptions.js";
import ModelExperimentalUtility from "./ModelExperimentalUtility.js";
import ModelLightingOptions from "./ModelLightingOptions.js";

Expand Down Expand Up @@ -86,6 +86,28 @@ export default function PrimitiveRenderResources(
*/
this.hasFeatureIds = false;

/**
* A dictionary mapping uniform name to functions that return the uniform
* values. Inherited from the node render resources.
*
* @type {Object.<String, Function>}
* @readonly
*
* @private
*/
this.uniformMap = clone(nodeRenderResources.uniformMap);

/**
* Options for configuring the alpha stage such as pass and alpha mode. Inherited from the node
* render resources.
*
* @type {ModelAlphaOptions}
* @readonly
*
* @private
*/
this.alphaOptions = clone(nodeRenderResources.alphaOptions);

/**
* The computed model matrix for this primitive. This is cloned from the
* node render resources as the primitive may further modify it
Expand Down Expand Up @@ -180,16 +202,7 @@ export default function PrimitiveRenderResources(
nodeRenderResources.instancingTranslationMax,
nodeRenderResources.instancingTranslationMin
);
/**
* A dictionary mapping uniform name to functions that return the uniform
* values.
*
* @type {Object.<String, Function>}
* @readonly
*
* @private
*/
this.uniformMap = {};

/**
* Options for configuring the lighting stage such as selecting between
* unlit and PBR shading.
Expand All @@ -200,15 +213,6 @@ export default function PrimitiveRenderResources(
* @private
*/
this.lightingOptions = new ModelLightingOptions();
/**
* Options for configuring the alpha stage such as pass and alpha mode.
*
* @type {ModelAlphaOptions}
* @readonly
*
* @private
*/
this.alphaOptions = new ModelAlphaOptions();

/**
* The shader variable to use for picking.
Expand Down
4 changes: 4 additions & 0 deletions Source/Shaders/ModelExperimental/MaterialStageFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ void materialStage(inout czm_modelMaterial material, ProcessedAttributes attribu
material.diffuse = baseColorWithAlpha.rgb;
material.alpha = baseColorWithAlpha.a;

#ifdef HAS_MODEL_COLOR
material.diffuse = mix(material.diffuse, model_color.rgb, model_colorBlend);
#endif
ptrgags marked this conversation as resolved.
Show resolved Hide resolved

#ifdef HAS_OCCLUSION_TEXTURE
vec2 occlusionTexCoords = TEXCOORD_OCCLUSION;
#ifdef HAS_OCCLUSION_TEXTURE_TRANSFORM
Expand Down
Loading