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

fix ground primitives crossing IDL in 2D #6984

Merged
merged 1 commit into from
Aug 31, 2018
Merged
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
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Change Log
* Fixed an issue where switching from 2D to 3D could cause a crash. [#6929](https://github.com/AnalyticalGraphicsInc/cesium/issues/6929)
* Fixed an issue where point primitives behind the camera would appear in view. [#6904](https://github.com/AnalyticalGraphicsInc/cesium/issues/6904)
* The `createGroundPolylineGeometry` web worker no longer depends on `GroundPolylinePrimitive`, making the worker smaller and potentially avoiding a hanging build in some webpack configurations.
* Fixed an issue that cause terrain entities (entities with unspecified `height`) and `GroundPrimitives` to fail when crossing the international date line in 3D. [#6951](https://github.com/AnalyticalGraphicsInc/cesium/issues/6951)
* Fixed an issue that cause terrain entities (entities with unspecified `height`) and `GroundPrimitives` to fail when crossing the international date line. [#6951](https://github.com/AnalyticalGraphicsInc/cesium/issues/6951)
* Fixed normal calculation for `CylinderGeometry` when the top radius is not equal to the bottom radius [#6863](https://github.com/AnalyticalGraphicsInc/cesium/pull/6863)

### 1.48 - 2018-08-01
Expand Down
8 changes: 4 additions & 4 deletions Source/Scene/ClassificationPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ define([
vsPick = Primitive._updatePickColorAttribute(vsPick);

var pickFS3D = shadowVolumeAppearance.createPickFragmentShader(false);
var pickVS3D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, false);
var pickVS3D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, false, frameState.mapProjection);

classificationPrimitive._spPick = ShaderProgram.replaceCache({
context : context,
Expand All @@ -605,7 +605,7 @@ define([
var pickProgram2D = context.shaderCache.getDerivedShaderProgram(classificationPrimitive._spPick, '2dPick');
if (!defined(pickProgram2D)) {
var pickFS2D = shadowVolumeAppearance.createPickFragmentShader(true);
var pickVS2D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, true);
var pickVS2D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, true, frameState.mapProjection);

pickProgram2D = context.shaderCache.createDerivedShaderProgram(classificationPrimitive._spPick, '2dPick', {
vertexShaderSource : pickVS2D,
Expand Down Expand Up @@ -640,7 +640,7 @@ define([

// Create a fragment shader that computes only required material hookups using screen space techniques
var fsColorSource = shadowVolumeAppearance.createFragmentShader(false);
var vsColorSource = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, false);
var vsColorSource = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, false, frameState.mapProjection);

classificationPrimitive._spColor = ShaderProgram.replaceCache({
context : context,
Expand All @@ -657,7 +657,7 @@ define([
var colorProgram2D = context.shaderCache.getDerivedShaderProgram(classificationPrimitive._spColor, '2dColor');
if (!defined(colorProgram2D)) {
var fsColorSource2D = shadowVolumeAppearance.createFragmentShader(true);
var vsColorSource2D = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, true);
var vsColorSource2D = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, true, frameState.mapProjection);

colorProgram2D = context.shaderCache.createDerivedShaderProgram(classificationPrimitive._spColor, '2dColor', {
vertexShaderSource : vsColorSource2D,
Expand Down
54 changes: 49 additions & 5 deletions Source/Scene/ShadowVolumeAppearance.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ define([
ShadowVolumeAppearanceFS) {
'use strict';

var projectionExtentDefines = {
eastMostYhighDefine : '',
eastMostYlowDefine : '',
westMostYhighDefine : '',
westMostYlowDefine : ''
};

/**
* Creates shaders for a ClassificationPrimitive to use a given Appearance, as well as for picking.
*
Expand Down Expand Up @@ -183,15 +190,17 @@ define([
* @param {String[]} defines External defines to pass to the vertex shader.
* @param {String} vertexShaderSource ShadowVolumeAppearanceVS with any required modifications for computing position.
* @param {Boolean} columbusView2D Whether the shader will be used for Columbus View or 2D.
* @param {MapProjection} mapProjection Current scene's map projection.
* @returns {String} Shader source for the vertex shader.
*/
ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D) {
ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) {
//>>includeStart('debug', pragmas.debug);
Check.defined('defines', defines);
Check.typeOf.string('vertexShaderSource', vertexShaderSource);
Check.typeOf.bool('columbusView2D', columbusView2D);
Check.defined('mapProjection', mapProjection);
//>>includeEnd('debug');
return createShadowVolumeAppearanceVS(this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance);
return createShadowVolumeAppearanceVS(this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance, mapProjection);
};

/**
Expand All @@ -200,20 +209,55 @@ define([
* @param {String[]} defines External defines to pass to the vertex shader.
* @param {String} vertexShaderSource ShadowVolumeAppearanceVS with any required modifications for computing position and picking.
* @param {Boolean} columbusView2D Whether the shader will be used for Columbus View or 2D.
* @param {MapProjection} mapProjection Current scene's map projection.
* @returns {String} Shader source for the vertex shader.
*/
ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D) {
ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) {
//>>includeStart('debug', pragmas.debug);
Check.defined('defines', defines);
Check.typeOf.string('vertexShaderSource', vertexShaderSource);
Check.typeOf.bool('columbusView2D', columbusView2D);
Check.defined('mapProjection', mapProjection);
//>>includeEnd('debug');
return createShadowVolumeAppearanceVS(this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource);
return createShadowVolumeAppearanceVS(this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, undefined, mapProjection);
};

function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance) {
var longitudeExtentsCartesianScratch = new Cartesian3();
var longitudeExtentsCartographicScratch = new Cartographic();
var longitudeExtentsEncodeScratch = {
high : 0.0,
low : 0.0
};
function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance, mapProjection) {
var allDefines = defines.slice();

if (projectionExtentDefines.eastMostYhighDefine === '') {
var eastMostCartographic = longitudeExtentsCartographicScratch;
eastMostCartographic.longitude = CesiumMath.PI;
eastMostCartographic.latitude = 0.0;
eastMostCartographic.height = 0.0;
var eastMostCartesian = mapProjection.project(eastMostCartographic, longitudeExtentsCartesianScratch);
var encoded = EncodedCartesian3.encode(eastMostCartesian.x, longitudeExtentsEncodeScratch);
projectionExtentDefines.eastMostYhighDefine = 'EAST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1);
projectionExtentDefines.eastMostYlowDefine = 'EAST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1);

var westMostCartographic = longitudeExtentsCartographicScratch;
westMostCartographic.longitude = -CesiumMath.PI;
westMostCartographic.latitude = 0.0;
westMostCartographic.height = 0.0;
var westMostCartesian = mapProjection.project(westMostCartographic, longitudeExtentsCartesianScratch);
encoded = EncodedCartesian3.encode(westMostCartesian.x, longitudeExtentsEncodeScratch);
projectionExtentDefines.westMostYhighDefine = 'WEST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1);
projectionExtentDefines.westMostYlowDefine = 'WEST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1);
}

if (columbusView2D) {
allDefines.push(projectionExtentDefines.eastMostYhighDefine);
allDefines.push(projectionExtentDefines.eastMostYlowDefine);
allDefines.push(projectionExtentDefines.westMostYhighDefine);
allDefines.push(projectionExtentDefines.westMostYlowDefine);
}

if (defined(appearance) && appearance instanceof PerInstanceColorAppearance) {
allDefines.push('PER_INSTANCE_COLOR');
}
Expand Down
18 changes: 18 additions & 0 deletions Source/Shaders/ShadowVolumeAppearanceVS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ void main()
#ifdef COLUMBUS_VIEW_2D
vec4 planes2D_high = czm_batchTable_planes2D_HIGH(batchId);
vec4 planes2D_low = czm_batchTable_planes2D_LOW(batchId);

// If the primitive is split across the IDL (planes2D_high.x > planes2D_high.w):
// - If this vertex is on the east side of the IDL (position3DLow.y > 0.0, comparison with position3DHigh may produce artifacts)
// - existing "east" is on the wrong side of the world, far away (planes2D_high/low.w)
// - so set "east" as beyond the eastmost extent of the projection (idlSplitNewPlaneHiLow)
vec2 idlSplitNewPlaneHiLow = vec2(EAST_MOST_X_HIGH - (WEST_MOST_X_HIGH - planes2D_high.w), EAST_MOST_X_LOW - (WEST_MOST_X_LOW - planes2D_low.w));
bool idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y > 0.0;
planes2D_high.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.w);
planes2D_low.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.w);

// - else, if this vertex is on the west side of the IDL (position3DLow.y < 0.0)
// - existing "west" is on the wrong side of the world, far away (planes2D_high/low.x)
// - so set "west" as beyond the westmost extent of the projection (idlSplitNewPlaneHiLow)
idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y < 0.0;
idlSplitNewPlaneHiLow = vec2(WEST_MOST_X_HIGH - (EAST_MOST_X_HIGH - planes2D_high.x), WEST_MOST_X_LOW - (EAST_MOST_X_LOW - planes2D_low.x));
planes2D_high.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.x);
planes2D_low.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.x);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a branchless equivalent to:

if (planes2D_high.x > planes2D_high.w) {
    // If the primitive is split across the IDL
    if (position3DLow.y > 0.0) { // Comparison with position3DHigh may produce artifacts
        // If this vertex is on the east side of the IDL:
        // - existing "east" is on the wrong side of the world, far away
        // - set "east" as beyond the eastmost extent of the projection
        planes2D_high.w = EAST_MOST_X_HIGH - (WEST_MOST_X_HIGH - planes2D_high.w);
        planes2D_low.w = EAST_MOST_X_LOW - (WEST_MOST_X_LOW - planes2D_low.w);
    } else {
        // If this vertex is on the west side of the IDL:
        // - existing "west" is on the wrong side of the world, far away
        // - set "west" as beyond the westmost extent of the projection
        planes2D_high.x = WEST_MOST_X_HIGH - (EAST_MOST_X_HIGH - planes2D_high.x);
        planes2D_low.x = WEST_MOST_X_LOW - (EAST_MOST_X_LOW - planes2D_low.x);
    }
}

vec3 southWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.xy), vec3(0.0, planes2D_low.xy))).xyz;
vec3 northWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.x, planes2D_high.z), vec3(0.0, planes2D_low.x, planes2D_low.z))).xyz;
vec3 southEastCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.w, planes2D_high.y), vec3(0.0, planes2D_low.w, planes2D_low.y))).xyz;
Expand Down
32 changes: 31 additions & 1 deletion Specs/Scene/GroundPrimitiveSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ defineSuite([
geometryInstances : new GeometryInstance({
geometry : new RectangleGeometry({
ellipsoid : ellipsoid,
rectangle : rectangle
rectangle : Rectangle.fromDegrees(-180 + CesiumMath.EPSILON4, -90 + CesiumMath.EPSILON4, 180 - CesiumMath.EPSILON4, 90 - CesiumMath.EPSILON4)
}),
id : 'depth rectangle',
attributes : {
Expand Down Expand Up @@ -600,6 +600,36 @@ defineSuite([
verifyLargerScene(largeRectanglePrimitive, [255, 255, 255, 255], largeRectangle);
});

it('renders GeometryInstances with texture classifying terrain across the IDL', function() {
if (!GroundPrimitive.isSupported(scene) || !GroundPrimitive.supportsMaterials(scene)) {
return;
}

var whiteImageMaterial = Material.fromType(Material.DiffuseMapType);
whiteImageMaterial.uniforms.image = './Data/Images/White.png';

var largeRectangle = Rectangle.fromDegrees(179.0, 30.0, -179.0, 31.0);
var largeRectanglePrimitive = new GroundPrimitive({
geometryInstances : new GeometryInstance({
geometry : new RectangleGeometry({
ellipsoid : ellipsoid,
rectangle : largeRectangle
})
}),
id : 'largeRectangle',
appearance : new EllipsoidSurfaceAppearance({
aboveGround : false,
flat : true,
material : whiteImageMaterial
}),
asynchronous : false,
classificationType : ClassificationType.TERRAIN
});

scene.morphToColumbusView(0);
verifyLargerScene(largeRectanglePrimitive, [255, 255, 255, 255], largeRectangle);
});

it('renders with invert classification and an opaque color', function() {
if (!GroundPrimitive.isSupported(scene)) {
return;
Expand Down
Loading