从符号到地形的世界风线

mai*_*rgs 7 java opengl jogl worldwind

Worldwind的Point PlaceMark可渲染具有通过调用setLineEnabled从地标到地形的一条线,如下截图所示:

在此输入图像描述

我正在尝试做的是添加一条这样的线,它也适用于可渲染的战术符号.我的第一个想法是从PointPlacemark可渲染中借用逻辑来执行此操作,并将其添加到AbstractTacticalSymbol可渲染.我试过了,到目前为止我还没有成功.

这是我到目前为止所做的:

  1. 将此添加到OrderedSymbol类:

    public Vec4 terrainPoint;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 更新了computeSymbolPoints以计算terrainPoint

    protected void computeSymbolPoints(DrawContext dc, OrderedSymbol osym)
    {
        osym.placePoint = null;
        osym.screenPoint = null;
        osym.terrainPoint = null;
        osym.eyeDistance = 0;
    
        Position pos = this.getPosition();
        if (pos == null)
            return;
    
        if (this.altitudeMode == WorldWind.CLAMP_TO_GROUND || dc.is2DGlobe())
        {
            osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0);
        }
        else if (this.altitudeMode == WorldWind.RELATIVE_TO_GROUND)
        {
            osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), pos.getAltitude());
        }
        else // Default to ABSOLUTE
        {
            double height = pos.getElevation() * dc.getVerticalExaggeration();
            osym.placePoint = dc.getGlobe().computePointFromPosition(pos.getLatitude(), pos.getLongitude(), height);
        }
    
        if (osym.placePoint == null)
            return;
    
        // Compute the symbol's screen location the distance between the eye point and the place point.
        osym.screenPoint = dc.getView().project(osym.placePoint);
        osym.eyeDistance = osym.placePoint.distanceTo3(dc.getView().getEyePoint());
    
        // Compute a terrain point if needed.
        if (this.isLineEnabled() && this.altitudeMode != WorldWind.CLAMP_TO_GROUND && !dc.is2DGlobe())
            osym.terrainPoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0);
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 添加了此逻辑(取自PointPlacemark.java并更新以符合AbstractTacticalSymbol.java).请注意,我将lineEnabled设置为true,因此默认情况下应该绘制该行.

    boolean lineEnabled = true;
    
    
    double lineWidth = 1;
    protected int linePickWidth = 10;
    Color lineColor = Color.white;
    
    /**
     * Indicates whether a line from the placemark point to the corresponding position on the terrain is drawn.
     *
     * @return true if the line is drawn, otherwise false.
     */
    public boolean isLineEnabled()
    {
        return lineEnabled;
    }
    
    /**
     * Specifies whether a line from the placemark point to the corresponding position on the terrain is drawn.
     *
     * @param lineEnabled true if the line is drawn, otherwise false.
     */
    public void setLineEnabled(boolean lineEnabled)
    {
        this.lineEnabled = lineEnabled;
    }
    
    /**
     * Determines whether the placemark's optional line should be drawn and whether it intersects the view frustum.
     *
     * @param dc the current draw context.
     *
     * @return true if the line should be drawn and it intersects the view frustum, otherwise false.
     */
    protected boolean isDrawLine(DrawContext dc, OrderedSymbol opm)
    {
        if (!this.isLineEnabled() || dc.is2DGlobe() || this.getAltitudeMode() == WorldWind.CLAMP_TO_GROUND
            || opm.terrainPoint == null)
            return false;
    
        if (dc.isPickingMode())
            return dc.getPickFrustums().intersectsAny(opm.placePoint, opm.terrainPoint);
        else
            return dc.getView().getFrustumInModelCoordinates().intersectsSegment(opm.placePoint, opm.terrainPoint);
    }
    
    
    
    
    /**
     * Draws the placemark's line.
     *
     * @param dc             the current draw context.
     * @param pickCandidates the pick support object to use when adding this as a pick candidate.
     */
    protected void drawLine(DrawContext dc, PickSupport pickCandidates, OrderedSymbol opm)
    {
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
    
        if ((!dc.isDeepPickingEnabled()))
            gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL);
        gl.glDepthMask(true);
    
        try
        {
            dc.getView().pushReferenceCenter(dc, opm.placePoint); // draw relative to the place point
    
            this.setLineWidth(dc);
            this.setLineColor(dc, pickCandidates);
    
            gl.glBegin(GL2.GL_LINE_STRIP);
            gl.glVertex3d(Vec4.ZERO.x, Vec4.ZERO.y, Vec4.ZERO.z);
            gl.glVertex3d(opm.terrainPoint.x - opm.placePoint.x, opm.terrainPoint.y - opm.placePoint.y,
                opm.terrainPoint.z - opm.placePoint.z);
            gl.glEnd();
        }
        finally
        {
            dc.getView().popReferenceCenter(dc);
        }
    }
    
    
    /**
     * Sets the width of the placemark's line during rendering.
     *
     * @param dc the current draw context.
     */
    protected void setLineWidth(DrawContext dc)
    {
        Double lineWidth = this.lineWidth;
        if (lineWidth != null)
        {
            GL gl = dc.getGL();
    
            if (dc.isPickingMode())
            {
                gl.glLineWidth(lineWidth.floatValue() + linePickWidth);
            }
            else
                gl.glLineWidth(lineWidth.floatValue());
    
            if (!dc.isPickingMode())
            {
                gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_FASTEST);
                gl.glEnable(GL.GL_LINE_SMOOTH);
            }
        }
    }
    
    
    /**
     * Sets the color of the placemark's line during rendering.
     *
     * @param dc             the current draw context.
     * @param pickCandidates the pick support object to use when adding this as a pick candidate.
     */
    protected void setLineColor(DrawContext dc, PickSupport pickCandidates)
    {
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
    
        if (!dc.isPickingMode())
        {
            Color color = this.lineColor;
            gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(),
                (byte) color.getAlpha());
        }
        else
        {
            Color pickColor = dc.getUniquePickColor();
            Object delegateOwner = this.getDelegateOwner();
            pickCandidates.addPickableObject(pickColor.getRGB(), delegateOwner != null ? delegateOwner : this,
                this.getPosition());
            gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue());
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 将此调用添加到drawOrderedRenderable方法的开头:

    boolean drawLine = this.isDrawLine(dc, osym);
    if (drawLine)
        this.drawLine(dc, pickCandidates, osym);
    
    Run Code Online (Sandbox Code Playgroud)

