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

  今天主要是分析学习了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学习系列一:顺利起航篇

 

 

 

你可能感兴趣的:(学习)