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

Allow users to define clipping regions with polygons #11750

Merged
merged 31 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
77bb0d1
ClippingPolygonCollection
ggetz Jan 9, 2024
eab1d19
Fix TS
ggetz Jan 9, 2024
0140ce0
Update CHANGES.md
ggetz Jan 9, 2024
15cad35
Draft
ggetz Mar 12, 2024
5079310
Merge branch 'main' into clip-region
ggetz Mar 12, 2024
7a789fd
Draft 2
ggetz Mar 13, 2024
70f1170
Merge branch 'main' into clip-region
ggetz Mar 15, 2024
b5ba48d
Draft
ggetz Mar 18, 2024
c185b7b
Merge branch 'main' into clip-region
ggetz Mar 18, 2024
fe5704e
Start cleanup
ggetz Mar 19, 2024
f42b7db
Update Specs
ggetz Mar 22, 2024
be45ded
Update clipping plane performance, wire through terrain clipping
ggetz Mar 25, 2024
c624775
Merge branch 'main' into clip-region
ggetz Mar 25, 2024
aca4f14
cleanup doc
ggetz Mar 25, 2024
3158943
Cleanup private classes
ggetz Mar 25, 2024
e87589d
Fix jagged edges
ggetz Apr 3, 2024
7305ce1
Specs cleanup
ggetz Apr 5, 2024
1b24f93
More specs
ggetz Apr 5, 2024
3cf00dc
More specs
ggetz Apr 5, 2024
58b5a42
Cleanup AEC example for tutorial
ggetz Apr 10, 2024
73cf3e2
Fix typos and whitespace
Apr 10, 2024
a43d78f
Fix typos and whitespace
Apr 11, 2024
dc84c67
Feedback from PR
ggetz Apr 12, 2024
3ac081f
Fix issue with terrain when zoomed out
ggetz Apr 15, 2024
38a2b9d
Update tests
ggetz Apr 16, 2024
e69d21f
Fix P3DT not clipping when zoomed out
ggetz Apr 16, 2024
b32fa28
Cleanup:
ggetz Apr 17, 2024
0f5c0a3
Cleanup
ggetz Apr 17, 2024
859abb9
Fix minor docs typos
Apr 22, 2024
71f7197
Fix sandcastle angle, too agressive simplification
ggetz Apr 23, 2024
620a0ec
Adjust clip polygon region combining
ggetz Apr 26, 2024
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Feedback from PR
  • Loading branch information
