Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve webgl coordinate precision. #1005

Merged
merged 1 commit into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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