*
* @type {Event}
- * @default {enabled : true, occlusionAngle : 0.1}
+ * @default {enabled : true, occlusionAngle : 0.1, rangeParameter : 1.0}
*/
this.pointCloudPostProcessorOptions = {
enabled : defaultValue(options.enabled, true),
- occlusionAngle : defaultValue(options.occlusionAngle, 0.1)
+ occlusionAngle : defaultValue(options.occlusionAngle, 0.1),
+ rangeParameter : defaultValue(options.rangeParameter, 0.01),
+ neighborhoodHalfWidth : defaultValue(options.neighborhoodHalfWidth, 4),
+ numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 8)
};
+ this._pointCloudPostProcessor = new PointCloudPostProcessor(this.pointCloudPostProcessorOptions);
+
var that = this;
// We don't know the distance of the tileset until tileset.json is loaded, so use the default distance for now
@@ -1612,7 +1616,10 @@ define([
// TODO : make the processor a static class so it can be used by multiple tilesets?
tileset._pointCloudPostProcessor.update(frameState, numberOfInitialCommands, {
enabled : tileset.pointCloudPostProcessorOptions.enabled,
- occlusionAngle : tileset.pointCloudPostProcessorOptions.occlusionAngle
+ occlusionAngle : tileset.pointCloudPostProcessorOptions.occlusionAngle,
+ rangeParameter : tileset.pointCloudPostProcessorOptions.rangeParameter,
+ neighborhoodHalfWidth : tileset.pointCloudPostProcessorOptions.neighborhoodHalfWidth,
+ numRegionGrowingPasses : tileset.pointCloudPostProcessorOptions.numRegionGrowingPasses
});
}
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index 7d91e2c69baa..0ed3f1c16167 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -46,7 +46,7 @@ define([
/**
* @private
*/
- function PointCloudPostProcessor() {
+ function PointCloudPostProcessor(options) {
this._framebuffers = undefined;
this._colorTextures = undefined;
this._ecTexture = undefined;
@@ -55,7 +55,10 @@ define([
this._blendCommand = undefined;
this._clearCommands = undefined;
- this.occlusionAngle = 0.1;
+ this.occlusionAngle = options.occlusionAngle;
+ this.rangeParameter = options.rangeParameter;
+ this.neighborhoodHalfWidth = options.neighborhoodHalfWidth;
+ this.numRegionGrowingPasses = options.numRegionGrowingPasses;
}
function createSampler() {
@@ -178,6 +181,11 @@ define([
processor._ecTexture = ecTexture;
}
+ function replaceConstants(sourceStr, constantName, replacement) {
+ var r = "#define\\s" + constantName + "\\s([0-9.]+)";
+ return sourceStr.replace(new RegExp(r, "g"), "#define " + constantName + " " + replacement);
+ };
+
function pointOcclusionStage(processor, context) {
var uniformMap = {
pointCloud_colorTexture : function() {
@@ -190,7 +198,14 @@ define([
return processor.occlusionAngle;
}
};
- return context.createViewportQuadCommand(PointOcclusionPass, {
+
+ var pointOcclusionStr = replaceConstants(
+ PointOcclusionPass,
+ "neighborhoodHalfWidth",
+ processor.neighborhoodHalfWidth
+ );
+
+ return context.createViewportQuadCommand(pointOcclusionStr, {
uniformMap : uniformMap,
framebuffer : processor._framebuffers.screenSpacePass,
renderState : RenderState.fromCache({
@@ -213,6 +228,9 @@ define([
},
pointCloud_depthTexture : function() {
return processor._depthTextures[i];
+ },
+ rangeParameter : function() {
+ return processor.rangeParameter;
}
};
@@ -235,7 +253,7 @@ define([
}
function createCommands(processor, context) {
- var numRegionGrowingPasses = 4;
+ var numRegionGrowingPasses = processor.numRegionGrowingPasses;
var drawCommands = new Array(numRegionGrowingPasses + 1);
var i;
@@ -376,15 +394,21 @@ define([
var dirty = false;
// Set options here
- if (options.occlusionAngle != this.occlusionAngle) {
+ if (options.occlusionAngle != this.occlusionAngle ||
+ options.rangeParameter != this.rangeParameter ||
+ options.neighborhoodHalfWidth != this.neighborhoodHalfWidth ||
+ options.numRegionGrowingPasses != this.numRegionGrowingPasses) {
this.occlusionAngle = options.occlusionAngle;
+ this.rangeParameter = options.rangeParameter;
+ this.neighborhoodHalfWidth = options.neighborhoodHalfWidth;
+ this.numRegionGrowingPasses = options.numRegionGrowingPasses;
dirty = true;
}
if (!options.enabled) {
return;
}
-
+
createResources(this, frameState.context, dirty);
// Render point cloud commands into an offscreen FBO.
From 449f3251c0d101808d5d011ee21be7be8b09b300 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 22 Jun 2017 15:30:55 -0400
Subject: [PATCH 024/240] Fixes bug where additional region growing passes
didn't grow empty areas
---
Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
index d17f00df6ebd..7198b7004d02 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
@@ -70,12 +70,11 @@ void fastMedianFinder(in float[neighborhoodSize] neighbors,
if (neighbors[i] <= 1.0 - EPS) {
outDepth = neighbors[i / 2];
outColor = colorNeighbors[i / 2];
- //outColor = vec4(1, 0, 0, 1);
return;
}
}
- outDepth = 0.0;
+ outDepth = 1.0;
outColor = vec4(0, 0, 0, 0);
}
From ce5bf10583ba436d981a7ff65768e2fed0548ede Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 22 Jun 2017 15:31:22 -0400
Subject: [PATCH 025/240] More sane parameter for the number of region growing
passes
---
Source/Scene/Cesium3DTileset.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index ea5fb1ae480a..3f575fbdfa63 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -733,7 +733,7 @@ define([
occlusionAngle : defaultValue(options.occlusionAngle, 0.1),
rangeParameter : defaultValue(options.rangeParameter, 0.01),
neighborhoodHalfWidth : defaultValue(options.neighborhoodHalfWidth, 4),
- numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 8)
+ numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 2)
};
this._pointCloudPostProcessor = new PointCloudPostProcessor(this.pointCloudPostProcessorOptions);
From 2520c89e073905c7e9dc553943b93af7ee23f426 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 22 Jun 2017 15:40:09 -0400
Subject: [PATCH 026/240] Some code cleanup in the region growing filter
---
.../PostProcessFilters/RegionGrowingPass.glsl | 46 +++++++++----------
1 file changed, 22 insertions(+), 24 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
index 7198b7004d02..98e31d81564b 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
@@ -42,28 +42,10 @@ void comparisonNetwork8(inout float[neighborhoodSize] neighbors,
// NOTE: This can be sped up a lot by replacing the depth
// primitive array with two vec4s and using swizzle operations!
// (assuming that the neighborhood is exactly 3x3)
-void fastMedianFinder(in float[neighborhoodSize] neighbors,
- in vec4[neighborhoodSize] colorNeighbors,
- out float outDepth,
- out vec4 outColor) {
- /*for (int i = 0; i < neighborhoodSize; i++) {
- float key = neighbors[i];
- int modifiedFlag = 0;
-
- for (int c = neighborhoodSize - 1; c >= 0; c--) {
- if (c > i - 1)
- continue;
-
- if (neighbors[c] <= key) {
- neighbors[c + 1] = key;
- modifiedFlag = 1;
- break;
- }
- neighbors[c + 1] = neighbors[c];
- }
- if (modifiedFlag == 0)
- neighbors[0] = key;
- }*/
+void fastMedian3(in float[neighborhoodSize] neighbors,
+ in vec4[neighborhoodSize] colorNeighbors,
+ out float outDepth,
+ out vec4 outColor) {
comparisonNetwork8(neighbors, colorNeighbors);
for (int i = neighborhoodSize - 1; i >= 0; i--) {
@@ -78,6 +60,17 @@ void fastMedianFinder(in float[neighborhoodSize] neighbors,
outColor = vec4(0, 0, 0, 0);
}
+void genericMedianFinder(in float[neighborhoodSize] neighbors,
+ in vec4[neighborhoodSize] colorNeighbors,
+ out float outDepth,
+ out vec4 outColor) {
+ // Perhaps we should have a valid way of handling the
+ // difficult-to-optimize cases.
+ // For now this does nothing.
+ outDepth = 0.0;
+ outColor = vec4(1, 0, 0, 1);
+}
+
void main() {
vec4 color = texture2D(pointCloud_colorTexture, v_textureCoordinates);
float depth = texture2D(pointCloud_depthTexture, v_textureCoordinates).r;
@@ -115,7 +108,11 @@ void main() {
}
}
- fastMedianFinder(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+#if neighborhoodFullWidth == 3
+ fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+#else
+ genericMedianFinder(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+#endif
}
// Otherwise if our depth value is valid
else {
@@ -140,7 +137,8 @@ void main() {
float depthDelta = abs(neighbor - depth);
- float weight = (1.0 - rI / 2.0) * (1.0 - min(1.0, depthDelta / max(1e-5, rangeParameter)));
+ float weight = (1.0 - rI / 2.0) * (1.0 - min(1.0, depthDelta / max(1e-5,
+ rangeParameter)));
depthAccum += weight * neighbor;
colorAccum += weight * colorNeighbor;
normalization += weight;
From 8331358eba71f7ca7bc10a9dc888ff2ffc10fa4e Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Fri, 23 Jun 2017 11:07:06 -0400
Subject: [PATCH 027/240] Sector histogram modification has better branching
now
---
.../PointOcclusionPass.glsl | 90 ++++++++++++-------
1 file changed, 58 insertions(+), 32 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
index 4a4d4e96055b..f6f525b41ecc 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
@@ -19,43 +19,69 @@ void modifySectorHistogram(in int index,
in float value,
inout vec4 shFirst,
inout vec4 shSecond) {
- if (index == 0)
- shFirst.x = value;
- else if (index == 1)
- shFirst.y = value;
- else if (index == 2)
- shFirst.z = value;
- else if (index == 3)
- shFirst.w = value;
- else if (index == 4)
- shSecond.x = value;
- else if (index == 5)
- shSecond.y = value;
- else if (index == 6)
- shSecond.z = value;
- else if (index == 7)
- shSecond.w = value;
+ if (index < 4) {
+ if (index < 2) {
+ if (index == 0) {
+ shFirst.x = value;
+ } else {
+ shFirst.y = value;
+ }
+ } else {
+ if (index == 2) {
+ shFirst.z = value;
+ } else {
+ shFirst.w = value;
+ }
+ }
+ } else {
+ if (index < 6) {
+ if (index == 4) {
+ shSecond.x = value;
+ } else {
+ shSecond.y = value;
+ }
+ } else {
+ if (index == 6) {
+ shSecond.z = value;
+ } else {
+ shSecond.w = value;
+ }
+ }
+ }
}
float readSectorHistogram(in int index,
in vec4 shFirst,
in vec4 shSecond) {
- if (index == 0)
- return shFirst.x;
- else if (index == 1)
- return shFirst.y;
- else if (index == 2)
- return shFirst.z;
- else if (index == 3)
- return shFirst.w;
- else if (index == 4)
- return shSecond.x;
- else if (index == 5)
- return shSecond.y;
- else if (index == 6)
- return shSecond.z;
- else if (index == 7)
- return shSecond.w;
+ if (index < 4) {
+ if (index < 2) {
+ if (index == 0) {
+ return shFirst.x;
+ } else {
+ return shFirst.y;
+ }
+ } else {
+ if (index == 2) {
+ return shFirst.z;
+ } else {
+ return shFirst.w;
+ }
+ }
+ } else {
+ if (index < 6) {
+ if (index == 4) {
+ return shSecond.x;
+ } else {
+ return shSecond.y;
+ }
+ } else {
+ if (index == 6) {
+ return shSecond.z;
+ } else {
+ return shSecond.w;
+ }
+ }
+ }
}
int getSector(in vec2 d) {
From c22a98e2af4b7d89b595c8bf4838edef53559f75 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Fri, 23 Jun 2017 15:30:09 -0400
Subject: [PATCH 028/240] Better inverse trig
---
.../PointOcclusionPass.glsl | 25 ++++++++++++++-----
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
index f6f525b41ecc..724fd19d8ae8 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
@@ -2,6 +2,11 @@
#define TAU 6.28318530718
#define PI 3.14159265359
+#define PI_4 0.785398163
+#define C0 1.57073
+#define C1 -0.212053
+#define C2 0.0740935
+#define C3 -0.0186166
#define EPS 1e-6
#define neighborhoodHalfWidth 4 // TUNABLE PARAMETER -- half-width of point-occlusion neighborhood
#define numSectors 8
@@ -11,8 +16,20 @@ uniform sampler2D pointCloud_ECTexture;
uniform float occlusionAngle;
varying vec2 v_textureCoordinates;
+float acosFast(in float inX) {
+ float x = abs(inX);
+ float res = ((C3 * x + C2) * x + C1) * x + C0; // p(x)
+ res *= sqrt(1.0 - x);
+
+ return (inX >= 0.0) ? res : PI - res;
+}
+
+float atanFast(in float x) {
+ return PI_4 * x - x * (abs(x) - 1.0) * (0.2447 + 0.0663 * abs(x));
+}
+
float atan2(in float y, in float x) {
- return x == 0.0 ? sign(y) * PI / 2.0 : atan(y, x);
+ return x == 0.0 ? sign(y) * PI / 2.0 : atanFast(y / x);
}
void modifySectorHistogram(in int index,
@@ -111,9 +128,6 @@ void main() {
float near = czm_currentFrustum.x;
float far = czm_currentFrustum.y;
ivec2 pos = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));
- vec4 color = texture2D(pointCloud_colorTexture, v_textureCoordinates);
- //vec4 color = texture2D(pointCloud_colorTexture, gl_FragCoord.xy / czm_viewport.zw);
- //vec4 EC = texture2D(pointCloud_ECTexture, gl_FragCoord.xy / czm_viewport.zw);
// The position of this pixel in 3D (i.e the position of the point)
vec3 centerPosition = texture2D(pointCloud_ECTexture, v_textureCoordinates).xyz;
@@ -123,7 +137,6 @@ void main() {
if (length(centerPosition) == 0.)
discard;
-
// We split our region of interest (the point of interest and its
// neighbors)
// into sectors. For the purposes of this shader, we have eight
@@ -185,7 +198,7 @@ void main() {
// |vec_1| * |vec_2| * cos(angle_between), and in this case,
// the magnitude of both vectors is 1 because they are both
// normalized.
- float angle = acos(dotProduct);
+ float angle = acosFast(dotProduct);
// This horizon point is behind the current point. That means that it can't
// occlude the current point. So we ignore it and move on.
From 6930938547ad12f8bb9ef323dcf4d6a3ddab670a Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Fri, 23 Jun 2017 16:37:30 -0400
Subject: [PATCH 029/240] Some code cleanup and branch optimization
---
.../PostProcessFilters/RegionGrowingPass.glsl | 106 ++++++++++--------
1 file changed, 58 insertions(+), 48 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
index 98e31d81564b..030267e0ab08 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
@@ -4,6 +4,7 @@
#define neighborhoodFullWidth 3
#define neighborhoodSize 8
#define EPS 1e-6
+#define SQRT2 1.414213562
uniform sampler2D pointCloud_colorTexture;
uniform sampler2D pointCloud_depthTexture;
@@ -71,6 +72,34 @@ void genericMedianFinder(in float[neighborhoodSize] neighbors,
outColor = vec4(1, 0, 0, 1);
}
+void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
+ inout vec4[neighborhoodSize] colorNeighbors) {
+ bool pastCenter = false;
+ for (int j = -neighborhoodHalfWidth; j <= neighborhoodHalfWidth; j++) {
+ for (int i = -neighborhoodHalfWidth; i <= neighborhoodHalfWidth; i++) {
+ ivec2 d = ivec2(i, j);
+ if (d == ivec2(0, 0)) {
+ pastCenter = true;
+ continue;
+ }
+ vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
+ float neighbor = texture2D(pointCloud_depthTexture, neighborCoords).r;
+ vec4 colorNeighbor = texture2D(pointCloud_colorTexture, neighborCoords);
+ if (pastCenter) {
+ depthNeighbors[(j + 1) * neighborhoodFullWidth + i] =
+ neighbor;
+ colorNeighbors[(j + 1) * neighborhoodFullWidth + i] =
+ colorNeighbor;
+ } else {
+ depthNeighbors[(j + 1) * neighborhoodFullWidth + i + 1] =
+ neighbor;
+ colorNeighbors[(j + 1) * neighborhoodFullWidth + i + 1] =
+ colorNeighbor;
+ }
+ }
+ }
+}
+
void main() {
vec4 color = texture2D(pointCloud_colorTexture, v_textureCoordinates);
float depth = texture2D(pointCloud_depthTexture, v_textureCoordinates).r;
@@ -78,36 +107,22 @@ void main() {
vec4 finalColor = color;
float finalDepth = depth;
+ float depthNeighbors[neighborhoodSize];
+ vec4 colorNeighbors[neighborhoodSize];
+ float rIs[neighborhoodSize];
+ rIs[0] = SQRT2;
+ rIs[1] = 1.0;
+ rIs[2] = SQRT2;
+ rIs[3] = 1.0;
+ rIs[4] = 1.0;
+ rIs[5] = SQRT2;
+ rIs[6] = 1.0;
+ rIs[7] = SQRT2;
+
+ loadIntoArray(depthNeighbors, colorNeighbors);
+
// If our depth value is invalid
if (depth > 1.0 - EPS) {
- float depthNeighbors[neighborhoodSize];
- vec4 colorNeighbors[neighborhoodSize];
-
- int pastCenter = 0;
- for (int j = -neighborhoodHalfWidth; j <= neighborhoodHalfWidth; j++) {
- for (int i = -neighborhoodHalfWidth; i <= neighborhoodHalfWidth; i++) {
- ivec2 d = ivec2(i, j);
- if (d == ivec2(0, 0)) {
- pastCenter = 1;
- continue;
- }
- vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
- float neighbor = texture2D(pointCloud_depthTexture, neighborCoords).r;
- vec4 colorNeighbor = texture2D(pointCloud_colorTexture, neighborCoords);
- if (pastCenter == 1) {
- depthNeighbors[(j + 1) * neighborhoodFullWidth + i] =
- neighbor;
- colorNeighbors[(j + 1) * neighborhoodFullWidth + i] =
- colorNeighbor;
- } else {
- depthNeighbors[(j + 1) * neighborhoodFullWidth + i + 1] =
- neighbor;
- colorNeighbors[(j + 1) * neighborhoodFullWidth + i + 1] =
- colorNeighbor;
- }
- }
- }
-
#if neighborhoodFullWidth == 3
fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
#else
@@ -120,33 +135,28 @@ void main() {
vec4 colorAccum = vec4(0);
float normalization = 0.0;
- for (int j = -neighborhoodHalfWidth; j <= neighborhoodHalfWidth; j++) {
- for (int i = -neighborhoodHalfWidth; i <= neighborhoodHalfWidth; i++) {
- ivec2 d = ivec2(i, j);
-
- // Does this even make sense?
- /*if (d == ivec2(0, 0)) {
- continue;
- }*/
-
- float rI = sqrt(float(d.x * d.x + d.y * d.y));
-
- vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
- float neighbor = texture2D(pointCloud_depthTexture, neighborCoords).r;
- vec4 colorNeighbor = texture2D(pointCloud_colorTexture, neighborCoords);
+ for (int i = 0; i < neighborhoodSize; i++) {
+ float neighbor = depthNeighbors[i];
+ vec4 colorNeighbor = colorNeighbors[i];
+ float rI = rIs[i];
+ if (neighbor < 1.0 - EPS) {
float depthDelta = abs(neighbor - depth);
- float weight = (1.0 - rI / 2.0) * (1.0 - min(1.0, depthDelta / max(1e-5,
- rangeParameter)));
- depthAccum += weight * neighbor;
- colorAccum += weight * colorNeighbor;
+ float weight =
+ (1.0 - rI / 2.0) *
+ (1.0 - min(1.0, depthDelta / max(1e-5, rangeParameter)));
+
+ depthAccum += neighbor * weight;
+ colorAccum += colorNeighbor * weight;
normalization += weight;
}
}
- finalDepth = depthAccum / normalization;
- finalColor = colorAccum / normalization;
+ if (depthAccum > EPS) {
+ finalDepth = depthAccum / normalization;
+ finalColor = colorAccum / normalization;
+ }
}
gl_FragColor = finalColor;
From 03f2266c0ee258633830e192aeb6fd06717ab9d2 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Tue, 27 Jun 2017 15:52:42 -0400
Subject: [PATCH 030/240] Updates capability flags for WebGL 2
---
Source/Renderer/Context.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/Source/Renderer/Context.js b/Source/Renderer/Context.js
index d490e65eeea6..4658b7ac3182 100644
--- a/Source/Renderer/Context.js
+++ b/Source/Renderer/Context.js
@@ -195,7 +195,7 @@ define([
webglOptions.alpha = defaultValue(webglOptions.alpha, false); // WebGL default is true
webglOptions.stencil = defaultValue(webglOptions.stencil, true); // WebGL default is false
- var defaultToWebgl2 = false;
+ var defaultToWebgl2 = true;
var requestWebgl2 = defaultToWebgl2 && (typeof WebGL2RenderingContext !== 'undefined');
var webgl2 = false;
@@ -269,11 +269,11 @@ define([
this._antialias = gl.getContextAttributes().antialias;
// Query and initialize extensions
- this._standardDerivatives = !!getExtension(gl, ['OES_standard_derivatives']);
- this._elementIndexUint = !!getExtension(gl, ['OES_element_index_uint']);
- this._depthTexture = !!getExtension(gl, ['WEBGL_depth_texture', 'WEBKIT_WEBGL_depth_texture']);
- this._textureFloat = !!getExtension(gl, ['OES_texture_float']);
- this._fragDepth = !!getExtension(gl, ['EXT_frag_depth']);
+ this._standardDerivatives = !!getExtension(gl, ['OES_standard_derivatives']) || this._webgl2;
+ this._elementIndexUint = !!getExtension(gl, ['OES_element_index_uint']) || this._webgl2;
+ this._depthTexture = !!getExtension(gl, ['WEBGL_depth_texture', 'WEBKIT_WEBGL_depth_texture']) || this._webgl2;
+ this._textureFloat = !!getExtension(gl, ['OES_texture_float']) || this._webgl2;
+ this._fragDepth = !!getExtension(gl, ['EXT_frag_depth']) || this._webgl2;
this._debugShaders = getExtension(gl, ['WEBGL_debug_shaders']);
this._s3tc = !!getExtension(gl, ['WEBGL_compressed_texture_s3tc', 'MOZ_WEBGL_compressed_texture_s3tc', 'WEBKIT_WEBGL_compressed_texture_s3tc']);
From d6b1869b288d6c622eef11c7178eb043c41c78d0 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Tue, 27 Jun 2017 15:53:46 -0400
Subject: [PATCH 031/240] Newline after version in ShaderSource
---
Source/Renderer/ShaderSource.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Source/Renderer/ShaderSource.js b/Source/Renderer/ShaderSource.js
index 9d8a9ff6fd0d..8147b191277e 100644
--- a/Source/Renderer/ShaderSource.js
+++ b/Source/Renderer/ShaderSource.js
@@ -213,7 +213,7 @@ define([
// #version must be first
// defaults to #version 100 if not specified
if (defined(version)) {
- result = '#version ' + version;
+ result = '#version ' + version + '\n';
}
for (i = 0; i < extensions.length; i++) {
From 5862b6ba3cb064c758ea5375003a6d4396454edb Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Tue, 27 Jun 2017 15:55:18 -0400
Subject: [PATCH 032/240] Updates pointcloud processor to WebGL 2.0
---
Source/Scene/PointCloudPostProcessor.js | 114 +++++++++++++++++-
.../PointOcclusionPass.glsl | 12 +-
.../PostProcessFilters/RegionGrowingPass.glsl | 17 +--
3 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index 0ed3f1c16167..a6ab86ada3b3 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -263,6 +263,21 @@ define([
drawCommands[i + 1] = regionGrowingStage(processor, context, i);
}
+ for (i = 0; i < drawCommands.length; i++) {
+ var shaderProgram = drawCommands[i].shaderProgram;
+ var vsSource = shaderProgram.vertexShaderSource.clone();
+ var fsSource = shaderProgram.fragmentShaderSource.clone();
+ var attributeLocations = shaderProgram._attributeLocations;
+ for (var a = 0; a < vsSource.sources.length; a++) {
+ vsSource.sources[a] = glslModernize(vsSource.sources[a], false, true);
+ }
+ drawCommands[i].shaderProgram = context.shaderCache.getShaderProgram({
+ vertexShaderSource : vsSource,
+ fragmentShaderSource : fsSource,
+ attributeLocations : attributeLocations
+ });
+ }
+
// TODO : point cloud depth information is lost
var blendFS =
'uniform sampler2D pointCloud_colorTexture; \n' +
@@ -341,6 +356,92 @@ define([
return context.depthTexture;
}
+ function glslModernize(source, isFragmentShader, first) {
+ var mainFunctionRegex = /void\s+main\(\)/;
+ var splitSource = source.split('\n');
+ var mainFunctionLine;
+ for (var number = 0; number < splitSource.length; number++) {
+ var line = splitSource[number];
+ if (mainFunctionRegex.exec(line)) {
+ mainFunctionLine = number;
+ }
+ };
+
+ function replaceInSource(regex, replacement) {
+ for (var number = 0; number < splitSource.length; number++) {
+ splitSource[number] = splitSource[number].replace(regex, replacement);
+ }
+ }
+
+ function findInSource(regex) {
+ for (var number = 0; number < splitSource.length; number++) {
+ if (splitSource[number].search(regex) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function compileSource() {
+ var wholeSource = "";
+ for (var number = 0; number < splitSource.length; number++) {
+ wholeSource += splitSource[number] + "\n";
+ }
+ return wholeSource;
+ }
+
+ function removeExtension(name) {
+ var regex = "#extension\\s+GL_" + name + "\\s+:\\s+[a-zA-Z0-9]+\\s*$";
+ replaceInSource(new RegExp(regex, "g"), "");
+ }
+
+ for (var i = 0; i < 10; i++) {
+ var fragDataString = "gl_FragData\\[" + i + "\\]";
+ var newOutput = 'czm_out' + i;
+ var regex = new RegExp(fragDataString, "g");
+ if (source.search(fragDataString) != -1) {
+ replaceInSource(regex, newOutput);
+ splitSource.splice(mainFunctionLine, 0,
+ "layout(location = " + i + ") out vec4 " +
+ newOutput + ";");
+ }
+ }
+
+ if (findInSource(/gl_FragColor/)) {
+ replaceInSource(/gl_FragColor/, "czm_fragColor");
+ splitSource.splice(mainFunctionLine, 0, "layout(location = 0) out vec4 czm_fragColor");
+ }
+
+ if (first === true) {
+ var versionThree = "#version 300 es";
+ var foundVersion = false;
+ for (var number = 0; number < splitSource.length; number++) {
+ if (splitSource[number].search(/#version/) != -1) {
+ splitSource[number] = versionThree;
+ foundVersion = true;
+ }
+ }
+
+ if (!foundVersion) {
+ splitSource.splice(0, 0, versionThree);
+ }
+ }
+
+ removeExtension("EXT_draw_buffers");
+ removeExtension("EXT_frag_depth");
+
+ replaceInSource(/texture2D/, "texture");
+
+ if (isFragmentShader) {
+ replaceInSource(/varying/, "in");
+ } else {
+ replaceInSource(/attribute/, "in");
+ replaceInSource(/varying/, "out");
+ }
+
+ return compileSource();
+ }
+
function getECShaderProgram(context, shaderProgram) {
var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, 'EC');
if (!defined(shader)) {
@@ -375,7 +476,18 @@ define([
'{ \n' +
' czm_point_cloud_post_process_main(); \n' +
' gl_FragData[1] = vec4(v_positionECPS, 0); \n' +
- '}');
+ '}');
+
+ var modernized, i;
+ for (i = 0; i < vs.sources.length; i++) {
+ modernized = glslModernize(vs.sources[i], false, i === 0);
+ vs.sources[i] = modernized;
+ }
+
+ for (i = 0; i < fs.sources.length; i++) {
+ modernized = glslModernize(fs.sources[i], true, i === 0);
+ fs.sources[i] = modernized;
+ }
shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, 'EC', {
vertexShaderSource : vs,
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
index 724fd19d8ae8..c38337fefd4c 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
@@ -1,4 +1,4 @@
-#extension GL_EXT_frag_depth : enable
+#version 300 es
#define TAU 6.28318530718
#define PI 3.14159265359
@@ -14,7 +14,7 @@
uniform sampler2D pointCloud_colorTexture;
uniform sampler2D pointCloud_ECTexture;
uniform float occlusionAngle;
-varying vec2 v_textureCoordinates;
+in vec2 v_textureCoordinates;
float acosFast(in float inX) {
float x = abs(inX);
@@ -130,7 +130,7 @@ void main() {
ivec2 pos = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));
// The position of this pixel in 3D (i.e the position of the point)
- vec3 centerPosition = texture2D(pointCloud_ECTexture, v_textureCoordinates).xyz;
+ vec3 centerPosition = texture(pointCloud_ECTexture, v_textureCoordinates).xyz;
// If the EC of this pixel is zero, that means that it's not a valid
// pixel. We don't care about reprojecting it.
@@ -169,8 +169,8 @@ void main() {
ivec2 pI = pos + d;
// We now calculate the actual 3D position of the horizon pixel (the horizon point)
- vec3 neighborPosition = texture2D(pointCloud_ECTexture,
- vec2(pI) / czm_viewport.zw).xyz;
+ vec3 neighborPosition = texture(pointCloud_ECTexture,
+ vec2(pI) / czm_viewport.zw).xyz;
// If our horizon pixel doesn't exist, ignore it and move on
if (length(neighborPosition) < EPS || pI == pos) {
@@ -231,5 +231,5 @@ void main() {
// This is the depth of this pixel... assuming that it's valid.
float linearizedDepth = (-centerPosition.z - near) / (far - near);
- gl_FragDepthEXT = linearizedDepth;
+ gl_FragDepth = linearizedDepth;
}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
index 030267e0ab08..9a79787ccb18 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
@@ -1,4 +1,4 @@
-#extension GL_EXT_frag_depth : enable
+#version 300 es
#define neighborhoodHalfWidth 1 // TUNABLE PARAMETER -- half-width of region-growing kernel
#define neighborhoodFullWidth 3
@@ -10,7 +10,8 @@ uniform sampler2D pointCloud_colorTexture;
uniform sampler2D pointCloud_depthTexture;
uniform float rangeParameter;
-varying vec2 v_textureCoordinates;
+in vec2 v_textureCoordinates;
+layout(location = 0) out vec4 colorOut;
#define otherswap(a, b, aC, bC) if (a > b) { temp = a; a = b; b = temp; tempColor = aC; aC = bC; bC = tempColor; }
@@ -83,8 +84,8 @@ void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
continue;
}
vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
- float neighbor = texture2D(pointCloud_depthTexture, neighborCoords).r;
- vec4 colorNeighbor = texture2D(pointCloud_colorTexture, neighborCoords);
+ float neighbor = texture(pointCloud_depthTexture, neighborCoords).r;
+ vec4 colorNeighbor = texture(pointCloud_colorTexture, neighborCoords);
if (pastCenter) {
depthNeighbors[(j + 1) * neighborhoodFullWidth + i] =
neighbor;
@@ -101,8 +102,8 @@ void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
}
void main() {
- vec4 color = texture2D(pointCloud_colorTexture, v_textureCoordinates);
- float depth = texture2D(pointCloud_depthTexture, v_textureCoordinates).r;
+ vec4 color = texture(pointCloud_colorTexture, v_textureCoordinates);
+ float depth = texture(pointCloud_depthTexture, v_textureCoordinates).r;
vec4 finalColor = color;
float finalDepth = depth;
@@ -159,6 +160,6 @@ void main() {
}
}
- gl_FragColor = finalColor;
- gl_FragDepthEXT = finalDepth;
+ colorOut = finalColor;
+ gl_FragDepth = finalDepth;
}
From 37cef074bcb37d39516b95d7baf01b124da9346f Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 09:14:45 -0400
Subject: [PATCH 033/240] Adds support for the EXT_color_buffer_float extension
---
Source/Renderer/Context.js | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/Source/Renderer/Context.js b/Source/Renderer/Context.js
index 4658b7ac3182..3ef399b048f0 100644
--- a/Source/Renderer/Context.js
+++ b/Source/Renderer/Context.js
@@ -276,6 +276,10 @@ define([
this._fragDepth = !!getExtension(gl, ['EXT_frag_depth']) || this._webgl2;
this._debugShaders = getExtension(gl, ['WEBGL_debug_shaders']);
+ if (this._webgl2) {
+ this._colorBufferFloat = !!getExtension(gl, ['EXT_color_buffer_float']);
+ }
+
this._s3tc = !!getExtension(gl, ['WEBGL_compressed_texture_s3tc', 'MOZ_WEBGL_compressed_texture_s3tc', 'WEBKIT_WEBGL_compressed_texture_s3tc']);
this._pvrtc = !!getExtension(gl, ['WEBGL_compressed_texture_pvrtc', 'WEBKIT_WEBGL_compressed_texture_pvrtc']);
this._etc1 = !!getExtension(gl, ['WEBGL_compressed_texture_etc1']);
@@ -615,6 +619,20 @@ define([
}
},
+ /**
+ * true if the EXT_color_buffer_float extension is supported. This
+ * extension makes the formats gl.R16F, gl.RG16F, gl.RGBA16F, gl.R32F, gl.RG32F,
+ * gl.RGBA32F, gl.R11F_G11F_B10F color renderable.
+ * @memberof Context.prototype
+ * @type {Boolean}
+ * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/}
+ */
+ colorBufferFloat : {
+ get : function() {
+ return this._colorBufferFloat;
+ }
+ },
+
/**
* true if the WEBGL_draw_buffers extension is supported. This
* extensions provides support for multiple render targets. The framebuffer object can have mutiple
From e9855c058a35d1124eaae6cc8677f961eb53d794 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 10:04:09 -0400
Subject: [PATCH 034/240] Moves GLSLModernizer to its own file
---
Source/Renderer/GLSLModernizer.js | 100 ++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 Source/Renderer/GLSLModernizer.js
diff --git a/Source/Renderer/GLSLModernizer.js b/Source/Renderer/GLSLModernizer.js
new file mode 100644
index 000000000000..e85ce03e827a
--- /dev/null
+++ b/Source/Renderer/GLSLModernizer.js
@@ -0,0 +1,100 @@
+/*global define*/
+define([], function() {
+ 'use strict';
+
+ /**
+ * A function to port GLSL shaders from GLSL ES 1.00 to GLSL ES 2.00
+ *
+ * This function is nowhere near comprehensive or complete. It just
+ * handles some common cases.
+ *
+ * @private
+ */
+ function glslModernize(source, isFragmentShader, first) {
+ var mainFunctionRegex = /void\s+main\(\)/;
+ var splitSource = source.split('\n');
+ var mainFunctionLine;
+ for (var number = 0; number < splitSource.length; number++) {
+ var line = splitSource[number];
+ if (mainFunctionRegex.exec(line)) {
+ mainFunctionLine = number;
+ }
+ };
+
+ function replaceInSource(regex, replacement) {
+ for (var number = 0; number < splitSource.length; number++) {
+ splitSource[number] = splitSource[number].replace(regex, replacement);
+ }
+ }
+
+ function findInSource(regex) {
+ for (var number = 0; number < splitSource.length; number++) {
+ if (splitSource[number].search(regex) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function compileSource() {
+ var wholeSource = "";
+ for (var number = 0; number < splitSource.length; number++) {
+ wholeSource += splitSource[number] + "\n";
+ }
+ return wholeSource;
+ }
+
+ function removeExtension(name) {
+ var regex = "#extension\\s+GL_" + name + "\\s+:\\s+[a-zA-Z0-9]+\\s*$";
+ replaceInSource(new RegExp(regex, "g"), "");
+ }
+
+ for (var i = 0; i < 10; i++) {
+ var fragDataString = "gl_FragData\\[" + i + "\\]";
+ var newOutput = 'czm_out' + i;
+ var regex = new RegExp(fragDataString, "g");
+ if (source.search(fragDataString) != -1) {
+ replaceInSource(regex, newOutput);
+ splitSource.splice(mainFunctionLine, 0,
+ "layout(location = " + i + ") out vec4 " +
+ newOutput + ";");
+ }
+ }
+
+ if (findInSource(/gl_FragColor/)) {
+ replaceInSource(/gl_FragColor/, "czm_fragColor");
+ splitSource.splice(mainFunctionLine, 0, "layout(location = 0) out vec4 czm_fragColor");
+ }
+
+ if (first === true) {
+ var versionThree = "#version 300 es";
+ var foundVersion = false;
+ for (var number = 0; number < splitSource.length; number++) {
+ if (splitSource[number].search(/#version/) != -1) {
+ splitSource[number] = versionThree;
+ foundVersion = true;
+ }
+ }
+
+ if (!foundVersion) {
+ splitSource.splice(0, 0, versionThree);
+ }
+ }
+
+ removeExtension("EXT_draw_buffers");
+ removeExtension("EXT_frag_depth");
+
+ replaceInSource(/texture2D/, "texture");
+
+ if (isFragmentShader) {
+ replaceInSource(/varying/, "in");
+ } else {
+ replaceInSource(/attribute/, "in");
+ replaceInSource(/varying/, "out");
+ }
+
+ return compileSource();
+ }
+
+ return glslModernize;
+});
From 4e9ad177dd80c9a76c586c533f53a8cff5bfc8b2 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 10:24:58 -0400
Subject: [PATCH 035/240] Fixes issues where glslModernize does not add a
semicolon when updating gl_FragColor
---
Source/Renderer/GLSLModernizer.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Source/Renderer/GLSLModernizer.js b/Source/Renderer/GLSLModernizer.js
index e85ce03e827a..568b48b11faa 100644
--- a/Source/Renderer/GLSLModernizer.js
+++ b/Source/Renderer/GLSLModernizer.js
@@ -63,7 +63,7 @@ define([], function() {
if (findInSource(/gl_FragColor/)) {
replaceInSource(/gl_FragColor/, "czm_fragColor");
- splitSource.splice(mainFunctionLine, 0, "layout(location = 0) out vec4 czm_fragColor");
+ splitSource.splice(mainFunctionLine, 0, "layout(location = 0) out vec4 czm_fragColor;");
}
if (first === true) {
From 19251646036d8f6882f9a989532bbfb15bfa6e94 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 10:42:37 -0400
Subject: [PATCH 036/240] Refactors GLSLModernizer
---
Source/Renderer/GLSLModernizer.js | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/Source/Renderer/GLSLModernizer.js b/Source/Renderer/GLSLModernizer.js
index 568b48b11faa..ab73b31a2aaa 100644
--- a/Source/Renderer/GLSLModernizer.js
+++ b/Source/Renderer/GLSLModernizer.js
@@ -96,5 +96,25 @@ define([], function() {
return compileSource();
}
- return glslModernize;
+ function glslModernizeShaderProgram(context, shaderProgram) {
+ var vsSource = shaderProgram.vertexShaderSource.clone();
+ var fsSource = shaderProgram.fragmentShaderSource.clone();
+
+ var newShaderProgramOptions = {
+ vertexShaderSource : vsSource,
+ fragmentShaderSource : fsSource,
+ gl : shaderProgram._gl,
+ logShaderCompilation : shaderProgram._logShaderCompilation,
+ attributeLocations : shaderProgram._attributeLocations
+ };
+
+ return context.shaderCache.getShaderProgram(newShaderProgramOptions);
+ }
+
+ var GLSLModernizer = {
+ glslModernize : glslModernize,
+ glslModernizeShaderProgram : glslModernizeShaderProgram
+ };
+
+ return GLSLModernizer;
});
From 1196a06696873e1acfa1e2ee82bf9fa59fe88f3b Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 11:14:18 -0400
Subject: [PATCH 037/240] Another refactor of GLSLModernizer -- now supports
cleaning up ShaderSource(s)
---
Source/Renderer/GLSLModernizer.js | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/Source/Renderer/GLSLModernizer.js b/Source/Renderer/GLSLModernizer.js
index ab73b31a2aaa..f4e1b1bda8d9 100644
--- a/Source/Renderer/GLSLModernizer.js
+++ b/Source/Renderer/GLSLModernizer.js
@@ -10,7 +10,15 @@ define([], function() {
*
* @private
*/
- function glslModernize(source, isFragmentShader, first) {
+ function glslModernizeShaderSource(shaderSource, isFragmentShader) {
+ for (var i = 0; i < shaderSource.sources.length; i++) {
+ shaderSource.sources[i] =
+ glslModernizeShaderText(shaderSource.sources[i], isFragmentShader, i === 0);
+ }
+ shaderSource.defines.push("MODERNIZED");
+ }
+
+ function glslModernizeShaderText(source, isFragmentShader, first) {
var mainFunctionRegex = /void\s+main\(\)/;
var splitSource = source.split('\n');
var mainFunctionLine;
@@ -100,6 +108,9 @@ define([], function() {
var vsSource = shaderProgram.vertexShaderSource.clone();
var fsSource = shaderProgram.fragmentShaderSource.clone();
+ glslModernizeShaderSource(vsSource, false);
+ glslModernizeShaderSource(fsSource, true);
+
var newShaderProgramOptions = {
vertexShaderSource : vsSource,
fragmentShaderSource : fsSource,
@@ -112,7 +123,8 @@ define([], function() {
}
var GLSLModernizer = {
- glslModernize : glslModernize,
+ glslModernizeShaderText : glslModernizeShaderText,
+ glslModernizeShaderSource : glslModernizeShaderSource,
glslModernizeShaderProgram : glslModernizeShaderProgram
};
From 99304d167fa938101c5adb1283871696bfc3fa58 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 11:14:56 -0400
Subject: [PATCH 038/240] Modifies PointCloudPostProcessor so that it now uses
the new GLSLModernizer
---
Source/Scene/PointCloudPostProcessor.js | 102 ++----------------------
1 file changed, 5 insertions(+), 97 deletions(-)
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index a6ab86ada3b3..f15ae3e88842 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -7,6 +7,7 @@ define([
'../Renderer/ClearCommand',
'../Renderer/DrawCommand',
'../Renderer/Framebuffer',
+ '../Renderer/GLSLModernizer',
'../Renderer/Pass',
'../Renderer/PixelDatatype',
'../Renderer/RenderState',
@@ -28,6 +29,7 @@ define([
ClearCommand,
DrawCommand,
Framebuffer,
+ GLSLModernizer,
Pass,
PixelDatatype,
RenderState,
@@ -269,7 +271,7 @@ define([
var fsSource = shaderProgram.fragmentShaderSource.clone();
var attributeLocations = shaderProgram._attributeLocations;
for (var a = 0; a < vsSource.sources.length; a++) {
- vsSource.sources[a] = glslModernize(vsSource.sources[a], false, true);
+ vsSource.sources[a] = GLSLModernizer.glslModernizeShaderText(vsSource.sources[a], false, true);
}
drawCommands[i].shaderProgram = context.shaderCache.getShaderProgram({
vertexShaderSource : vsSource,
@@ -356,92 +358,6 @@ define([
return context.depthTexture;
}
- function glslModernize(source, isFragmentShader, first) {
- var mainFunctionRegex = /void\s+main\(\)/;
- var splitSource = source.split('\n');
- var mainFunctionLine;
- for (var number = 0; number < splitSource.length; number++) {
- var line = splitSource[number];
- if (mainFunctionRegex.exec(line)) {
- mainFunctionLine = number;
- }
- };
-
- function replaceInSource(regex, replacement) {
- for (var number = 0; number < splitSource.length; number++) {
- splitSource[number] = splitSource[number].replace(regex, replacement);
- }
- }
-
- function findInSource(regex) {
- for (var number = 0; number < splitSource.length; number++) {
- if (splitSource[number].search(regex) != -1) {
- return true;
- }
- }
- return false;
- }
-
- function compileSource() {
- var wholeSource = "";
- for (var number = 0; number < splitSource.length; number++) {
- wholeSource += splitSource[number] + "\n";
- }
- return wholeSource;
- }
-
- function removeExtension(name) {
- var regex = "#extension\\s+GL_" + name + "\\s+:\\s+[a-zA-Z0-9]+\\s*$";
- replaceInSource(new RegExp(regex, "g"), "");
- }
-
- for (var i = 0; i < 10; i++) {
- var fragDataString = "gl_FragData\\[" + i + "\\]";
- var newOutput = 'czm_out' + i;
- var regex = new RegExp(fragDataString, "g");
- if (source.search(fragDataString) != -1) {
- replaceInSource(regex, newOutput);
- splitSource.splice(mainFunctionLine, 0,
- "layout(location = " + i + ") out vec4 " +
- newOutput + ";");
- }
- }
-
- if (findInSource(/gl_FragColor/)) {
- replaceInSource(/gl_FragColor/, "czm_fragColor");
- splitSource.splice(mainFunctionLine, 0, "layout(location = 0) out vec4 czm_fragColor");
- }
-
- if (first === true) {
- var versionThree = "#version 300 es";
- var foundVersion = false;
- for (var number = 0; number < splitSource.length; number++) {
- if (splitSource[number].search(/#version/) != -1) {
- splitSource[number] = versionThree;
- foundVersion = true;
- }
- }
-
- if (!foundVersion) {
- splitSource.splice(0, 0, versionThree);
- }
- }
-
- removeExtension("EXT_draw_buffers");
- removeExtension("EXT_frag_depth");
-
- replaceInSource(/texture2D/, "texture");
-
- if (isFragmentShader) {
- replaceInSource(/varying/, "in");
- } else {
- replaceInSource(/attribute/, "in");
- replaceInSource(/varying/, "out");
- }
-
- return compileSource();
- }
-
function getECShaderProgram(context, shaderProgram) {
var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, 'EC');
if (!defined(shader)) {
@@ -478,16 +394,8 @@ define([
' gl_FragData[1] = vec4(v_positionECPS, 0); \n' +
'}');
- var modernized, i;
- for (i = 0; i < vs.sources.length; i++) {
- modernized = glslModernize(vs.sources[i], false, i === 0);
- vs.sources[i] = modernized;
- }
-
- for (i = 0; i < fs.sources.length; i++) {
- modernized = glslModernize(fs.sources[i], true, i === 0);
- fs.sources[i] = modernized;
- }
+ GLSLModernizer.glslModernizeShaderSource(vs, false);
+ GLSLModernizer.glslModernizeShaderSource(fs, true);
shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, 'EC', {
vertexShaderSource : vs,
From af64702ff9c8fcf7243c463941ac11afe8c8f080 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 11:32:39 -0400
Subject: [PATCH 039/240] Uses the correct internal format for floating point
RGBA textures in WebGL 2
---
Source/Renderer/Texture.js | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Source/Renderer/Texture.js b/Source/Renderer/Texture.js
index a330e3aecfc0..69adb4baad96 100644
--- a/Source/Renderer/Texture.js
+++ b/Source/Renderer/Texture.js
@@ -72,6 +72,20 @@ define([
internalFormat = WebGLConstants.DEPTH_COMPONENT24;
}
}
+
+ if (pixelDatatype == PixelDatatype.FLOAT) {
+ switch (pixelFormat) {
+ case PixelFormat.RGBA:
+ internalFormat = WebGLConstants.RGBA32F;
+ break;
+ case PixelFormat.RG:
+ internalFormat = WebGLConstants.RG32F;
+ break;
+ case PixelFormat.R:
+ internalFormat = WebGLConstants.R32F;
+ break;
+ }
+ }
}
//>>includeStart('debug', pragmas.debug);
From 915442c9f8f4334dc30afbe8638c21958f2bcfd4 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 16:00:44 -0400
Subject: [PATCH 040/240] GLSLModernizer is now preprocessor-branch aware
---
Source/Renderer/GLSLModernizer.js | 140 +++++++++++++++++++++++++++++-
1 file changed, 137 insertions(+), 3 deletions(-)
diff --git a/Source/Renderer/GLSLModernizer.js b/Source/Renderer/GLSLModernizer.js
index f4e1b1bda8d9..ce41a6dace8b 100644
--- a/Source/Renderer/GLSLModernizer.js
+++ b/Source/Renderer/GLSLModernizer.js
@@ -17,7 +17,7 @@ define([], function() {
}
shaderSource.defines.push("MODERNIZED");
}
-
+
function glslModernizeShaderText(source, isFragmentShader, first) {
var mainFunctionRegex = /void\s+main\(\)/;
var splitSource = source.split('\n');
@@ -37,7 +37,7 @@ define([], function() {
function findInSource(regex) {
for (var number = 0; number < splitSource.length; number++) {
- if (splitSource[number].search(regex) != -1) {
+ if (splitSource[number].search(regex) !== -1) {
return true;
}
}
@@ -51,27 +51,161 @@ define([], function() {
}
return wholeSource;
}
+
+ function setAdd(variable, set1) {
+ if (set1.indexOf(variable) === -1)
+ set1.push(variable);
+ }
+
+ function setUnion(set1, set2) {
+ for (var a = 0; a < set2.length; a++) {
+ setAdd(set2[a], set1);
+ }
+ }
+
+ function getVariablePreprocessorBranch(variablesThatWeCareAbout) {
+ var variableMap = {};
+ var negativeMap = {};
+
+ for (var a = 0; a < variablesThatWeCareAbout.length; a++) {
+ var variableThatWeCareAbout = variablesThatWeCareAbout[a];
+ variableMap[variableThatWeCareAbout] = [null];
+ }
+
+ var stack = [];
+ for (var i = 0; i < splitSource.length; i++) {
+ var line = splitSource[i];
+ var hasIF = line.search(/(#ifdef|#if)/g) !== -1;
+ var hasELSE = line.search(/#else/g) !== -1;
+ var hasENDIF = line.search(/#endif/g) !== -1;
+
+ if (hasIF) {
+ stack.push(line);
+ } else if (hasELSE) {
+ var top = stack[stack.length - 1];
+ var op = top.replace("ifdef", "ifndef");
+ if (op.search(/if/g) !== -1) {
+ op = op.replace(/(#if\s+)(\S*)([^]*)/, "$1!($2)$3");
+ }
+ stack.pop();
+ stack.push(op);
+
+ negativeMap[top] = op;
+ negativeMap[op] = top;
+ } else if (hasENDIF) {
+ stack.pop();
+ } else if (line.search(/layout/g) === -1) {
+ for (a = 0; a < variablesThatWeCareAbout.length; a++) {
+ var care = variablesThatWeCareAbout[a];
+ if (line.indexOf(care) !== -1) {
+ if (variableMap[care].length === 1 &&
+ variableMap[care][0] === null) {
+ variableMap[care] = stack.slice();
+ } else {
+ variableMap[care] = variableMap[care].filter(
+ function(x) { return stack.indexOf(x) >= 0; });
+ }
+ }
+ }
+ }
+ }
+
+ // This code is probably no longer needed... it was used to handle
+ // removing negative conditions
+ for (var care in variableMap) {
+ if (variableMap.hasOwnProperty(care)) {
+ var entry = variableMap[care];
+ var toDelete = [];
+ for (var b = 0; b < entry.length; b++) {
+ var item = entry[b];
+ if (entry.indexOf(negativeMap[item]) !== -1) {
+ toDelete.push(item);
+ toDelete.push(negativeMap[item]);
+ }
+ }
+
+ for (var c = 0; c < toDelete.length; c++) {
+ var ind = entry.indexOf(toDelete[c]);
+ if (ind !== -1) {
+ entry.splice(ind, 1);
+ }
+ }
+ }
+ }
+
+ for (var care in variableMap) {
+ if (variableMap.hasOwnProperty(care)) {
+ if (variableMap.length === 1 &&
+ variableMap[0] === null) {
+ variableMap.splice(0, 1);
+ }
+ }
+ }
+
+ return variableMap;
+ }
function removeExtension(name) {
var regex = "#extension\\s+GL_" + name + "\\s+:\\s+[a-zA-Z0-9]+\\s*$";
replaceInSource(new RegExp(regex, "g"), "");
}
+ var variableSet = [];
+
for (var i = 0; i < 10; i++) {
var fragDataString = "gl_FragData\\[" + i + "\\]";
var newOutput = 'czm_out' + i;
var regex = new RegExp(fragDataString, "g");
if (source.search(fragDataString) != -1) {
+ setAdd(newOutput, variableSet);
replaceInSource(regex, newOutput);
splitSource.splice(mainFunctionLine, 0,
"layout(location = " + i + ") out vec4 " +
newOutput + ";");
+ mainFunctionLine += 1;
}
}
+ var czmFragColor = "czm_fragColor";
if (findInSource(/gl_FragColor/)) {
- replaceInSource(/gl_FragColor/, "czm_fragColor");
+ setAdd(czmFragColor, variableSet);
+ replaceInSource(/gl_FragColor/, czmFragColor);
splitSource.splice(mainFunctionLine, 0, "layout(location = 0) out vec4 czm_fragColor;");
+ mainFunctionLine += 1;
+ }
+
+ var variableMap = getVariablePreprocessorBranch(variableSet);
+ console.log(variableMap);
+ var lineAdds = {};
+ for (var c = 0; c < splitSource.length; c++) {
+ var l = splitSource[c];
+ for (var care in variableMap) {
+ if (variableMap.hasOwnProperty(care)) {
+ var matchVar =
+ new RegExp("(layout)[^]+(out)[^]+(" + care + ")[^]+", "g");
+ if (matchVar.exec(l) !== null) {
+ lineAdds[l] = care;
+ }
+ }
+ }
+ }
+
+ for (var layoutDeclaration in lineAdds) {
+ if (lineAdds.hasOwnProperty(layoutDeclaration)) {
+ var variableName = lineAdds[layoutDeclaration];
+ var lineNumber = splitSource.indexOf(layoutDeclaration);
+ var entry = variableMap[variableName];
+ var depth = entry.length;
+ var d;
+ //console.log(entry);
+ for (d = 0; d < depth; d++) {
+ splitSource.splice(lineNumber, 0, entry[d]);
+ }
+ lineNumber += depth + 1;
+ for (d = depth - 1; d >= 0; d--) {
+ splitSource.splice(lineNumber, 0, "#endif //" + entry[d]);
+ }
+ }
}
if (first === true) {
From c2cea4711f0d78460fa325289660b684d16ab53a Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 16:10:44 -0400
Subject: [PATCH 041/240] Adds GLSLModernizer calls to OIT
---
Source/Scene/OIT.js | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/Source/Scene/OIT.js b/Source/Scene/OIT.js
index 8f0131f6cae2..6bc03a584ba7 100644
--- a/Source/Scene/OIT.js
+++ b/Source/Scene/OIT.js
@@ -9,6 +9,7 @@ define([
'../Renderer/ClearCommand',
'../Renderer/DrawCommand',
'../Renderer/Framebuffer',
+ '../Renderer/GLSLModernizer',
'../Renderer/PixelDatatype',
'../Renderer/RenderState',
'../Renderer/ShaderSource',
@@ -27,6 +28,7 @@ define([
ClearCommand,
DrawCommand,
Framebuffer,
+ GLSLModernizer,
PixelDatatype,
RenderState,
ShaderSource,
@@ -255,6 +257,11 @@ define([
uniformMap : uniformMap,
owner : this
});
+ if (context.webgl2) {
+ this._compositeCommand.shaderProgram =
+ GLSLModernizer.glslModernizeShaderProgram(
+ context, this._compositeCommand.shaderProgram);
+ }
}
if (!defined(this._adjustTranslucentCommand)) {
@@ -277,6 +284,11 @@ define([
uniformMap : uniformMap,
owner : this
});
+ if (context.webgl2) {
+ this._adjustTranslucentCommand.shaderProgram =
+ GLSLModernizer.glslModernizeShaderProgram(
+ context, this._adjustTranslucentCommand.shaderProgram);
+ }
} else if (this._translucentMultipassSupport) {
fs = new ShaderSource({
sources : [AdjustTranslucentFS]
@@ -295,6 +307,11 @@ define([
uniformMap : uniformMap,
owner : this
});
+ if (context.webgl2) {
+ this._adjustTranslucentCommand.shaderProgram =
+ GLSLModernizer.glslModernizeShaderProgram(
+ context, this._adjustTranslucentCommand.shaderProgram);
+ }
uniformMap = {
u_bgColor : function() {
@@ -309,6 +326,11 @@ define([
uniformMap : uniformMap,
owner : this
});
+ if (context.webgl2) {
+ this._adjustAlphaCommand.shaderProgram =
+ GLSLModernizer.glslModernizeShaderProgram(
+ context, this._adjustAlphaCommand.shaderProgram);
+ }
}
}
From 5e66040c144f701976fda521d4b81f26b01eb166 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Wed, 28 Jun 2017 17:26:40 -0400
Subject: [PATCH 042/240] GLSLModernizer now ignores shaders that are already
written in GLSL ES 3.00
---
Source/Renderer/GLSLModernizer.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Source/Renderer/GLSLModernizer.js b/Source/Renderer/GLSLModernizer.js
index ce41a6dace8b..bf96157ef6bf 100644
--- a/Source/Renderer/GLSLModernizer.js
+++ b/Source/Renderer/GLSLModernizer.js
@@ -21,6 +21,11 @@ define([], function() {
function glslModernizeShaderText(source, isFragmentShader, first) {
var mainFunctionRegex = /void\s+main\(\)/;
var splitSource = source.split('\n');
+
+ if (source.search(/#version 300 es/g) !== -1) {
+ return source;
+ }
+
var mainFunctionLine;
for (var number = 0; number < splitSource.length; number++) {
var line = splitSource[number];
From 5562f2430114301ab0640ba165e7e0c656780ce6 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 09:46:26 -0400
Subject: [PATCH 043/240] Adds WebGL 2 checks
---
Source/Scene/PointCloudPostProcessor.js | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index f15ae3e88842..3cfc7bc03707 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -271,7 +271,10 @@ define([
var fsSource = shaderProgram.fragmentShaderSource.clone();
var attributeLocations = shaderProgram._attributeLocations;
for (var a = 0; a < vsSource.sources.length; a++) {
- vsSource.sources[a] = GLSLModernizer.glslModernizeShaderText(vsSource.sources[a], false, true);
+ if (context.webgl2) {
+ vsSource.sources[a] = GLSLModernizer.glslModernizeShaderText(
+ vsSource.sources[a], false, true);
+ }
}
drawCommands[i].shaderProgram = context.shaderCache.getShaderProgram({
vertexShaderSource : vsSource,
@@ -392,10 +395,12 @@ define([
'{ \n' +
' czm_point_cloud_post_process_main(); \n' +
' gl_FragData[1] = vec4(v_positionECPS, 0); \n' +
- '}');
+ '}');
- GLSLModernizer.glslModernizeShaderSource(vs, false);
- GLSLModernizer.glslModernizeShaderSource(fs, true);
+ if (context.webgl2) {
+ GLSLModernizer.glslModernizeShaderSource(vs, false);
+ GLSLModernizer.glslModernizeShaderSource(fs, true);
+ }
shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, 'EC', {
vertexShaderSource : vs,
From a1db0a31ba572e6428ca9f78bf32ea266dac8a19 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 10:00:09 -0400
Subject: [PATCH 044/240] PointCloudPostProcessor now loads different shaders
depending on the WebGL version
---
Source/Scene/PointCloudPostProcessor.js | 20 +-
.../PointOcclusionPassGL1.glsl | 235 ++++++++++++++++++
...onPass.glsl => PointOcclusionPassGL2.glsl} | 0
.../RegionGrowingPassGL1.glsl | 164 ++++++++++++
...ingPass.glsl => RegionGrowingPassGL2.glsl} | 0
5 files changed, 413 insertions(+), 6 deletions(-)
create mode 100644 Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
rename Source/Shaders/PostProcessFilters/{PointOcclusionPass.glsl => PointOcclusionPassGL2.glsl} (100%)
create mode 100644 Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
rename Source/Shaders/PostProcessFilters/{RegionGrowingPass.glsl => RegionGrowingPassGL2.glsl} (100%)
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index 3cfc7bc03707..fa7826b3f5c5 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -19,8 +19,10 @@ define([
'../Renderer/TextureMinificationFilter',
'../Renderer/TextureWrap',
'../Scene/BlendingState',
- '../Shaders/PostProcessFilters/PointOcclusionPass',
- '../Shaders/PostProcessFilters/RegionGrowingPass'
+ '../Shaders/PostProcessFilters/PointOcclusionPassGL1',
+ '../Shaders/PostProcessFilters/RegionGrowingPassGL1',
+ '../Shaders/PostProcessFilters/PointOcclusionPassGL2',
+ '../Shaders/PostProcessFilters/RegionGrowingPassGL2'
], function(
Color,
defined,
@@ -41,8 +43,11 @@ define([
TextureMinificationFilter,
TextureWrap,
BlendingState,
- PointOcclusionPass,
- RegionGrowingPass) {
+ PointOcclusionPassGL1,
+ RegionGrowingPassGL1,
+ PointOcclusionPassGL2,
+ RegionGrowingPassGL2,
+ ) {
'use strict';
/**
@@ -202,7 +207,7 @@ define([
};
var pointOcclusionStr = replaceConstants(
- PointOcclusionPass,
+ (context.webgl2) ? PointOcclusionPassGL2 : PointOcclusionPassGL1,
"neighborhoodHalfWidth",
processor.neighborhoodHalfWidth
);
@@ -240,7 +245,10 @@ define([
processor._framebuffers.regionGrowingPassA :
processor._framebuffers.regionGrowingPassB;
- return context.createViewportQuadCommand(RegionGrowingPass, {
+ var regionGrowingPassStr = (context.webgl2) ?
+ RegionGrowingPassGL2 :
+ RegionGrowingPassGL1;
+ return context.createViewportQuadCommand(regionGrowingPassStr, {
uniformMap : uniformMap,
framebuffer : framebuffer,
renderState : RenderState.fromCache({
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
new file mode 100644
index 000000000000..724fd19d8ae8
--- /dev/null
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
@@ -0,0 +1,235 @@
+#extension GL_EXT_frag_depth : enable
+
+#define TAU 6.28318530718
+#define PI 3.14159265359
+#define PI_4 0.785398163
+#define C0 1.57073
+#define C1 -0.212053
+#define C2 0.0740935
+#define C3 -0.0186166
+#define EPS 1e-6
+#define neighborhoodHalfWidth 4 // TUNABLE PARAMETER -- half-width of point-occlusion neighborhood
+#define numSectors 8
+
+uniform sampler2D pointCloud_colorTexture;
+uniform sampler2D pointCloud_ECTexture;
+uniform float occlusionAngle;
+varying vec2 v_textureCoordinates;
+
+float acosFast(in float inX) {
+ float x = abs(inX);
+ float res = ((C3 * x + C2) * x + C1) * x + C0; // p(x)
+ res *= sqrt(1.0 - x);
+
+ return (inX >= 0.0) ? res : PI - res;
+}
+
+float atanFast(in float x) {
+ return PI_4 * x - x * (abs(x) - 1.0) * (0.2447 + 0.0663 * abs(x));
+}
+
+float atan2(in float y, in float x) {
+ return x == 0.0 ? sign(y) * PI / 2.0 : atanFast(y / x);
+}
+
+void modifySectorHistogram(in int index,
+ in float value,
+ inout vec4 shFirst,
+ inout vec4 shSecond) {
+ if (index < 4) {
+ if (index < 2) {
+ if (index == 0) {
+ shFirst.x = value;
+ } else {
+ shFirst.y = value;
+ }
+ } else {
+ if (index == 2) {
+ shFirst.z = value;
+ } else {
+ shFirst.w = value;
+ }
+ }
+ } else {
+ if (index < 6) {
+ if (index == 4) {
+ shSecond.x = value;
+ } else {
+ shSecond.y = value;
+ }
+ } else {
+ if (index == 6) {
+ shSecond.z = value;
+ } else {
+ shSecond.w = value;
+ }
+ }
+ }
+}
+
+float readSectorHistogram(in int index,
+ in vec4 shFirst,
+ in vec4 shSecond) {
+ if (index < 4) {
+ if (index < 2) {
+ if (index == 0) {
+ return shFirst.x;
+ } else {
+ return shFirst.y;
+ }
+ } else {
+ if (index == 2) {
+ return shFirst.z;
+ } else {
+ return shFirst.w;
+ }
+ }
+ } else {
+ if (index < 6) {
+ if (index == 4) {
+ return shSecond.x;
+ } else {
+ return shSecond.y;
+ }
+ } else {
+ if (index == 6) {
+ return shSecond.z;
+ } else {
+ return shSecond.w;
+ }
+ }
+ }
+}
+
+int getSector(in vec2 d) {
+ float angle = (atan2(float(d.y), float(d.x)) + PI) / TAU;
+ return int(angle * float(numSectors));
+}
+
+// Subsamples the neighbor pixel and stores the sector number
+// in each component of the output
+ivec4 getSectors(in vec2 vi) {
+ return ivec4(getSector(vi + vec2(-0.5, 0.5)),
+ getSector(vi + vec2(0.5, -0.5)),
+ getSector(vi + vec2(0.5, 0.5)),
+ getSector(vi + vec2(-0.5, -0.5)));
+}
+
+ivec2 collapseSectors(in ivec4 sectors) {
+ int first = sectors[0];
+ ivec2 collapsed = ivec2(first, first);
+ for (int i = 1; i < 4; i++)
+ if (sectors[i] != first)
+ collapsed.y = sectors[i];
+ return collapsed;
+}
+
+void main() {
+ float near = czm_currentFrustum.x;
+ float far = czm_currentFrustum.y;
+ ivec2 pos = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));
+
+ // The position of this pixel in 3D (i.e the position of the point)
+ vec3 centerPosition = texture2D(pointCloud_ECTexture, v_textureCoordinates).xyz;
+
+ // If the EC of this pixel is zero, that means that it's not a valid
+ // pixel. We don't care about reprojecting it.
+ if (length(centerPosition) == 0.)
+ discard;
+
+ // We split our region of interest (the point of interest and its
+ // neighbors)
+ // into sectors. For the purposes of this shader, we have eight
+ // sectors.
+ //
+ // Each entry of sector_histogram contains the current best horizon
+ // pixel angle
+ ivec2 halfNeighborhood = ivec2(neighborhoodHalfWidth / 2,
+ neighborhoodHalfWidth / 2);
+ // Upper left corner of the neighborhood
+ ivec2 upperLeftCorner = pos - halfNeighborhood;
+ // Lower right corner of the neighborhood
+ ivec2 lowerRightCorner = pos + halfNeighborhood;
+
+ // The widest the cone can be is 90 degrees
+ float maxAngle = PI / 2.0;
+
+ vec4 shFirst = vec4(maxAngle);
+ vec4 shSecond = vec4(maxAngle);
+
+ // Right now this is obvious because everything happens in eye space,
+ // but this kind of statement is nice for a reference implementation
+ vec3 viewer = vec3(0.0);
+
+ for (int i = -neighborhoodHalfWidth; i <= neighborhoodHalfWidth; i++) {
+ for (int j = -neighborhoodHalfWidth; j <= neighborhoodHalfWidth; j++) {
+ // d is the relative offset from the horizon pixel to the center pixel
+ // in 2D
+ ivec2 d = ivec2(i, j);
+ ivec2 pI = pos + d;
+
+ // We now calculate the actual 3D position of the horizon pixel (the horizon point)
+ vec3 neighborPosition = texture2D(pointCloud_ECTexture,
+ vec2(pI) / czm_viewport.zw).xyz;
+
+ // If our horizon pixel doesn't exist, ignore it and move on
+ if (length(neighborPosition) < EPS || pI == pos) {
+ continue;
+ }
+
+ // sectors contains both possible sectors that the
+ // neighbor pixel could be in
+ ivec2 sectors = collapseSectors(getSectors(vec2(d)));
+
+ // This is the offset of the horizon point from the center in 3D
+ // (a 3D analog of d)
+ vec3 c = neighborPosition - centerPosition;
+
+ // Now we calculate the dot product between the vector
+ // from the viewer to the center and the vector to the horizon pixel.
+ // We normalize both vectors first because we only care about their relative
+ // directions
+ // TODO: Redo the math and figure out whether the result should be negated or not
+ float dotProduct = dot(normalize(viewer - centerPosition),
+ normalize(c));
+
+ // We calculate the angle that this horizon pixel would make
+ // in the cone. The dot product is be equal to
+ // |vec_1| * |vec_2| * cos(angle_between), and in this case,
+ // the magnitude of both vectors is 1 because they are both
+ // normalized.
+ float angle = acosFast(dotProduct);
+
+ // This horizon point is behind the current point. That means that it can't
+ // occlude the current point. So we ignore it and move on.
+ if (angle > maxAngle)
+ continue;
+ // If we've found a horizon pixel, store it in the histogram
+ if (readSectorHistogram(sectors.x, shFirst, shSecond) > angle) {
+ modifySectorHistogram(sectors.x, angle, shFirst, shSecond);
+ }
+ if (readSectorHistogram(sectors.y, shFirst, shSecond) > angle) {
+ modifySectorHistogram(sectors.y, angle, shFirst, shSecond);
+ }
+ }
+ }
+
+ float accumulator = 0.0;
+ for (int i = 0; i < numSectors; i++) {
+ float angle = readSectorHistogram(i, shFirst, shSecond);
+ // If the z component is less than zero,
+ // that means that there is no valid horizon pixel
+ if (angle <= 0.0 || angle > maxAngle)
+ angle = maxAngle;
+ accumulator += angle;
+ }
+
+ // The solid angle is too small, so we occlude this point
+ if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
+ discard;
+ }
+
+ // This is the depth of this pixel... assuming that it's valid.
+ float linearizedDepth = (-centerPosition.z - near) / (far - near);
+ gl_FragDepthEXT = linearizedDepth;
+}
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
similarity index 100%
rename from Source/Shaders/PostProcessFilters/PointOcclusionPass.glsl
rename to Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
new file mode 100644
index 000000000000..030267e0ab08
--- /dev/null
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
@@ -0,0 +1,164 @@
+#extension GL_EXT_frag_depth : enable
+
+#define neighborhoodHalfWidth 1 // TUNABLE PARAMETER -- half-width of region-growing kernel
+#define neighborhoodFullWidth 3
+#define neighborhoodSize 8
+#define EPS 1e-6
+#define SQRT2 1.414213562
+
+uniform sampler2D pointCloud_colorTexture;
+uniform sampler2D pointCloud_depthTexture;
+uniform float rangeParameter;
+
+varying vec2 v_textureCoordinates;
+
+#define otherswap(a, b, aC, bC) if (a > b) { temp = a; a = b; b = temp; tempColor = aC; aC = bC; bC = tempColor; }
+
+void comparisonNetwork8(inout float[neighborhoodSize] neighbors,
+ inout vec4[neighborhoodSize] neighborsColor) {
+ float temp;
+ vec4 tempColor;
+
+ otherswap(neighbors[0], neighbors[1], neighborsColor[0], neighborsColor[1]);
+ otherswap(neighbors[2], neighbors[3], neighborsColor[2], neighborsColor[3]);
+ otherswap(neighbors[0], neighbors[2], neighborsColor[0], neighborsColor[2]);
+ otherswap(neighbors[1], neighbors[3], neighborsColor[1], neighborsColor[3]);
+ otherswap(neighbors[1], neighbors[2], neighborsColor[1], neighborsColor[2]);
+ otherswap(neighbors[4], neighbors[5], neighborsColor[4], neighborsColor[5]);
+ otherswap(neighbors[6], neighbors[7], neighborsColor[6], neighborsColor[7]);
+ otherswap(neighbors[4], neighbors[6], neighborsColor[4], neighborsColor[6]);
+ otherswap(neighbors[5], neighbors[7], neighborsColor[5], neighborsColor[7]);
+ otherswap(neighbors[5], neighbors[6], neighborsColor[5], neighborsColor[6]);
+ otherswap(neighbors[0], neighbors[4], neighborsColor[0], neighborsColor[4]);
+ otherswap(neighbors[1], neighbors[5], neighborsColor[1], neighborsColor[5]);
+ otherswap(neighbors[1], neighbors[4], neighborsColor[1], neighborsColor[4]);
+ otherswap(neighbors[2], neighbors[6], neighborsColor[2], neighborsColor[6]);
+ otherswap(neighbors[3], neighbors[7], neighborsColor[3], neighborsColor[7]);
+ otherswap(neighbors[3], neighbors[6], neighborsColor[3], neighborsColor[6]);
+ otherswap(neighbors[2], neighbors[4], neighborsColor[2], neighborsColor[4]);
+ otherswap(neighbors[3], neighbors[5], neighborsColor[3], neighborsColor[5]);
+ otherswap(neighbors[3], neighbors[4], neighborsColor[3], neighborsColor[4]);
+}
+
+// NOTE: This can be sped up a lot by replacing the depth
+// primitive array with two vec4s and using swizzle operations!
+// (assuming that the neighborhood is exactly 3x3)
+void fastMedian3(in float[neighborhoodSize] neighbors,
+ in vec4[neighborhoodSize] colorNeighbors,
+ out float outDepth,
+ out vec4 outColor) {
+ comparisonNetwork8(neighbors, colorNeighbors);
+
+ for (int i = neighborhoodSize - 1; i >= 0; i--) {
+ if (neighbors[i] <= 1.0 - EPS) {
+ outDepth = neighbors[i / 2];
+ outColor = colorNeighbors[i / 2];
+ return;
+ }
+ }
+
+ outDepth = 1.0;
+ outColor = vec4(0, 0, 0, 0);
+}
+
+void genericMedianFinder(in float[neighborhoodSize] neighbors,
+ in vec4[neighborhoodSize] colorNeighbors,
+ out float outDepth,
+ out vec4 outColor) {
+ // Perhaps we should have a valid way of handling the
+ // difficult-to-optimize cases.
+ // For now this does nothing.
+ outDepth = 0.0;
+ outColor = vec4(1, 0, 0, 1);
+}
+
+void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
+ inout vec4[neighborhoodSize] colorNeighbors) {
+ bool pastCenter = false;
+ for (int j = -neighborhoodHalfWidth; j <= neighborhoodHalfWidth; j++) {
+ for (int i = -neighborhoodHalfWidth; i <= neighborhoodHalfWidth; i++) {
+ ivec2 d = ivec2(i, j);
+ if (d == ivec2(0, 0)) {
+ pastCenter = true;
+ continue;
+ }
+ vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
+ float neighbor = texture2D(pointCloud_depthTexture, neighborCoords).r;
+ vec4 colorNeighbor = texture2D(pointCloud_colorTexture, neighborCoords);
+ if (pastCenter) {
+ depthNeighbors[(j + 1) * neighborhoodFullWidth + i] =
+ neighbor;
+ colorNeighbors[(j + 1) * neighborhoodFullWidth + i] =
+ colorNeighbor;
+ } else {
+ depthNeighbors[(j + 1) * neighborhoodFullWidth + i + 1] =
+ neighbor;
+ colorNeighbors[(j + 1) * neighborhoodFullWidth + i + 1] =
+ colorNeighbor;
+ }
+ }
+ }
+}
+
+void main() {
+ vec4 color = texture2D(pointCloud_colorTexture, v_textureCoordinates);
+ float depth = texture2D(pointCloud_depthTexture, v_textureCoordinates).r;
+
+ vec4 finalColor = color;
+ float finalDepth = depth;
+
+ float depthNeighbors[neighborhoodSize];
+ vec4 colorNeighbors[neighborhoodSize];
+ float rIs[neighborhoodSize];
+ rIs[0] = SQRT2;
+ rIs[1] = 1.0;
+ rIs[2] = SQRT2;
+ rIs[3] = 1.0;
+ rIs[4] = 1.0;
+ rIs[5] = SQRT2;
+ rIs[6] = 1.0;
+ rIs[7] = SQRT2;
+
+ loadIntoArray(depthNeighbors, colorNeighbors);
+
+ // If our depth value is invalid
+ if (depth > 1.0 - EPS) {
+#if neighborhoodFullWidth == 3
+ fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+#else
+ genericMedianFinder(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+#endif
+ }
+ // Otherwise if our depth value is valid
+ else {
+ float depthAccum = 0.0;
+ vec4 colorAccum = vec4(0);
+ float normalization = 0.0;
+
+ for (int i = 0; i < neighborhoodSize; i++) {
+ float neighbor = depthNeighbors[i];
+ vec4 colorNeighbor = colorNeighbors[i];
+ float rI = rIs[i];
+
+ if (neighbor < 1.0 - EPS) {
+ float depthDelta = abs(neighbor - depth);
+
+ float weight =
+ (1.0 - rI / 2.0) *
+ (1.0 - min(1.0, depthDelta / max(1e-5, rangeParameter)));
+
+ depthAccum += neighbor * weight;
+ colorAccum += colorNeighbor * weight;
+ normalization += weight;
+ }
+ }
+
+ if (depthAccum > EPS) {
+ finalDepth = depthAccum / normalization;
+ finalColor = colorAccum / normalization;
+ }
+ }
+
+ gl_FragColor = finalColor;
+ gl_FragDepthEXT = finalDepth;
+}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
similarity index 100%
rename from Source/Shaders/PostProcessFilters/RegionGrowingPass.glsl
rename to Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
From 1c0f9ed6fe7c5968f2a5d12b7ebdf61fadba640a Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 10:14:06 -0400
Subject: [PATCH 045/240] PointOcclusionPass now takes advantage of
non-constant array indexing
---
.../PointOcclusionPassGL2.glsl | 87 +++----------------
1 file changed, 11 insertions(+), 76 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
index c38337fefd4c..1780f02ba9be 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
@@ -32,75 +32,6 @@ float atan2(in float y, in float x) {
return x == 0.0 ? sign(y) * PI / 2.0 : atanFast(y / x);
}
-void modifySectorHistogram(in int index,
- in float value,
- inout vec4 shFirst,
- inout vec4 shSecond) {
- if (index < 4) {
- if (index < 2) {
- if (index == 0) {
- shFirst.x = value;
- } else {
- shFirst.y = value;
- }
- } else {
- if (index == 2) {
- shFirst.z = value;
- } else {
- shFirst.w = value;
- }
- }
- } else {
- if (index < 6) {
- if (index == 4) {
- shSecond.x = value;
- } else {
- shSecond.y = value;
- }
- } else {
- if (index == 6) {
- shSecond.z = value;
- } else {
- shSecond.w = value;
- }
- }
- }
-}
-
-float readSectorHistogram(in int index,
- in vec4 shFirst,
- in vec4 shSecond) {
- if (index < 4) {
- if (index < 2) {
- if (index == 0) {
- return shFirst.x;
- } else {
- return shFirst.y;
- }
- } else {
- if (index == 2) {
- return shFirst.z;
- } else {
- return shFirst.w;
- }
- }
- } else {
- if (index < 6) {
- if (index == 4) {
- return shSecond.x;
- } else {
- return shSecond.y;
- }
- } else {
- if (index == 6) {
- return shSecond.z;
- } else {
- return shSecond.w;
- }
- }
- }
-}
-
int getSector(in vec2 d) {
float angle = (atan2(float(d.y), float(d.x)) + PI) / TAU;
return int(angle * float(numSectors));
@@ -154,8 +85,12 @@ void main() {
// The widest the cone can be is 90 degrees
float maxAngle = PI / 2.0;
- vec4 shFirst = vec4(maxAngle);
- vec4 shSecond = vec4(maxAngle);
+ // Our sector array defaults to an angle of "maxAngle" in each sector
+ // (i.e no horizon pixels!)
+ float sh[numSectors];
+ for (int i = 0; i < numSectors; i++) {
+ sh[i] = maxAngle;
+ }
// Right now this is obvious because everything happens in eye space,
// but this kind of statement is nice for a reference implementation
@@ -205,18 +140,18 @@ void main() {
if (angle > maxAngle)
continue;
// If we've found a horizon pixel, store it in the histogram
- if (readSectorHistogram(sectors.x, shFirst, shSecond) > angle) {
- modifySectorHistogram(sectors.x, angle, shFirst, shSecond);
+ if (sh[sectors.x] > angle) {
+ sh[sectors.x] = angle;
}
- if (readSectorHistogram(sectors.y, shFirst, shSecond) > angle) {
- modifySectorHistogram(sectors.y, angle, shFirst, shSecond);
+ if (sh[sectors.y] > angle) {
+ sh[sectors.y] = angle;
}
}
}
float accumulator = 0.0;
for (int i = 0; i < numSectors; i++) {
- float angle = readSectorHistogram(i, shFirst, shSecond);
+ float angle = sh[i];
// If the z component is less than zero,
// that means that there is no valid horizon pixel
if (angle <= 0.0 || angle > maxAngle)
From 33e680933dd45bc3ab266f8f65c15a0a15adc3bf Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 13:54:52 -0400
Subject: [PATCH 046/240] Starts the transition over the multifrustrum support
---
Source/Scene/Scene.js | 2 +-
Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index 48098c1b70d4..ac4532665287 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -436,7 +436,7 @@ define([
* @type {Number}
* @default 1000.0
*/
- this.farToNearRatio = 1e8;
+ this.farToNearRatio = 1000.0;
/**
* Determines the uniform depth size in meters of each frustum of the multifrustum in 2D. If a primitive or model close
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
index 1780f02ba9be..432b2f11a771 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
@@ -56,8 +56,8 @@ ivec2 collapseSectors(in ivec4 sectors) {
}
void main() {
- float near = czm_currentFrustum.x;
- float far = czm_currentFrustum.y;
+ float near = czm_entireFrustum.x;
+ float far = czm_entireFrustum.y;
ivec2 pos = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));
// The position of this pixel in 3D (i.e the position of the point)
From 6ae66d22b714cab0eaeffde1e8691727e1653ad2 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 16:17:52 -0400
Subject: [PATCH 047/240] Point occlusion operator now writes depth to a color
attachment
---
Source/Scene/PointCloudPostProcessor.js | 62 +++++++++----------
.../PointOcclusionPassGL2.glsl | 11 ++--
.../RegionGrowingPassGL2.glsl | 25 ++++----
3 files changed, 51 insertions(+), 47 deletions(-)
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index fa7826b3f5c5..c86bbdefa9b8 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -58,6 +58,7 @@ define([
this._colorTextures = undefined;
this._ecTexture = undefined;
this._depthTextures = undefined;
+ this._dirty = undefined;
this._drawCommands = undefined;
this._blendCommand = undefined;
this._clearCommands = undefined;
@@ -80,6 +81,7 @@ define([
function destroyFramebuffers(processor) {
processor._depthTextures[0].destroy();
processor._depthTextures[1].destroy();
+ processor._dirty.destroy();
processor._colorTextures[0].destroy();
processor._colorTextures[1].destroy();
processor._ecTexture.destroy();
@@ -112,24 +114,31 @@ define([
sampler : createSampler()
});
- for (i = 0; i < 3; ++i) {
- if (i < 2) {
- colorTextures[i] = new Texture({
- context : context,
- width : screenWidth,
- height : screenHeight,
- pixelFormat : PixelFormat.RGBA,
- pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
- sampler : createSampler()
- });
- }
+ var dirty = new Texture({
+ context: context,
+ width: screenWidth,
+ height: screenHeight,
+ pixelFormat: PixelFormat.DEPTH_STENCIL,
+ pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
+ sampler: createSampler()
+ });
+
+ for (i = 0; i < 2; ++i) {
+ colorTextures[i] = new Texture({
+ context : context,
+ width : screenWidth,
+ height : screenHeight,
+ pixelFormat : PixelFormat.RGBA,
+ pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
+ sampler : createSampler()
+ });
depthTextures[i] = new Texture({
context : context,
width : screenWidth,
height : screenHeight,
- pixelFormat : PixelFormat.DEPTH_STENCIL,
- pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8,
+ pixelFormat : PixelFormat.RGBA,
+ pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
sampler : createSampler()
});
}
@@ -139,18 +148,18 @@ define([
*
* 1. We render normally to our prior:
* * Color -> 0
- * * Depth -> 2 ("dirty depth")
+ * * Depth -> dirty ("dirty depth")
* * EC -> 0
* 2. Then we perform the screen-space point occlusion stage with color[0] and EC:
* * No color
- * * Depth -> 0
+ * * Pseudo-depth -> 0
* * No EC
* 3a. Then we perform the region growing stage with color[0] and depth[0]:
* * Color -> 1
- * * Depth -> 1
+ * * Pseudo-depth -> 1
* 3b. We do the region growing stage again with color[1] and depth[1]:
* * Color -> 0
- * * Depth -> 0
+ * * Pseudo-depth -> 0
* 3c. Repeat steps 3a and 3b until all holes are filled and/or we run
* out of time.
*/
@@ -162,30 +171,29 @@ define([
colorTextures[0],
ecTexture
],
- depthStencilTexture : depthTextures[2],
+ depthStencilTexture : dirty,
destroyAttachments : false
}),
"screenSpacePass": new Framebuffer({
context : context,
- depthStencilTexture : depthTextures[0],
+ colorTextures : [depthTextures[0]],
destroyAttachments : false
}),
"regionGrowingPassA": new Framebuffer({
context : context,
- depthStencilTexture : depthTextures[1],
- colorTextures : [colorTextures[1]],
+ colorTextures : [colorTextures[1], depthTextures[1]],
destroyAttachments : false
}),
"regionGrowingPassB": new Framebuffer({
context: context,
- depthStencilTexture: depthTextures[0],
- colorTextures: [colorTextures[0]],
+ colorTextures: [colorTextures[0], depthTextures[0]],
destroyAttachments: false
})
};
processor._depthTextures = depthTextures;
processor._colorTextures = colorTextures;
processor._ecTexture = ecTexture;
+ processor._dirty = dirty;
}
function replaceConstants(sourceStr, constantName, replacement) {
@@ -216,10 +224,6 @@ define([
uniformMap : uniformMap,
framebuffer : processor._framebuffers.screenSpacePass,
renderState : RenderState.fromCache({
- depthMask : true,
- depthTest : {
- enabled : true
- }
}),
pass : Pass.CESIUM_3D_TILE,
owner : processor
@@ -252,10 +256,6 @@ define([
uniformMap : uniformMap,
framebuffer : framebuffer,
renderState : RenderState.fromCache({
- depthMask : true,
- depthTest : {
- enabled : true
- }
}),
pass : Pass.CESIUM_3D_TILE,
owner : processor
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
index 432b2f11a771..fc6abcd1c84f 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
@@ -16,6 +16,8 @@ uniform sampler2D pointCloud_ECTexture;
uniform float occlusionAngle;
in vec2 v_textureCoordinates;
+layout(location = 0) out vec4 depthOut;
+
float acosFast(in float inX) {
float x = abs(inX);
float res = ((C3 * x + C2) * x + C1) * x + C0; // p(x)
@@ -161,10 +163,11 @@ void main() {
// The solid angle is too small, so we occlude this point
if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
+ depthOut = czm_packDepth(0.0);
discard;
+ } else {
+ // This is the depth of this pixel... assuming that it's valid.
+ float linearizedDepth = (-centerPosition.z - near) / (far - near);
+ depthOut = czm_packDepth(linearizedDepth);
}
-
- // This is the depth of this pixel... assuming that it's valid.
- float linearizedDepth = (-centerPosition.z - near) / (far - near);
- gl_FragDepth = linearizedDepth;
}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
index 9a79787ccb18..1b9b4b5077d2 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
@@ -3,7 +3,7 @@
#define neighborhoodHalfWidth 1 // TUNABLE PARAMETER -- half-width of region-growing kernel
#define neighborhoodFullWidth 3
#define neighborhoodSize 8
-#define EPS 1e-6
+#define EPS 1e-8
#define SQRT2 1.414213562
uniform sampler2D pointCloud_colorTexture;
@@ -12,6 +12,7 @@ uniform float rangeParameter;
in vec2 v_textureCoordinates;
layout(location = 0) out vec4 colorOut;
+layout(location = 1) out vec4 depthOut;
#define otherswap(a, b, aC, bC) if (a > b) { temp = a; a = b; b = temp; tempColor = aC; aC = bC; bC = tempColor; }
@@ -50,15 +51,15 @@ void fastMedian3(in float[neighborhoodSize] neighbors,
out vec4 outColor) {
comparisonNetwork8(neighbors, colorNeighbors);
- for (int i = neighborhoodSize - 1; i >= 0; i--) {
- if (neighbors[i] <= 1.0 - EPS) {
- outDepth = neighbors[i / 2];
- outColor = colorNeighbors[i / 2];
+ for (int i = 0; i < neighborhoodSize; i++) {
+ if (neighbors[i] > EPS) {
+ outDepth = neighbors[i + (neighborhoodSize - 1 - i) / 2];
+ outColor = colorNeighbors[i + (neighborhoodSize - 1 - i) / 2];
return;
}
}
- outDepth = 1.0;
+ outDepth = 0.0;
outColor = vec4(0, 0, 0, 0);
}
@@ -84,7 +85,7 @@ void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
continue;
}
vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
- float neighbor = texture(pointCloud_depthTexture, neighborCoords).r;
+ float neighbor = czm_unpackDepth(texture(pointCloud_depthTexture, neighborCoords));
vec4 colorNeighbor = texture(pointCloud_colorTexture, neighborCoords);
if (pastCenter) {
depthNeighbors[(j + 1) * neighborhoodFullWidth + i] =
@@ -103,7 +104,7 @@ void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
void main() {
vec4 color = texture(pointCloud_colorTexture, v_textureCoordinates);
- float depth = texture(pointCloud_depthTexture, v_textureCoordinates).r;
+ float depth = czm_unpackDepth(texture(pointCloud_depthTexture, v_textureCoordinates));
vec4 finalColor = color;
float finalDepth = depth;
@@ -123,7 +124,7 @@ void main() {
loadIntoArray(depthNeighbors, colorNeighbors);
// If our depth value is invalid
- if (depth > 1.0 - EPS) {
+ if (depth < EPS) {
#if neighborhoodFullWidth == 3
fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
#else
@@ -141,12 +142,12 @@ void main() {
vec4 colorNeighbor = colorNeighbors[i];
float rI = rIs[i];
- if (neighbor < 1.0 - EPS) {
+ if (neighbor > EPS) {
float depthDelta = abs(neighbor - depth);
float weight =
(1.0 - rI / 2.0) *
- (1.0 - min(1.0, depthDelta / max(1e-5, rangeParameter)));
+ (1.0 - min(1.0, depthDelta / max(1e-38, rangeParameter)));
depthAccum += neighbor * weight;
colorAccum += colorNeighbor * weight;
@@ -161,5 +162,5 @@ void main() {
}
colorOut = finalColor;
- gl_FragDepth = finalDepth;
+ depthOut = czm_packDepth(finalDepth);
}
From 636a423ce9f1754f837125b410d65490884b9795 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 16:18:16 -0400
Subject: [PATCH 048/240] Adjusts defaults for the region growing parameter
---
.../gallery/3D Tiles Point Cloud Post Processing.html | 2 +-
Source/Scene/Cesium3DTileset.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html
index a8ce046043c6..1ddf60c90bc0 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html
@@ -49,7 +49,7 @@
Region Growing Range Parameter
-
+
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index 3f575fbdfa63..31f7cc8bbda3 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -731,7 +731,7 @@ define([
this.pointCloudPostProcessorOptions = {
enabled : defaultValue(options.enabled, true),
occlusionAngle : defaultValue(options.occlusionAngle, 0.1),
- rangeParameter : defaultValue(options.rangeParameter, 0.01),
+ rangeParameter : defaultValue(options.rangeParameter, 2e-38),
neighborhoodHalfWidth : defaultValue(options.neighborhoodHalfWidth, 4),
numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 2)
};
From 36665930907de2921d8f0054c4e0e574acb72c23 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 16:32:12 -0400
Subject: [PATCH 049/240] Removes unnecessary write
---
Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl | 1 -
1 file changed, 1 deletion(-)
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
index fc6abcd1c84f..ffb4526bff5e 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
@@ -163,7 +163,6 @@ void main() {
// The solid angle is too small, so we occlude this point
if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
- depthOut = czm_packDepth(0.0);
discard;
} else {
// This is the depth of this pixel... assuming that it's valid.
From dcaafafe9289663b4273c78da151d60d16555845 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 16:37:34 -0400
Subject: [PATCH 050/240] Fixes the GLSL ES 1.00 shaders
---
.../PointOcclusionPassGL1.glsl | 2 +-
.../RegionGrowingPassGL1.glsl | 21 ++++++++++---------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
index 724fd19d8ae8..a83fb1957938 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
@@ -231,5 +231,5 @@ void main() {
// This is the depth of this pixel... assuming that it's valid.
float linearizedDepth = (-centerPosition.z - near) / (far - near);
- gl_FragDepthEXT = linearizedDepth;
+ gl_FragData[0] = czm_packDepth(linearizedDepth);
}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
index 030267e0ab08..08f1dcf23238 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
@@ -1,9 +1,10 @@
#extension GL_EXT_frag_depth : enable
+#extension GL_EXT_draw_buffers : enable
#define neighborhoodHalfWidth 1 // TUNABLE PARAMETER -- half-width of region-growing kernel
#define neighborhoodFullWidth 3
#define neighborhoodSize 8
-#define EPS 1e-6
+#define EPS 1e-8
#define SQRT2 1.414213562
uniform sampler2D pointCloud_colorTexture;
@@ -49,15 +50,15 @@ void fastMedian3(in float[neighborhoodSize] neighbors,
out vec4 outColor) {
comparisonNetwork8(neighbors, colorNeighbors);
- for (int i = neighborhoodSize - 1; i >= 0; i--) {
- if (neighbors[i] <= 1.0 - EPS) {
- outDepth = neighbors[i / 2];
- outColor = colorNeighbors[i / 2];
+ for (int i = 0; i < neighborhoodSize; i++) {
+ if (neighbors[i] > EPS) {
+ outDepth = neighbors[i + (neighborhoodSize - 1 - i) / 2];
+ outColor = colorNeighbors[i + (neighborhoodSize - 1 - i) / 2];
return;
}
}
- outDepth = 1.0;
+ outDepth = 0.0;
outColor = vec4(0, 0, 0, 0);
}
@@ -122,7 +123,7 @@ void main() {
loadIntoArray(depthNeighbors, colorNeighbors);
// If our depth value is invalid
- if (depth > 1.0 - EPS) {
+ if (depth < EPS) {
#if neighborhoodFullWidth == 3
fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
#else
@@ -140,7 +141,7 @@ void main() {
vec4 colorNeighbor = colorNeighbors[i];
float rI = rIs[i];
- if (neighbor < 1.0 - EPS) {
+ if (neighbor > EPS) {
float depthDelta = abs(neighbor - depth);
float weight =
@@ -159,6 +160,6 @@ void main() {
}
}
- gl_FragColor = finalColor;
- gl_FragDepthEXT = finalDepth;
+ gl_FragData[0] = finalColor;
+ gl_FragData[1] = czm_packDepth(finalDepth);
}
From f81d3569641a477fbbde9d49346a8f902b56e123 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 29 Jun 2017 16:51:06 -0400
Subject: [PATCH 051/240] Code review fixes
---
Source/Scene/PointCloudPostProcessor.js | 56 ++++++++++++-------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index c86bbdefa9b8..8e7fd406a620 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -143,29 +143,29 @@ define([
});
}
- /* We want to reuse textures as much as possible, so here's the order
- * of events:
- *
- * 1. We render normally to our prior:
- * * Color -> 0
- * * Depth -> dirty ("dirty depth")
- * * EC -> 0
- * 2. Then we perform the screen-space point occlusion stage with color[0] and EC:
- * * No color
- * * Pseudo-depth -> 0
- * * No EC
- * 3a. Then we perform the region growing stage with color[0] and depth[0]:
- * * Color -> 1
- * * Pseudo-depth -> 1
- * 3b. We do the region growing stage again with color[1] and depth[1]:
- * * Color -> 0
- * * Pseudo-depth -> 0
- * 3c. Repeat steps 3a and 3b until all holes are filled and/or we run
- * out of time.
- */
-
+ // (EC stands for eye-space)
+ //
+ // We want to reuse textures as much as possible, so here's the order
+ // of events:
+ //
+ // 1. We render normally to our prior:
+ // * Color -> 0
+ // * Depth -> dirty ("dirty depth")
+ // * EC -> 0
+ // 2. Then we perform the screen-space point occlusion stage with color[0] and EC:
+ // * No color
+ // * Pseudo-depth -> 0
+ // * No EC
+ // 3a. Then we perform the region growing stage with color[0] and depth[0]:
+ // * Color -> 1
+ // * Pseudo-depth -> 1
+ // 3b. We do the region growing stage again with color[1] and depth[1]:
+ // * Color -> 0
+ // * Pseudo-depth -> 0
+ // 3c. Repeat steps 3a and 3b until all holes are filled and/or we run
+ // out of time.
processor._framebuffers = {
- "prior": new Framebuffer({
+ prior : new Framebuffer({
context : context,
colorTextures : [
colorTextures[0],
@@ -174,17 +174,17 @@ define([
depthStencilTexture : dirty,
destroyAttachments : false
}),
- "screenSpacePass": new Framebuffer({
+ screenSpacePass : new Framebuffer({
context : context,
colorTextures : [depthTextures[0]],
destroyAttachments : false
}),
- "regionGrowingPassA": new Framebuffer({
+ regionGrowingPassA : new Framebuffer({
context : context,
colorTextures : [colorTextures[1], depthTextures[1]],
destroyAttachments : false
}),
- "regionGrowingPassB": new Framebuffer({
+ regionGrowingPassB : new Framebuffer({
context: context,
colorTextures: [colorTextures[0], depthTextures[0]],
destroyAttachments: false
@@ -197,8 +197,8 @@ define([
}
function replaceConstants(sourceStr, constantName, replacement) {
- var r = "#define\\s" + constantName + "\\s([0-9.]+)";
- return sourceStr.replace(new RegExp(r, "g"), "#define " + constantName + " " + replacement);
+ var r = '#define\\s' + constantName + '\\s([0-9.]+)';
+ return sourceStr.replace(new RegExp(r, 'g'), '#define ' + constantName + ' ' + replacement);
};
function pointOcclusionStage(processor, context) {
@@ -216,7 +216,7 @@ define([
var pointOcclusionStr = replaceConstants(
(context.webgl2) ? PointOcclusionPassGL2 : PointOcclusionPassGL1,
- "neighborhoodHalfWidth",
+ 'neighborhoodHalfWidth',
processor.neighborhoodHalfWidth
);
From 92c042241eec855148614750025f2e608d1438e3 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Fri, 30 Jun 2017 14:24:03 -0400
Subject: [PATCH 052/240] Adds distance-based depth and triangle wave method
---
LICENSE.md | 22 +++
Source/Scene/Cesium3DTileset.js | 2 +-
Source/Scene/PointCloudPostProcessor.js | 3 +
.../PointOcclusionPassGL2.glsl | 171 +++++++++++++++++-
.../RegionGrowingPassGL2.glsl | 2 +-
5 files changed, 195 insertions(+), 5 deletions(-)
diff --git a/LICENSE.md b/LICENSE.md
index db1b62612992..2a76662d2bc5 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -451,6 +451,28 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+### deck.gl
+
+Copyright (c) 2015 - 2017 Uber Technologies, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
Tests
=====
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index 31f7cc8bbda3..513747710ef9 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -731,7 +731,7 @@ define([
this.pointCloudPostProcessorOptions = {
enabled : defaultValue(options.enabled, true),
occlusionAngle : defaultValue(options.occlusionAngle, 0.1),
- rangeParameter : defaultValue(options.rangeParameter, 2e-38),
+ rangeParameter : defaultValue(options.rangeParameter, 0.001),
neighborhoodHalfWidth : defaultValue(options.neighborhoodHalfWidth, 4),
numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 2)
};
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index 8e7fd406a620..7bb8f5791219 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -211,6 +211,9 @@ define([
},
occlusionAngle : function() {
return processor.occlusionAngle;
+ },
+ ONE : function() {
+ return 1.0;
}
};
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
index ffb4526bff5e..0b854607597b 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
@@ -11,6 +11,11 @@
#define neighborhoodHalfWidth 4 // TUNABLE PARAMETER -- half-width of point-occlusion neighborhood
#define numSectors 8
+#define PERIOD 1e-5
+#define USE_TRIANGLE
+
+uniform float ONE;
+
uniform sampler2D pointCloud_colorTexture;
uniform sampler2D pointCloud_ECTexture;
uniform float occlusionAngle;
@@ -18,6 +23,118 @@ in vec2 v_textureCoordinates;
layout(location = 0) out vec4 depthOut;
+// TODO: Include Uber copyright
+
+vec2 split(float a) {
+ const float SPLIT = 4097.0;
+ float t = a * SPLIT;
+ float a_hi = t * ONE - (t - a);
+ float a_lo = a * ONE - a_hi;
+ return vec2(a_hi, a_lo);
+}
+
+vec2 twoSub(float a, float b) {
+ float s = (a - b);
+ float v = (s * ONE - a) * ONE;
+ float err = (a - (s - v) * ONE) * ONE * ONE * ONE - (b + v);
+ return vec2(s, err);
+}
+
+vec2 twoSum(float a, float b) {
+ float s = (a + b);
+ float v = (s * ONE - a) * ONE;
+ float err = (a - (s - v) * ONE) * ONE * ONE * ONE + (b - v);
+ return vec2(s, err);
+}
+
+vec2 twoSqr(float a) {
+ float prod = a * a;
+ vec2 a_fp64 = split(a);
+ float err = ((a_fp64.x * a_fp64.x - prod) * ONE + 2.0 * a_fp64.x *
+ a_fp64.y * ONE * ONE) + a_fp64.y * a_fp64.y * ONE * ONE * ONE;
+ return vec2(prod, err);
+}
+
+vec2 twoProd(float a, float b) {
+ float prod = a * b;
+ vec2 a_fp64 = split(a);
+ vec2 b_fp64 = split(b);
+ float err = ((a_fp64.x * b_fp64.x - prod) + a_fp64.x * b_fp64.y +
+ a_fp64.y * b_fp64.x) + a_fp64.y * b_fp64.y;
+ return vec2(prod, err);
+}
+
+vec2 quickTwoSum(float a, float b) {
+ float sum = (a + b) * ONE;
+ float err = b - (sum - a) * ONE;
+ return vec2(sum, err);
+}
+
+vec2 sum_fp64(vec2 a, vec2 b) {
+ vec2 s, t;
+ s = twoSum(a.x, b.x);
+ t = twoSum(a.y, b.y);
+ s.y += t.x;
+ s = quickTwoSum(s.x, s.y);
+ s.y += t.y;
+ s = quickTwoSum(s.x, s.y);
+ return s;
+}
+
+vec2 sub_fp64(vec2 a, vec2 b) {
+ vec2 s, t;
+ s = twoSub(a.x, b.x);
+ t = twoSub(a.y, b.y);
+ s.y += t.x;
+ s = quickTwoSum(s.x, s.y);
+ s.y += t.y;
+ s = quickTwoSum(s.x, s.y);
+ return s;
+}
+
+vec2 mul_fp64(vec2 a, vec2 b) {
+ vec2 prod = twoProd(a.x, b.x);
+ // y component is for the error
+ prod.y += a.x * b.y;
+ prod.y += a.y * b.x;
+ prod = quickTwoSum(prod.x, prod.y);
+ return prod;
+}
+
+vec2 divFP64(in vec2 a, in vec2 b) {
+ float xn = 1.0 / b.x;
+ vec2 yn = a * xn;
+ float diff = (sub_fp64(a, mul_fp64(b, yn))).x;
+ vec2 prod = twoProd(xn, diff);
+ return sum_fp64(yn, prod);
+}
+
+vec2 sqrt_fp64(vec2 a) {
+ if (a.x == 0.0 && a.y == 0.0) return vec2(0.0, 0.0);
+ if (a.x < 0.0) return vec2(0.0 / 0.0, 0.0 / 0.0);
+ float x = 1.0 / sqrt(a.x);
+ float yn = a.x * x;
+ vec2 yn_sqr = twoSqr(yn) * ONE;
+ float diff = sub_fp64(a, yn_sqr).x;
+ vec2 prod = twoProd(x * 0.5, diff);
+ return sum_fp64(vec2(yn, 0.0), prod);
+}
+
+float triangle(in float x, in float period) {
+ return abs(mod(x, period) / period - 0.5) + EPS;
+}
+
+float triangleFP64(in vec2 x, in float period) {
+ float lowPrecision = x.x + x.y;
+ vec2 floorTerm = split(floor(lowPrecision / period));
+ vec2 periodHighPrecision = split(period);
+ vec2 term2 = mul_fp64(periodHighPrecision, floorTerm);
+ vec2 moduloTerm = sub_fp64(x, term2);
+ vec2 normalized = divFP64(moduloTerm, periodHighPrecision);
+ normalized = sub_fp64(normalized, split(0.5));
+ return abs(normalized.x + normalized.y) + EPS;
+}
+
float acosFast(in float inX) {
float x = abs(inX);
float res = ((C3 * x + C2) * x + C1) * x + C0; // p(x)
@@ -165,8 +282,56 @@ void main() {
if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
discard;
} else {
- // This is the depth of this pixel... assuming that it's valid.
- float linearizedDepth = (-centerPosition.z - near) / (far - near);
- depthOut = czm_packDepth(linearizedDepth);
+ // Write out the distance of the point
+ //
+ // We use the distance of the point rather than
+ // the linearized depth. This is because we want
+ // to encode as much information about position disparities
+ // between points as we can, and the z-values of
+ // neighboring points are usually very similar.
+ // On the other hand, the x-values and y-values are
+ // usually fairly different.
+#ifdef USE_TRIANGLE
+ // We can get even more accuracy by passing the 64-bit
+ // distance into a triangle wave function that
+ // uses 64-bit primitives internally. The region
+ // growing pass only cares about deltas between
+ // different pixels, so we just have to ensure that
+ // the period of triangle function is greater than that
+ // of the largest possible delta can arise between
+ // different points.
+ //
+ // The triangle function is C0 continuous, which avoids
+ // artifacts from discontinuities. That said, I have noticed
+ // some inexplicable artifacts occasionally, so please
+ // disable this optimization if that becomes an issue.
+ //
+ // It's important that the period of the triangle function
+ // is at least two orders of magnitude greater than
+ // the average depth delta that we are likely to come
+ // across. The triangle function works because we have
+ // some assumption of locality in the depth domain.
+ // Massive deltas break that locality -- but that's
+ // actually not an issue. Deltas that are larger than
+ // the period function will be "wrapped around", and deltas
+ // that are much larger than the period function may be
+ // "wrapped around" many times. A similar process occurs
+ // in many random number generators. The resulting delta
+ // is usually at least an order of magnitude greater than
+ // the average delta, so it won't even be considered in
+ // the region growing pass.
+ vec2 highPrecisionX = split(centerPosition.x);
+ vec2 highPrecisionY = split(centerPosition.y);
+ vec2 highPrecisionZ = split(centerPosition.z);
+ vec2 highPrecisionLength =
+ sqrt_fp64(sum_fp64(sum_fp64(
+ mul_fp64(highPrecisionX, highPrecisionX),
+ mul_fp64(highPrecisionY, highPrecisionY)),
+ mul_fp64(highPrecisionZ, highPrecisionZ)));
+ float triangleResult = triangleFP64(highPrecisionLength, PERIOD);
+ depthOut = czm_packDepth(triangleResult);
+#else
+ depthOut = czm_packDepth(length(centerPosition));
+#endif
}
}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
index 1b9b4b5077d2..3a03a3fd9cb0 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
@@ -124,7 +124,7 @@ void main() {
loadIntoArray(depthNeighbors, colorNeighbors);
// If our depth value is invalid
- if (depth < EPS) {
+ if (abs(depth) < EPS) {
#if neighborhoodFullWidth == 3
fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
#else
From 2a8e8421af1c4ad616d7d057263bb7e88dd1cc32 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Fri, 30 Jun 2017 14:28:17 -0400
Subject: [PATCH 053/240] Adds abs() calls for checks against the depth
---
Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
index 3a03a3fd9cb0..d2c018ffda12 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
@@ -52,7 +52,7 @@ void fastMedian3(in float[neighborhoodSize] neighbors,
comparisonNetwork8(neighbors, colorNeighbors);
for (int i = 0; i < neighborhoodSize; i++) {
- if (neighbors[i] > EPS) {
+ if (abs(neighbors[i]) > EPS) {
outDepth = neighbors[i + (neighborhoodSize - 1 - i) / 2];
outColor = colorNeighbors[i + (neighborhoodSize - 1 - i) / 2];
return;
@@ -142,7 +142,7 @@ void main() {
vec4 colorNeighbor = colorNeighbors[i];
float rI = rIs[i];
- if (neighbor > EPS) {
+ if (abs(neighbor) > EPS) {
float depthDelta = abs(neighbor - depth);
float weight =
@@ -155,7 +155,7 @@ void main() {
}
}
- if (depthAccum > EPS) {
+ if (abs(depthAccum) > EPS) {
finalDepth = depthAccum / normalization;
finalColor = colorAccum / normalization;
}
From f73ba356eec1911883eb2299b19d7e5aec4a9998 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Fri, 30 Jun 2017 14:32:53 -0400
Subject: [PATCH 054/240] Adds multifrustrum support to the GLSL ES 1.00
shaders
---
.../PointOcclusionPassGL1.glsl | 174 +++++++++++++++++-
.../RegionGrowingPassGL1.glsl | 8 +-
2 files changed, 174 insertions(+), 8 deletions(-)
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
index a83fb1957938..c6ef25e78f68 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL1.glsl
@@ -11,11 +11,129 @@
#define neighborhoodHalfWidth 4 // TUNABLE PARAMETER -- half-width of point-occlusion neighborhood
#define numSectors 8
+
+#define PERIOD 1e-5
+#define USE_TRIANGLE
+
+uniform float ONE;
+
uniform sampler2D pointCloud_colorTexture;
uniform sampler2D pointCloud_ECTexture;
uniform float occlusionAngle;
varying vec2 v_textureCoordinates;
+// TODO: Include Uber copyright
+
+vec2 split(float a) {
+ const float SPLIT = 4097.0;
+ float t = a * SPLIT;
+ float a_hi = t * ONE - (t - a);
+ float a_lo = a * ONE - a_hi;
+ return vec2(a_hi, a_lo);
+}
+
+vec2 twoSub(float a, float b) {
+ float s = (a - b);
+ float v = (s * ONE - a) * ONE;
+ float err = (a - (s - v) * ONE) * ONE * ONE * ONE - (b + v);
+ return vec2(s, err);
+}
+
+vec2 twoSum(float a, float b) {
+ float s = (a + b);
+ float v = (s * ONE - a) * ONE;
+ float err = (a - (s - v) * ONE) * ONE * ONE * ONE + (b - v);
+ return vec2(s, err);
+}
+
+vec2 twoSqr(float a) {
+ float prod = a * a;
+ vec2 a_fp64 = split(a);
+ float err = ((a_fp64.x * a_fp64.x - prod) * ONE + 2.0 * a_fp64.x *
+ a_fp64.y * ONE * ONE) + a_fp64.y * a_fp64.y * ONE * ONE * ONE;
+ return vec2(prod, err);
+}
+
+vec2 twoProd(float a, float b) {
+ float prod = a * b;
+ vec2 a_fp64 = split(a);
+ vec2 b_fp64 = split(b);
+ float err = ((a_fp64.x * b_fp64.x - prod) + a_fp64.x * b_fp64.y +
+ a_fp64.y * b_fp64.x) + a_fp64.y * b_fp64.y;
+ return vec2(prod, err);
+}
+
+vec2 quickTwoSum(float a, float b) {
+ float sum = (a + b) * ONE;
+ float err = b - (sum - a) * ONE;
+ return vec2(sum, err);
+}
+
+vec2 sum_fp64(vec2 a, vec2 b) {
+ vec2 s, t;
+ s = twoSum(a.x, b.x);
+ t = twoSum(a.y, b.y);
+ s.y += t.x;
+ s = quickTwoSum(s.x, s.y);
+ s.y += t.y;
+ s = quickTwoSum(s.x, s.y);
+ return s;
+}
+
+vec2 sub_fp64(vec2 a, vec2 b) {
+ vec2 s, t;
+ s = twoSub(a.x, b.x);
+ t = twoSub(a.y, b.y);
+ s.y += t.x;
+ s = quickTwoSum(s.x, s.y);
+ s.y += t.y;
+ s = quickTwoSum(s.x, s.y);
+ return s;
+}
+
+vec2 mul_fp64(vec2 a, vec2 b) {
+ vec2 prod = twoProd(a.x, b.x);
+ // y component is for the error
+ prod.y += a.x * b.y;
+ prod.y += a.y * b.x;
+ prod = quickTwoSum(prod.x, prod.y);
+ return prod;
+}
+
+vec2 divFP64(in vec2 a, in vec2 b) {
+ float xn = 1.0 / b.x;
+ vec2 yn = a * xn;
+ float diff = (sub_fp64(a, mul_fp64(b, yn))).x;
+ vec2 prod = twoProd(xn, diff);
+ return sum_fp64(yn, prod);
+}
+
+vec2 sqrt_fp64(vec2 a) {
+ if (a.x == 0.0 && a.y == 0.0) return vec2(0.0, 0.0);
+ if (a.x < 0.0) return vec2(0.0 / 0.0, 0.0 / 0.0);
+ float x = 1.0 / sqrt(a.x);
+ float yn = a.x * x;
+ vec2 yn_sqr = twoSqr(yn) * ONE;
+ float diff = sub_fp64(a, yn_sqr).x;
+ vec2 prod = twoProd(x * 0.5, diff);
+ return sum_fp64(vec2(yn, 0.0), prod);
+}
+
+float triangle(in float x, in float period) {
+ return abs(mod(x, period) / period - 0.5) + EPS;
+}
+
+float triangleFP64(in vec2 x, in float period) {
+ float lowPrecision = x.x + x.y;
+ vec2 floorTerm = split(floor(lowPrecision / period));
+ vec2 periodHighPrecision = split(period);
+ vec2 term2 = mul_fp64(periodHighPrecision, floorTerm);
+ vec2 moduloTerm = sub_fp64(x, term2);
+ vec2 normalized = divFP64(moduloTerm, periodHighPrecision);
+ normalized = sub_fp64(normalized, split(0.5));
+ return abs(normalized.x + normalized.y) + EPS;
+}
+
float acosFast(in float inX) {
float x = abs(inX);
float res = ((C3 * x + C2) * x + C1) * x + C0; // p(x)
@@ -227,9 +345,57 @@ void main() {
// The solid angle is too small, so we occlude this point
if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
discard;
+ } else {
+ // Write out the distance of the point
+ //
+ // We use the distance of the point rather than
+ // the linearized depth. This is because we want
+ // to encode as much information about position disparities
+ // between points as we can, and the z-values of
+ // neighboring points are usually very similar.
+ // On the other hand, the x-values and y-values are
+ // usually fairly different.
+#ifdef USE_TRIANGLE
+ // We can get even more accuracy by passing the 64-bit
+ // distance into a triangle wave function that
+ // uses 64-bit primitives internally. The region
+ // growing pass only cares about deltas between
+ // different pixels, so we just have to ensure that
+ // the period of triangle function is greater than that
+ // of the largest possible delta can arise between
+ // different points.
+ //
+ // The triangle function is C0 continuous, which avoids
+ // artifacts from discontinuities. That said, I have noticed
+ // some inexplicable artifacts occasionally, so please
+ // disable this optimization if that becomes an issue.
+ //
+ // It's important that the period of the triangle function
+ // is at least two orders of magnitude greater than
+ // the average depth delta that we are likely to come
+ // across. The triangle function works because we have
+ // some assumption of locality in the depth domain.
+ // Massive deltas break that locality -- but that's
+ // actually not an issue. Deltas that are larger than
+ // the period function will be "wrapped around", and deltas
+ // that are much larger than the period function may be
+ // "wrapped around" many times. A similar process occurs
+ // in many random number generators. The resulting delta
+ // is usually at least an order of magnitude greater than
+ // the average delta, so it won't even be considered in
+ // the region growing pass.
+ vec2 highPrecisionX = split(centerPosition.x);
+ vec2 highPrecisionY = split(centerPosition.y);
+ vec2 highPrecisionZ = split(centerPosition.z);
+ vec2 highPrecisionLength =
+ sqrt_fp64(sum_fp64(sum_fp64(
+ mul_fp64(highPrecisionX, highPrecisionX),
+ mul_fp64(highPrecisionY, highPrecisionY)),
+ mul_fp64(highPrecisionZ, highPrecisionZ)));
+ float triangleResult = triangleFP64(highPrecisionLength, PERIOD);
+ gl_FragData[0] = czm_packDepth(triangleResult);
+#else
+ gl_FragData[0] = czm_packDepth(length(centerPosition));
+#endif
}
-
- // This is the depth of this pixel... assuming that it's valid.
- float linearizedDepth = (-centerPosition.z - near) / (far - near);
- gl_FragData[0] = czm_packDepth(linearizedDepth);
}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
index 08f1dcf23238..5ff240b54fb1 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL1.glsl
@@ -51,7 +51,7 @@ void fastMedian3(in float[neighborhoodSize] neighbors,
comparisonNetwork8(neighbors, colorNeighbors);
for (int i = 0; i < neighborhoodSize; i++) {
- if (neighbors[i] > EPS) {
+ if (abs(neighbors[i]) > EPS) {
outDepth = neighbors[i + (neighborhoodSize - 1 - i) / 2];
outColor = colorNeighbors[i + (neighborhoodSize - 1 - i) / 2];
return;
@@ -123,7 +123,7 @@ void main() {
loadIntoArray(depthNeighbors, colorNeighbors);
// If our depth value is invalid
- if (depth < EPS) {
+ if (abs(depth) < EPS) {
#if neighborhoodFullWidth == 3
fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
#else
@@ -141,7 +141,7 @@ void main() {
vec4 colorNeighbor = colorNeighbors[i];
float rI = rIs[i];
- if (neighbor > EPS) {
+ if (abs(neighbor) > EPS) {
float depthDelta = abs(neighbor - depth);
float weight =
@@ -154,7 +154,7 @@ void main() {
}
}
- if (depthAccum > EPS) {
+ if (abs(depthAccum) > EPS) {
finalDepth = depthAccum / normalization;
finalColor = colorAccum / normalization;
}
From 10a36b812730c25b481abb4da9c81c6ca02594d3 Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 6 Jul 2017 14:54:02 -0400
Subject: [PATCH 055/240] Adds parameter tuning for the region growing operator
---
Source/Scene/Cesium3DTileset.js | 10 +-
Source/Scene/PointCloudPostProcessor.js | 117 +++++++++--
.../DensityEstimationPass.glsl | 47 +++++
.../PointOcclusionPassGL2.glsl | 198 +++++++++---------
.../RegionGrowingPassGL2.glsl | 28 ++-
5 files changed, 284 insertions(+), 116 deletions(-)
create mode 100644 Source/Shaders/PostProcessFilters/DensityEstimationPass.glsl
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index 513747710ef9..5f3421319dce 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -733,7 +733,10 @@ define([
occlusionAngle : defaultValue(options.occlusionAngle, 0.1),
rangeParameter : defaultValue(options.rangeParameter, 0.001),
neighborhoodHalfWidth : defaultValue(options.neighborhoodHalfWidth, 4),
- numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 2)
+ numRegionGrowingPasses : defaultValue(options.numRegionGrowingPasses, 4),
+ densityHalfWidth : defaultValue(options.densityHalfWidth, 4),
+ neighborhoodVectorSize : defaultValue(options.neighborhoodVectorSize, 10.0),
+ densityViewEnabled : defaultValue(options.densityViewEnabled, false)
};
this._pointCloudPostProcessor = new PointCloudPostProcessor(this.pointCloudPostProcessorOptions);
@@ -1619,7 +1622,10 @@ define([
occlusionAngle : tileset.pointCloudPostProcessorOptions.occlusionAngle,
rangeParameter : tileset.pointCloudPostProcessorOptions.rangeParameter,
neighborhoodHalfWidth : tileset.pointCloudPostProcessorOptions.neighborhoodHalfWidth,
- numRegionGrowingPasses : tileset.pointCloudPostProcessorOptions.numRegionGrowingPasses
+ numRegionGrowingPasses : tileset.pointCloudPostProcessorOptions.numRegionGrowingPasses,
+ densityHalfWidth : tileset.pointCloudPostProcessorOptions.densityHalfWidth,
+ neighborhoodVectorSize : tileset.pointCloudPostProcessorOptions.neighborhoodVectorSize,
+ densityViewEnabled : tileset.pointCloudPostProcessorOptions.densityViewEnabled
});
}
diff --git a/Source/Scene/PointCloudPostProcessor.js b/Source/Scene/PointCloudPostProcessor.js
index 7bb8f5791219..3596d5106c2b 100644
--- a/Source/Scene/PointCloudPostProcessor.js
+++ b/Source/Scene/PointCloudPostProcessor.js
@@ -22,7 +22,8 @@ define([
'../Shaders/PostProcessFilters/PointOcclusionPassGL1',
'../Shaders/PostProcessFilters/RegionGrowingPassGL1',
'../Shaders/PostProcessFilters/PointOcclusionPassGL2',
- '../Shaders/PostProcessFilters/RegionGrowingPassGL2'
+ '../Shaders/PostProcessFilters/RegionGrowingPassGL2',
+ '../Shaders/PostProcessFilters/DensityEstimationPass'
], function(
Color,
defined,
@@ -47,6 +48,7 @@ define([
RegionGrowingPassGL1,
PointOcclusionPassGL2,
RegionGrowingPassGL2,
+ DensityEstimationPass
) {
'use strict';
@@ -58,6 +60,7 @@ define([
this._colorTextures = undefined;
this._ecTexture = undefined;
this._depthTextures = undefined;
+ this._densityTexture = undefined;
this._dirty = undefined;
this._drawCommands = undefined;
this._blendCommand = undefined;
@@ -67,6 +70,9 @@ define([
this.rangeParameter = options.rangeParameter;
this.neighborhoodHalfWidth = options.neighborhoodHalfWidth;
this.numRegionGrowingPasses = options.numRegionGrowingPasses;
+ this.densityHalfWidth = options.densityHalfWidth;
+ this.neighborhoodVectorSize = options.neighborhoodVectorSize;
+ this.densityViewEnabled = options.densityViewEnabled;
}
function createSampler() {
@@ -81,6 +87,7 @@ define([
function destroyFramebuffers(processor) {
processor._depthTextures[0].destroy();
processor._depthTextures[1].destroy();
+ processor._densityTexture.destroy();
processor._dirty.destroy();
processor._colorTextures[0].destroy();
processor._colorTextures[1].destroy();
@@ -114,6 +121,15 @@ define([
sampler : createSampler()
});
+ var densityMap = new Texture({
+ context : context,
+ width : screenWidth,
+ height : screenHeight,
+ pixelFormat : PixelFormat.RGBA,
+ pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
+ sampler : createSampler()
+ });
+
var dirty = new Texture({
context: context,
width: screenWidth,
@@ -179,6 +195,11 @@ define([
colorTextures : [depthTextures[0]],
destroyAttachments : false
}),
+ densityEstimationPass : new Framebuffer({
+ context : context,
+ colorTextures : [densityMap],
+ destroyAttachments : false
+ }),
regionGrowingPassA : new Framebuffer({
context : context,
colorTextures : [colorTextures[1], depthTextures[1]],
@@ -191,15 +212,26 @@ define([
})
};
processor._depthTextures = depthTextures;
+ processor._densityTexture = densityMap;
processor._colorTextures = colorTextures;
processor._ecTexture = ecTexture;
processor._dirty = dirty;
}
function replaceConstants(sourceStr, constantName, replacement) {
- var r = '#define\\s' + constantName + '\\s([0-9.]+)';
- return sourceStr.replace(new RegExp(r, 'g'), '#define ' + constantName + ' ' + replacement);
- };
+ var r;
+ if (typeof(replacement) === "boolean") {
+ if (replacement === false) {
+ r = '#define\\s' + constantName;
+ return sourceStr.replace(new RegExp(r, 'g'), '/*#define ' + constantName + '*/');
+ } else {
+ return sourceStr;
+ }
+ } else {
+ r = '#define\\s' + constantName + '\\s([0-9.]+)';
+ return sourceStr.replace(new RegExp(r, 'g'), '#define ' + constantName + ' ' + replacement);
+ }
+ }
function pointOcclusionStage(processor, context) {
var uniformMap = {
@@ -233,6 +265,37 @@ define([
});
}
+ function densityEstimationStage(processor, context) {
+ var uniformMap = {
+ pointCloud_depthTexture : function() {
+ return processor._depthTextures[0];
+ },
+ neighborhoodVectorSize : function() {
+ return processor.neighborhoodVectorSize;
+ }
+ };
+
+ var densityEstimationStr = replaceConstants(
+ DensityEstimationPass,
+ 'neighborhoodHalfWidth',
+ processor.densityHalfWidth
+ );
+
+ if (context.webgl2) {
+ densityEstimationStr = GLSLModernizer.
+ glslModernizeShaderText(densityEstimationStr, true, true);
+ }
+
+ return context.createViewportQuadCommand(densityEstimationStr, {
+ uniformMap : uniformMap,
+ framebuffer : processor._framebuffers.densityEstimationPass,
+ renderState : RenderState.fromCache({
+ }),
+ pass : Pass.CESIUM_3D_TILE,
+ owner : processor
+ });
+ }
+
function regionGrowingStage(processor, context, iteration) {
var i = iteration % 2;
@@ -243,8 +306,17 @@ define([
pointCloud_depthTexture : function() {
return processor._depthTextures[i];
},
+ pointCloud_densityTexture : function() {
+ return processor._densityTexture;
+ },
rangeParameter : function() {
return processor.rangeParameter;
+ },
+ densityHalfWidth : function() {
+ return processor.densityHalfWidth;
+ },
+ iterationNumber : function() {
+ return iteration;
}
};
@@ -255,6 +327,13 @@ define([
var regionGrowingPassStr = (context.webgl2) ?
RegionGrowingPassGL2 :
RegionGrowingPassGL1;
+
+ regionGrowingPassStr = replaceConstants(
+ regionGrowingPassStr,
+ 'DENSITY_VIEW',
+ processor.densityViewEnabled
+ );
+
return context.createViewportQuadCommand(regionGrowingPassStr, {
uniformMap : uniformMap,
framebuffer : framebuffer,
@@ -271,9 +350,10 @@ define([
var i;
drawCommands[0] = pointOcclusionStage(processor, context);
+ drawCommands[1] = densityEstimationStage(processor, context);
for (i = 0; i < numRegionGrowingPasses; i++) {
- drawCommands[i + 1] = regionGrowingStage(processor, context, i);
+ drawCommands[i + 2] = regionGrowingStage(processor, context, i);
}
for (i = 0; i < drawCommands.length; i++) {
@@ -294,7 +374,6 @@ define([
});
}
- // TODO : point cloud depth information is lost
var blendFS =
'uniform sampler2D pointCloud_colorTexture; \n' +
'varying vec2 v_textureCoordinates; \n' +
@@ -430,14 +509,20 @@ define([
var dirty = false;
// Set options here
- if (options.occlusionAngle != this.occlusionAngle ||
- options.rangeParameter != this.rangeParameter ||
- options.neighborhoodHalfWidth != this.neighborhoodHalfWidth ||
- options.numRegionGrowingPasses != this.numRegionGrowingPasses) {
+ if (options.occlusionAngle !== this.occlusionAngle ||
+ options.rangeParameter !== this.rangeParameter ||
+ options.neighborhoodHalfWidth !== this.neighborhoodHalfWidth ||
+ options.numRegionGrowingPasses !== this.numRegionGrowingPasses ||
+ options.densityHalfWidth !== this.densityHalfWidth ||
+ options.neighborhoodVectorSize !== this.neighborhoodVectorSize ||
+ options.densityViewEnabled !== this.densityViewEnabled) {
this.occlusionAngle = options.occlusionAngle;
this.rangeParameter = options.rangeParameter;
this.neighborhoodHalfWidth = options.neighborhoodHalfWidth;
this.numRegionGrowingPasses = options.numRegionGrowingPasses;
+ this.densityHalfWidth = options.densityHalfWidth;
+ this.neighborhoodVectorSize = options.neighborhoodVectorSize;
+ this.densityViewEnabled = options.densityViewEnabled;
dirty = true;
}
@@ -479,10 +564,14 @@ define([
if (i == 0) {
commandList.push(clearCommands['screenSpacePass']);
} else {
- if (i % 2 == 1)
- commandList.push(clearCommands['regionGrowingPassA']);
- else
- commandList.push(clearCommands['regionGrowingPassB']);
+ if (i == 1) {
+ commandList.push(clearCommands['densityEstimationPass']);
+ } else {
+ if (i % 2 == 0)
+ commandList.push(clearCommands['regionGrowingPassA']);
+ else
+ commandList.push(clearCommands['regionGrowingPassB']);
+ }
}
commandList.push(drawCommands[i]);
diff --git a/Source/Shaders/PostProcessFilters/DensityEstimationPass.glsl b/Source/Shaders/PostProcessFilters/DensityEstimationPass.glsl
new file mode 100644
index 000000000000..aeee1b062715
--- /dev/null
+++ b/Source/Shaders/PostProcessFilters/DensityEstimationPass.glsl
@@ -0,0 +1,47 @@
+#extension GL_EXT_draw_buffers : enable
+
+#define neighborhoodHalfWidth 4 // TUNABLE PARAMETER -- half-width of region-growing kernel
+
+#define EPS 1e-8
+
+#define densityScaleFactor 32.0
+
+uniform sampler2D pointCloud_depthTexture;
+uniform float neighborhoodVectorSize;
+varying vec2 v_textureCoordinates;
+
+void main() {
+ float center = czm_unpackDepth(texture2D(pointCloud_depthTexture,
+ v_textureCoordinates));
+ ivec2 pos = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y));
+
+ int closestNeighbor = neighborhoodHalfWidth + 1;
+ vec2 neighborhoodAccum = vec2(0.0);
+
+ if (center < EPS) {
+ for (int i = -neighborhoodHalfWidth; i <= neighborhoodHalfWidth; i++) {
+ for (int j = -neighborhoodHalfWidth; j <= neighborhoodHalfWidth; j++) {
+ ivec2 d = ivec2(i, j);
+ ivec2 pI = pos + d;
+
+ float neighbor = czm_unpackDepth(texture2D(pointCloud_depthTexture,
+ vec2(pI) / czm_viewport.zw));
+ if (neighbor < EPS || pI == pos) {
+ continue;
+ }
+
+ neighborhoodAccum += vec2(d);
+ closestNeighbor = min(closestNeighbor,
+ max(abs(i), abs(j)));
+ }
+ }
+
+ if (closestNeighbor <= neighborhoodHalfWidth &&
+ length(neighborhoodAccum) < neighborhoodVectorSize) {
+ gl_FragData[0] = czm_packDepth(float(closestNeighbor) /
+ densityScaleFactor);
+ } else {
+ gl_FragData[0] = czm_packDepth(0.0);
+ }
+ }
+}
diff --git a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
index 0b854607597b..d4fb92a20f73 100644
--- a/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/PointOcclusionPassGL2.glsl
@@ -9,6 +9,7 @@
#define C3 -0.0186166
#define EPS 1e-6
#define neighborhoodHalfWidth 4 // TUNABLE PARAMETER -- half-width of point-occlusion neighborhood
+#define neighborhoodSize 9
#define numSectors 8
#define PERIOD 1e-5
@@ -181,11 +182,12 @@ void main() {
// The position of this pixel in 3D (i.e the position of the point)
vec3 centerPosition = texture(pointCloud_ECTexture, v_textureCoordinates).xyz;
+ bool invalid = false;
// If the EC of this pixel is zero, that means that it's not a valid
// pixel. We don't care about reprojecting it.
- if (length(centerPosition) == 0.)
- discard;
+ if (length(centerPosition) < EPS)
+ invalid = true;
// We split our region of interest (the point of interest and its
// neighbors)
@@ -231,107 +233,111 @@ void main() {
continue;
}
- // sectors contains both possible sectors that the
- // neighbor pixel could be in
- ivec2 sectors = collapseSectors(getSectors(vec2(d)));
-
- // This is the offset of the horizon point from the center in 3D
- // (a 3D analog of d)
- vec3 c = neighborPosition - centerPosition;
-
- // Now we calculate the dot product between the vector
- // from the viewer to the center and the vector to the horizon pixel.
- // We normalize both vectors first because we only care about their relative
- // directions
- // TODO: Redo the math and figure out whether the result should be negated or not
- float dotProduct = dot(normalize(viewer - centerPosition),
- normalize(c));
-
- // We calculate the angle that this horizon pixel would make
- // in the cone. The dot product is be equal to
- // |vec_1| * |vec_2| * cos(angle_between), and in this case,
- // the magnitude of both vectors is 1 because they are both
- // normalized.
- float angle = acosFast(dotProduct);
-
- // This horizon point is behind the current point. That means that it can't
- // occlude the current point. So we ignore it and move on.
- if (angle > maxAngle)
- continue;
- // If we've found a horizon pixel, store it in the histogram
- if (sh[sectors.x] > angle) {
- sh[sectors.x] = angle;
- }
- if (sh[sectors.y] > angle) {
- sh[sectors.y] = angle;
+ if (!invalid) {
+ // sectors contains both possible sectors that the
+ // neighbor pixel could be in
+ ivec2 sectors = collapseSectors(getSectors(vec2(d)));
+
+ // This is the offset of the horizon point from the center in 3D
+ // (a 3D analog of d)
+ vec3 c = neighborPosition - centerPosition;
+
+ // Now we calculate the dot product between the vector
+ // from the viewer to the center and the vector to the horizon pixel.
+ // We normalize both vectors first because we only care about their relative
+ // directions
+ // TODO: Redo the math and figure out whether the result should be negated or not
+ float dotProduct = dot(normalize(viewer - centerPosition),
+ normalize(c));
+
+ // We calculate the angle that this horizon pixel would make
+ // in the cone. The dot product is be equal to
+ // |vec_1| * |vec_2| * cos(angle_between), and in this case,
+ // the magnitude of both vectors is 1 because they are both
+ // normalized.
+ float angle = acosFast(dotProduct);
+
+ // This horizon point is behind the current point. That means that it can't
+ // occlude the current point. So we ignore it and move on.
+ if (angle > maxAngle)
+ continue;
+ // If we've found a horizon pixel, store it in the histogram
+ if (sh[sectors.x] > angle) {
+ sh[sectors.x] = angle;
+ }
+ if (sh[sectors.y] > angle) {
+ sh[sectors.y] = angle;
+ }
}
}
}
- float accumulator = 0.0;
- for (int i = 0; i < numSectors; i++) {
- float angle = sh[i];
- // If the z component is less than zero,
- // that means that there is no valid horizon pixel
- if (angle <= 0.0 || angle > maxAngle)
- angle = maxAngle;
- accumulator += angle;
- }
+ if (!invalid) {
+ float accumulator = 0.0;
+ for (int i = 0; i < numSectors; i++) {
+ float angle = sh[i];
+ // If the z component is less than zero,
+ // that means that there is no valid horizon pixel
+ if (angle <= 0.0 || angle > maxAngle)
+ angle = maxAngle;
+ accumulator += angle;
+ }
- // The solid angle is too small, so we occlude this point
- if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
- discard;
- } else {
- // Write out the distance of the point
- //
- // We use the distance of the point rather than
- // the linearized depth. This is because we want
- // to encode as much information about position disparities
- // between points as we can, and the z-values of
- // neighboring points are usually very similar.
- // On the other hand, the x-values and y-values are
- // usually fairly different.
+ // The solid angle is too small, so we occlude this point
+ if (accumulator < (2.0 * PI) * (1.0 - occlusionAngle)) {
+ depthOut = czm_packDepth(0.0);
+ } else {
+ // Write out the distance of the point
+ //
+ // We use the distance of the point rather than
+ // the linearized depth. This is because we want
+ // to encode as much information about position disparities
+ // between points as we can, and the z-values of
+ // neighboring points are usually very similar.
+ // On the other hand, the x-values and y-values are
+ // usually fairly different.
#ifdef USE_TRIANGLE
- // We can get even more accuracy by passing the 64-bit
- // distance into a triangle wave function that
- // uses 64-bit primitives internally. The region
- // growing pass only cares about deltas between
- // different pixels, so we just have to ensure that
- // the period of triangle function is greater than that
- // of the largest possible delta can arise between
- // different points.
- //
- // The triangle function is C0 continuous, which avoids
- // artifacts from discontinuities. That said, I have noticed
- // some inexplicable artifacts occasionally, so please
- // disable this optimization if that becomes an issue.
- //
- // It's important that the period of the triangle function
- // is at least two orders of magnitude greater than
- // the average depth delta that we are likely to come
- // across. The triangle function works because we have
- // some assumption of locality in the depth domain.
- // Massive deltas break that locality -- but that's
- // actually not an issue. Deltas that are larger than
- // the period function will be "wrapped around", and deltas
- // that are much larger than the period function may be
- // "wrapped around" many times. A similar process occurs
- // in many random number generators. The resulting delta
- // is usually at least an order of magnitude greater than
- // the average delta, so it won't even be considered in
- // the region growing pass.
- vec2 highPrecisionX = split(centerPosition.x);
- vec2 highPrecisionY = split(centerPosition.y);
- vec2 highPrecisionZ = split(centerPosition.z);
- vec2 highPrecisionLength =
- sqrt_fp64(sum_fp64(sum_fp64(
- mul_fp64(highPrecisionX, highPrecisionX),
- mul_fp64(highPrecisionY, highPrecisionY)),
- mul_fp64(highPrecisionZ, highPrecisionZ)));
- float triangleResult = triangleFP64(highPrecisionLength, PERIOD);
- depthOut = czm_packDepth(triangleResult);
+ // We can get even more accuracy by passing the 64-bit
+ // distance into a triangle wave function that
+ // uses 64-bit primitives internally. The region
+ // growing pass only cares about deltas between
+ // different pixels, so we just have to ensure that
+ // the period of triangle function is greater than that
+ // of the largest possible delta can arise between
+ // different points.
+ //
+ // The triangle function is C0 continuous, which avoids
+ // artifacts from discontinuities. That said, I have noticed
+ // some inexplicable artifacts occasionally, so please
+ // disable this optimization if that becomes an issue.
+ //
+ // It's important that the period of the triangle function
+ // is at least two orders of magnitude greater than
+ // the average depth delta that we are likely to come
+ // across. The triangle function works because we have
+ // some assumption of locality in the depth domain.
+ // Massive deltas break that locality -- but that's
+ // actually not an issue. Deltas that are larger than
+ // the period function will be "wrapped around", and deltas
+ // that are much larger than the period function may be
+ // "wrapped around" many times. A similar process occurs
+ // in many random number generators. The resulting delta
+ // is usually at least an order of magnitude greater than
+ // the average delta, so it won't even be considered in
+ // the region growing pass.
+ vec2 highPrecisionX = split(centerPosition.x);
+ vec2 highPrecisionY = split(centerPosition.y);
+ vec2 highPrecisionZ = split(centerPosition.z);
+ vec2 highPrecisionLength =
+ sqrt_fp64(sum_fp64(sum_fp64(
+ mul_fp64(highPrecisionX, highPrecisionX),
+ mul_fp64(highPrecisionY, highPrecisionY)),
+ mul_fp64(highPrecisionZ, highPrecisionZ)));
+ float triangleResult = triangleFP64(highPrecisionLength, PERIOD);
+ depthOut = czm_packDepth(triangleResult);
#else
- depthOut = czm_packDepth(length(centerPosition));
+ depthOut = czm_packDepth(length(centerPosition));
#endif
+ }
}
}
diff --git a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
index d2c018ffda12..65c98a9653b7 100644
--- a/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
+++ b/Source/Shaders/PostProcessFilters/RegionGrowingPassGL2.glsl
@@ -5,10 +5,15 @@
#define neighborhoodSize 8
#define EPS 1e-8
#define SQRT2 1.414213562
+#define densityScaleFactor 32.0
+#define DENSITY_VIEW
uniform sampler2D pointCloud_colorTexture;
+uniform sampler2D pointCloud_densityTexture;
uniform sampler2D pointCloud_depthTexture;
uniform float rangeParameter;
+uniform int densityHalfWidth;
+uniform int iterationNumber;
in vec2 v_textureCoordinates;
layout(location = 0) out vec4 colorOut;
@@ -85,7 +90,8 @@ void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
continue;
}
vec2 neighborCoords = vec2(vec2(d) + gl_FragCoord.xy) / czm_viewport.zw;
- float neighbor = czm_unpackDepth(texture(pointCloud_depthTexture, neighborCoords));
+ float neighbor = czm_unpackDepth(texture(pointCloud_depthTexture,
+ neighborCoords));
vec4 colorNeighbor = texture(pointCloud_colorTexture, neighborCoords);
if (pastCenter) {
depthNeighbors[(j + 1) * neighborhoodFullWidth + i] =
@@ -104,7 +110,8 @@ void loadIntoArray(inout float[neighborhoodSize] depthNeighbors,
void main() {
vec4 color = texture(pointCloud_colorTexture, v_textureCoordinates);
- float depth = czm_unpackDepth(texture(pointCloud_depthTexture, v_textureCoordinates));
+ float depth = czm_unpackDepth(texture(pointCloud_depthTexture,
+ v_textureCoordinates));
vec4 finalColor = color;
float finalDepth = depth;
@@ -123,13 +130,22 @@ void main() {
loadIntoArray(depthNeighbors, colorNeighbors);
+ float density = densityScaleFactor * czm_unpackDepth(
+ texture(pointCloud_densityTexture, v_textureCoordinates));
+
// If our depth value is invalid
if (abs(depth) < EPS) {
+ // If the area that we want to region grow is sufficently sparse
+ if (float(iterationNumber) <= density + EPS) {
#if neighborhoodFullWidth == 3
- fastMedian3(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+ fastMedian3(depthNeighbors,
+ colorNeighbors,
+ finalDepth,
+ finalColor);
#else
- genericMedianFinder(depthNeighbors, colorNeighbors, finalDepth, finalColor);
+ genericMedianFinder(depthNeighbors, colorNeighbors, finalDepth, finalColor);
#endif
+ }
}
// Otherwise if our depth value is valid
else {
@@ -161,6 +177,10 @@ void main() {
}
}
+ #ifdef DENSITY_VIEW
+ colorOut = vec4(vec3(density / float(densityHalfWidth)), 1.0);
+ #else
colorOut = finalColor;
+ #endif
depthOut = czm_packDepth(finalDepth);
}
From cab382235919aa165242a116f12d398be39f4acd Mon Sep 17 00:00:00 2001
From: Srinivas Kaza
Date: Thu, 6 Jul 2017 14:56:55 -0400
Subject: [PATCH 056/240] Updates sandcastle demo
---
.../3D Tiles Point Cloud Post Processing.html | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html
index 1ddf60c90bc0..006d652f250a 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Post Processing.html
@@ -40,7 +40,7 @@