WorldWind对于图层的渲染过程

WorldWindGLAutoDrawable继承GLEventListener,按照jogl的模式调用init,display,reshape,dispose进行渲染。

先看display

public void display(GLAutoDrawable glAutoDrawable)
    {
        // Performing shutdown here in order to do so with a current GL context for GL resource disposal.
        if (this.shuttingDown)
        {
            try
            {
                this.doShutdown();
            }
            catch (Exception e)
            {
                Logging.logger().log(Level.SEVERE, Logging.getMessage(
                    "WorldWindowGLCanvas.ExceptionWhileShuttingDownWorldWindow"), e);
            }
            return;
        }

        try
        {
            SceneController sc = this.getSceneController();
            if (sc == null)
            {
                String msg = Logging.getMessage("WorldWindowGLCanvas.ScnCntrllerNullOnRepaint");
                Logging.logger().severe(msg);
                throw new IllegalStateException(msg);
            }

            // Determine if the view has changed since the last frame.
            this.checkForViewChange();

            Position positionAtStart = this.getCurrentPosition();
            PickedObject selectionAtStart = this.getCurrentSelection();
            PickedObjectList boxSelectionAtStart = this.getCurrentBoxSelection();

            try
            {
                this.callRenderingListeners(new RenderingEvent(this.drawable, RenderingEvent.BEFORE_RENDERING));
            }
            catch (Exception e)
            {
                Logging.logger().log(Level.SEVERE,
                    Logging.getMessage("WorldWindowGLAutoDrawable.ExceptionDuringGLEventListenerDisplay"), e);
            }

            int redrawDelay = this.doDisplay();
            if (redrawDelay > 0)
            {
                if (this.redrawTimer == null)
                {
                    this.redrawTimer = new Timer(redrawDelay, new ActionListener()
                    {
                        public void actionPerformed(ActionEvent actionEvent)
                        {
                            redraw();
                            redrawTimer = null;
                        }
                    });
                    redrawTimer.setRepeats(false);
                    redrawTimer.start();
                }
            }

            try
            {
                this.callRenderingListeners(new RenderingEvent(this.drawable, RenderingEvent.BEFORE_BUFFER_SWAP));
            }
            catch (Exception e)
            {
                Logging.logger().log(Level.SEVERE,
                    Logging.getMessage("WorldWindowGLAutoDrawable.ExceptionDuringGLEventListenerDisplay"), e);
            }

            this.doSwapBuffers(this.drawable);

            Double frameTime = sc.getFrameTime();
            if (frameTime != null)
                this.setValue(PerformanceStatistic.FRAME_TIME, frameTime);

            Double frameRate = sc.getFramesPerSecond();
            if (frameRate != null)
                this.setValue(PerformanceStatistic.FRAME_RATE, frameRate);

            // Dispatch the rendering exceptions accumulated by the SceneController during this frame to our
            // RenderingExceptionListeners.
            Iterable<Throwable> renderingExceptions = sc.getRenderingExceptions();
            if (renderingExceptions != null)
            {
                for (Throwable t : renderingExceptions)
                {
                    if (t != null)
                        this.callRenderingExceptionListeners(t);
                }
            }

            this.callRenderingListeners(new RenderingEvent(this.drawable, RenderingEvent.AFTER_BUFFER_SWAP));

            // Position and selection notification occurs only on triggering conditions, not same-state conditions:
            // start == null, end == null: nothing selected -- don't notify
            // start == null, end != null: something now selected -- notify
            // start != null, end == null: something was selected but no longer is -- notify
            // start != null, end != null, start != end: something new was selected -- notify
            // start != null, end != null, start == end: same thing is selected -- don't notify

            Position positionAtEnd = this.getCurrentPosition();
            if (positionAtStart != null || positionAtEnd != null)
            {
                // call the listener if both are not null or positions are the same
                if (positionAtStart != null && positionAtEnd != null)
                {
                    if (!positionAtStart.equals(positionAtEnd))
                        this.callPositionListeners(new PositionEvent(this.drawable, sc.getPickPoint(),
                            positionAtStart, positionAtEnd));
                }
                else
                {
                    this.callPositionListeners(new PositionEvent(this.drawable, sc.getPickPoint(),
                        positionAtStart, positionAtEnd));
                }
            }

            PickedObject selectionAtEnd = this.getCurrentSelection();
            if (selectionAtStart != null || selectionAtEnd != null)
            {
                this.callSelectListeners(new SelectEvent(this.drawable, SelectEvent.ROLLOVER,
                    sc.getPickPoint(), sc.getPickedObjectList()));
            }

            PickedObjectList boxSelectionAtEnd = this.getCurrentBoxSelection();
            if (boxSelectionAtStart != null || boxSelectionAtEnd != null)
            {
                this.callSelectListeners(new SelectEvent(this.drawable, SelectEvent.BOX_ROLLOVER,
                    sc.getPickRectangle(), sc.getObjectsInPickRectangle()));
            }
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, Logging.getMessage(
                "WorldWindowGLCanvas.ExceptionAttemptingRepaintWorldWindow"), e);
        }
    }

