Skip to content

Commit

Permalink
Merge pull request #1005 from OpenGeoscience/view-matrix-precision
Browse files Browse the repository at this point in the history
Improve webgl coordinate precision.
  • Loading branch information
manthey authored Jul 11, 2019
2 parents 513ba9e + e11e3b6 commit 64929d6
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 18 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
### Improvements
- More response zooming via mouse wheel (#993)
- Explicitly exit retired renderers when autosharing renderers (#1007)
- If a point has no stroke or fill, don't return it from pointSearch (#1003)
- WebGL point, line, polygon, and contour features use a localized origin for improved precision at high zoom levels. This reduces panning jitter in zoom levels 19 and up (#1005)
- When doing a point search on a line feature, report which line segment is found (#1008)

### Changes
- Idle handlers no longer defer to scene-graph parents. Parents still wait for all children to be idle (#1001)
Expand Down
8 changes: 7 additions & 1 deletion src/contourFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ var meshFeature = require('./meshFeature');
* that point won't be included in the results.
* @property {number|function} [opacity=1] The opacity for the whole feature on
* a scale of 0 to 1.
* @property {number[]|function} [origin] Origin in map gcs coordinates used
* for to ensure high precision drawing in this location. When called as a
* function, this is passed the vertex positions as a single continuous array
* in map gcs coordinates. It defaults to the first vertex used in the
* contour.
*/

/**
Expand Down Expand Up @@ -214,7 +219,8 @@ var contourFeature = function (arg) {
opacity: 1.0,
value: function (d, i) {
return m_this.position()(d, i).z;
}
},
origin: (p) => (p.length >= 3 ? [p[0], p[1], 0] : [0, 0, 0])
},
arg.style === undefined ? {} : arg.style
);
Expand Down
8 changes: 7 additions & 1 deletion src/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ var util = require('./util');
* visible gradient. This is a single value that applies to all lines.
* @property {string|function} [debug] If 'debug', render lines in debug mode.
* This is a single value that applies to all lines.
* @property {number[]|function} [origin] Origin in map gcs coordinates used
* for to ensure high precision drawing in this location. When called as a
* function, this is passed the vertex positions as a single continuous array
* in map gcs coordinates. It defaults to the first line's first vertex's
* position.
*/

/**
Expand Down Expand Up @@ -353,7 +358,8 @@ var lineFeature = function (arg) {
antialiasing: 2.0,
closed: false,
line: function (d) { return d; },
position: function (d) { return d; }
position: function (d) { return d; },
origin: (p) => (p.length >= 3 ? p.slice(0, 3) : [0, 0, 0])
},
arg.style === undefined ? {} : arg.style
);
Expand Down
8 changes: 7 additions & 1 deletion src/pointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ var feature = require('./feature');
* @property {geo.geoColor|function} [fillColor] Color to fill each point.
* @property {number|function} [fillOpacity=1] Opacity for each point. Opacity
* is on a [0-1] scale.
* @property {number[]|function} [origin] Origin in map gcs coordinates used
* for to ensure high precision drawing in this location. When called as a
* function, this is passed the point positions as a single continuous array
* in map gcs coordinates. It defaults to the first point's position.
*/

/**
Expand Down Expand Up @@ -312,6 +316,7 @@ var pointFeature = function (arg) {
// Find points inside the bounding box
idx = m_rangeTree.range(min.x, min.y, max.x, max.y);

idx.sort((a, b) => a - b);
// Filter by circular region
idx.forEach(function (i) {
var d = data[i],
Expand Down Expand Up @@ -411,7 +416,8 @@ var pointFeature = function (arg) {
fillColor: { r: 1.0, g: 0.839, b: 0.439 },
fill: true,
fillOpacity: 0.8,
position: function (d) { return d; }
position: function (d) { return d; },
origin: (p) => (p.length >= 3 ? p.slice(0, 3) : [0, 0, 0])
},
arg.style === undefined ? {} : arg.style
);
Expand Down
15 changes: 14 additions & 1 deletion src/polygonFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ var transform = require('./transform');
* each polygon has a uniform style (uniform fill color, fill opacity, stroke
* color, and stroke opacity). Can vary by polygon.
* @property {boolean|function} [closed=true] Ignored. Always `true`.
* @property {number[]|function} [origin] Origin in map gcs coordinates used
* for to ensure high precision drawing in this location. When called as a
* function, this is passed an array of items, each of which has a vertices
* property that is a single continuous array in map gcs coordinates. It
* defaults to the first polygon's first vertex's position.
*/

/**
Expand Down Expand Up @@ -583,7 +588,15 @@ var polygonFeature = function (arg) {
strokeColor: {r: 0.0, g: 1.0, b: 1.0},
strokeOpacity: 1.0,
polygon: function (d) { return d; },
position: function (d) { return d; }
position: function (d) { return d; },
origin: (items) => {
for (let i = 0; i < items.length; i += 1) {
if (items[i].vertices.length >= 3) {
return items[i].vertices.slice(0, 3);
}
}
return [0, 0, 0];
}
},
arg.style === undefined ? {} : arg.style
);
Expand Down
2 changes: 1 addition & 1 deletion src/quadFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ var quadFeature = function (arg) {
clrQuads: clrQuads,
imgQuads: imgQuads,
vidQuads: vidQuads,
origin: origin
origin: new Float32Array(origin)
};
return m_quads;
};
Expand Down
16 changes: 14 additions & 2 deletions src/webgl/contourFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ var webgl_contourFeature = function (arg) {
m_stepsUniform = null,
m_steppedUniform = null,
m_dynamicDraw = arg.dynamicDraw === undefined ? false : arg.dynamicDraw,
m_origin,
m_modelViewUniform,
s_init = this._init,
s_update = this._update;

Expand Down Expand Up @@ -95,6 +97,16 @@ var webgl_contourFeature = function (arg) {
m_texture.setColorTable(colorTable);
contour.pos = transform.transformCoordinates(
m_this.gcs(), m_this.layer().map().gcs(), contour.pos, 3);
m_origin = new Float32Array(m_this.style.get('origin')(contour.pos));
if (m_origin[0] || m_origin[1] || m_origin[2]) {
for (i = 0; i < contour.pos.length; i += 3) {
contour.pos[i] -= m_origin[0];
contour.pos[i + 1] -= m_origin[1];
contour.pos[i + 2] -= m_origin[2];
}
}
m_modelViewUniform.setOrigin(m_origin);

posBuf = util.getGeomBuffer(geom, 'pos', numPts * 3);
opacityBuf = util.getGeomBuffer(geom, 'opacity', numPts);
valueBuf = util.getGeomBuffer(geom, 'value', numPts);
Expand Down Expand Up @@ -128,7 +140,6 @@ var webgl_contourFeature = function (arg) {
mat = vgl.material(),
tex = vgl.lookupTable(),
geom = vgl.geometryData(),
modelViewUniform = new vgl.modelViewUniform('modelViewMatrix'),
projectionUniform = new vgl.projectionUniform('projectionMatrix'),
samplerUniform = new vgl.uniform(vgl.GL.INT, 'sampler2d'),
vertexShader = createVertexShader(),
Expand All @@ -142,6 +153,7 @@ var webgl_contourFeature = function (arg) {
sourceOpacity = vgl.sourceDataAnyfv(
1, vgl.vertexAttributeKeysIndexed.Two, {'name': 'opacity'}),
primitive = new vgl.triangles();
m_modelViewUniform = new vgl.modelViewOriginUniform('modelViewMatrix');

s_init.call(m_this, arg);
m_mapper = vgl.mapper({dynamicDraw: m_dynamicDraw});
Expand All @@ -150,7 +162,7 @@ var webgl_contourFeature = function (arg) {
prog.addVertexAttribute(valueAttr, vgl.vertexAttributeKeysIndexed.One);
prog.addVertexAttribute(opacityAttr, vgl.vertexAttributeKeysIndexed.Two);

prog.addUniform(modelViewUniform);
prog.addUniform(m_modelViewUniform);
prog.addUniform(projectionUniform);
m_minColorUniform = new vgl.uniform(vgl.GL.FLOAT_VEC4, 'minColor');
prog.addUniform(m_minColorUniform);
Expand Down
16 changes: 14 additions & 2 deletions src/webgl/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ var webgl_lineFeature = function (arg) {
m_flagsUniform,
m_dynamicDraw = arg.dynamicDraw === undefined ? false : arg.dynamicDraw,
m_geometry,
m_origin,
m_modelViewUniform,
s_init = this._init,
s_update = this._update;

Expand Down Expand Up @@ -186,6 +188,16 @@ var webgl_lineFeature = function (arg) {

position = transform.transformCoordinates(
m_this.gcs(), m_this.layer().map().gcs(), position, 3);
m_origin = new Float32Array(m_this.style.get('origin')(position));
if (m_origin[0] || m_origin[1] || m_origin[2]) {
for (i = 0; i < position.length; i += 3) {
position[i] -= m_origin[0];
position[i + 1] -= m_origin[1];
position[i + 2] -= m_origin[2];
}
}
m_modelViewUniform.setOrigin(m_origin);

len = numSegments * orderLen;
posBuf = util.getGeomBuffer(geom, 'pos', len * 3);
prevBuf = util.getGeomBuffer(geom, 'prev', len * 3);
Expand Down Expand Up @@ -381,7 +393,6 @@ var webgl_lineFeature = function (arg) {
strkColorAttr = vgl.vertexAttribute('strokeColor'),
strkOpacityAttr = vgl.vertexAttribute('strokeOpacity'),
// Shader uniforms
mviUnif = new vgl.modelViewUniform('modelViewMatrix'),
prjUnif = new vgl.projectionUniform('projectionMatrix'),
geom = vgl.geometryData(),
// Sources
Expand All @@ -402,6 +413,7 @@ var webgl_lineFeature = function (arg) {
1, vgl.vertexAttributeKeysIndexed.Three, {name: 'strokeOpacity'}),
// Primitive indices
triangles = vgl.triangles();
m_modelViewUniform = new vgl.modelViewOriginUniform('modelViewMatrix');

m_pixelWidthUnif = new vgl.floatUniform(
'pixelWidth', 1.0 / m_this.renderer().width());
Expand All @@ -424,7 +436,7 @@ var webgl_lineFeature = function (arg) {
prog.addVertexAttribute(farAttr, vgl.vertexAttributeKeysIndexed.Six);
prog.addVertexAttribute(flagsAttr, vgl.vertexAttributeKeysIndexed.Seven);

prog.addUniform(mviUnif);
prog.addUniform(m_modelViewUniform);
prog.addUniform(prjUnif);
prog.addUniform(m_pixelWidthUnif);
prog.addUniform(m_aspectUniform);
Expand Down
16 changes: 13 additions & 3 deletions src/webgl/pointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ var webgl_pointFeature = function (arg) {
* 'triangle' seems to be fastest on low-powered hardware, but 'square'
* visits fewer fragments. */
m_primitiveShape = 'sprite', // arg can change this, below
m_modelViewUniform,
m_origin,
s_init = this._init,
s_update = this._update,
s_updateStyleFromArray = this.updateStyleFromArray;
Expand Down Expand Up @@ -167,6 +169,15 @@ var webgl_pointFeature = function (arg) {
}
position = transform.transformCoordinates(
m_this.gcs(), m_this.layer().map().gcs(), position, 3);
m_origin = new Float32Array(m_this.style.get('origin')(position));
if (m_origin[0] || m_origin[1] || m_origin[2]) {
for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
position[i3] -= m_origin[0];
position[i3 + 1] -= m_origin[1];
position[i3 + 2] -= m_origin[2];
}
}
m_modelViewUniform.setOrigin(m_origin);

posBuf = util.getGeomBuffer(geom, 'pos', vpf * numPts * 3);

Expand Down Expand Up @@ -363,7 +374,6 @@ var webgl_pointFeature = function (arg) {
strokeAttr = vgl.vertexAttribute('stroke'),
fillOpacityAttr = vgl.vertexAttribute('fillOpacity'),
strokeOpacityAttr = vgl.vertexAttribute('strokeOpacity'),
modelViewUniform = new vgl.modelViewUniform('modelViewMatrix'),
projectionUniform = new vgl.projectionUniform('projectionMatrix'),
mat = vgl.material(),
blend = vgl.blend(),
Expand All @@ -388,6 +398,7 @@ var webgl_pointFeature = function (arg) {
sourceStrokeOpacity = vgl.sourceDataAnyfv(
1, vgl.vertexAttributeKeysIndexed.Nine, {'name': 'strokeOpacity'}),
primitive = new vgl.triangles();
m_modelViewUniform = new vgl.modelViewOriginUniform('modelViewMatrix', m_origin);

if (m_primitiveShape === 'sprite') {
primitive = new vgl.points();
Expand All @@ -401,7 +412,6 @@ var webgl_pointFeature = function (arg) {
s_init.call(m_this, arg);
m_mapper = vgl.mapper({dynamicDraw: m_dynamicDraw});

// TODO: Right now this is ugly but we will fix it.
prog.addVertexAttribute(posAttr, vgl.vertexAttributeKeys.Position);
if (m_primitiveShape !== 'sprite') {
prog.addVertexAttribute(unitAttr, vgl.vertexAttributeKeysIndexed.One);
Expand All @@ -418,7 +428,7 @@ var webgl_pointFeature = function (arg) {

prog.addUniform(m_pixelWidthUniform);
prog.addUniform(m_aspectUniform);
prog.addUniform(modelViewUniform);
prog.addUniform(m_modelViewUniform);
prog.addUniform(projectionUniform);

prog.addShader(fragmentShader);
Expand Down
14 changes: 9 additions & 5 deletions src/webgl/polygonFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ var webgl_polygonFeature = function (arg) {
m_mapper = vgl.mapper(),
m_material = vgl.material(),
m_geometry,
m_origin,
m_modelViewUniform,
s_init = this._init,
s_update = this._update,
m_builtOnce,
Expand Down Expand Up @@ -167,6 +169,8 @@ var webgl_polygonFeature = function (arg) {
geom.primitive(0).setIndices(indices);
}
m_geometry = {items: items, numPts: numPts};
m_origin = new Float32Array(m_this.style.get('origin')(items));
m_modelViewUniform.setOrigin(m_origin);
} else {
items = m_geometry.items;
numPts = m_geometry.numPts;
Expand Down Expand Up @@ -214,9 +218,9 @@ var webgl_polygonFeature = function (arg) {
} else {
j = items[k].triangles[i] * 3;
if (!onlyStyle) {
posBuf[d3] = vertices[j];
posBuf[d3 + 1] = vertices[j + 1];
posBuf[d3 + 2] = vertices[j + 2];
posBuf[d3] = vertices[j] - m_origin[0];
posBuf[d3 + 1] = vertices[j + 1] - m_origin[1];
posBuf[d3 + 2] = vertices[j + 2] - m_origin[2];
indices[d] = i;
}
if (!uniform && fillColorVal === undefined) {
Expand Down Expand Up @@ -255,7 +259,6 @@ var webgl_polygonFeature = function (arg) {
posAttr = vgl.vertexAttribute('pos'),
fillColorAttr = vgl.vertexAttribute('fillColor'),
fillOpacityAttr = vgl.vertexAttribute('fillOpacity'),
modelViewUniform = new vgl.modelViewUniform('modelViewMatrix'),
projectionUniform = new vgl.projectionUniform('projectionMatrix'),
vertexShader = createVertexShader(),
fragmentShader = createFragmentShader(),
Expand All @@ -267,12 +270,13 @@ var webgl_polygonFeature = function (arg) {
sourceFillOpacity = vgl.sourceDataAnyfv(
1, vgl.vertexAttributeKeysIndexed.Three, {'name': 'fillOpacity'}),
trianglePrimitive = vgl.triangles();
m_modelViewUniform = new vgl.modelViewOriginUniform('modelViewMatrix');

prog.addVertexAttribute(posAttr, vgl.vertexAttributeKeys.Position);
prog.addVertexAttribute(fillColorAttr, vgl.vertexAttributeKeysIndexed.Two);
prog.addVertexAttribute(fillOpacityAttr, vgl.vertexAttributeKeysIndexed.Three);

prog.addUniform(modelViewUniform);
prog.addUniform(m_modelViewUniform);
prog.addUniform(projectionUniform);

prog.addShader(fragmentShader);
Expand Down
2 changes: 1 addition & 1 deletion tests/external-data/base-images.tgz.sha512
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3b3eb2d6d4bf78cd9ff98319a7745ca7a3c115ec8d47a706165e5bdb224e8e49ba122acacb647ae4edb994fe3e3ab7e1456bfa1577c7dd0fe6e1b524f37d186d
28a26c252b7e013ad542fb3be0286f22b153b6bb8a791e3aef118c54944094807f041e1b4073a02c7a14f45848740dd63e5c6f20141e8801db8a0594ffb8efc5

0 comments on commit 64929d6

Please sign in to comment.