• [WorldWind学习]11.TerrainViewer插件和双线程


     TerrainViewer的入口Main()函数:

    View Code
     1  static void Main(string[] args)
     2  {
     3             using (Viewer viewer = new Viewer())
     4               {
     5                  viewer.ProcessArgs(args);        // Read command line args
     6                  viewer.InitializeDevice();        // Direct 3D device setup
     7                 viewer.InitializeKeyboard();    // Keyboard setup
     8                  viewer.InitializeMapList();        // Create Map menu
     9                  viewer.InitializeVerticalFactorMenu(); // Create vertical factor menu
    10                 viewer.InitializeTexturesMenu();// Create Textures menu
    11                  viewer.InitializeSidesMenu();    // Create Sides menu
    12                  viewer.InitializeSkyMenu();        // Create Sky menu
    13                  viewer.MapMenuSelectMap(0);        // Load first map
    14                  viewer.Show();
    15                  Application.Run(viewer);        // Run
    16              }
    17 }

    初始化设备:InitializeDevice()

    鼠标交互的基本原理:

    根据地图位置(参数dist)设置相机,之后相机位置保持不变。滚轮操作和键盘操作更改dist,修改相机位置。

    如下为处理键盘操作的部分代码。

     1 // Change Distance
     2 if (keys[Key.NumPadPlus] && !shift && !ctrl)    
     3       {
     4     dist -= dist * 0.02f;
     5     redraw = true;
     6       }
     7 if (keys[Key.NumPadMinus] && !shift && !ctrl)
     8       {
     9     dist += dist * 0.02f;
    10     redraw = true;
    11       }

    查看重载的OnPaint函数,在OnPaint中调用了CameraViewSetup()方法。

    1 // Camera setup
    2   private void CameraViewSetup()
    3   {
    4       float aspectRatio =  (float)device.Viewport.Width / device.Viewport.Height;
    5       device.Transform.Projection = Matrix.PerspectiveFovLH(fov, aspectRatio, mapWidth == 0 ? 15f : (float)(mapWidth / 10), mapWidth == 0 ? 5000f : (float)(mapWidth * 3));
    6       device.Transform.View = Matrix.LookAtLH(new Vector3(0,0,dist), new Vector3(0,0,0), new Vector3(1,0,0));
    7   }

    鼠标左键点击拖动,移动地图,更改了参数dx和dy。

    鼠标右键点击拖动,旋转地图,更改了参数angle和angle2

     1 protected override void OnMouseMove(MouseEventArgs e)
     2         {
     3             if(mouseDownStartPosition == Point.Empty)
     4                 return;
     5             // Mouse drag
     6             bool isMouseLeftButtonDown = ((int)e.Button & (int)MouseButtons.Left) != 0;
     7             bool isMouseRightButtonDown = ((int)e.Button & (int)MouseButtons.Right) != 0;
     8             double dxMouse = this.mouseDownStartPosition.X - e.X;
     9             double dyMouse = this.mouseDownStartPosition.Y - e.Y;
    10             if(isMouseLeftButtonDown && !isMouseRightButtonDown) 
    11             {
    12                 // Move map
    13                 double moveFactor = dist * 0.001f;
    14                 dx = mouseDownStartDx - (float)(Math.Sin(angle) * dxMouse * moveFactor) + (float)(Math.Cos(angle) * dyMouse * moveFactor);
    15                 dy = mouseDownStartDy - (float)(Math.Cos(angle) * dxMouse * moveFactor) - (float)(Math.Sin(angle) * dyMouse * moveFactor);
    16                 redraw = true;
    17             }
    18             if(isMouseRightButtonDown && !isMouseLeftButtonDown) 
    19             {
    20                 // Rotate map
    21                 double spinFactor = 0.003f;
    22                 angle = mouseDownStartAngle + (float)(dxMouse * spinFactor * rightClickFactor);
    23                 angle2 = mouseDownStartAngle2 + (float)(dyMouse * spinFactor * rightClickFactor);
    24                 redraw = true;
    25             }
    26             if(isMouseRightButtonDown && isMouseLeftButtonDown) 
    27             {
    28                 // Rotate light
    29                 double spinFactor = 0.003f;
    30                 lightHeading = mouseDownLightAngle + (float)(dxMouse * spinFactor);
    31                 lightElevation = mouseDownLightAngle2 + (float)(dyMouse * spinFactor);
    32                 redraw = true;
    33             }
    34         }

    在OnPaint函数中调用了如下代码。

    1 // Translation and Orientation angle / angle2
    2 if(angle2 < 0) angle2 = 0;
    3 if(angle2 > Math.PI / 2) angle2 = (float)(Math.PI / 2);
    4 device.Transform.World = Matrix.Translation(dx, dy, dz);
    5 device.Transform.World *= Matrix.RotationZ(angle);
    6 device.Transform.World *= Matrix.RotationY(angle2);

    改变世界坐标矩阵,实现平移和旋转。

    这个插件和WW鼠标操作的机制很像,感觉游戏或者三维就是不断地修改参数(变量为某一限定域所有),然后重新渲染场景。

    不过游戏是以第一人称观察(第三人称相机)(相机在动),物体位置不动,所以有身临其境的感觉;而这个插件的基本模式则是改变模型,是物体在动(相机不动)。还是有些区别的。

    当然这个插件和ArcScene也可以改变相机,不过不是基本的。

    此插件通过不断触发OnPaint事件来更改场景,WW通过Idle()来更改场景?

    WW是双线程的?这个再理解一下。

    MainApplication方法调用worldWindow.Render();方法,即主线程负责渲染。

    WorldWindow的Render()方法启动了一个名为WorldWindow.WorkerThreadFunc线程。

      1 public void Render()
      2         {
      3             long startTicks = 0;
      4             PerformanceTimer.QueryPerformanceCounter(ref startTicks);
      5 
      6             try
      7             {
      8                 this.drawArgs.BeginRender();
      9 
     10                 // Render the sky according to view - example, close to earth, render sky blue, render space as black
     11                 System.Drawing.Color backgroundColor = System.Drawing.Color.Black;
     12 
     13                 /*if(drawArgs.WorldCamera != null && 
     14                     drawArgs.WorldCamera.Altitude < 1000000f &&
     15                     m_World != null &&
     16                     m_World.Name.IndexOf("Earth") >= 0)
     17                 {
     18                     float percent = 1 - (float)(drawArgs.WorldCamera.Altitude / 1000000);
     19                     if(percent > 1.0f)
     20                         percent = 1.0f;
     21                     else if(percent < 0.0f)
     22                         percent = 0.0f;
     23 
     24                     backgroundColor = System.Drawing.Color.FromArgb(
     25                         (int)(World.Settings.SkyColor.R*percent),
     26                         (int)(World.Settings.SkyColor.G*percent),
     27                         (int)(World.Settings.SkyColor.B*percent));
     28                 }*/
     29 
     30                 m_Device3d.Clear(ClearFlags.Target | ClearFlags.ZBuffer, backgroundColor, 1.0f, 0);
     31 
     32                 if (m_World == null)
     33                 {
     34                     m_Device3d.BeginScene();
     35                     m_Device3d.EndScene();
     36                     m_Device3d.Present();
     37                     Thread.Sleep(25);
     38                     return;
     39                 }
     40 
     41                 if (m_WorkerThread == null)
     42                 {
     43                     m_WorkerThreadRunning = true;
     44                     m_WorkerThread = new Thread(new ThreadStart(WorkerThreadFunc));
     45                     m_WorkerThread.Name = "WorldWindow.WorkerThreadFunc";
     46                     m_WorkerThread.IsBackground = true;
     47                     if (World.Settings.UseBelowNormalPriorityUpdateThread)
     48                     {
     49                         m_WorkerThread.Priority = ThreadPriority.BelowNormal;
     50                     }
     51                     else
     52                     {
     53                         m_WorkerThread.Priority = ThreadPriority.Normal;
     54                     }
     55                     // BelowNormal makes rendering smooth, but on slower machines updates become slow or stops
     56                     // TODO: Implement dynamic FPS limiter (or different solution)
     57                     m_WorkerThread.Start();//启动后台线程
     58                 }
     59 
     60                 this.drawArgs.WorldCamera.Update(m_Device3d);//更新相机
     61 
     62                 m_Device3d.BeginScene();
     63 
     64                 // Set fill mode
     65                 if (renderWireFrame)
     66                     m_Device3d.RenderState.FillMode = FillMode.WireFrame;
     67                 else
     68                     m_Device3d.RenderState.FillMode = FillMode.Solid;
     69 
     70                 drawArgs.RenderWireFrame = renderWireFrame;
     71 
     72                 // Render the current planet
     73                 m_World.Render(this.drawArgs);//渲染地球
     74 
     75                 if (World.Settings.ShowCrosshairs)
     76                     this.DrawCrossHairs();
     77 
     78                 frameCounter++;
     79                 if (frameCounter == 30)
     80                 {
     81                     fps = frameCounter / (float)(DrawArgs.CurrentFrameStartTicks - lastFpsUpdateTime) * PerformanceTimer.TicksPerSecond;
     82                     frameCounter = 0;
     83                     lastFpsUpdateTime = DrawArgs.CurrentFrameStartTicks;
     84                 }
     85 
     86                 m_RootWidget.Render(drawArgs);//渲染部件
     87                 m_NewRootWidget.Render(drawArgs);
     88 
     89                 if (saveScreenShotFilePath != null)
     90                     SaveScreenShot();
     91 
     92                 drawArgs.device.RenderState.ZBufferEnable = false;
     93 
     94                 // 3D rendering complete, switch to 2D for UI rendering
     95 
     96                 // Restore normal fill mode
     97                 if (renderWireFrame)
     98                     m_Device3d.RenderState.FillMode = FillMode.Solid;
     99 
    100                 // Disable fog for UI
    101                 m_Device3d.RenderState.FogEnable = false;
    102 
    103                 /*
    104                                 if(World.Settings.ShowDownloadIndicator)
    105                                 {
    106                                     if(m_downloadIndicator == null)
    107                                         m_downloadIndicator = new DownloadIndicator();
    108                                     m_downloadIndicator.Render(drawArgs);
    109                                 }
    110                 */
    111                 RenderPositionInfo();
    112 
    113                 _menuBar.Render(drawArgs);
    114                 m_FpsGraph.Render(drawArgs);
    115                 
    116                 if (m_World.OnScreenMessages != null)
    117                 {
    118                     try
    119                     {
    120                         foreach (OnScreenMessage dm in m_World.OnScreenMessages)
    121                         {
    122                             int xPos = (int)Math.Round(dm.X * this.Width);
    123                             int yPos = (int)Math.Round(dm.Y * this.Height);
    124                             Rectangle posRect =
    125                                 new Rectangle(xPos, yPos, this.Width, this.Height);
    126                             this.drawArgs.defaultDrawingFont.DrawText(null,
    127                                 dm.Message, posRect,
    128                                 DrawTextFormat.NoClip | DrawTextFormat.WordBreak,
    129                                 Color.White);
    130                         }
    131                     }
    132                     catch (Exception)
    133                     {
    134                         // Don't let a script error cancel the frame.
    135                     }
    136                 }
    137 
    138                 m_Device3d.EndScene();
    139             }
    140             catch (Exception ex)
    141             {
    142                 Log.Write(ex);
    143             }
    144             finally
    145             {
    146                 
    147                 if(World.Settings.ShowFpsGraph)
    148                 {
    149                     long endTicks = 0;
    150                     PerformanceTimer.QueryPerformanceCounter(ref endTicks);
    151                     float elapsedMilliSeconds = 1000.0f / (1000.0f*(float)(endTicks - startTicks)/PerformanceTimer.TicksPerSecond);
    152                     m_FrameTimes.Add(elapsedMilliSeconds);
    153                 }
    154                 this.drawArgs.EndRender();
    155             }
    156             drawArgs.UpdateMouseCursor(this);
    157         }

    启动后台线程后调用异步方法WorkerThreadFunc()

     1 /// <summary>
     2         /// Background worker thread loop (updates UI)
     3         /// </summary>
     4         private void WorkerThreadFunc()
     5         {
     6             const int refreshIntervalMs = 150; // Max 6 updates per seconds
     7             while(m_WorkerThreadRunning)
     8             {
     9                 try
    10                 {
    11                     if(World.Settings.UseBelowNormalPriorityUpdateThread && m_WorkerThread.Priority == System.Threading.ThreadPriority.Normal)
    12                     {
    13                         m_WorkerThread.Priority = System.Threading.ThreadPriority.BelowNormal;
    14                     }
    15                     else if(!World.Settings.UseBelowNormalPriorityUpdateThread && m_WorkerThread.Priority == System.Threading.ThreadPriority.BelowNormal)
    16                     {
    17                         m_WorkerThread.Priority = System.Threading.ThreadPriority.Normal;
    18                     }
    19 
    20                     long startTicks = 0;
    21                     PerformanceTimer.QueryPerformanceCounter(ref startTicks);
    22 
    23                     m_World.Update(this.drawArgs);//更新世界对象
    24 
    25                     long endTicks = 0;
    26                     PerformanceTimer.QueryPerformanceCounter(ref endTicks);
    27                     float elapsedMilliSeconds = 1000*(float)(endTicks - startTicks)/PerformanceTimer.TicksPerSecond;
    28                     float remaining = refreshIntervalMs - elapsedMilliSeconds;
    29                     if(remaining > 0)
    30                         Thread.Sleep((int)remaining);
    31                 }
    32                 catch(Exception caught)
    33                 {
    34                     Log.Write(caught);
    35                 }
    36             }
    37         }

    World的Update方法:

    Update
     1  public override void Update(DrawArgs drawArgs)
     2         {
     3             if (!this.isInitialized)
     4             {
     5                 this.Initialize(drawArgs);
     6             }
     7 
     8             if (this.RenderableObjects != null)
     9             {
    10                 this.RenderableObjects.Update(drawArgs);
    11             }
    12             if (this.m_WorldSurfaceRenderer != null)
    13             {
    14                 this.m_WorldSurfaceRenderer.Update(drawArgs);
    15             }
    16 
    17             if (this.m_projectedVectorRenderer != null)
    18             {
    19                 this.m_projectedVectorRenderer.Update(drawArgs);
    20             }
    21 
    22             if (this.TerrainAccessor != null)
    23             {
    24                 if (drawArgs.WorldCamera.Altitude < 300000)
    25                 {
    26                     if (System.DateTime.Now - this.lastElevationUpdate > TimeSpan.FromMilliseconds(500))
    27                     {
    28                         drawArgs.WorldCamera.TerrainElevation = (short)this.TerrainAccessor.GetElevationAt(drawArgs.WorldCamera.Latitude.Degrees, drawArgs.WorldCamera.Longitude.Degrees, 100.0 / drawArgs.WorldCamera.ViewRange.Degrees);
    29                         this.lastElevationUpdate = System.DateTime.Now;
    30                     }
    31                 }
    32                 else
    33                     drawArgs.WorldCamera.TerrainElevation = 0;
    34             }
    35             else
    36             {
    37                 drawArgs.WorldCamera.TerrainElevation = 0;
    38             }
    39 
    40             if (World.Settings.EnableAtmosphericScattering && m_outerSphere != null)
    41                 m_outerSphere.Update(drawArgs);
    42         }
    文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。 欢迎大家留言交流,转载请注明出处。
  • 相关阅读:
    探讨e.target与e.currentTarget
    JavaScript事件模型
    博客
    angular创建自定义指令的四种方式
    jqueryMobile模块整理—图标(icons)
    jqueryMobile模块整理—按钮(buttons)
    Visio 2010,如何打开多个窗口
    Ajax.ActionLink浏览器中代码解析问题
    响应式布局
    jquery的each
  • 原文地址:https://www.cnblogs.com/yhlx125/p/3015197.html
Copyright © 2020-2023  润新知