The NASA WorldWind Javascript SDK (WebWW) includes the library and examples for creating geo-browser web applications and for embedding a 3D globe in HTML5 web pages.
Picking of any SurfaceShapes is unpredictable, because JS canvas still does not allow to switch off anti-aliasing for strokes during rendering of pick frame.
This issue makes picking of SurfaceShapes unusable (see animation below).
https://github.com/WorldWindEarth/worldwindjs/issues/27
Create several SurfacePolylines close to each other so that they will be located on the same terrain tile.
Try to pick one of them on mouse move.
You will see that it picks random shape located on this tile.
This problem appears because anti-aliasing not only make contour pixels transparent, but also make color value average between shape color and background. This average color is equal to pick color of some other shape in tile.
To fix this issue you need to do three steps:
1) Disable anti-aliasing for path stroke on canvas to avoid appearance of semi-transparent pixels with wrong average color on the edge of the shape.
As I have researched - there is no possibility to disable canvas anti-aliasing for shapes. There is an option only for images. That's why we have two possibilities: ignore pick color with alpha != 1 during pick procedure or remove semi-transparent pixels which may contain wrong color from resulted tile. First approach is faster, but require changes in several places and may have some side effect on other renderables selection except surface shapes. That's why I propose to go with second approach - remove semi transparent pixels in SurfaceShapeTile.prototype.updateTexture.
shape.renderToTexture(dc, ctx2D, xScale, yScale, xOffset, yOffset);
}
// Remove semi-transparent pixels which may contain wrong pick color
if (dc.pickingMode) {
const imageData = ctx2D.getImageData(0, 0, canvas.width, canvas.height);
for (let i = 3, n = canvas.width * canvas.height * 4; i < n; i += 4) {
if (imageData.data[i] < 255) {
imageData.data[i - 3] = 0;
imageData.data[i - 2] = 0;
imageData.data[i - 1] = 0;
imageData.data[i] = 0;
}
}
ctx2D.putImageData(imageData, 0, 0);
}
this.gpuCacheKey = this.getCacheKey();
2) We need to use NEAREST value for TEXTURE_MIN_FILTER and TEXTURE_MAG_FILTER in pickingMode the same way as in WorldWindAndroid, to avoid appearance of average color pixels during texture filtering in WebGL.
Texture.prototype.applyTexParameters = function (dc) {
var gl = dc.currentGlContext;
// Configure the OpenGL texture minification function. Use nearest in pickingMode or linear by default.
var textureMinFilter = dc.pickingMode ? gl.NEAREST : this.texParameters[gl.TEXTURE_MIN_FILTER] || gl.LINEAR;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, textureMinFilter);
// Configure the OpenGL texture magnification function. Use nearest in pickingMode or linear by default.
var textureMagFilter = dc.pickingMode ? gl.NEAREST : this.texParameters[gl.TEXTURE_MAG_FILTER] || gl.LINEAR;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, textureMagFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.texParameters[gl.TEXTURE_WRAP_S] || gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.texParameters[gl.TEXTURE_WRAP_T] || gl.CLAMP_TO_EDGE);
// Try to enable the anisotropic texture filtering only if we have a linear magnification filter.
// This can't be enabled all the time because Windows seems to ignore the TEXTURE_MAG_FILTER parameter when
// this extension is enabled.
if (textureMagFilter === gl.LINEAR) {
// Setup 4x anisotropic texture filtering when this feature is available.
if (this.anisotropicFilterExt) {
gl.texParameteri(gl.TEXTURE_2D, this.anisotropicFilterExt.TEXTURE_MAX_ANISOTROPY_EXT, 4);
}
}
};
3) Remove texture parameters setting from Texture constructor, as it now located in applyTextParameters.
gl.bindTexture(gl.TEXTURE_2D, textureId);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
gl.texImage2D(gl.TEXTURE_2D, 0,
gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
if (isPowerOfTwo) {
gl.generateMipmap(gl.TEXTURE_2D);
}
this.textureId = textureId;
/**
* The time at which this texture was created.
* @type {Date}
*/
this.creationTime = new Date();
// Internal use only. Intentionally not documented.
this.texParameters = {};
this.texParameters[gl.TEXTURE_MIN_FILTER] = isPowerOfTwo ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR;
this.texParameters[gl.TEXTURE_WRAP_S] = wrapMode;
this.texParameters[gl.TEXTURE_WRAP_T] = wrapMode;
Second and third part is a 100% MUST, but first part of my fix is little bit performance ineffective. So if anybody knows better way to avoid wrong color pixels during shape anti-alising or knows how to disable anti-alising, please, let me know.
Picking of any SurfaceShapes is unpredictable, because JS canvas still does not allow to switch off anti-aliasing for strokes during rendering of pick frame. This issue makes picking of SurfaceShapes unusable (see animation below). https://github.com/WorldWindEarth/worldwindjs/issues/27
This problem appears because anti-aliasing not only make contour pixels transparent, but also make color value average between shape color and background. This average color is equal to pick color of some other shape in tile.
To fix this issue you need to do three steps:
1) Disable anti-aliasing for path stroke on canvas to avoid appearance of semi-transparent pixels with wrong average color on the edge of the shape.
As I have researched - there is no possibility to disable canvas anti-aliasing for shapes. There is an option only for images. That's why we have two possibilities: ignore pick color with alpha != 1 during pick procedure or remove semi-transparent pixels which may contain wrong color from resulted tile. First approach is faster, but require changes in several places and may have some side effect on other renderables selection except surface shapes. That's why I propose to go with second approach - remove semi transparent pixels in SurfaceShapeTile.prototype.updateTexture.
2) We need to use NEAREST value for TEXTURE_MIN_FILTER and TEXTURE_MAG_FILTER in pickingMode the same way as in WorldWindAndroid, to avoid appearance of average color pixels during texture filtering in WebGL.
3) Remove texture parameters setting from Texture constructor, as it now located in applyTextParameters.
Second and third part is a 100% MUST, but first part of my fix is little bit performance ineffective. So if anybody knows better way to avoid wrong color pixels during shape anti-alising or knows how to disable anti-alising, please, let me know.