Worldwind PointPlacemark Pitch

Solution 1:

The problem is that in PointPlacemark.doDrawOrderedRenderable(), the orthographic projection matrix used uses a range of depth values from -1 to 1.

When the pitch remains at 0, the z coordinates also remain at 0, safely in the middle of this range (actually, there is some slight fudging of this coordinate in WorldWind, but never mind that). As it pitches, of course the z coordinates change, until at 90° all of the y coordinates are 0 while z will go to half of the height of the image. This is why only a slice of the image that falls within the range -1,1 is visible while the rest is clipped.

That z range is defined by the following code:

// The image is drawn using a parallel projection.
osh.pushProjectionIdentity(gl);
gl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -1d, 1d);

If we examine the equivalent code in CompassLayer, we can see that here they do factor in the scaled icon size (although the comment suggests that perhaps at some earlier iteration, less care had been taken over the z dimension):

double width = this.getScaledIconWidth();
double height = this.getScaledIconHeight();

// Load a parallel projection with xy dimensions (viewportWidth, viewportHeight)
// into the GL projection matrix.
java.awt.Rectangle viewport = dc.getView().getViewport();
ogsh.pushProjectionIdentity(gl);
double maxwh = width > height ? width : height;
if (maxwh == 0)
    maxwh = 1;
gl.glOrtho(0d, viewport.width, 0d, viewport.height, -0.6 * maxwh, 0.6 * maxwh);

In this case, the arguments for z (±0.6 * maxwh) use 0.6 presumably as 0.5 plus some margin. The actual geometry is a unit quad, which is translated by half width/height in x/y, scaled and rotated accordingly.

For PointPlacemark, we can account for the size of the renderable in a similar way. Rearranging the code slightly so that scale computation happens before setting the projection, and adding a maxwh value:

// Compute the scale
double xscale;
Double scale = this.getActiveAttributes().getScale();
if (scale != null)
    xscale = scale * this.activeTexture.getWidth(dc);
else
    xscale = this.activeTexture.getWidth(dc);

double yscale;
if (scale != null)
    yscale = scale * this.activeTexture.getHeight(dc);
else
    yscale = this.activeTexture.getHeight(dc);
double maxwh = Math.max(xscale, yscale);

// The image is drawn using a parallel projection.
osh.pushProjectionIdentity(gl);
gl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -0.6 * maxwh, 0.6 * maxwh);

Again, 0.6 allows some margin.

It would probably be perfectly fine to have hardcoded values for the z range, as long as they were large enough for any image we might want to draw but not so large that numerical precision became an issue. Conversely, one could go even further and factor in trig to work out the actual depth needed for a given rotation and image size, but there would not be much to gain by doing so.

This was indeed a bug with WorldWindJava that has been reported, along with a link here for the fix.