WorldWind学习系列六:渲染过程解析篇

it2024-11-07  7

  今天主要是分析学习了Render问题,搞明白了WorldWind中整个Render绘制处理过程。其中关键类是:RenderableObject.cs ,RenderobjectList.cs.  WW中所有需要绘制的对象都RenderableObject,WW的各功能的执行显示都是不断地调用相应的Render方法。        1.RenderableObject整个绘制对象继承图

  WW绘制都是通过RenderableObject类,将所有的要绘制对象都看做是RenderableObject,从而统一了整个系统WW的绘制对象的绘制过程。   2.RenderableObjectList也继承自RenderableObject,先看看它的继承图  

 

  摘录内容:

  “实际的点线,平面纹理等渲染对象都是从RenderableObject继承,最终的渲染实现也是在从它继续下来的类中,RenderableObjectList的成员m_children(protected ArrayList m_children = new ArrayList();)包含WW中所有的渲染对象,绘制过程中按如下的优先级进行:

public enum RenderPriority

     {

         SurfaceImages = 0,

         TerrainMappedImages = 100,

         AtmosphericImages = 200,

         LinePaths = 300,

         Icons = 400,

         Placenames = 500,

         Custom = 600

     }

  这里对WW调试过程中的m_children的成员做个截图,需要注意的是m_children的成员大部分还是RenderableObjectList对象,向下包含的层次很多,但只有最底层的从RenderableObject继续的对象才是渲染的最终实现。”摘自:

http://blog.sina.com.cn/s/blog_467b6cd601008mmd.html~type=v5_one&label=rela_nextarticle   RenderableObjectList可以简单看作RenderableObject对象的集合,但实质上存储RenderableObject对象集合的仅仅是其中的属性m_children,它有很多特有的针对m_children管理的方法,如:Add(RenderableObject ro)、Remove(RenderableObject layer)。RenderableObjectList里通过该Timer.Elapsed 事件实现了自动刷新渲染的功能。这里还有个知识点,我们可以学习一下,就是Timer.Elapsed 事件使用,请参考MS的 http://msdn.microsoft.com/zh-cn/library/system.timers.timer.elapsed(VS.80).aspx   3.下面让我们一起看看WW实现渲染绘制的整个代码调用流程,主要分为两部分:一、获取到所有的要绘制对象集合,二、绘制所有要绘制的对象。分析入口还是从WorldWind.cs的MainAppliaction()方法开始的。           3.1获取到所有的要绘制对象集合,存放到World.cs中的 RenderableObjects属性里 MainAppliaction()中调用OpenStartupWorld() ——》2974行OpenWorld( curWorldFile );调用了private void OpenWorld(string worldXmlFile)方法 ——》3049行 worldWindow.CurrentWorld = WorldWind.ConfigurationLoader.Load(worldXmlFile, worldWindow.Cache);调用了CongfigurationLoader.cs的public static World Load(string filename, Cache cache)方法

 

——》CongfigurationLoader.cs 的110行 newWorld.RenderableObjects = getRenderablesFromLayerDirectory(layerDirectory, newWorld, cache); 看代码

