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

来源:互联网 发布:sql not in not exists 编辑:程序博客网 时间:2024/06/03 03:36

原文转自: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);            }        }