2016-06-18 10 views
7

Точка Placemark отображаемый WorldWind имеет функцию черкнуть от Placemark вниз к местности, вызвав setLineEnabled, как на этом скриншоте:WorldWind линия от символа к Terrain

enter image description here

То, что я пытаюсь do добавляет такую ​​строку, которая также работает с визуализируемым тактическим символом. Моя первая мысль заключалась в том, чтобы просто позаимствовать логику, чтобы сделать это из рендеринга 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 toTextTacticalSymbol.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

Итак, проблема здесь является смешиванием между орфографической и перспективной проекцией в рамках. Кардинально, если мы посмотрим на beginDrawing PointPlaceMark мы видим:

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-сцене, например: рендеринг значков! video showing the difference between orthographic and perspective rendering

Мне неловко объяснять словами, но рендеринг перспективы дает вам перспективу, а орфографический рендеринг не делает, поэтому вы получаете что-то похожее на 2D-игру, которая хорошо работает для пользовательского интерфейса, но не для реалистичных 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