加载渲染对象代码          public   static  World Load( string  filename, Cache cache)        {            Log.Write(Log.Levels.Debug,  " CONF " " Loading  "   +  filename);             //  get the World Wind Settings through reflection to avoid changing the signature of Load().             Assembly a  =  Assembly.GetEntryAssembly();            Type appType  =  a.GetType( " WorldWind.MainApplication " );            System.Reflection.FieldInfo finfo  =  appType.GetField( " Settings " , BindingFlags.Static  |  BindingFlags.Public  |  BindingFlags.GetField);            WorldWindSettings settings  =  finfo.GetValue( null as  WorldWindSettings;            XmlReaderSettings readerSettings  =   new  XmlReaderSettings();             if  (settings.ValidateXML)            {                Log.Write(Log.Levels.Debug,  " CONF " " validating  "   +  filename  +   "  against WorldXmlDescriptor.xsd and LayerSet.xsd " );                readerSettings.ValidationType  =  ValidationType.Schema;                 /*  load the schema to validate against instead of hoping for an inline schema reference  */                 XmlSchemaSet schemas  =   new  XmlSchemaSet();                schemas.Add( null , settings.ConfigPath  +   " /WorldXmlDescriptor.xsd " );                schemas.Add( null , settings.ConfigPath  +   " /Earth/LayerSet.xsd " );                readerSettings.Schemas  =  schemas;                readerSettings.ValidationEventHandler  +=   new  ValidationEventHandler(XMLValidationCallback);                readerSettings.ValidationFlags  |=  System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;            }             else             {                Log.Write(Log.Levels.Debug,  " CONF " " loading  "   +  filename  +   "  without validation " );                readerSettings.ValidationType  =  ValidationType.None;            }             try             {                XmlReader docReader  =  XmlReader.Create(filename, readerSettings);                XPathDocument docNav  =   new  XPathDocument(docReader);                XPathNavigator nav  =  docNav.CreateNavigator();                XPathNodeIterator worldIter  =  nav.Select( " /World[@Name] " );                 if  (worldIter.Count  >   0 )                {                    worldIter.MoveNext();                     string  worldName  =  worldIter.Current.GetAttribute( " Name " "" );                     double  equatorialRadius  =  ParseDouble(worldIter.Current.GetAttribute( " EquatorialRadius " "" ));                     string  layerDirectory  =  worldIter.Current.GetAttribute( " LayerDirectory " "" );                     if  (layerDirectory.IndexOf( " : " <   0 )                    {                        layerDirectory  =  Path.Combine(Path.GetDirectoryName(filename), layerDirectory);                    }                    TerrainAccessor[] terrainAccessor  =  getTerrainAccessorsFromXPathNodeIterator(worldIter.Current.Select( " TerrainAccessor " ),                        System.IO.Path.Combine(cache.CacheDirectory, worldName));                    World newWorld  =   new  World(                        worldName,                         new  Microsoft.DirectX.Vector3( 0 0 0 ),                         new  Microsoft.DirectX.Quaternion( 0 0 0 0 ),                        equatorialRadius,                        cache.CacheDirectory,                        (terrainAccessor  !=   null   ?  terrainAccessor[ 0 ] :  null ) // TODO: Oops, World should be able to handle an array of terrainAccessors                         );                     //加载所有要渲染绘制的对象                      newWorld.RenderableObjects  =  getRenderablesFromLayerDirectory(layerDirectory, newWorld, cache);                      return  newWorld;                }            }             catch  (XmlSchemaException ex)            {                Log.Write(Log.Levels.Error,  " CONF " " Exception caught during XML parsing:  "   +  ex.Message);                Log.Write(Log.Levels.Error,  " CONF " " File  "   +  filename  +   "  was not read successfully. " );                 //  TODO: should pop up a message box or something.                  return   null ;            }             return   null ;        }

 

          ——》170 public static RenderableObjectList getRenderableFromLayerFile(string layerFile, World parentWorld, Cache cache, bool enableRefresh)方法,真正加载绘制对象集合的函数。

  3.2绘制所有要绘制的对象  WorldWind.cs中MainAppliaction()中——》675worldWindow.Render();调用了WorldWindow.cs的Render()方法——》785 m_World.Render(this.drawArgs);调用World.cs的public override void Render(DrawArgs drawArgs)方法

分类分层次地调用渲染代码   public   override   void  Render(DrawArgs drawArgs)        {             try             {                 if  (m_WorldSurfaceRenderer  !=   null   &&  World.Settings.UseWorldSurfaceRenderer)                {                    m_WorldSurfaceRenderer.RenderSurfaceImages(drawArgs);                }                 //   Old method -- problems with RenderPriority sorting                 //     RenderableObjects.Render(drawArgs);                 RenderStars(drawArgs, RenderableObjects);                 if  (drawArgs.CurrentWorld.IsEarth  &&  World.Settings.EnableAtmosphericScattering)                {                     float  aspectRatio  =  ( float )drawArgs.WorldCamera.Viewport.Width  /  drawArgs.WorldCamera.Viewport.Height;                     float  zNear  =  ( float )drawArgs.WorldCamera.Altitude  *   0.1f ;                     double  distToCenterOfPlanet  =  (drawArgs.WorldCamera.Altitude  +  equatorialRadius);                     double  tangentalDistance  =  Math.Sqrt(distToCenterOfPlanet  *  distToCenterOfPlanet  -  equatorialRadius  *  equatorialRadius);                     double  amosphereThickness  =  Math.Sqrt(m_outerSphere.m_radius  *  m_outerSphere.m_radius  +  equatorialRadius  *  equatorialRadius);                    Matrix proj  =  drawArgs.device.Transform.Projection;                    drawArgs.device.Transform.Projection  =  Matrix.PerspectiveFovRH(( float )drawArgs.WorldCamera.Fov.Radians, aspectRatio, zNear, ( float )(tangentalDistance  +  amosphereThickness));                    drawArgs.device.RenderState.ZBufferEnable  =   false ;                    drawArgs.device.RenderState.CullMode  =  Cull.CounterClockwise;                    m_outerSphere.Render(drawArgs);                    drawArgs.device.RenderState.CullMode  =  Cull.Clockwise;                    drawArgs.device.RenderState.ZBufferEnable  =   true ;                    drawArgs.device.Transform.Projection  =  proj;                }                 if  (World.Settings.EnableSunShading)                    RenderSun(drawArgs);                 //分类、分层次地调用渲染方法                  // render SurfaceImages                 Render(RenderableObjects, WorldWind.Renderable.RenderPriority.TerrainMappedImages, drawArgs);                 if  (m_projectedVectorRenderer  !=   null )                     m_projectedVectorRenderer.Render(drawArgs);                 // render AtmosphericImages                 Render(RenderableObjects, WorldWind.Renderable.RenderPriority.AtmosphericImages, drawArgs);                 // render LinePaths                 Render(RenderableObjects, WorldWind.Renderable.RenderPriority.LinePaths, drawArgs);                 // render Placenames                 Render(RenderableObjects, WorldWind.Renderable.RenderPriority.Placenames, drawArgs);                 // render Icons                 Render(RenderableObjects, WorldWind.Renderable.RenderPriority.Icons, drawArgs);                 // render Custom                 Render(RenderableObjects, WorldWind.Renderable.RenderPriority.Custom, drawArgs);                  if  (Settings.showPlanetAxis)                     this .DrawAxis(drawArgs);            }             catch  (Exception ex)            {                Log.Write(ex);            }        }

 

——》分类绘制过程中是调用 485行的private void Render(WorldWind.Renderable.RenderableObject renderable, WorldWind.Renderable.RenderPriority priority, DrawArgs drawArgs)方法。

 

被各类对象调用的渲染方法 private   void  Render(WorldWind.Renderable.RenderableObject renderable, WorldWind.Renderable.RenderPriority priority, DrawArgs drawArgs)        {             if  ( ! renderable.IsOn  ||  (renderable.Name  !=   null   &&  renderable.Name.Equals( " Starfield " )))                 return ;             try             {                 if  (priority  ==  WorldWind.Renderable.RenderPriority.Icons  &&  renderable  is  Icons)                {             //关键代码,真正调用DirectX实施渲染绘制的,Render()方法被RenderObject类的子类渲染对象重载,实际上调用的是子类的Render()方法。                      renderable.Render(drawArgs);                 }                 else   if  (renderable  is  WorldWind.Renderable.RenderableObjectList)                {                    WorldWind.Renderable.RenderableObjectList rol  =  (WorldWind.Renderable.RenderableObjectList)renderable;                     for  ( int  i  =   0 ; i  <  rol.ChildObjects.Count; i ++ )                    {                        Render((WorldWind.Renderable.RenderableObject)rol.ChildObjects[i], priority, drawArgs);                    }                }                 //  hack at the moment                  else   if  (priority  ==  WorldWind.Renderable.RenderPriority.TerrainMappedImages)                {                     if  (renderable.RenderPriority  ==  WorldWind.Renderable.RenderPriority.SurfaceImages  ||  renderable.RenderPriority  ==  WorldWind.Renderable.RenderPriority.TerrainMappedImages)                    {                        renderable.Render(drawArgs);                    }                }                 else   if  (renderable.RenderPriority  ==  priority)                {                    renderable.Render(drawArgs);                }            }             catch  (Exception ex)            {                Log.Write(ex);            }        }

 

说明:该方法中596行 renderable.Render(drawArgs);实质上是调用各个RenderableObject具体的子类重写的Render()方法,实现绘制的。

  4.以WavingFlagLayer.cs类重写的588行Render()方法为例,看看是如何完成绘制的。

WavingFlagLayer类渲染代码   public   override   void  Render(DrawArgs drawArgs)        {             if  ( ! isInitialized)                 return ;             if  (m_polygonFeature  ==   null   ||   ! drawArgs.WorldCamera.ViewFrustum.Intersects(m_polygonFeature.BoundingBox))                 return ;             try             {                 double  offset  =   0 ;                 if  (Bar3D  !=   null   &&  Bar3D.IsOn)                {                    Bar3D.Render(drawArgs);                    offset  =  Bar3D.RenderedHeight;                }                Cull cull  =  drawArgs.device.RenderState.CullMode;                drawArgs.device.RenderState.CullMode  =  Cull.None;                drawArgs.device.RenderState.ZBufferEnable  =   true ;                drawArgs.device.TextureState[ 0 ].ColorOperation  =  TextureOperation.SelectArg1;                drawArgs.device.TextureState[ 0 ].ColorArgument1  =  TextureArgument.TextureColor;                Vector3 surfacePos  =  MathEngine.SphericalToCartesian(m_latitude, m_longitude, World.EquatorialRadius);                Vector3 rc  =   new  Vector3(                    ( float )drawArgs.WorldCamera.ReferenceCenter.X,                    ( float )drawArgs.WorldCamera.ReferenceCenter.Y,                    ( float )drawArgs.WorldCamera.ReferenceCenter.Z                    );                Vector3 projectedPoint  =  drawArgs.WorldCamera.Project(surfacePos  -  rc);                 int  mouseBuffer  =   15 ;                 if  (projectedPoint.X  >  DrawArgs.LastMousePosition.X  -  mouseBuffer  &&                         projectedPoint.X  <  DrawArgs.LastMousePosition.X  +  mouseBuffer  &&                         projectedPoint.Y  >  DrawArgs.LastMousePosition.Y  -  mouseBuffer  &&                         projectedPoint.Y  <  DrawArgs.LastMousePosition.Y  +  mouseBuffer)                {                     if  ( ! m_isMouseInside)                    {                        m_isMouseInside  =   true ;                         if  (OnMouseEnterEvent  !=   null )                        {                            OnMouseEnterEvent( this null );                        }                    }                }                 else                 {                     if  (m_isMouseInside)                    {                        m_isMouseInside  =   false ;                         if  (OnMouseLeaveEvent  !=   null )                        {                            OnMouseLeaveEvent( this null );                        }                    }                }                drawArgs.device.RenderState.CullMode  =  Cull.None;                 if  (ShowHighlight)                    renderHighlight(drawArgs);                RenderFlag(drawArgs, offset);                drawArgs.device.RenderState.CullMode  =  cull;            }             catch  (Exception ex)            {                Log.Write(ex);            }        }

本系列其他部分:

WorldWind学习系列五:插件加载过程全解析

WorldWind学习系列四:功能分析——Show Planet Axis、Show Position 、Show Cross Hairs功能

WorldWind学习系列三:简单功能分析——主窗体的键盘监听处理及拷贝和粘贴位置坐标功能

WorldWind学习系列三:功能分析——截屏功能和“关于”窗体分析

WorldWind学习系列二:擒贼先擒王篇2

WorldWind学习系列二:擒贼先擒王篇1

WorldWind学习系列一:顺利起航篇

 

 

 

转载于:https://www.cnblogs.com/wuhenke/archive/2009/12/14/1624122.html

相关资源:数据结构—成绩单生成器
最新回复(0)