我相信这很接近于PointPlacemark正在做什么以使线到地形出现,但这是我在运行TacticalSymbols示例时得到的结果:

在此输入图像描述

以下是我的(尝试)更改的整个AbsractTacticalSymbol文件:http://pastebin.com/aAC7zn0p (对于SO来说太大了)

TWT*_*TWT 5

好吧,这里的问题是框架内的正交投影和透视投影之间的混合.至关重要的是,如果我们看看PointPlaceMark,beginDrawing我们会看到:

GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.

int attrMask =
        GL2.GL_DEPTH_BUFFER_BIT // for depth test, depth mask and depth func
            ... bunch more bits being set ...

gl.glPushAttrib(attrMask);

if (!dc.isPickingMode())
{
    gl.glEnable(GL.GL_BLEND);
    OGLUtil.applyBlending(gl, false);
}
Run Code Online (Sandbox Code Playgroud)

而已.但是如果我们看一下AbstractTacticalSymbol,beginDrawing我们会看到更多的代码,特别是这两行:

this.BEogsh.pushProjectionIdentity(gl);
gl.glOrtho(0d, viewport.getWidth(), 0d, viewport.getHeight(), 0d, -1d);
Run Code Online (Sandbox Code Playgroud)

从视角切换的OpenGL投影到正交模式中,两个完全不同的投影技术不拌匀,除了几个显着的情况:他们中的一个UI渲染在3D场景,例如:绘制图标!视频显示正交和透视渲染之间的差异

我觉得别扭言传,但角度呈现给你的角度来看,和正交渲染没有,那么你得到的东西就像一个2D游戏,这对于UI效果很好,但不适合逼真的3D图像.

但PointPlaceMark也会渲染一个图标,那么该文件在两种投影模式之间切换的位置是什么?事实证明他们doDrawOrderedRenderable 通话这样做drawLine(第976行).

那么,为什么会出错呢?现在框架内部有很多魔法,所以我不能确切地知道会发生什么,但我已经大家都知道出了什么问题.这是错误的,因为透视投影允许您以完全不同的方式提供坐标到正投影(在框架中),在这种情况下可能提供(x,y,z)投影渲染渲染点(X,Y,Z) )世界空间,而正交渲染渲染在(x,y,z)屏幕空间(或剪辑空间,我不是专业人士).因此,当您现在在坐标(300000,300000,z)处从图标到地面绘制一条线时,它们当然会脱离屏幕而不可见,因为您没有300000x3000000像素的屏幕.也可能两种方法都允许在世界空间中提供坐标(虽然这似乎不太可能),在这种情况下,下图说明了问题.两个相机在下面的方框中指向相同的方向,但看到不同的东西.

透视与正交 特别注意透视渲染如何让您看到更多的框.

因此,由于渲染代码在透视投影在开出render()的方法,解决这个是延迟的正投影开始简单之后,我们已经绘制的线条,就像PointPlaceMark的代码.这正是我在这里做的(1962年到1968年),它只是在正交投影之外移动了几行代码,所以之前beginDrawing,你差不多完成了.

现在这个解决方案不是很优雅,因为代码的功能现在很大程度上取决于它的执行顺序,这通常非常容易出错.这部分是因为我做了简单的修复,但主要是因为框架遵循不推荐的OpenGL标准来切换视角(除此之外),所以我无法生成一个真正完美的解决方案,无论这样的解决方案是否在我的内部能力.

根据您的偏好,您可能希望使用继承来创建SymbolWithLine超类或接口,或使用组合来添加功能.或者你可以这样离开,如果你不需要这个功能与许多其他类.无论如何,我希望这是解决这个问题的足够信息.

根据您的要求,以下行演示了线宽和线条颜色的变化(第1965行):

this.lineColor = Color.CYAN;
this.lineWidth = 3;
this.drawLine(dc, this.pickSupport, osym);
Run Code Online (Sandbox Code Playgroud)

线条颜色和宽度

更新了AbstractTacticalSymbol的代码

我不确定这是否属于"规范性答案",但我很乐意用任何建议更新答案,或者更多地澄清我的解释.我认为答案的关键在于对正交投影与透视投影的理解,但我认为这不是真正回答这个问题的典型答案的地方.

  • 这个解释非常有帮助.再次感谢你. (3认同)
  • 谢谢你看看.这正是我所寻找的(截图) - 以及控制线宽和颜色的能力.如果你不介意,你会解释你需要做出的改变吗? (2认同)