世界风点地标球场

Worldwind PointPlacemark Pitch

我想弄清楚为什么 PointPlacemarkAttributes 中的 setPitch 似乎无法正常工作。

我认为 PointPlacemark.java 中的这段 JOGL 代码是出错的地方:

        Double heading = getActiveAttributes().getHeading();
        Double pitch = getActiveAttributes().getPitch();

        // Adjust heading to be relative to globe or screen
        if (heading != null)
        {
            if (AVKey.RELATIVE_TO_GLOBE.equals(this.getActiveAttributes().getHeadingReference()))
                heading = dc.getView().getHeading().degrees - heading;
            else
                heading = -heading;
        }

        // Apply the heading and pitch if specified.
        if (heading != null || pitch != null)
        {
            gl.glTranslated(xscale / 2, yscale / 2, 0);
            if (pitch != null)
                gl.glRotated(pitch, 1, 0, 0);
            if (heading != null)
                gl.glRotated(heading, 0, 0, 1);
            gl.glTranslated(-xscale / 2, -yscale / 2, 0);
        }

        // Scale the unit quad
        gl.glScaled(xscale, yscale, 1);

这是一个我一直用来玩的简单驱动程序:

public class Placemarks extends ApplicationTemplate {
    public static class AppFrame extends ApplicationTemplate.AppFrame {
        public AppFrame() {
            super(true, true, false);

            final RenderableLayer layer = new RenderableLayer();

            PointPlacemark pp = new PointPlacemark(Position.fromDegrees(28, -102, 30000));
            pp.setLabelText("PointPlacemark");
            pp.setLineEnabled(false);
            pp.setAltitudeMode(WorldWind.ABSOLUTE);
            PointPlacemarkAttributes attrs = new PointPlacemarkAttributes();
            attrs.setImageAddress("gov/nasa/worldwindx/examples/images/georss.png");
            attrs.setScale(1.0);
            attrs.setImageOffset(Offset.CENTER);


            attrs.setPitch(45.0);

            pp.setAttributes(attrs);
            layer.addRenderable(pp);

            // Add the layer to the model.
            insertBeforeCompass(getWwd(), layer);
        }
    }

    public static void main(String[] args) {
        ApplicationTemplate.start("WorldWind Placemarks", AppFrame.class);
    }
}

如果我不设置间距,它看起来不错:

但是当我设置 45 度的俯仰角时,它看起来像这样:

我不明白它与我设置的值有何关联。我希望它能像 CompassLayer:

中的 Compass 那样工作

更新

评论建议迭代音高值以查看其工作原理。我这样做了,但我仍然没有看到它应该如何工作。看起来它只是水平 "cropping" 图像,没有做任何其他事情。这是一些代码:

public class Placemarks extends ApplicationTemplate {
    public static class AppFrame extends ApplicationTemplate.AppFrame {
        public AppFrame() {
            super(true, true, false);

            final RenderableLayer layer = new RenderableLayer();

            PointPlacemark pp = new PointPlacemark(Position.fromDegrees(28, -102, 30000));
            pp.setLabelText("PointPlacemark");
            pp.setLineEnabled(false);
            pp.setAltitudeMode(WorldWind.ABSOLUTE);
            PointPlacemarkAttributes attrs = new PointPlacemarkAttributes();
            attrs.setImageAddress("gov/nasa/worldwindx/examples/images/georss.png");
            attrs.setScale(1.0);
            attrs.setImageOffset(Offset.CENTER);


            pp.setAttributes(attrs);
            layer.addRenderable(pp);

            // Add the layer to the model.
            insertBeforeCompass(getWwd(), layer);

            Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    for(double i = 0.0; i<360; i+=.1) {
                        attrs.setPitch(i);


                        System.out.println("Pitch is now "+i);

                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        AppFrame.this.getWwd().redrawNow();
                    }

                }
            });
            t.start();
        }
    }

    public static void main(String[] args) {
        ApplicationTemplate.start("WorldWind Placemarks", AppFrame.class);
    }
}

并且录屏GIF:

问题是在PointPlacemark.doDrawOrderedRenderable()中使用的正交投影矩阵使用了从-1到1的深度值范围。

当俯仰保持在0时,z坐标也保持在0,安全地在这个范围的中间(实际上,这个坐标在WorldWind中有一些轻微的伪造,但不要介意)。当它倾斜时,z 坐标当然会发生变化,直到 90° 所有 y 坐标都为 0,而 z 将达到图像高度的一半。这就是为什么只有落在 -1,1 范围内的图像切片可见而其余部分被剪裁的原因。

该 z 范围由以下代码定义:

// 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);

如果我们检查 CompassLayer 中的等效代码,我们可以看到它们在这里 缩放图标大小的因素(尽管评论表明可能在某些情况下较早的迭代,对 z 维度的关注较少):

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);

在这种情况下,z (±0.6 * maxwh) 的参数使用 0.6 大概是 0.5 加上一些余量。实际几何体是一个单位四边形,在 x/y 中平移一半 width/height,并相应地缩放和旋转。

对于 PointPlacemark,我们可以用类似的方式计算可渲染对象的大小。稍微重新排列代码,以便在设置投影之前进行比例计算,并添加一个 maxwh 值:

// 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);

同样,0.6 允许一些余量。

z 范围的硬编码值可能会非常好,只要它们对于我们可能想要绘制的任何图像足够大,但又不会大到数值精度成为问题。相反,人们可以走得更远,并考虑三角因素来计算给定旋转和图像大小所需的实际深度,但这样做不会有太多收获。

这确实是已报告的 WorldWindJava 错误,以及 link 此处的修复程序。