WorldWind的渲染引擎

WorldWind中显示图像的是一个继承自Control的WorldWindow控件,代码:html

public class WorldWindow : Control, IGlobeapp

 

初始化代码:less

public WorldWindow()

{ide

    this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);oop

    // The m_Device3d can't be created unless the control is at least 1 x 1 pixels in sizethis

    this.Size = new Size(1,1); spa

    try线程

     {3d

         if(!IsInDesignMode()) this.InitializeGraphics();orm

         ...... 

     }

    catch (InvalidCallException caught)

     {

         throw new InvalidCallException(

             "Unable to locate a compatible graphics adapter.", caught );

     }

    catch (NotAvailableException caught)

     {

         throw new NotAvailableException(

             "Unable to locate a compatible graphics adapter.", caught );

     }

}

初始化代码中主要的是:

(1) 设置窗体的样式:

   this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);

(2) 初始化DirectX,具体的关于DirectX的初始化参见《WorldWind-Direct3D的初始化》

    if(!IsInDesignMode()) this.InitializeGraphics();

 

WorldWindow控件的 OnPaint() 方法:

protected override void OnPaint(PaintEventArgs e)

{

    try

     {

         if(m_Device3d==null)

         {

              e.Graphics.Clear(SystemColors.Control);

             return;

         } 

         Render();

         m_Device3d.Present();

     }

    catch(DeviceLostException)

     {

         try

         {

              AttemptRecovery();

              Render(); 

              m_Device3d.Present();

         }

         catch(DirectXException){ }

     }

}

从代码中能够看出,主要的渲染操做都存在于 Render() 方法中。

 

Render()方法:

public void Render()

   try

    {

        this.drawArgs.BeginRender();

 

        System.Drawing.Color backgroundColor = System.Drawing.Color.Black; 

        m_Device3d.Clear(ClearFlags.Target | ClearFlags.ZBuffer, backgroundColor, 1.0f, 0); 

        if (m_World == null)

        {

            m_Device3d.BeginScene();

            m_Device3d.EndScene();

            m_Device3d.Present();

           Thread.Sleep(25);

           return;

        } 

        // 用于对图像进行逻辑处理的线程

        if (m_WorkerThread == null)

        {

            m_WorkerThreadRunning = true;

            m_WorkerThread = new Thread(new ThreadStart(WorkerThreadFunc));

            m_WorkerThread.Name = "WorldWindow.WorkerThreadFunc";

            m_WorkerThread.IsBackground = true;

           if (World.Settings.UseBelowNormalPriorityUpdateThread)

            {

                m_WorkerThread.Priority = ThreadPriority.BelowNormal;

            }

           else

            {

                m_WorkerThread.Priority = ThreadPriority.Normal;

            }

            m_WorkerThread.Start();

        } 

        m_Device3d.BeginScene();

 

        // 渲染当前星球,这是主要的渲染过程

        m_World.Render(this.drawArgs); 

        // 渲染位置信息

        RenderPositionInfo(); 

        // 渲染菜单栏

        _menuBar.Render(drawArgs);

        m_FpsGraph.Render(drawArgs);   

        // 渲染屏幕消息    

        if (m_World.OnScreenMessages != null)

        {

           try

            {

               foreach (OnScreenMessage dm in m_World.OnScreenMessages)

                {

                   int xPos = (int)Math.Round(dm.X * this.Width);

                   int yPos = (int)Math.Round(dm.Y * this.Height);

                   Rectangle posRect = new Rectangle(xPos, yPos, this.Width, this.Height);

                   this.drawArgs.defaultDrawingFont.DrawText(null,

                        dm.Message, posRect,

                       DrawTextFormat.NoClip | DrawTextFormat.WordBreak,

                        Color.White);

                }

            }

           catch (Exception){}

        } 

        m_Device3d.EndScene();

    }

   catch (Exception ex){ Log.Write(ex);}

    finallythis.drawArgs.EndRender();}

    drawArgs.UpdateMouseCursor(this);

}

 

图像逻辑处理线程方法:

private void WorkerThreadFunc()

{

    const int refreshIntervalMs = 150; // 更新频率:Max 6 updates per second

    while(m_WorkerThreadRunning)

     {

         try

         { 

             long startTicks = 0;

             PerformanceTimer.QueryPerformanceCounter(ref startTicks);

 

              m_World.Update(this.drawArgs);

 

             long endTicks = 0;

             PerformanceTimer.QueryPerformanceCounter(ref endTicks);

 

             float elapsedMilliSeconds = 1000*(float)(endTicks - startTicks)/PerformanceTimer.TicksPerSecond;

             float remaining = refreshIntervalMs - elapsedMilliSeconds;

             if(remaining > 0) Thread.Sleep((int)remaining);

         }

         catch(Exception caught){ Log.Write(caught);}

     }

}

 

WorldWind渲染循环:

/// <summary>

/// The world render loop. Borrowed from FlightGear and Tom Miller's blog

/// </summary>

public void OnApplicationIdle(object sender, EventArgs e)

{

    // Sleep will always overshoot by a bit so under-sleep by 2ms in the hopes of never oversleeping.

    const float SleepOverHeadSeconds = 2e-3f;

    // Overhead associated with displaying the frame

    const float PresentOverheadSeconds = 0;//3e-4f;

    try

     {

         if (Parent.Focused && !Focused) Focus(); 

         while (IsAppStillIdle)

         { 

              Render(); 

             if (World.Settings.ThrottleFpsHz > 0)

              {

                  // optionally throttle the frame rate (to get consistent frame rates or reduce CPU usage.

                  float frameSeconds = 1.0f / World.Settings.ThrottleFpsHz - PresentOverheadSeconds;

                  // Sleep for remaining period of time until next render

                  float sleepSeconds = frameSeconds - SleepOverHeadSeconds - DrawArgs.SecondsSinceLastFrame;

                  if(sleepSeconds > 0)

                   {

                      // Don't sleep too long. We don't know the accuracy of Thread.Sleep

                      Thread.Sleep((int) (1000 * sleepSeconds));

                      // Burn off what little time still remains at 100% CPU load

                      while(DrawArgs.SecondsSinceLastFrame < frameSeconds)

                       {

                           // Patience

                       }

                   }

              }

              drawArgs.Present();

         }

     }

    catch(DeviceLostException){ AttemptRecovery();}

    catch(Exception caught){ Log.Write(caught);}

}

 

IsAppStillIdle属性 

/// <summary>

/// Determine whether any window messages is queued.

/// </summary>

private static bool IsAppStillIdle

{

    get

     {

         NativeMethods.Message msg;

         return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);

     }

 

 

WorldWind的渲染循环是在 Application Idle 时进行的:

Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

MainApplication app = new MainApplication();

Application.Idle += new EventHandler(app.WorldWindow.OnApplicationIdle);

Application.Run(app);