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

Generate outlines 2 #75

Draft
wants to merge 19 commits into
base: terriajs
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Source/DataSources/ModelGraphics.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ function createArticulationStagePropertyBag(value) {
* @property {PropertyBag | Object.<string, TranslationRotationScale>} [nodeTransformations] An object, where keys are names of nodes, and values are {@link TranslationRotationScale} Properties describing the transformation to apply to that node. The transformation is applied after the node's existing transformation as specified in the glTF, and does not replace the node's existing transformation.
* @property {PropertyBag | Object.<string, number>} [articulations] An object, where keys are composed of an articulation name, a single space, and a stage name, and the values are numeric properties.
* @property {Property | ClippingPlaneCollection} [clippingPlanes] A property specifying the {@link ClippingPlaneCollection} used to selectively disable rendering the model.
* @property {Property | ModelOutlineGenerationMode} [options.outlineGenerationMode] A property that determines whether outlines should be generated for this model.
* @property {Property | Number} [options.outlineGenerationMinimumAngle] A property that if generating outlines for this model, determines what the minimum angle between the normals of two faces has to be for the edge between them to receive an outline.
*/

/**
Expand Down Expand Up @@ -108,6 +110,8 @@ function ModelGraphics(options) {
this._articulationsSubscription = undefined;
this._clippingPlanes = undefined;
this._clippingPlanesSubscription = undefined;
this._outlineGenerationMode = undefined;
this._outlineGenerationMinimumAngle = undefined;

this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
}
Expand Down Expand Up @@ -312,6 +316,22 @@ Object.defineProperties(ModelGraphics.prototype, {
*/
clippingPlanes: createPropertyDescriptor("clippingPlanes"),

/**
* A property that determines whether outlines should be generated for this model.
* @memberof ModelGraphics.prototype
* @type {Property|undefined}
*/
outlineGenerationMode: createPropertyDescriptor("outlineGenerationMode"),

/**
* A property that if generating outlines for this model, determines what the minimum angle between the normals of two faces has to be for the edge between them to receive an outline.
* @memberof ModelGraphics.prototype
* @type {Property|undefined}
*/
outlineGenerationMinimumAngle: createPropertyDescriptor(
"outlineGenerationMinimumAngle"
),

/**
* A property specifying the {@link Axis} up axis of the model.
* @memberOf ModelGraphics.prototype
Expand Down Expand Up @@ -357,6 +377,8 @@ ModelGraphics.prototype.clone = function (result) {
result.nodeTransformations = this.nodeTransformations;
result.articulations = this.articulations;
result.clippingPlanes = this.clippingPlanes;
result.outlineGenerationMode = this.outlineGenerationMode;
result.outlineGenerationMinimumAngle = this.outlineGenerationMinimumAngle;
return result;
};

Expand Down Expand Up @@ -427,6 +449,14 @@ ModelGraphics.prototype.merge = function (source) {
this.clippingPlanes,
source.clippingPlanes
);
this.outlineGenerationMode = defaultValue(
this.outlineGenerationMode,
source.outlineGenerationMode
);
this.outlineGenerationMinimumAngle = defaultValue(
this.outlineGenerationMinimumAngle,
source.outlineGenerationMinimumAngle
);

var sourceNodeTransformations = source.nodeTransformations;
if (defined(sourceNodeTransformations)) {
Expand Down
16 changes: 16 additions & 0 deletions Source/DataSources/ModelVisualizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ ModelVisualizer.prototype.update = function (time) {
defaultIncrementallyLoadTextures
),
scene: this._scene,
outlineGenerationMode: Property.getValueOrDefault(
modelGraphics._outlineGenerationMode,
time
),
outlineGenerationMinimumAngle: Property.getValueOrDefault(
modelGraphics._outlineGenerationMinimumAngle,
time
),
});
model.id = entity;
primitives.add(model);
Expand Down Expand Up @@ -224,6 +232,14 @@ ModelVisualizer.prototype.update = function (time) {
modelGraphics._forwardAxis,
time
);
model._outlineGenerationMode = Property.getValueOrUndefined(
modelGraphics._outlineGenerationMode,
time
);
model._outlineGenerationMinimumAngle = Property.getValueOrUndefined(
modelGraphics._outlineGenerationMinimumAngle,
time
);

if (model.ready) {
var runAnimations = Property.getValueOrDefault(
Expand Down
4 changes: 4 additions & 0 deletions Source/Scene/Batched3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ function initialize(content, arrayBuffer, byteOffset) {
sphericalHarmonicCoefficients: tileset.sphericalHarmonicCoefficients,
specularEnvironmentMaps: tileset.specularEnvironmentMaps,
backFaceCulling: tileset.backFaceCulling,
outlineGenerationMode: tileset.outlineGenerationMode,
outlineGenerationMinimumAngle: tileset.outlineGenerationMinimumAngle
});
content._model.readyPromise.then(function (model) {
model.activeAnimations.addAll({
Expand Down Expand Up @@ -541,6 +543,8 @@ Batched3DModel3DTileContent.prototype.update = function (tileset, frameState) {
this._model.sphericalHarmonicCoefficients = this._tileset.sphericalHarmonicCoefficients;
this._model.specularEnvironmentMaps = this._tileset.specularEnvironmentMaps;
this._model.backFaceCulling = this._tileset.backFaceCulling;
this._model.outlineGenerationMode = this._tileset.outlineGenerationMode;
this._model.outlineGenerationMinimumAngle = this._tileset.outlineGenerationMinimumAngle;
this._model.debugWireframe = this._tileset.debugWireframe;

// Update clipping planes
Expand Down
38 changes: 38 additions & 0 deletions Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import StencilConstants from "./StencilConstants.js";
import TileBoundingRegion from "./TileBoundingRegion.js";
import TileBoundingSphere from "./TileBoundingSphere.js";
import TileOrientedBoundingBox from "./TileOrientedBoundingBox.js";
import ModelOutlineGenerationMode from "./ModelOutlineGenerationMode.js";

/**
* A {@link https://github.com/CesiumGS/3d-tiles/tree/master/specification|3D Tiles tileset},
Expand Down Expand Up @@ -90,6 +91,8 @@ import TileOrientedBoundingBox from "./TileOrientedBoundingBox.js";
* @param {Cartesian3[]} [options.sphericalHarmonicCoefficients] The third order spherical harmonic coefficients used for the diffuse color of image-based lighting.
* @param {String} [options.specularEnvironmentMaps] A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
* @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the glTF material's doubleSided property; when false, back face culling is disabled.
* @param {ModelOutlineGenerationMode} [options.outlineGenerationMode] Determines whether outlines should be generated for this model.
* @param {Number} [options.outlineGenerationMinimumAngle] If generating outlines for this model, determines what the minimum angle between the normals of two faces has to be for the edge between them to receive an outline.
* @param {String} [options.debugHeatmapTilePropertyName] The tile variable to colorize as a heatmap. All rendered tiles will be colorized relative to each other's specified variable value.
* @param {Boolean} [options.debugFreezeFrame=false] For debugging only. Determines if only the tiles from last frame should be used for rendering.
* @param {Boolean} [options.debugColorizeTiles=false] For debugging only. When true, assigns a random color to each tile.
Expand Down Expand Up @@ -760,6 +763,41 @@ function Cesium3DTileset(options) {
*/
this.backFaceCulling = defaultValue(options.backFaceCulling, true);

/**
* Determines whether outlines should be generated for this tileset.
*
* @type {ModelOutlineGenerationMode}
*
* @default ModelOutlineGenerationMode.USE_GLTF_SETTINGS
*
* @see ModelOutlineGenerator
*/
this.outlineGenerationMode = defaultValue(
options.outlineGenerationMode,
ModelOutlineGenerationMode.USE_GLTF_SETTINGS
);

/**
* If generating outlines for this model, determines what the minimum angle
* between the normals of two faces has to be for the edge between them to
* receive an outline.
*
* This follows @see Cesium3DTileset.outlineGenerationMode — if outlineGenerationMode is
* OFF or USE_GLTF_SETTINGS, this value will be ignored. If undefined, it will
* use the value from the glTF if it exists, or otherwise the default value
* specified by ModelOutlineGenerator.
*
* @type {number}
*
* @default undefined
*
* @see ModelOutlineGenerator
*/
this.outlineGenerationMinimumAngle = defaultValue(
options.outlineGenerationMinimumAngle,
undefined
);

/**
* This property is for debugging only; it is not optimized for production use.
* <p>
Expand Down
79 changes: 58 additions & 21 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import processModelMaterialsCommon from "./processModelMaterialsCommon.js";
import processPbrMaterials from "./processPbrMaterials.js";
import SceneMode from "./SceneMode.js";
import ShadowMode from "./ShadowMode.js";
import ModelOutlineGenerationMode from "./ModelOutlineGenerationMode.js";

var boundingSphereCartesian3Scratch = new Cartesian3();

Expand Down Expand Up @@ -317,6 +318,41 @@ function Model(options) {
*/
this.silhouetteSize = defaultValue(options.silhouetteSize, 0.0);

/**
* Determines whether outlines should be generated for this model.
*
* @type {ModelOutlineGenerationMode}
*
* @default ModelOutlineGenerationMode.USE_GLTF_SETTINGS
*
* @see ModelOutlineGenerator
*/
this.outlineGenerationMode = defaultValue(
options.outlineGenerationMode,
ModelOutlineGenerationMode.USE_GLTF_SETTINGS
);

/**
* If generating outlines for this model, determines what the minimum angle
* between the normals of two faces has to be for the edge between them to
* receive an outline.
*
* This follows @see Model.outlineGenerationMode — if outlineGenerationMode is
* OFF or USE_GLTF_SETTINGS, this value will be ignored. If undefined, it will
* use the value from the glTF if it exists, or otherwise the default value
* specified by ModelOutlineGenerator.
*
* @type {number}
*
* @default undefined
*
* @see ModelOutlineGenerator
*/
this.outlineGenerationMinimumAngle = defaultValue(
options.outlineGenerationMinimumAngle,
undefined
);

/**
* The 4x4 transformation matrix that transforms the model from model to world coordinates.
* When this is the identity matrix, the model is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
Expand Down Expand Up @@ -1385,6 +1421,8 @@ function containsGltfMagic(uint8Array) {
* @param {Boolean} [options.dequantizeInShader=true] Determines if a {@link https://github.com/google/draco|Draco} encoded model is dequantized on the GPU. This decreases total memory usage for encoded models.
* @param {Credit|String} [options.credit] A credit for the model, which is displayed on the canvas.
* @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the material's doubleSided property; when false, back face culling is disabled. Back faces are not culled if {@link Model#color} is translucent or {@link Model#silhouetteSize} is greater than 0.0.
* @param {ModelOutlineGenerationMode} [options.outlineGenerationMode] Determines whether outlines should be generated for this model.
* @param {Number} [options.outlineGenerationMinimumAngle] If generating outlines for this model, determines what the minimum angle between the normals of two faces has to be for the edge between them to receive an outline.
*
* @returns {Model} The newly created model.
*
Expand Down Expand Up @@ -2454,16 +2492,15 @@ function createProgram(programToCreate, model, context) {
var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded);
var drawFS = modifyShader(fs, programId, model._fragmentShaderLoaded);


if (isOutline) {
drawFS = drawFS.replace(
"czm_writeLogDepth();",
" czm_writeLogDepth();\n" +
"#if defined(LOG_DEPTH) && !defined(DISABLE_LOG_DEPTH_FRAGMENT_WRITE)\n" +
" gl_FragDepthEXT -= 5e-5;\n" +
"#endif"
);
}
if (isOutline) {
drawFS = drawFS.replace(
"czm_writeLogDepth();",
" czm_writeLogDepth();\n" +
"#if defined(LOG_DEPTH) && !defined(DISABLE_LOG_DEPTH_FRAGMENT_WRITE)\n" +
" gl_FragDepthEXT -= 5e-5;\n" +
"#endif"
);
}
if (!defined(model._uniformMapLoaded)) {
drawFS = "uniform vec4 czm_pickColor;\n" + drawFS;
}
Expand Down Expand Up @@ -2582,17 +2619,16 @@ function recreateProgram(programToCreate, model, context) {
var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded);
var drawFS = modifyShader(finalFS, programId, model._fragmentShaderLoaded);


var isOutline = program.isOutline;
if (isOutline) {
drawFS = drawFS.replace(
"czm_writeLogDepth();",
" czm_writeLogDepth();\n" +
"#if defined(LOG_DEPTH) && !defined(DISABLE_LOG_DEPTH_FRAGMENT_WRITE)\n" +
" gl_FragDepthEXT -= 5e-5;\n" +
"#endif"
);
}
var isOutline = program.isOutline;
if (isOutline) {
drawFS = drawFS.replace(
"czm_writeLogDepth();",
" czm_writeLogDepth();\n" +
"#if defined(LOG_DEPTH) && !defined(DISABLE_LOG_DEPTH_FRAGMENT_WRITE)\n" +
" gl_FragDepthEXT -= 5e-5;\n" +
"#endif"
);
}
if (!defined(model._uniformMapLoaded)) {
drawFS = "uniform vec4 czm_pickColor;\n" + drawFS;
}
Expand Down Expand Up @@ -5276,6 +5312,7 @@ Model.prototype.update = function (frameState) {

var options = {
addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders,
outlineGenerationMode: this.outlineGenerationMode,
};

processModelMaterialsCommon(gltf, options);
Expand Down
18 changes: 18 additions & 0 deletions Source/Scene/ModelOutlineGenerationMode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Defines different modes for automatically generating outlines for models.
*
* USE_GLTF_SETTINGS will follow whatever is set in the glTF underlying the model.
* OFF forces outlines to not be generated, overriding what is specified in the model.
* ON forces outlines to be generated, overriding what is specified in the model.
*
* @enum {Number}
*
* @see Model.generateOutlines
*/
var ModelOutlineGenerationMode = {
OFF: 0,
ON: 1,
USE_GLTF_SETTINGS: 2,
};

export default Object.freeze(ModelOutlineGenerationMode);
Loading