2016-06-18 79 views
7

世界風的點地標渲染具有如下特徵:通過調用setLineEnabled在這個截圖下降從標線到地形:世界風號線在地形

enter image description here

什麼我想做的是添加一個像這樣的線,也可以與戰術符號一起使用。我的第一個想法是借用邏輯來從PointPlacemark可渲染的邏輯中執行此操作,並將其添加到AbstractTacticalSymbol可渲染的。我已經嘗試過,而且迄今爲止我一直沒有成功。

以下是我迄今所做的:

  1. 將此添加到OrderedSymbol類:

    public Vec4 terrainPoint; 
    
  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); 
    
    } 
    
  3. 添加了此邏輯(取自PointPlacemark.java並更新爲complian ce到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()); 
        } 
    } 
    
  4. 添加了這個調用drawOrderedRenderable方法的開頭:

    boolean drawLine = this.isDrawLine(dc, osym); 
    if (drawLine) 
        this.drawLine(dc, pickCandidates, osym); 
    

我相信這基本上反映了什麼PointPlacemark做去地形出現行了,但是這是什麼我在運行TacticalSymbols示例時遇到了我的更改:

enter image description here

這裏是我的(未遂)改變整個AbsractTacticalSymbol文件:http://pastebin.com/aAC7zn0p(其太大SO)

回答

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

就是這樣。但是,如果我們看一下AbstractTacticalSymbol的beginDrawing我們看到了更大量的代碼,特別是這兩行:

this.BEogsh.pushProjectionIdentity(gl); 
gl.glOrtho(0d, viewport.getWidth(), 0d, viewport.getHeight(), 0d, -1d); 

從視角切換的OpenGL投影到正交模式中,兩個完全不同的投影技術,不要混很除了幾個值得注意的情況外:其中一個UI渲染在3D場景中,例如:渲染圖標! 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超類或接口,或者使用合成來添加功能。或者你可以像這樣離開它,如果你不需要許多其他類的功能。無論如何,我希望這是足夠的信息來解決這個問題。

按照您的要求,下面的線表明了線寬和線顏色的變化(1965線):

this.lineColor = Color.CYAN; 
this.lineWidth = 3; 
this.drawLine(dc, this.pickSupport, osym); 

Line color and width

Updated code for AbstractTacticalSymbol

我不知道,如果這素質要求作爲一個「規範的答案」,但我很樂意用任何建議更新答案,或者更多地澄清我的解釋。我認爲答案的關鍵在於理解正投與透視投影,但我覺得這並不是對這個問題進行規範回答的地方。

+2

謝謝你的採訪。這正是我所需要的(屏幕截圖) - 以及控制線條寬度和顏色的功能。如果你不介意,你解釋你需要做的改變? – systemoutprintln

+0

我已經用解釋更新了我的答案。 – TWT

+3

這個解釋非常有幫助。再次感謝你。 – systemoutprintln