• 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(nullas 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(000),
                            
    new Microsoft.DirectX.Quaternion(0000),
                            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(
    thisnull);

                            }

                        }

                    }

                    
    else
                    {

                        
    if (m_isMouseInside)
                        {

                            m_isMouseInside 
    = false;

                            
    if (OnMouseLeaveEvent != null)
                            {

                                OnMouseLeaveEvent(
    thisnull);

                            }

                        }

                    }

                    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学习系列一:顺利起航篇

     

  • 相关阅读:
    C语言之数组中你所不在意的重要知识
    Word2007怎样从随意页開始设置页码 word07页码设置毕业论文
    天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,增益其所不能
    高速排序算法
    Cocos2d-x中停止播放背景音乐
    Netflix公司监控内部安全的开源项目
    Linux内核——进程管理与调度
    WebService之Soap头验证入门
    Google搜索解析
    android-sdk-windows版本号下载
  • 原文地址:https://www.cnblogs.com/wuhenke/p/1624122.html
Copyright © 2020-2023  润新知