在NASA WorldWind Java中,我使用PointPlacemark表示图像,因为无论缩放级别如何,图像都保持不变。问题是,即使相机倾斜,我也要在Point Placemark上设置航向并将其保持在指南针航向上。当查看倾斜的地球仪时,它的功能完全符合我的要求,但是当我倾斜时,地标将继续面对屏幕,而不是与地球仪一起倾斜,这会使它的工作方式变得奇怪。

这是说明我所见内容的GIF:https://giphy.com/embed/3o7WIqZUceR8xh6BOg

我希望点地标图像即使在倾斜时也保持相对于地球的标题-因此,随着视图的倾斜,图像实际上是“变平的”,而无论缩放级别如何,其尺寸都保持不变。

这是我正在使用的代码段。我正在设置attrs.setHeadingReference(AVKey.RELATIVE_TO_GLOBE);在关联的PointPlacemarkAttributes上。在此示例中,我将航向设置为135度。

import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.Offset;
import gov.nasa.worldwind.render.PointPlacemark;
import gov.nasa.worldwind.render.PointPlacemarkAttributes;

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("Airplane");
            pp.setLineEnabled(false);
            pp.setAltitudeMode(WorldWind.ABSOLUTE);
            PointPlacemarkAttributes attrs = new PointPlacemarkAttributes();
            attrs.setImageAddress("images/airplane.png");
            attrs.setScale(0.05);
            attrs.setImageOffset(Offset.CENTER);

            //Point to 135.0
            attrs.setHeading(135.0);
            attrs.setHeadingReference(AVKey.RELATIVE_TO_GLOBE);

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

}

我还玩过在多边形上应用纹理的游戏。它的定位方式是我一直在寻找的-除了我希望图标保持相同的大小而不考虑缩放级别(例如PointPlacemark所做的事情)。

这是一个GIF,说明我在使用Polygon时看到的内容。注意地球倾斜时的行为:https://giphy.com/embed/xThta4USlDzd8Ii5ZS

这是我用于多边形的来源:
import java.awt.geom.AffineTransform;
import java.util.Arrays;
import java.util.List;

import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.BasicShapeAttributes;
import gov.nasa.worldwind.render.Polygon;

public class TexturedPolygon extends ApplicationTemplate {

    public static Polygon createPolygonTexturedImage(String filePath, Position pos, double heading, double scale) {

        double offsetDist = 1.0D * scale;

        Position p1 = Position.fromDegrees(pos.getLatitude().addDegrees(-offsetDist).getDegrees(),
                pos.getLongitude().addDegrees(-offsetDist).getDegrees(), pos.getAltitude());
        Position p2 = Position.fromDegrees(pos.getLatitude().addDegrees(offsetDist).getDegrees(),
                pos.getLongitude().addDegrees(-offsetDist).getDegrees());
        Position p3 = Position.fromDegrees(pos.getLatitude().addDegrees(offsetDist).getDegrees(),
                pos.getLongitude().addDegrees(offsetDist).getDegrees());
        Position p4 = Position.fromDegrees(pos.getLatitude().addDegrees(-offsetDist).getDegrees(),
                pos.getLongitude().addDegrees(offsetDist).getDegrees());

        double[] points = new double[] { p1.getLatitude().getDegrees(), p1.getLongitude().getDegrees(),
                p2.getLatitude().getDegrees(), p2.getLongitude().getDegrees(), p3.getLatitude().getDegrees(),
                p3.getLongitude().getDegrees(), p4.getLatitude().getDegrees(), p4.getLongitude().getDegrees() };

        double[] transformedPoints = new double[8];
        AffineTransform rotation = new AffineTransform();
        rotation.rotate(Math.toRadians(heading), pos.getLatitude().getDegrees(), pos.getLongitude().getDegrees());
        rotation.transform(points, 0, transformedPoints, 0, 4);

        double altitude = pos.getAltitude();
        p1 = Position.fromDegrees(transformedPoints[0], transformedPoints[1], altitude);
        p2 = Position.fromDegrees(transformedPoints[2], transformedPoints[3], altitude);
        p3 = Position.fromDegrees(transformedPoints[4], transformedPoints[5], altitude);
        p4 = Position.fromDegrees(transformedPoints[6], transformedPoints[7], altitude);

        List<Position> positions = Arrays.asList(p1, p2, p3, p4);
        Polygon polygon = new Polygon(positions);
        polygon.setAltitudeMode(WorldWind.ABSOLUTE);

        BasicShapeAttributes mattr = new BasicShapeAttributes();
        mattr.setDrawOutline(false);
        mattr.setDrawInterior(true);
        polygon.setAttributes(mattr);
        polygon.setTextureImageSource(filePath, new float[] { 0.0F, 0.0F, 1.0F, 0.0F, 1.0F, 1.0F, 0.0F, 1.0F }, 4);

        return polygon;
    }

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

