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

Polylines on terrain via Primitive API #6615

Merged
merged 41 commits into from
Jun 13, 2018
Merged
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bc4a24a
renderable polylines on terrain
likangning93 May 18, 2018
cbd2eb7
synchronization of ground polyline attributes by ID
likangning93 May 18, 2018
b2ac735
picking GroundPolylinePrimitive ignores material type (useful for das…
likangning93 May 21, 2018
bafa5f2
removed vertex normals for polyline shadow volumes
likangning93 May 21, 2018
0371307
Support for 2D/CV
likangning93 May 21, 2018
0c22456
add interpolation for long line segments, fixes for end normals
likangning93 May 22, 2018
ac29934
Sandcastle example for polylines on terrain via Primitive API [ci skip]
likangning93 May 22, 2018
ad8d711
fix some artifacts, fix doubledraw, add per-instance color support [c…
likangning93 May 24, 2018
4f71916
Merge branch 'master' into polylinesOnTerrain
likangning93 May 26, 2018
612152b
switch from batch table and many instances to fat vertices
likangning93 May 28, 2018
fe4849e
integrate ApproximateTerrainHeights into GroundPolylineGeometry, perm…
likangning93 May 29, 2018
5de9ded
some shader cleanup, restore automatic width attribute for polylines …
likangning93 May 29, 2018
9abaa8c
simulate morph [ci skip]
likangning93 May 30, 2018
e6e2c18
additional doc and Primitive parameters, fixed bounding volume comput…
likangning93 May 30, 2018
fe3531f
switch GroundPolylineGeometry to take cartesian positions
likangning93 May 31, 2018
02e7f22
split polyline shadow volumes across IDL and PM [ci skip]
likangning93 May 31, 2018
6a51e44
handle looping and normal projection for IDL/PM split [ci skip]
likangning93 Jun 1, 2018
63db595
fix additional IDL bugs [ci skip]
likangning93 Jun 1, 2018
9e39ecc
specs for GroundPolylineGeometry
likangning93 Jun 1, 2018
bed6ecf
special handling for lines near-parallel to IDL
likangning93 Jun 4, 2018
fd903d2
fix GroundPolylineGeometry test failure for built Cesium
likangning93 Jun 4, 2018
071a636
fix discontinuity for GroundPolylineGeometry due to plane origins bei…
likangning93 Jun 4, 2018
4aebfa1
specs for GroundPolylinePrimitive
likangning93 Jun 5, 2018
6ac0dd5
update Sandcastle example with Z-indexing demonstration
likangning93 Jun 5, 2018
5ee4a47
additional specs for GroundPolylinePrimitive, fix eslint errors
likangning93 Jun 5, 2018
436631a
reduce overdraw for tight corners
likangning93 Jun 7, 2018
d11829d
add defines to enable/disable varyings
likangning93 Jun 7, 2018
1d1850a
PR feedback
likangning93 Jun 7, 2018
1bd9695
Merge branch 'master' into polylinesOnTerrain
likangning93 Jun 7, 2018
6147990
remove custom pick commands for GroundPolylinePrimitive, picking what…
likangning93 Jun 7, 2018
43dbae2
performance tweak for polylines on terrain shader
likangning93 Jun 8, 2018
11d7bc4
adjust epsilons for polylines on terrain IDL handling
likangning93 Jun 8, 2018
7869029
typo fix
likangning93 Jun 8, 2018
eb95073
style/doc fixes, special geometry handling for sceneMode3D
likangning93 Jun 11, 2018
361c4cd
fix IDL split bug for CV and normalization error IDL/PM split bug
likangning93 Jun 11, 2018
fa7075f
push bottom vertices of volumes at far view distances
likangning93 Jun 11, 2018
81a23c8
fix artifacts in 2D and morph
likangning93 Jun 11, 2018
163d254
early discards
likangning93 Jun 11, 2018
403e500
remove unneeded options, add example doc for GroundPolylinePrimitive,…
likangning93 Jun 12, 2018
a822e15
update CHANGES.md
likangning93 Jun 12, 2018
3ec30e3
PR comments, back to breaking turns with larger angles
likangning93 Jun 12, 2018
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
307 changes: 179 additions & 128 deletions Source/Core/GroundPolylineGeometry.js

Large diffs are not rendered by default.

40 changes: 25 additions & 15 deletions Source/Scene/GroundPolylinePrimitive.js
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ define([
* A GroundPolylinePrimitive represents a polyline draped over the terrain in the {@link Scene}.
* <p>
*
* Only to be used with GeometryInstances containing GroundPolylineGeometries
* Only to be used with GeometryInstances containing {@link GroundPolylineGeometry}
*
* @param {Object} [options] Object with the following properties:
* @param {Array|GeometryInstance} [options.geometryInstances] GeometryInstances containing GroundPolylineGeometry
@@ -397,20 +397,27 @@ define([
// which causes problems when interpolating log depth from vertices.
// So force computing and writing log depth in the fragment shader.
// Re-enable at far distances to avoid z-fighting.
var colorDefine = appearance instanceof PolylineColorAppearance ? 'PER_INSTANCE_COLOR' : '';
var vsDefines = ['ENABLE_GL_POSITION_LOG_DEPTH_AT_HEIGHT', colorDefine];
var fsDefines = groundPolylinePrimitive.debugShowShadowVolume ? ['DEBUG_SHOW_VOLUME', colorDefine] : [colorDefine];
var materialShaderSource = defined(appearance.material) ? appearance.material.shaderSource : '';

// Check for use of v_width and v_polylineAngle in material shader
// to determine whether these varyings should be active in the vertex shader.
if (materialShaderSource.search(/varying\s+float\s+v_polylineAngle;/g) === -1) {
vsDefines.push('ANGLE_VARYING');
}
if (materialShaderSource.search(/varying\s+float\s+v_width;/g) === -1) {
vsDefines.push('WIDTH_VARYING');
var vsDefines = ['ENABLE_GL_POSITION_LOG_DEPTH_AT_HEIGHT'];
var colorDefine = '';
var materialShaderSource = '';
if (defined(appearance.material)) {
materialShaderSource = defined(appearance.material) ? appearance.material.shaderSource : '';

// Check for use of v_width and v_polylineAngle in material shader
// to determine whether these varyings should be active in the vertex shader.
if (materialShaderSource.search(/varying\s+float\s+v_polylineAngle;/g) === -1) {
vsDefines.push('ANGLE_VARYING');
}
if (materialShaderSource.search(/varying\s+float\s+v_width;/g) === -1) {
vsDefines.push('WIDTH_VARYING');
}
} else {
colorDefine = 'PER_INSTANCE_COLOR';
}

vsDefines.push(colorDefine);
var fsDefines = groundPolylinePrimitive.debugShowShadowVolume ? ['DEBUG_SHOW_VOLUME', colorDefine] : [colorDefine];

var vsColor3D = new ShaderSource({
defines : vsDefines,
sources : [vs]
@@ -498,7 +505,7 @@ define([
command.shaderProgram = groundPolylinePrimitive._sp;
command.uniformMap = uniformMap;
command.pass = pass;
command.pickId = 'czm_batchTable_pickColor(v_endPlaneNormalEC_and_batchId.w)';
command.pickId = 'czm_batchTable_pickColor(v_endPlaneNormalEcAndBatchId.w)';

// derive for 2D
var derivedColorCommand = command.derivedCommands.color2D;
@@ -511,7 +518,7 @@ define([
derivedColorCommand.shaderProgram = groundPolylinePrimitive._sp2D;
derivedColorCommand.uniformMap = uniformMap;
derivedColorCommand.pass = pass;
derivedColorCommand.pickId = 'czm_batchTable_pickColor(v_endPlaneNormalEC_and_batchId.w)';
derivedColorCommand.pickId = 'czm_batchTable_pickColor(v_endPlaneNormalEcAndBatchId.w)';

// derive for Morph
derivedColorCommand = command.derivedCommands.colorMorph;
@@ -633,6 +640,9 @@ define([
});
}

// Update each geometry for framestate.scene3DOnly = true
geometryInstance.geometry._scene3DOnly = frameState.scene3DOnly;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not do the same thing for projection?


groundInstances[i] = new GeometryInstance({
geometry : geometryInstance.geometry,
attributes : attributes,
3 changes: 2 additions & 1 deletion Source/Scene/PolylineColorAppearance.js
Original file line number Diff line number Diff line change
@@ -20,7 +20,8 @@ define([
var defaultFragmentShaderSource = PerInstanceFlatColorAppearanceFS;

/**
* An appearance for {@link GeometryInstance} instances with color attributes and {@link PolylineGeometry}.
* An appearance for {@link GeometryInstance} instances with color attributes and
* {@link PolylineGeometry} or {@link GroundPolylineGeometry}.
* This allows several geometry instances, each with a different color, to
* be drawn with the same {@link Primitive}.
*
4 changes: 2 additions & 2 deletions Source/Shaders/Builtin/Functions/planeDistance.glsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Computes distance from an point to a plane, typically in eye space.
* Computes distance from a point to a plane.
*
* @name czm_planeDistance
* @glslFunction
@@ -13,7 +13,7 @@ float czm_planeDistance(vec4 plane, vec3 point) {
}

/**
* Computes distance from an point to a plane, typically in eye space.
* Computes distance from a point to a plane.
*
* @name czm_planeDistance
* @glslFunction
30 changes: 13 additions & 17 deletions Source/Shaders/PolylineShadowVolumeFS.glsl
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
#ifdef GL_EXT_frag_depth
#extension GL_EXT_frag_depth : enable
#endif

varying vec4 v_startPlaneNormalEC_and_halfWidth;
varying vec4 v_endPlaneNormalEC_and_batchId;
varying vec4 v_startPlaneNormalEcAndHalfWidth;
varying vec4 v_endPlaneNormalEcAndBatchId;
varying vec4 v_rightPlaneEC; // Technically can compute distance for this here
varying vec4 v_ecEnd_and_ecStart_X;
varying vec4 v_texcoordNormalization_and_ecStart_YZ;
varying vec4 v_endEcAndStartEcX;
varying vec4 v_texcoordNormalizationAndStartEcYZ;

#ifdef PER_INSTANCE_COLOR
varying vec4 v_color;
@@ -15,21 +11,21 @@ varying vec4 v_color;
void main(void)
Copy link
Contributor

Choose a reason for hiding this comment

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

At quick glance, fragment shader does not look that expensive...very good.

Just overall fill rate will be the issue that we can address in the future.

{
float logDepthOrDepth = czm_unpackDepth(texture2D(czm_globeDepthTexture, gl_FragCoord.xy / czm_viewport.zw));
vec3 ecStart = vec3(v_ecEnd_and_ecStart_X.w, v_texcoordNormalization_and_ecStart_YZ.zw);
vec3 ecStart = vec3(v_endEcAndStartEcX.w, v_texcoordNormalizationAndStartEcYZ.zw);

// Discard for sky
bool shouldDiscard = logDepthOrDepth == 0.0;
bool shouldDiscard = (logDepthOrDepth == 0.0);

vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, logDepthOrDepth);
eyeCoordinate /= eyeCoordinate.w;

float halfMaxWidth = v_startPlaneNormalEC_and_halfWidth.w * czm_metersPerPixel(eyeCoordinate);
float halfMaxWidth = v_startPlaneNormalEcAndHalfWidth.w * czm_metersPerPixel(eyeCoordinate);
// Check distance of the eye coordinate against the right-facing plane
float widthwiseDistance = czm_planeDistance(v_rightPlaneEC, eyeCoordinate.xyz);

// Check eye coordinate against the mitering planes
float distanceFromStart = czm_planeDistance(v_startPlaneNormalEC_and_halfWidth.xyz, -dot(ecStart, v_startPlaneNormalEC_and_halfWidth.xyz), eyeCoordinate.xyz);
float distanceFromEnd = czm_planeDistance(v_endPlaneNormalEC_and_batchId.xyz, -dot(v_ecEnd_and_ecStart_X.xyz, v_endPlaneNormalEC_and_batchId.xyz), eyeCoordinate.xyz);
float distanceFromStart = czm_planeDistance(v_startPlaneNormalEcAndHalfWidth.xyz, -dot(ecStart, v_startPlaneNormalEcAndHalfWidth.xyz), eyeCoordinate.xyz);
float distanceFromEnd = czm_planeDistance(v_endPlaneNormalEcAndBatchId.xyz, -dot(v_endEcAndStartEcX.xyz, v_endPlaneNormalEcAndBatchId.xyz), eyeCoordinate.xyz);

shouldDiscard = shouldDiscard || (abs(widthwiseDistance) > halfMaxWidth || distanceFromStart < 0.0 || distanceFromEnd < 0.0);

@@ -40,14 +36,14 @@ void main(void)
vec3 alignedPlaneNormal;

// start aligned plane
alignedPlaneNormal = cross(v_rightPlaneEC.xyz, v_startPlaneNormalEC_and_halfWidth.xyz);
alignedPlaneNormal = cross(v_rightPlaneEC.xyz, v_startPlaneNormalEcAndHalfWidth.xyz);
alignedPlaneNormal = normalize(cross(alignedPlaneNormal, v_rightPlaneEC.xyz));
distanceFromStart = czm_planeDistance(alignedPlaneNormal, -dot(alignedPlaneNormal, ecStart), eyeCoordinate.xyz);

// end aligned plane
alignedPlaneNormal = cross(v_rightPlaneEC.xyz, v_endPlaneNormalEC_and_batchId.xyz);
alignedPlaneNormal = cross(v_rightPlaneEC.xyz, v_endPlaneNormalEcAndBatchId.xyz);
alignedPlaneNormal = normalize(cross(alignedPlaneNormal, v_rightPlaneEC.xyz));
distanceFromEnd = czm_planeDistance(alignedPlaneNormal, -dot(alignedPlaneNormal, v_ecEnd_and_ecStart_X.xyz), eyeCoordinate.xyz);
distanceFromEnd = czm_planeDistance(alignedPlaneNormal, -dot(alignedPlaneNormal, v_endEcAndStartEcX.xyz), eyeCoordinate.xyz);

shouldDiscard = shouldDiscard || distanceFromStart < -halfMaxWidth || distanceFromEnd < -halfMaxWidth;

@@ -66,7 +62,7 @@ void main(void)
// Clamp - distance to aligned planes may be negative due to mitering,
// so fragment texture coordinate might be out-of-bounds.
float s = clamp(distanceFromStart / (distanceFromStart + distanceFromEnd), 0.0, 1.0);
s = (s * v_texcoordNormalization_and_ecStart_YZ.x) + v_texcoordNormalization_and_ecStart_YZ.y;
s = (s * v_texcoordNormalizationAndStartEcYZ.x) + v_texcoordNormalizationAndStartEcYZ.y;
float t = (widthwiseDistance + halfMaxWidth) / (2.0 * halfMaxWidth);

czm_materialInput materialInput;
9 changes: 0 additions & 9 deletions Source/Shaders/PolylineShadowVolumeMorphFS.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
#ifdef GL_EXT_frag_depth
#extension GL_EXT_frag_depth : enable
#endif

varying vec3 v_forwardDirectionEC;
varying vec3 v_texcoordNormalization_and_halfWidth;
varying float v_batchId;
@@ -23,9 +19,6 @@ void main(void)
vec4 eyeCoordinate = gl_FragCoord;
eyeCoordinate /= eyeCoordinate.w;

#ifdef PICK
gl_FragColor.a = 1.0;
#else // PICK
#ifdef PER_INSTANCE_COLOR
gl_FragColor = v_color;
#else // PER_INSTANCE_COLOR
@@ -49,6 +42,4 @@ void main(void)
czm_material material = czm_getMaterial(materialInput);
gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);
#endif // PER_INSTANCE_COLOR

#endif // PICK
}
24 changes: 12 additions & 12 deletions Source/Shaders/PolylineShadowVolumeMorphVS.glsl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
attribute vec3 position3DHigh;
attribute vec3 position3DLow;

attribute vec4 startHi_and_forwardOffsetX;
attribute vec4 startLo_and_forwardOffsetY;
attribute vec4 startNormal_and_forwardOffsetZ;
attribute vec4 endNormal_and_textureCoordinateNormalizationX;
attribute vec4 rightNormal_and_textureCoordinateNormalizationY;
attribute vec4 startHiAndForwardOffsetX;
attribute vec4 startLoAndForwardOffsetY;
attribute vec4 startNormalAndForwardOffsetZ;
attribute vec4 endNormalAndTextureCoordinateNormalizationX;
attribute vec4 rightNormalAndTextureCoordinateNormalizationY;
attribute vec4 startHiLo2D;
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, +1 for removing these four (!) attributes for 3D only.

attribute vec4 offsetAndRight2D;
attribute vec4 startEndNormals2D;
@@ -40,7 +40,7 @@ void main()

// Start position
vec4 posRelativeToEye2D = czm_translateRelativeToEye(vec3(0.0, startHiLo2D.xy), vec3(0.0, startHiLo2D.zw));
vec4 posRelativeToEye3D = czm_translateRelativeToEye(startHi_and_forwardOffsetX.xyz, startLo_and_forwardOffsetY.xyz);
vec4 posRelativeToEye3D = czm_translateRelativeToEye(startHiAndForwardOffsetX.xyz, startLoAndForwardOffsetY.xyz);
vec4 posRelativeToEye = czm_columbusViewMorph(posRelativeToEye2D, posRelativeToEye3D, czm_morphTime);
vec3 ecPos2D = (czm_modelViewRelativeToEye * posRelativeToEye2D).xyz;
vec3 ecPos3D = (czm_modelViewRelativeToEye * posRelativeToEye3D).xyz;
@@ -50,21 +50,21 @@ void main()
vec4 startPlane2D;
vec4 startPlane3D;
startPlane2D.xyz = czm_normal * vec3(0.0, startEndNormals2D.xy);
startPlane3D.xyz = czm_normal * startNormal_and_forwardOffsetZ.xyz;
startPlane3D.xyz = czm_normal * startNormalAndForwardOffsetZ.xyz;
startPlane2D.w = -dot(startPlane2D.xyz, ecPos2D);
startPlane3D.w = -dot(startPlane3D.xyz, ecPos3D);

// Right plane
vec4 rightPlane2D;
vec4 rightPlane3D;
rightPlane2D.xyz = czm_normal * vec3(0.0, offsetAndRight2D.zw);
rightPlane3D.xyz = czm_normal * rightNormal_and_textureCoordinateNormalizationY.xyz;
rightPlane3D.xyz = czm_normal * rightNormalAndTextureCoordinateNormalizationY.xyz;
rightPlane2D.w = -dot(rightPlane2D.xyz, ecPos2D);
rightPlane3D.w = -dot(rightPlane3D.xyz, ecPos3D);

// End position
posRelativeToEye2D = posRelativeToEye2D + vec4(0.0, offsetAndRight2D.xy, 0.0);
posRelativeToEye3D = posRelativeToEye3D + vec4(startHi_and_forwardOffsetX.w, startLo_and_forwardOffsetY.w, startNormal_and_forwardOffsetZ.w, 0.0);
posRelativeToEye3D = posRelativeToEye3D + vec4(startHiAndForwardOffsetX.w, startLoAndForwardOffsetY.w, startNormalAndForwardOffsetZ.w, 0.0);
posRelativeToEye = czm_columbusViewMorph(posRelativeToEye2D, posRelativeToEye3D, czm_morphTime);
ecPos2D = (czm_modelViewRelativeToEye * posRelativeToEye2D).xyz;
ecPos3D = (czm_modelViewRelativeToEye * posRelativeToEye3D).xyz;
@@ -74,7 +74,7 @@ void main()
vec4 endPlane2D;
vec4 endPlane3D;
endPlane2D.xyz = czm_normal * vec3(0.0, startEndNormals2D.zw);
endPlane3D.xyz = czm_normal * endNormal_and_textureCoordinateNormalizationX.xyz;
endPlane3D.xyz = czm_normal * endNormalAndTextureCoordinateNormalizationX.xyz;
endPlane2D.w = -dot(endPlane2D.xyz, ecPos2D);
endPlane3D.w = -dot(endPlane3D.xyz, ecPos3D);

@@ -83,7 +83,7 @@ void main()

v_texcoordNormalization_and_halfWidth.xy = mix(
vec2(abs(texcoordNormalization2D.x), texcoordNormalization2D.y),
vec2(abs(endNormal_and_textureCoordinateNormalizationX.w), rightNormal_and_textureCoordinateNormalizationY.w), czm_morphTime);
vec2(abs(endNormalAndTextureCoordinateNormalizationX.w), rightNormalAndTextureCoordinateNormalizationY.w), czm_morphTime);

#ifdef PER_INSTANCE_COLOR
v_color = czm_batchTable_color(batchId);
@@ -119,7 +119,7 @@ void main()
vec3 normalEC = normalize(cross(planeDirection, upOrDown)); // In practice, the opposite seems to work too.

// Determine if this vertex is on the "left" or "right"
normalEC *= sign(endNormal_and_textureCoordinateNormalizationX.w);
normalEC *= sign(endNormalAndTextureCoordinateNormalizationX.w);

// A "perfect" implementation would push along normals according to the angle against forward.
// In practice, just pushing the normal out by halfWidth is sufficient for morph views.
48 changes: 24 additions & 24 deletions Source/Shaders/PolylineShadowVolumeVS.glsl
Original file line number Diff line number Diff line change
@@ -2,11 +2,11 @@ attribute vec3 position3DHigh;
attribute vec3 position3DLow;

#ifndef COLUMBUS_VIEW_2D
attribute vec4 startHi_and_forwardOffsetX;
attribute vec4 startLo_and_forwardOffsetY;
attribute vec4 startNormal_and_forwardOffsetZ;
attribute vec4 endNormal_and_textureCoordinateNormalizationX;
attribute vec4 rightNormal_and_textureCoordinateNormalizationY;
attribute vec4 startHiAndForwardOffsetX;
attribute vec4 startLoAndForwardOffsetY;
attribute vec4 startNormalAndForwardOffsetZ;
attribute vec4 endNormalAndTextureCoordinateNormalizationX;
attribute vec4 rightNormalAndTextureCoordinateNormalizationY;
#else
attribute vec4 startHiLo2D;
attribute vec4 offsetAndRight2D;
@@ -16,11 +16,11 @@ attribute vec2 texcoordNormalization2D;

attribute float batchId;

varying vec4 v_startPlaneNormalEC_and_halfWidth;
varying vec4 v_endPlaneNormalEC_and_batchId;
varying vec4 v_startPlaneNormalEcAndHalfWidth;
varying vec4 v_endPlaneNormalEcAndBatchId;
varying vec4 v_rightPlaneEC;
varying vec4 v_ecEnd_and_ecStart_X;
varying vec4 v_texcoordNormalization_and_ecStart_YZ;
varying vec4 v_endEcAndStartEcX;
varying vec4 v_texcoordNormalizationAndStartEcYZ;

// For materials
#ifdef WIDTH_VARYING
@@ -57,36 +57,36 @@ void main()
endPlaneEC.xyz = czm_normal * vec3(0.0, startEndNormals2D.zw);
endPlaneEC.w = -dot(endPlaneEC.xyz, ecEnd);

v_texcoordNormalization_and_ecStart_YZ.xy = vec2(abs(texcoordNormalization2D.x), texcoordNormalization2D.y);
v_texcoordNormalizationAndStartEcYZ.xy = vec2(abs(texcoordNormalization2D.x), texcoordNormalization2D.y);

#else // COLUMBUS_VIEW_2D
vec3 ecStart = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(startHi_and_forwardOffsetX.xyz, startLo_and_forwardOffsetY.xyz)).xyz;
vec3 offset = czm_normal * vec3(startHi_and_forwardOffsetX.w, startLo_and_forwardOffsetY.w, startNormal_and_forwardOffsetZ.w);
vec3 ecStart = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(startHiAndForwardOffsetX.xyz, startLoAndForwardOffsetY.xyz)).xyz;
vec3 offset = czm_normal * vec3(startHiAndForwardOffsetX.w, startLoAndForwardOffsetY.w, startNormalAndForwardOffsetZ.w);
vec3 ecEnd = ecStart + offset;

vec3 forwardDirectionEC = normalize(offset);

// start plane
vec4 startPlaneEC;
startPlaneEC.xyz = czm_normal * startNormal_and_forwardOffsetZ.xyz;
startPlaneEC.xyz = czm_normal * startNormalAndForwardOffsetZ.xyz;
startPlaneEC.w = -dot(startPlaneEC.xyz, ecStart);

// end plane
vec4 endPlaneEC;
endPlaneEC.xyz = czm_normal * endNormal_and_textureCoordinateNormalizationX.xyz;
endPlaneEC.xyz = czm_normal * endNormalAndTextureCoordinateNormalizationX.xyz;
endPlaneEC.w = -dot(endPlaneEC.xyz, ecEnd);

// Right plane
v_rightPlaneEC.xyz = czm_normal * rightNormal_and_textureCoordinateNormalizationY.xyz;
v_rightPlaneEC.xyz = czm_normal * rightNormalAndTextureCoordinateNormalizationY.xyz;
v_rightPlaneEC.w = -dot(v_rightPlaneEC.xyz, ecStart);

v_texcoordNormalization_and_ecStart_YZ.xy = vec2(abs(endNormal_and_textureCoordinateNormalizationX.w), rightNormal_and_textureCoordinateNormalizationY.w);
v_texcoordNormalizationAndStartEcYZ.xy = vec2(abs(endNormalAndTextureCoordinateNormalizationX.w), rightNormalAndTextureCoordinateNormalizationY.w);

#endif // COLUMBUS_VIEW_2D

v_ecEnd_and_ecStart_X.xyz = ecEnd;
v_ecEnd_and_ecStart_X.w = ecStart.x;
v_texcoordNormalization_and_ecStart_YZ.zw = ecStart.yz;
v_endEcAndStartEcX.xyz = ecEnd;
v_endEcAndStartEcX.w = ecStart.x;
v_texcoordNormalizationAndStartEcYZ.zw = ecStart.yz;

#ifdef PER_INSTANCE_COLOR
v_color = czm_batchTable_color(batchId);
@@ -126,11 +126,11 @@ void main()
v_width = width;
#endif

v_startPlaneNormalEC_and_halfWidth.xyz = startPlaneEC.xyz;
v_startPlaneNormalEC_and_halfWidth.w = width * 0.5;
v_startPlaneNormalEcAndHalfWidth.xyz = startPlaneEC.xyz;
v_startPlaneNormalEcAndHalfWidth.w = width * 0.5;

v_endPlaneNormalEC_and_batchId.xyz = endPlaneEC.xyz;
v_endPlaneNormalEC_and_batchId.w = batchId;
v_endPlaneNormalEcAndBatchId.xyz = endPlaneEC.xyz;
v_endPlaneNormalEcAndBatchId.w = batchId;

width = width * max(0.0, czm_metersPerPixel(positionEC)); // width = distance to push along R
width = width / dot(normalEC, v_rightPlaneEC.xyz); // width = distance to push along N
@@ -139,7 +139,7 @@ void main()
#ifdef COLUMBUS_VIEW_2D
normalEC *= sign(texcoordNormalization2D.x);
#else
normalEC *= sign(endNormal_and_textureCoordinateNormalizationX.w);
normalEC *= sign(endNormalAndTextureCoordinateNormalizationX.w);
#endif

positionEC.xyz += width * normalEC;
101 changes: 66 additions & 35 deletions Specs/Core/GroundPolylineGeometrySpec.js
Original file line number Diff line number Diff line change
@@ -62,30 +62,30 @@ defineSuite([
expect(geometry.indices.length).toEqual(36);
expect(geometry.attributes.position.values.length).toEqual(24);

var startHi_and_forwardOffsetX = geometry.attributes.startHi_and_forwardOffsetX;
var startLo_and_forwardOffsetY = geometry.attributes.startLo_and_forwardOffsetY;
var startNormal_and_forwardOffsetZ = geometry.attributes.startNormal_and_forwardOffsetZ;
var endNormal_and_textureCoordinateNormalizationX = geometry.attributes.endNormal_and_textureCoordinateNormalizationX;
var rightNormal_and_textureCoordinateNormalizationY = geometry.attributes.rightNormal_and_textureCoordinateNormalizationY;
var startHiAndForwardOffsetX = geometry.attributes.startHiAndForwardOffsetX;
var startLoAndForwardOffsetY = geometry.attributes.startLoAndForwardOffsetY;
var startNormalAndForwardOffsetZ = geometry.attributes.startNormalAndForwardOffsetZ;
var endNormalAndTextureCoordinateNormalizationX = geometry.attributes.endNormalAndTextureCoordinateNormalizationX;
var rightNormalAndTextureCoordinateNormalizationY = geometry.attributes.rightNormalAndTextureCoordinateNormalizationY;
var startHiLo2D = geometry.attributes.startHiLo2D;
var offsetAndRight2D = geometry.attributes.offsetAndRight2D;
var startEndNormals2D = geometry.attributes.startEndNormals2D;
var texcoordNormalization2D = geometry.attributes.texcoordNormalization2D;

// Expect each entry in the additional attributes to be identical across all vertices since this is a single segment,
// except endNormal_and_textureCoordinateNormalizationX and texcoordNormalization2D, which should be "sided"
verifyAttributeValuesIdentical(startHi_and_forwardOffsetX);
verifyAttributeValuesIdentical(startLo_and_forwardOffsetY);
verifyAttributeValuesIdentical(startNormal_and_forwardOffsetZ);
verifyAttributeValuesIdentical(rightNormal_and_textureCoordinateNormalizationY);
// except endNormalAndTextureCoordinateNormalizationX and texcoordNormalization2D, which should be "sided"
verifyAttributeValuesIdentical(startHiAndForwardOffsetX);
verifyAttributeValuesIdentical(startLoAndForwardOffsetY);
verifyAttributeValuesIdentical(startNormalAndForwardOffsetZ);
verifyAttributeValuesIdentical(rightNormalAndTextureCoordinateNormalizationY);
verifyAttributeValuesIdentical(startHiLo2D);
verifyAttributeValuesIdentical(offsetAndRight2D);
verifyAttributeValuesIdentical(startEndNormals2D);

// Expect endNormal_and_textureCoordinateNormalizationX and texcoordNormalization2D.x to encode the "side" of the geometry
// Expect endNormalAndTextureCoordinateNormalizationX and texcoordNormalization2D.x to encode the "side" of the geometry
var i;
var index;
var values = endNormal_and_textureCoordinateNormalizationX.values;
var values = endNormalAndTextureCoordinateNormalizationX.values;
for (i = 0; i < 4; i++) {
index = i * 4 + 3;
expect(Math.sign(values[index])).toEqual(1.0);
@@ -112,32 +112,32 @@ defineSuite([
// - a right-facing normal
// - parameters for localizing the position along the line to texture coordinates
var startPosition3D = new Cartesian3();
startPosition3D.x = startHi_and_forwardOffsetX.values[0] + startLo_and_forwardOffsetY.values[0];
startPosition3D.y = startHi_and_forwardOffsetX.values[1] + startLo_and_forwardOffsetY.values[1];
startPosition3D.z = startHi_and_forwardOffsetX.values[2] + startLo_and_forwardOffsetY.values[2];
startPosition3D.x = startHiAndForwardOffsetX.values[0] + startLoAndForwardOffsetY.values[0];
startPosition3D.y = startHiAndForwardOffsetX.values[1] + startLoAndForwardOffsetY.values[1];
startPosition3D.z = startHiAndForwardOffsetX.values[2] + startLoAndForwardOffsetY.values[2];
var reconstructedCarto = Cartographic.fromCartesian(startPosition3D);
reconstructedCarto.height = 0.0;
expect(Cartographic.equalsEpsilon(reconstructedCarto, startCartographic, CesiumMath.EPSILON7)).toBe(true);

var endPosition3D = new Cartesian3();
endPosition3D.x = startPosition3D.x + startHi_and_forwardOffsetX.values[3];
endPosition3D.y = startPosition3D.y + startLo_and_forwardOffsetY.values[3];
endPosition3D.z = startPosition3D.z + startNormal_and_forwardOffsetZ.values[3];
endPosition3D.x = startPosition3D.x + startHiAndForwardOffsetX.values[3];
endPosition3D.y = startPosition3D.y + startLoAndForwardOffsetY.values[3];
endPosition3D.z = startPosition3D.z + startNormalAndForwardOffsetZ.values[3];
reconstructedCarto = Cartographic.fromCartesian(endPosition3D);
reconstructedCarto.height = 0.0;
expect(Cartographic.equalsEpsilon(reconstructedCarto, endCartographic, CesiumMath.EPSILON7)).toBe(true);

var startNormal3D = Cartesian3.unpack(startNormal_and_forwardOffsetZ.values);
var startNormal3D = Cartesian3.unpack(startNormalAndForwardOffsetZ.values);
expect(Cartesian3.equalsEpsilon(startNormal3D, new Cartesian3(0.0, 1.0, 0.0), CesiumMath.EPSILON2)).toBe(true);

var endNormal3D = Cartesian3.unpack(endNormal_and_textureCoordinateNormalizationX.values);
var endNormal3D = Cartesian3.unpack(endNormalAndTextureCoordinateNormalizationX.values);
expect(Cartesian3.equalsEpsilon(endNormal3D, new Cartesian3(0.0, -1.0, 0.0), CesiumMath.EPSILON2)).toBe(true);

var rightNormal3D = Cartesian3.unpack(rightNormal_and_textureCoordinateNormalizationY.values);
var rightNormal3D = Cartesian3.unpack(rightNormalAndTextureCoordinateNormalizationY.values);
expect(Cartesian3.equalsEpsilon(rightNormal3D, new Cartesian3(0.0, 0.0, -1.0), CesiumMath.EPSILON2)).toBe(true);

var texcoordNormalizationX = endNormal_and_textureCoordinateNormalizationX.values[3];
var texcoordNormalizationY = rightNormal_and_textureCoordinateNormalizationY.values[3];
var texcoordNormalizationX = endNormalAndTextureCoordinateNormalizationX.values[3];
var texcoordNormalizationY = rightNormalAndTextureCoordinateNormalizationY.values[3];
expect(texcoordNormalizationX).toEqualEpsilon(1.0, CesiumMath.EPSILON3);
expect(texcoordNormalizationY).toEqualEpsilon(0.0, CesiumMath.EPSILON3);

@@ -179,6 +179,33 @@ defineSuite([
expect(texcoordNormalizationY).toEqualEpsilon(0.0, CesiumMath.EPSILON3);
});

it('does not generate 2D attributes when scene3DOnly is true', function() {
var startCartographic = Cartographic.fromDegrees(0.01, 0.0);
var endCartographic = Cartographic.fromDegrees(0.02, 0.0);
var groundPolylineGeometry = new GroundPolylineGeometry({
positions : Cartesian3.fromRadiansArray([
startCartographic.longitude, startCartographic.latitude,
endCartographic.longitude, endCartographic.latitude
]),
granularity : 0.0
});

groundPolylineGeometry._scene3DOnly = true;

var geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry);

expect(geometry.attributes.startHiAndForwardOffsetX).toBeDefined();
expect(geometry.attributes.startLoAndForwardOffsetY).toBeDefined();
expect(geometry.attributes.startNormalAndForwardOffsetZ).toBeDefined();
expect(geometry.attributes.endNormalAndTextureCoordinateNormalizationX).toBeDefined();
expect(geometry.attributes.rightNormalAndTextureCoordinateNormalizationY).toBeDefined();

expect(geometry.attributes.startHiLo2D).not.toBeDefined();
expect(geometry.attributes.offsetAndRight2D).not.toBeDefined();
expect(geometry.attributes.startEndNormals2D).not.toBeDefined();
expect(geometry.attributes.texcoordNormalization2D).not.toBeDefined();
});

it('miters turns', function() {
var groundPolylineGeometry = new GroundPolylineGeometry({
positions : Cartesian3.fromDegreesArray([
@@ -193,11 +220,11 @@ defineSuite([
expect(geometry.indices.length).toEqual(72);
expect(geometry.attributes.position.values.length).toEqual(48);

var startNormal_and_forwardOffsetZvalues = geometry.attributes.startNormal_and_forwardOffsetZ.values;
var endNormal_and_textureCoordinateNormalizationXvalues = geometry.attributes.endNormal_and_textureCoordinateNormalizationX.values;
var startNormalAndForwardOffsetZvalues = geometry.attributes.startNormalAndForwardOffsetZ.values;
var endNormalAndTextureCoordinateNormalizationXvalues = geometry.attributes.endNormalAndTextureCoordinateNormalizationX.values;

var miteredStartNormal = Cartesian3.unpack(startNormal_and_forwardOffsetZvalues, 32);
var miteredEndNormal = Cartesian3.unpack(endNormal_and_textureCoordinateNormalizationXvalues, 0);
var miteredStartNormal = Cartesian3.unpack(startNormalAndForwardOffsetZvalues, 32);
var miteredEndNormal = Cartesian3.unpack(endNormalAndTextureCoordinateNormalizationXvalues, 0);
var reverseMiteredEndNormal = Cartesian3.multiplyByScalar(miteredEndNormal, -1.0, new Cartesian3());

expect(Cartesian3.equalsEpsilon(miteredStartNormal, reverseMiteredEndNormal, CesiumMath.EPSILON7)).toBe(true);
@@ -219,11 +246,11 @@ defineSuite([

var geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry);

var startNormal_and_forwardOffsetZvalues = geometry.attributes.startNormal_and_forwardOffsetZ.values;
var endNormal_and_textureCoordinateNormalizationXvalues = geometry.attributes.endNormal_and_textureCoordinateNormalizationX.values;
var startNormalAndForwardOffsetZvalues = geometry.attributes.startNormalAndForwardOffsetZ.values;
var endNormalAndTextureCoordinateNormalizationXvalues = geometry.attributes.endNormalAndTextureCoordinateNormalizationX.values;

var miteredStartNormal = Cartesian3.unpack(startNormal_and_forwardOffsetZvalues, 32);
var miteredEndNormal = Cartesian3.unpack(endNormal_and_textureCoordinateNormalizationXvalues, 0);
var miteredStartNormal = Cartesian3.unpack(startNormalAndForwardOffsetZvalues, 32);
var miteredEndNormal = Cartesian3.unpack(endNormalAndTextureCoordinateNormalizationXvalues, 0);
var reverseMiteredEndNormal = Cartesian3.multiplyByScalar(miteredEndNormal, -1.0, new Cartesian3());

expect(Cartesian3.equalsEpsilon(miteredStartNormal, reverseMiteredEndNormal, CesiumMath.EPSILON7)).toBe(true);
@@ -246,12 +273,12 @@ defineSuite([

geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry);

startNormal_and_forwardOffsetZvalues = geometry.attributes.startNormal_and_forwardOffsetZ.values;
endNormal_and_textureCoordinateNormalizationXvalues = geometry.attributes.endNormal_and_textureCoordinateNormalizationX.values;
startNormalAndForwardOffsetZvalues = geometry.attributes.startNormalAndForwardOffsetZ.values;
endNormalAndTextureCoordinateNormalizationXvalues = geometry.attributes.endNormalAndTextureCoordinateNormalizationX.values;

// Check normals at loop end
miteredStartNormal = Cartesian3.unpack(startNormal_and_forwardOffsetZvalues, 0);
miteredEndNormal = Cartesian3.unpack(endNormal_and_textureCoordinateNormalizationXvalues, 32 * 2);
miteredStartNormal = Cartesian3.unpack(startNormalAndForwardOffsetZvalues, 0);
miteredEndNormal = Cartesian3.unpack(endNormalAndTextureCoordinateNormalizationXvalues, 32 * 2);

expect(Cartesian3.equalsEpsilon(miteredStartNormal, miteredEndNormal, CesiumMath.EPSILON7)).toBe(true);

@@ -402,6 +429,7 @@ defineSuite([
loop : true,
granularity : 10.0 // no interpolative subdivision
});
groundPolylineGeometry._scene3DOnly = true;

var packedArray = [0];
GroundPolylineGeometry.pack(groundPolylineGeometry, packedArray, 1);
@@ -420,6 +448,7 @@ defineSuite([
expect(scratch.loop).toBe(true);
expect(scratch.granularity).toEqual(10.0);
expect(scratch.ellipsoid.equals(Ellipsoid.WGS84)).toBe(true);
expect(scratch._scene3DOnly).toBe(true);
});

var positions = Cartesian3.fromDegreesArray([
@@ -454,5 +483,7 @@ defineSuite([
Ellipsoid.pack(Ellipsoid.WGS84, packedInstance, packedInstance.length);

packedInstance.push(0.0); // projection index for Geographic (default)
packedInstance.push(0.0); // scene3DModeOnly = false

createPackableSpecs(GroundPolylineGeometry, polyline, packedInstance);
});