gpt4 book ai didi

java - 从符号到地形的 Worldwind 线

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:27:10 26 4
gpt4 key购买 nike

Worldwind 的 Point PlaceMark 可渲染具有通过调用 setLineEnabled 从地标向下到地形放置一条线的功能。如此屏幕截图所示:

enter image description here

我想要做的是添加这样的一行,它也适用于可渲染的战术符号。我的第一个想法是从 PointPlacemark 借用逻辑来做到这一点。可渲染并将其添加到 AbstractTacticalSymbol可渲染。我已经尝试过了,到目前为止我一直没有成功。

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

  • 将此添加到 OrderedSymbol 类:
    public Vec4 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);

    }
  • 添加了此逻辑(取自 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());
    }
    }
  • 将此调用添加到 drawOrderedRenderable 方法的开头:
    boolean drawLine = this.isDrawLine(dc, osym);
    if (drawLine)
    this.drawLine(dc, pickCandidates, osym);

  • 我相信这密切反射(reflect)了 PointPlacemark 正在做的使线到地形出现的工作,但这就是我运行 TacticalSymbols 时得到的结果。我的更改示例:

    enter image description here

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

    最佳答案

    好的,所以这里的问题是框架内正投影和透视投影的混合。至关重要的是,如果我们查看 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);
    }

    而已。但是如果我们看一下 AbstractTacticalSymbol 的 beginDrawing我们看到了更多的代码,特别是这两行:
    this.BEogsh.pushProjectionIdentity(gl);
    gl.glOrtho(0d, viewport.getWidth(), 0d, viewport.getHeight(), 0d, -1d);

    这将 OpenGL 投影从透视模式切换到正交模式,这两种截然不同的投影技术不能很好地混合,除了一些值得注意的情况:其中一种在 3D 场景上渲染 UI,例如:渲染图标! video showing the difference between orthographic and perspective rendering

    我觉得用文字解释很尴尬,但是透视渲染给了你透视,而正交渲染没有,所以你得到的东西很像 2D 游戏,它适用于 UI,但不适用于逼真的 3D 图像。

    但是PointPlaceMark也会渲染一个图标,那么那个文件在两种投影模式之间切换在哪里呢?原来他们在 doDrawOrderedRenderable 中这样做了调用后 drawLine (第 976 行)。

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

    Perspective vs Orthographic
    请特别注意透视渲染如何让您看到更多的框。

    所以,因为渲染代码是从 render() 中的透视投影开始的。方法,解决这个问题就像在我们画线后延迟正投影开始一样简单,就像在 PointPlaceMark 的代码中一样。
    这正是我所做的 here (第 1962 行到 1968 行),它只是将几行代码移到正投影之外,所以在 beginDrawing 之前,你快完成了。

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

    根据您的偏好,您可能希望使用继承来创建 SymbolWithLine父类(super class)或接口(interface),或使用组合来添加功能。或者,如果您不需要在许多其他类中使用此功能,您可以保持这种状态。无论如何,我希望这是足够的信息来解决这个问题。

    根据您的要求,以下几行演示了线宽和线颜色的变化(第 1965 行):
    this.lineColor = Color.CYAN;
    this.lineWidth = 3;
    this.drawLine(dc, this.pickSupport, osym);

    Line color and width

    Updated code for AbstractTacticalSymbol

    我不确定这是否符合“规范答案”,但我很乐意用任何建议更新答案,或者进一步澄清我的解释。我认为答案的关键在于对正交投影与透视投影的理解,但我觉得这并不是对这个问题给出规范答案的地方。

    关于java - 从符号到地形的 Worldwind 线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37900553/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com