            final RenderableLayer layer = new RenderableLayer();

            Position pos = Position.fromDegrees(28, -102, 30000);
            String url = "images/airplane.png";

            layer.addRenderable(createPolygonTexturedImage(url, pos, 135.0, 1.05));

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

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

}

为了完整起见-这是我正在使用的图像作为plane.png:

综上所述,我正在寻找:
  • 由图标图像表示的Renderable
  • 图标保持相同大小,而不考虑缩放级别
  • 即使相机视图倾斜了
  • ,图标仍会对准地球罗盘方向

    最佳答案

    通过将此解决方案与question和CompassLayer逻辑结合起来,该逻辑将屏幕倾斜度与间距相关联。

    将此方法添加到PointPlacemark.java(取自CompassLayer):

    protected double computePitch(View view)
    {
        if (view == null)
            return 0.0;
    
        if (!(view instanceof OrbitView))
            return 0.0;
    
        OrbitView orbitView = (OrbitView) view;
        return orbitView.getPitch().getDegrees();
    }
    

    然后在doDrawOrderedRenderable(DrawContext dc,PickSupport pickCandidates,OrderedPlacemark opm)方法中,使用以下逻辑:
    protected void doDrawOrderedRenderable(DrawContext dc, PickSupport pickCandidates, OrderedPlacemark opm)
    {
        if (this.isDrawLine(dc, opm))
            this.drawLine(dc, pickCandidates, opm);
    
        if (this.activeTexture == null)
        {
            if (this.isDrawPoint(dc))
                this.drawPoint(dc, pickCandidates, opm);
            return;
        }
    
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
    
        OGLStackHandler osh = new OGLStackHandler();
        try
        {
            if (dc.isPickingMode())
            {
                // Set up to replace the non-transparent texture colors with the single pick color.
                gl.glEnable(GL.GL_TEXTURE_2D);
                gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_COMBINE);
                gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_SRC0_RGB, GL2.GL_PREVIOUS);
                gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, GL2.GL_REPLACE);
    
                Color pickColor = dc.getUniquePickColor();
                pickCandidates.addPickableObject(this.createPickedObject(dc, pickColor));
                gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue());
            }
            else
            {
                gl.glEnable(GL.GL_TEXTURE_2D);
                Color color = this.getActiveAttributes().getImageColor();
                if (color == null)
                    color = PointPlacemarkAttributes.DEFAULT_IMAGE_COLOR;
                gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(),
                    (byte) color.getAlpha());
            }
    
            // This was relocated from the check in version.
            // 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.
            // This came from the fix in https://stackoverflow.com/questions/49637844/worldwind-pointplacemark-pitch
            osh.pushProjectionIdentity(gl);
            gl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -0.6 * maxwh, 0.6 * maxwh);
    
            // Apply the depth buffer but don't change it (for screen-space shapes).
            if ((!dc.isDeepPickingEnabled()))
                gl.glEnable(GL.GL_DEPTH_TEST);
            gl.glDepthMask(false);
    
            // Suppress any fully transparent image pixels.
            gl.glEnable(GL2.GL_ALPHA_TEST);
            gl.glAlphaFunc(GL2.GL_GREATER, 0.001f);
    
            // Adjust depth of image to bring it slightly forward
            double depth = opm.screenPoint.z - (8d * 0.00048875809d);
            depth = depth < 0d ? 0d : (depth > 1d ? 1d : depth);
            gl.glDepthFunc(GL.GL_LESS);
            gl.glDepthRange(depth, depth);
    
            // The image is drawn using a translated and scaled unit quad.
            // Translate to screen point and adjust to align hot spot.
            osh.pushModelviewIdentity(gl);
            gl.glTranslated(opm.screenPoint.x + this.dx, opm.screenPoint.y + this.dy, 0);
    
            Double heading = getActiveAttributes().getHeading();
            Double pitch =          this.computePitch(dc.getView());
    
            // 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);
    
            if (this.activeTexture.bind(dc))
                dc.drawUnitQuad(activeTexture.getTexCoords());
    
            gl.glDepthRange(0, 1); // reset depth range to the OGL default
    
            if (this.mustDrawLabel())
            {
                if (!dc.isPickingMode() || this.isEnableLabelPicking())
                    this.drawLabel(dc, pickCandidates, opm);
            }
        }
        finally
        {
            if (dc.isPickingMode())
            {
                gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, OGLUtil.DEFAULT_TEX_ENV_MODE);
                gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_SRC0_RGB, OGLUtil.DEFAULT_SRC0_RGB);
                gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, OGLUtil.DEFAULT_COMBINE_RGB);
            }
    
            gl.glDisable(GL.GL_TEXTURE_2D);
            osh.pop(gl);
        }
    }
    

    它看起来像这样:

    java - WorldWind Point地标标题-LMLPHP

    08-04 03:46