WorldWind 中的闪烁注释 Java

Flickering Annotations in WorldWind Java

我正在尝试在 NASA Worldwind 中为 Java 实现我自己的杂波过滤器,它导致了一个奇怪的问题——杂波过滤器还没有做太多,但我会用它来移动东西当我通过 "flickering" 问题时。每当移动鼠标时,GlobeAnnotation 可渲染对象就会闪烁。当我将杂波过滤器设置为空时,似乎没有出现闪烁。

这里有一个 GIF 动图来表达我的意思:https://media.giphy.com/media/xT9IgFiZwYZ3VJHQU8/giphy.gif

我从这里克隆了 NASA worldwind 代码:https://github.com/NASAWorldWind/WorldWindJava。我进行了一些更改以使最终过滤器适用。请注意,我希望 GlobeAnnotations 显示为始终位于其他所有内容之上。

如何让 GlobeAnnotations 不相互冲突和闪烁,但仍然出现在其他所有内容之上 - 同时打开杂波过滤器?

请注意,以下代码只是我为了说明我在 "real" 应用程序中遇到的问题而放在一起的示例。我希望 GlobeAnnotations 始终位于其他所有内容之上——但不会闪烁和相互争斗。

这是我的试车手:

package gov.nasa.worldwindx.examples;

import java.awt.Color;

import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.AnnotationLayer;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.GlobeAnnotation;
import gov.nasa.worldwind.render.Material;
import gov.nasa.worldwind.render.airspaces.CappedCylinder;

public class FlashyAnnotations extends ApplicationTemplate {
    @SuppressWarnings("unchecked")
    private static class AppFrame extends ApplicationTemplate.AppFrame {

        private AnnotationLayer layer;

        public AppFrame() {

            this.getWwd().getSceneController().setClutterFilter(new SimpleClutterFilter());

            CappedCylinder cappedCyl = new CappedCylinder(LatLon.fromDegrees(27, -100), 3000000);
            cappedCyl.getAttributes().setDrawInterior(true);
            cappedCyl.getAttributes().setInteriorMaterial(Material.GREEN);
            cappedCyl.getAttributes().setInteriorOpacity(.75f);
            cappedCyl.setAltitudes(10, 100000);
            RenderableLayer renderLayer = new RenderableLayer();

            renderLayer.addRenderable(cappedCyl);
            insertBeforeCompass(this.getWwd(), renderLayer);

            // Create example annotations
            this.setupAnnotations();

        }

        private void setupAnnotations() {

            // Create an AnnotationLayer with lots of annotations
            this.layer = new AnnotationLayer();

            GlobeAnnotation ga = new GlobeAnnotation("Annotation", Position.fromDegrees(20, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            ga.setAlwaysOnTop(true);
            layer.addAnnotation(ga);

            ga = new GlobeAnnotation("Annotation", Position.fromDegrees(25, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            ga.setAlwaysOnTop(true);
            layer.addAnnotation(ga);

            // Add layer to the layer list and update the layer panel
            insertBeforeCompass(this.getWwd(), layer);
        }

    }

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

这是我的(基本上是无操作的)杂波过滤器:

package gov.nasa.worldwindx.examples;

import java.util.List;

import gov.nasa.worldwind.render.Declutterable;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.ClutterFilter;

public class SimpleClutterFilter implements ClutterFilter{

    @Override
    public void apply(DrawContext dc, List<Declutterable> shapes) {
        for(Declutterable shape: shapes) {
            dc.addOrderedRenderable(shape);
        }

    }

}

而且我还必须更新 gov.nasa.worldwind.render.BasicAnnotationRenderer 以使其创建的 OrderedAnnotations 实现 Declutterable。 (此内部 class 的唯一变化是添加了 isEnableDecluttering 和 getBounds):

public class OrderedAnnotation implements OrderedRenderable, Declutterable
{
protected Annotation annotation;


protected double eyeDistance;
protected Layer layer;

public OrderedAnnotation(Annotation annotation, double eyeDistance)
{
    this.annotation = annotation;
    this.eyeDistance = eyeDistance;
}

public OrderedAnnotation(Annotation annotation, Layer layer, double eyeDistance)
{
    this.annotation = annotation;
    this.eyeDistance = eyeDistance;
    this.layer = layer;
}

public double getDistanceFromEye()
{
    return this.eyeDistance;
}

public void render(DrawContext dc)
{
    OGLStackHandler stackHandler = new OGLStackHandler();
    BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
    try
    {
        this.doRender(dc, this);
        // Draw as many as we can in a batch to save ogl state switching.
        while (dc.peekOrderedRenderables() instanceof OrderedAnnotation)
        {
            OrderedAnnotation oa = (OrderedAnnotation) dc.pollOrderedRenderables();
            this.doRender(dc, oa);
        }
    }
    catch (WWRuntimeException e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
    }
    catch (Exception e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
    }
    finally
    {
        BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
    }
}

public void pick(DrawContext dc, java.awt.Point pickPoint)
{
    OGLStackHandler stackHandler = new OGLStackHandler();
    BasicAnnotationRenderer.this.pickSupport.clearPickList();
    BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
    try
    {
        this.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
        this.doRender(dc, this);
        // Draw as many as we can in a batch to save ogl state switching.
        while (dc.peekOrderedRenderables() instanceof OrderedAnnotation)
        {
            OrderedAnnotation oa = (OrderedAnnotation) dc.pollOrderedRenderables();
            oa.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
            this.doRender(dc, oa);
        }
    }
    catch (WWRuntimeException e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
    }
    catch (Exception e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
    }
    finally
    {
        BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
        BasicAnnotationRenderer.this.pickSupport.resolvePick(dc, pickPoint, this.layer);
        BasicAnnotationRenderer.this.pickSupport.clearPickList(); // to ensure entries can be garbage collected
    }
}

protected void doRender(DrawContext dc, OrderedAnnotation oa)
{
    // Swap the draw context's current layer with that of the ordered annotation
    Layer previousCurrentLayer = dc.getCurrentLayer();
    try
    {
        dc.setCurrentLayer(oa.layer);
        oa.annotation.renderNow(dc);
    }
    finally
    {
        dc.setCurrentLayer(previousCurrentLayer); // restore the original layer
    }
}

@Override
public boolean isEnableDecluttering() {
    return (annotation instanceof GlobeAnnotation);
}

@Override
public Rectangle2D getBounds(DrawContext dc) {
    if(annotation instanceof GlobeAnnotation) {
        return ((GlobeAnnotation) annotation).computeBounds(dc);
    }
    return null;
}

}

首先;

https://forum.worldwindcentral.com/forum/world-wind-java-forums/development-help/13263-layer-priority-order

setupAnnotations 方法中,您将两个 GlobeAnnotation 对象的 alwaysOnTop 设置为 true。这可能是原因。

private void setupAnnotations() {

            // Create an AnnotationLayer with lots of annotations
            this.layer = new AnnotationLayer();

            GlobeAnnotation ga = new GlobeAnnotation("Annotation", Position.fromDegrees(20, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            **ga.setAlwaysOnTop(true);**
            layer.addAnnotation(ga);

            ga = new GlobeAnnotation("Annotation", Position.fromDegrees(25, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            **ga.setAlwaysOnTop(true);**
            layer.addAnnotation(ga);

            // Add layer to the layer list and update the layer panel
            insertBeforeCompass(this.getWwd(), layer);
        }

相反,将您希望始终位于顶部的注释放入单独的层并将其余的注释放入另一层可能是使用上面的链接的解决方案。