再找到关键的方法doDiaplay

protected int doDisplay()
    {
        return this.getSceneController().repaint();
    }

    /**
     * Performs the actual buffer swap. Provided so that subclasses may override the swap steps.
     *
     * @param drawable the window's associated drawable.
     */
    protected void doSwapBuffers(GLAutoDrawable drawable)
    {
        drawable.swapBuffers();
    }

    /**
     * See {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)}.
     *
     * @param glAutoDrawable the drawable
     */
    public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int w, int h)
    {
        // This is apparently necessary to enable the WWJ canvas to resize correctly with JSplitPane.
        ((Component) glAutoDrawable).setMinimumSize(new Dimension(0, 0));
    }

    @Override
    public void redraw()
    {
        if (this.drawable != null)
            ((AWTGLAutoDrawable) this.drawable).repaint();
    }

    public void redrawNow()
    {
        if (this.drawable != null)
            this.drawable.display();
    }

其中repaint是关键方法,repaint是借口SceneController的方法,在WorldWindGLAutoDrawable中调用的SceneController具体实现类为StereoOptionSceneController

    public WorldWindowImpl()
    {
        this.sceneController = (SceneController) WorldWind.createConfigurationComponent(
            AVKey.SCENE_CONTROLLER_CLASS_NAME);

        // Set up to initiate a repaint whenever a file is retrieved and added to the local file store.
        WorldWind.getDataFileStore().addPropertyChangeListener(this);
    }
   <Property name="gov.nasa.worldwind.avkey.SceneControllerClassName"
              value="gov.nasa.worldwind.StereoOptionSceneController"/>

然而,repaint是在父类AbstractScenceController中实现的,核心在于调用doRepaint

 public int repaint()
    {
        this.frameTime = System.currentTimeMillis();

        this.perFrameStatistics.clear();
        this.renderingExceptions.clear(); // Clear the rendering exceptions accumulated during the last frame.
        this.glRuntimeCaps.initialize(GLContext.getCurrent());
        this.initializeDrawContext(this.dc);
        this.doRepaint(this.dc);

        ++this.frame;
        long time = System.currentTimeMillis();
        this.frameTime = System.currentTimeMillis() - this.frameTime;
        if (time - this.timebase > 2000) // recalculate every two seconds
        {
            this.framesPerSecond = frame * 1000d / (time - timebase);
            this.timebase = time;
            this.frame = 0;
        }
        this.dc.setPerFrameStatistic(PerformanceStatistic.FRAME_TIME, "Frame Time (ms)", (int) this.frameTime);
        this.dc.setPerFrameStatistic(PerformanceStatistic.FRAME_RATE, "Frame Rate (fps)", (int) this.framesPerSecond);
        this.dc.setPerFrameStatistic(PerformanceStatistic.PICK_TIME, "Pick Time (ms)", (int) this.pickTime);

        Set<String> perfKeys = dc.getPerFrameStatisticsKeys();
        if (perfKeys == null)
            return dc.getRedrawRequested();

        if (perfKeys.contains(PerformanceStatistic.MEMORY_CACHE) || perfKeys.contains(PerformanceStatistic.ALL))
        {
            this.dc.setPerFrameStatistics(WorldWind.getMemoryCacheSet().getPerformanceStatistics());
        }

        if (perfKeys.contains(PerformanceStatistic.TEXTURE_CACHE) || perfKeys.contains(PerformanceStatistic.ALL))
        {
            if (dc.getTextureCache() != null)
                this.dc.setPerFrameStatistic(PerformanceStatistic.TEXTURE_CACHE,
                    "Texture Cache size (Kb)", this.dc.getTextureCache().getUsedCapacity() / 1000);
        }

        if (perfKeys.contains(PerformanceStatistic.JVM_HEAP) || perfKeys.contains(PerformanceStatistic.ALL))
        {
            long totalMemory = Runtime.getRuntime().totalMemory();
            this.dc.setPerFrameStatistic(PerformanceStatistic.JVM_HEAP,
                "JVM total memory (Kb)", totalMemory / 1000);

            this.dc.setPerFrameStatistic(PerformanceStatistic.JVM_HEAP_USED,
                "JVM used memory (Kb)", (totalMemory - Runtime.getRuntime().freeMemory()) / 1000);
        }

        return dc.getRedrawRequested();
    }

doRepaint是在StereoOptionSceneController的父类BasicSceneController中实现的