ggetz committed Apr 12, 2024
commit dc84c6758f27b1b667eb0ec42a18b87b7c909948
14 changes: 8 additions & 6 deletions Specs/ShaderBuilderTester.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ ShaderBuilderTester.expectHasVaryings = function (
shaderBuilder,
expectedVaryings
) {
expectEqualUnordered(
shaderBuilder._vertexShaderParts.varyingLines,
expectedVaryings.map((varying) => `out ${varying}`)
expect(shaderBuilder._vertexShaderParts.varyingLines).toEqual(
jasmine.arrayWithExactContents(
expectedVaryings.map((varying) => jasmine.stringContaining(varying))
)
);
expectEqualUnordered(
shaderBuilder._fragmentShaderParts.varyingLines,
expectedVaryings.map((varying) => `in ${varying}`)
expect(shaderBuilder._fragmentShaderParts.varyingLines).toEqual(
jasmine.arrayWithExactContents(
expectedVaryings.map((varying) => jasmine.stringContaining(varying))
)
);
};

Expand Down
9 changes: 6 additions & 3 deletions packages/engine/Source/Renderer/ShaderBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,21 +369,24 @@ ShaderBuilder.prototype.addAttribute = function (type, identifier) {
*
* @param {string} type The GLSL type of the varying
* @param {string} identifier An identifier for the varying. Identifiers must begin with <code>v_</code> to be consistent with Cesium's style guide.
* @param {string} [qualifier] A qualifier for the varying, such as <code>flat</code>.
*
* @example
* // creates the line "in vec3 v_color;" in the vertex shader
* // creates the line "out vec3 v_color;" in the fragment shader
* shaderBuilder.addVarying("vec3", "v_color");
*/
ShaderBuilder.prototype.addVarying = function (type, identifier) {
ShaderBuilder.prototype.addVarying = function (type, identifier, qualifier) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("type", type);
Check.typeOf.string("identifier", identifier);
//>>includeEnd('debug');

qualifier = defined(qualifier) ? `${qualifier} ` : "";

const line = `${type} ${identifier};`;
this._vertexShaderParts.varyingLines.push(`out ${line}`);
this._fragmentShaderParts.varyingLines.push(`in ${line}`);
this._vertexShaderParts.varyingLines.push(`${qualifier}out ${line}`);
this._fragmentShaderParts.varyingLines.push(`${qualifier}in ${line}`);
};

/**
Expand Down
16 changes: 14 additions & 2 deletions packages/engine/Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -802,10 +802,22 @@ function Cesium3DTileset(options) {
this.loadSiblings = defaultValue(options.loadSiblings, false);

this._clippingPlanes = undefined;
this.clippingPlanes = options.clippingPlanes;
if (defined(options.clippingPlanes)) {
ClippingPlaneCollection.setOwner(
options.clippingPlanes,
this,
"_clippingPlanes"
);
}

this._clippingPolygons = undefined;
this.clippingPolygons = options.clippingPolygons;
if (defined(options.clippingPolygons)) {
ClippingPolygonCollection.setOwner(
options.clippingPolygons,
this,
"_clippingPolygons"
);
}

if (defined(options.imageBasedLighting)) {
this._imageBasedLighting = options.imageBasedLighting;
Expand Down
6 changes: 6 additions & 0 deletions packages/engine/Source/Scene/ClippingPolygon.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ ClippingPolygon.prototype.computeSphericalExtents = function (result) {
result.north = sphereLatitude;
result.east = sphereLongitude;

// Slightly pad extents to avoid floating point error when fragment culling at edges.
result.south -= CesiumMath.EPSILON5;
result.west -= CesiumMath.EPSILON5;
result.north += CesiumMath.EPSILON5;
result.east += CesiumMath.EPSILON5;

return result;
};

Expand Down
36 changes: 7 additions & 29 deletions packages/engine/Source/Scene/ClippingPolygonCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import ComputeCommand from "../Renderer/ComputeCommand.js";
import PolygonSignedDistanceFS from "../Shaders/PolygonSignedDistanceFS.js";

/**
* Specifies a set of clipping polygons. Clipping polygons selectively disable rendering in a region on the
* outside of the specified list of {@link ClippingPolygon} objects for a single glTF model, 3D Tileset, or the globe.
* Specifies a set of clipping polygons. Clipping polygons selectively disable rendering in a region
* inside or outside the specified list of {@link ClippingPolygon} objects for a single glTF model, 3D Tileset, or the globe.
*
* Clipping Polygons are only supported in WebGL 2 contexts.
*
Expand All @@ -33,7 +33,7 @@ import PolygonSignedDistanceFS from "../Shaders/PolygonSignedDistanceFS.js";
* @param {object} [options] Object with the following properties:
* @param {ClippingPolygon[]} [options.polygons=[]] An array of {@link ClippingPolygon} objects used to selectively disable rendering on the inside of each polygon.
* @param {boolean} [options.enabled=true] Determines whether the clipping polygons are active.
* @param {boolean} [options.inverse=false] If true, a region will be clipped if it is on the outside of any polygon in the collection. Otherwise, a region will only be clipped if it is on the inside of every polygon.
* @param {boolean} [options.inverse=false] If true, a region will be clipped if it is outside of every polygon in the collection. Otherwise, a region will only be clipped if it is on the inside of any polygon.
*
* @example
* const positions = Cesium.Cartesian3.fromRadiansArray([
Expand Down Expand Up @@ -73,9 +73,9 @@ function ClippingPolygonCollection(options) {
this.enabled = defaultValue(options.enabled, true);

/**
* If true, a region will be clipped if it is on the outside of any polygon in the
* collection. Otherwise, a region will only be clipped if it is on the
* outside of every polygon.
* If true, a region will be clipped if it is outside of every polygon in the
* collection. Otherwise, a region will only be clipped if it is
* outside of any polygon.
*
* @memberof ClippingPolygonCollection.prototype
* @type {boolean}
Expand Down Expand Up @@ -459,12 +459,6 @@ function packPolygonsAsFloats(clippingPolygonCollection) {
// Pack extents
let extentsFloatIndex = 0;
for (const extents of extentsList) {
// Slightly pad extents to avoid floating point error when fragment culling at edges.
extents.south -= CesiumMath.EPSILON5;
extents.west -= CesiumMath.EPSILON5;
extents.north += CesiumMath.EPSILON5;
extents.east += CesiumMath.EPSILON5;

const longitudeRangeInverse = 1.0 / (extents.east - extents.west);
const latitudeRangeInverse = 1.0 / (extents.north - extents.south);

Expand Down Expand Up @@ -505,7 +499,7 @@ ClippingPolygonCollection.prototype.update = function (frameState) {
const dirty =
this._dirty ||
this._polygons.reduce(
(totalPositions, polygon) => (totalPositions += polygon.length),
(totalPositions, polygon) => totalPositions + polygon.length,
0
) !== this.totalPositions;
if (!dirty) {
Expand Down Expand Up @@ -660,8 +654,6 @@ ClippingPolygonCollection.prototype.queueCommands = function (frameState) {
}
};

const scratchCartesian = new Cartesian2();
const scratchExtentsDimensions = new Cartesian2();
function createSignedDistanceTextureCommand(collection) {
const polygonTexture = collection._polygonsTexture;
const extentsTexture = collection._extentsTexture;
Expand All @@ -679,23 +671,9 @@ function createSignedDistanceTextureCommand(collection) {
u_extentsTexture: function () {
return extentsTexture;
},
u_extentsTextureDimensions: function () {
return ClippingPolygonCollection.getTextureResolution(
extentsTexture,
collection.pixelsNeededForExtents,
scratchExtentsDimensions
);
},
u_polygonTexture: function () {
return polygonTexture;
},
u_polygonTextureDimensions: function () {
return ClippingPolygonCollection.getTextureResolution(
polygonTexture,
collection.pixelsNeededForPolygonPositions,
scratchCartesian
);
},
},
persists: false,
owner: collection,
Expand Down
61 changes: 33 additions & 28 deletions packages/engine/Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import Cartesian2 from "../Core/Cartesian2.js";
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
import TerrainQuantization from "../Core/TerrainQuantization.js";
import ShaderProgram from "../Renderer/ShaderProgram.js";
import getClippingFunction from "./getClippingFunction.js";
import ClippingPolygonCollection from "./ClippingPolygonCollection.js";
import SceneMode from "./SceneMode.js";

function GlobeSurfaceShader(
Expand Down Expand Up @@ -64,6 +62,31 @@ function getPositionMode(sceneMode) {
return positionMode;
}

function getPolygonClippingFunction(context) {
// return a noop for webgl1
if (!context.webgl2) {
return `void clipPolygons(highp sampler2D clippingDistance, int regionsLength, vec2 clippingPosition, int regionIndex) {
}`;
}

return `void clipPolygons(highp sampler2D clippingDistance, int regionsLength, vec2 clippingPosition, int regionIndex) {
czm_clipPolygons(clippingDistance, regionsLength, clippingPosition, regionIndex);
}`;
}

function getUnpackClippingFunction(context) {
// return a noop for webgl1
if (!context.webgl2) {
return `vec4 unpackClippingExtents(highp sampler2D extentsTexture, int index) {
return vec4();
}`;
}

return `vec4 unpackClippingExtents(highp sampler2D extentsTexture, int index) {
return czm_unpackClippingExtents(extentsTexture, index);
}`;
}

function get2DYPositionFraction(useWebMercatorProjection) {
const get2DYPositionFractionGeographicProjection =
"float get2DYPositionFraction(vec2 textureCoordinates) { return get2DGeographicYPositionFraction(textureCoordinates); }";
Expand All @@ -74,9 +97,6 @@ function get2DYPositionFraction(useWebMercatorProjection) {
: get2DYPositionFractionGeographicProjection;
}

const distanceResolutionScratch = new Cartesian2();
const extentsResolutionScratch = new Cartesian2();

GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
const frameState = options.frameState;
const surfaceTile = options.surfaceTile;
Expand Down Expand Up @@ -218,10 +238,17 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
const vs = this.baseVertexShaderSource.clone();
const fs = this.baseFragmentShaderSource.clone();

// Need to go before GlobeFS
if (currentClippingShaderState !== 0) {
fs.sources.unshift(
getClippingFunction(clippingPlanes, frameState.context)
); // Need to go before GlobeFS
);
}

// Need to go before GlobeFS
if (currentClippingPolygonsShaderState !== 0) {
fs.sources.unshift(getPolygonClippingFunction(frameState.context));
vs.sources.unshift(getUnpackClippingFunction(frameState.context));
}

vs.defines.push(quantizationDefine);
Expand Down Expand Up @@ -322,34 +349,12 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
fs.defines.push("CLIPPING_INVERSE");
}

const distanceTextureResolution = ClippingPolygonCollection.getClippingDistanceTextureResolution(
clippingPolygons,
distanceResolutionScratch
);

const extentsTextureResolution = ClippingPolygonCollection.getClippingExtentsTextureResolution(
clippingPolygons,
extentsResolutionScratch
);

fs.defines.push(
`CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`
);
vs.defines.push(
`CLIPPING_POLYGON_REGIONS_LENGTH ${clippingPolygons.extentsCount}`
);
fs.defines.push(
`CLIPPING_DISTANCE_TEXTURE_WIDTH ${distanceTextureResolution.x}`
);
fs.defines.push(
`CLIPPING_DISTANCE_TEXTURE_HEIGHT ${distanceTextureResolution.y}`
);
vs.defines.push(
`CLIPPING_EXTENTS_TEXTURE_WIDTH ${extentsTextureResolution.x}`
);
vs.defines.push(
`CLIPPING_EXTENTS_TEXTURE_HEIGHT ${extentsTextureResolution.y}`
);
}

if (colorCorrect) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import Cartesian2 from "../../Core/Cartesian2.js";
import ClippingPolygonCollection from "../ClippingPolygonCollection.js";
import combine from "../../Core/combine.js";
import ModelClippingPolygonsStageVS from "../../Shaders/Model/ModelClippingPolygonsStageVS.js";
import ModelClippingPolygonsStageFS from "../../Shaders/Model/ModelClippingPolygonsStageFS.js";
Expand All @@ -16,8 +14,6 @@ const ModelClippingPolygonsPipelineStage = {
name: "ModelClippingPolygonsPipelineStage", // Helps with debugging
};

const distanceResolutionScratch = new Cartesian2();
const extentsResolutionScratch = new Cartesian2();
/**
* Process a model for polygon clipping. This modifies the following parts of the render resources:
*
Expand Down Expand Up @@ -45,7 +41,7 @@ ModelClippingPolygonsPipelineStage.process = function (
const shaderBuilder = renderResources.shaderBuilder;

shaderBuilder.addDefine(
"HAS_CLIPPING_POLYGONS",
"ENABLE_CLIPPING_POLYGONS",
undefined,
ShaderDestination.BOTH
);
Expand All @@ -64,40 +60,6 @@ ModelClippingPolygonsPipelineStage.process = function (
ShaderDestination.BOTH
);

const distanceTextureResolution = ClippingPolygonCollection.getClippingDistanceTextureResolution(
clippingPolygons,
distanceResolutionScratch
);

const extentsTextureResolution = ClippingPolygonCollection.getClippingExtentsTextureResolution(
clippingPolygons,
extentsResolutionScratch
);

shaderBuilder.addDefine(
"CLIPPING_DISTANCE_TEXTURE_WIDTH",
distanceTextureResolution.x,
ShaderDestination.FRAGMENT
);

shaderBuilder.addDefine(
"CLIPPING_DISTANCE_TEXTURE_HEIGHT",
distanceTextureResolution.y,
ShaderDestination.FRAGMENT
);

shaderBuilder.addDefine(
"CLIPPING_EXTENTS_TEXTURE_WIDTH",
extentsTextureResolution.x,
ShaderDestination.VERTEX
);

shaderBuilder.addDefine(
"CLIPPING_EXTENTS_TEXTURE_HEIGHT",
extentsTextureResolution.y,
ShaderDestination.VERTEX
);

shaderBuilder.addUniform(
"sampler2D",
"model_clippingDistance",
Expand All @@ -110,7 +72,8 @@ ModelClippingPolygonsPipelineStage.process = function (
ShaderDestination.VERTEX
);

shaderBuilder.addVarying("vec3", "v_clippingPositionAndRegionIndex");
shaderBuilder.addVarying("vec2", "v_clippingPosition");
shaderBuilder.addVarying("int", "v_regionIndex", "flat");
shaderBuilder.addVertexLines(ModelClippingPolygonsStageVS);
shaderBuilder.addFragmentLines(ModelClippingPolygonsStageFS);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@ float getSignedDistance(vec2 uv, highp sampler2D clippingDistance) {
return (signedDistance - 0.5) * 2.0;
}

void czm_clipPolygons(highp sampler2D clippingDistance, vec2 clippingDistanceTextureDimensions, int polygonsLength, highp vec2 clippingPosition, int polygonIndex) {
void czm_clipPolygons(highp sampler2D clippingDistance, int polygonsLength, vec2 clippingPosition, int regionIndex) {
// Position is completely outside of polygons bounds
vec2 rectUv = clippingPosition;
if (rectUv.x <= 0.0 || rectUv.y <= 0.0 || rectUv.x >= 1.0 || rectUv.y >= 1.0) {
if (regionIndex < 0 || rectUv.x <= 0.0 || rectUv.y <= 0.0 || rectUv.x >= 1.0 || rectUv.y >= 1.0) {
#ifdef CLIPPING_INVERSE
discard;
#endif
return;
}

vec2 clippingDistanceTextureDimensions = vec2(textureSize(clippingDistance, 0));
vec2 sampleOffset = max(1.0 / clippingDistanceTextureDimensions, vec2(0.005));
float dimension = max(ceil(log2(float(polygonsLength))), float(polygonsLength));
ggetz marked this conversation as resolved.
Show resolved Hide resolved
vec2 polygonTextureSize = clippingDistanceTextureDimensions / dimension;
ggetz marked this conversation as resolved.
Show resolved Hide resolved

vec2 textureOffset = vec2(mod(float(polygonIndex), dimension), floor(float(polygonIndex) / dimension)) / dimension;
vec2 textureOffset = vec2(mod(float(regionIndex), dimension), floor(float(regionIndex) / dimension)) / dimension;
vec2 uv = textureOffset + rectUv / dimension;

vec2 pixelAlignedUv = (floor(uv / sampleOffset)) * sampleOffset;
Expand All @@ -43,4 +44,4 @@ void czm_clipPolygons(highp sampler2D clippingDistance, vec2 clippingDistanceTex
discard;
}
#endif
}
}
Loading
Loading