WorldWind學習系列六:渲染過程解析篇

原文轉自:http://www.cnblogs.com/wuhenke/archive/2009/12/14/1624122.html

今天主要是分析學習了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); 看代碼

加載渲染對象代碼 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->        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)方法

分類分層次地調用渲染代碼 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 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)方法。

 

被各類對象調用的渲染方法 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->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類渲染代碼 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 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);

            }

        }


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章