public class BasicSceneController extends AbstractSceneController
{
    SectorGeometryList sglC, sglL, sglR;
    Sector visibleSectorC, visibleSectorL, visibleSectorR;

    public void doRepaint(DrawContext dc)
    {
        this.initializeFrame(dc);
        try
        {
            if (dc.getGlobe() instanceof Globe2D && ((Globe2D)dc.getGlobe()).isContinuous())
                this.do2DContiguousRepaint(dc);
            else
                this.doNormalRepaint(dc);
        }
        finally
        {
            this.finalizeFrame(dc);
        }
    }

    protected void doNormalRepaint(DrawContext dc)
    {
        this.applyView(dc);
        this.createPickFrustum(dc);
        this.createTerrain(dc);
        this.preRender(dc);
        this.clearFrame(dc);
        this.pick(dc);
        this.clearFrame(dc);
        this.draw(dc);
    }

绘制图层的方法就在draw这个方法里面了,它在AbstractSceneController中实现

  protected void draw(DrawContext dc)
    {
        try
        {
            // Draw the layers.
            if (dc.getLayers() != null)
            {
                for (Layer layer : dc.getLayers())
                {
                    try
                    {
                        if (layer != null)
                        {
                            dc.setCurrentLayer(layer);
                            layer.render(dc);
                        }
                    }
                    catch (Exception e)
                    {
                        String message = Logging.getMessage("SceneController.ExceptionWhileRenderingLayer",
                            (layer != null ? layer.getClass().getName() : Logging.getMessage("term.unknown")));
                        Logging.logger().log(Level.SEVERE, message, e);
                        // Don't abort; continue on to the next layer.
                    }
                }

                dc.setCurrentLayer(null);
            }

            // Draw the deferred/ordered surface renderables.
            this.drawOrderedSurfaceRenderables(dc);

            if (this.isDeferOrderedRendering())
                return;

            if (this.screenCreditController != null)
                this.screenCreditController.render(dc);

            // Draw the deferred/ordered renderables.
            dc.setOrderedRenderingMode(true);
//            dc.applyGroupingFilters();
            dc.applyClutterFilter();
            while (dc.peekOrderedRenderables() != null)
            {
                try
                {
                    dc.pollOrderedRenderables().render(dc);
                }
                catch (Exception e)
                {
                    Logging.logger().log(Level.WARNING,
                        Logging.getMessage("BasicSceneController.ExceptionDuringRendering"), e);
                }
            }
            dc.setOrderedRenderingMode(false);

            // Draw the diagnostic displays.
            if (dc.getSurfaceGeometry() != null && dc.getModel() != null && (dc.getModel().isShowWireframeExterior() ||
                dc.getModel().isShowWireframeInterior() || dc.getModel().isShowTessellationBoundingVolumes()))
            {
                Model model = dc.getModel();

                float[] previousColor = new float[4];
                GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
                gl.glGetFloatv(GL2.GL_CURRENT_COLOR, previousColor, 0);

                for (SectorGeometry sg : dc.getSurfaceGeometry())
                {
                    if (model.isShowWireframeInterior() || model.isShowWireframeExterior())
                        sg.renderWireframe(dc, model.isShowWireframeInterior(), model.isShowWireframeExterior());

                    if (model.isShowTessellationBoundingVolumes())
                    {
                        gl.glColor3d(1, 0, 0);
                        sg.renderBoundingVolume(dc);
                    }
                }

                gl.glColor4fv(previousColor, 0);
            }
        }
        catch (Throwable e)
        {
            Logging.logger().log(Level.SEVERE, Logging.getMessage("BasicSceneController.ExceptionDuringRendering"), e);
        }
    }

layer.render()就是在进行绘制渲染的过程,因为所有的图层类都继承了AbstractLayer,render()在AbstractLayer就做了实现

public void render(DrawContext dc)
    {
        if (!this.enabled)
            return; // Don't check for arg errors if we're disabled

        if (null == dc)
        {
            String message = Logging.getMessage("nullValue.DrawContextIsNull");
            Logging.logger().severe(message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getGlobe())
        {
            String message = Logging.getMessage("layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext");
            Logging.logger().severe(message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getView())
        {
            String message = Logging.getMessage("layers.AbstractLayer.NoViewSpecifiedInDrawingContext");
            Logging.logger().severe(message);
            throw new IllegalStateException(message);
        }

        if (!this.isLayerActive(dc))
            return;

        if (!this.isLayerInView(dc))
            return;

        this.doRender(dc);
    }

具体不同的图层渲染的区别主要在于对Render()的重载实现不同!

所以,自定RenderableLayer渲染图层时,就是重载render()方法,利用opengl命令进行绘制即可。

参考示例:https://github.com/upcdxlq/WorldWindCampus/blob/master/RenderableLayer/DrawCubeLayer.java



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值