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

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

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

            }

        }


 

NASA WorldWind三维地理可视化技术手册全解析 相较WMS按需渲染整幅图像,WMTS采用预先切分好的瓦片集合(Tile Matrix Set),显著提升访问效率。其核心优势在于:所有瓦片具有固定大小(通常为256×256像素),并按金字塔层级组织,每一层对应特定比例尺。WMTS的关键概念包括::定义一组瓦片矩阵,包含CRS、缩放级别数量、每个级别的分辨率与瓦片数量。TileMatrix:单个缩放级别下的瓦片网格结构,含行列数与像素大小。Style:图层渲染风格。Format:瓦片返回格式(如。 阅读详情

相关推荐

[WorldWind学习]4.DrawArgs对象

 WorldWindWorldWindow控件包含只读属性DrawArgs public DrawArgs DrawArgs { get { return this.drawArgs; } } DrawArgs渲染参数对象,负责记录当前渲染的各个参数 WorldWindow的CurrentWorld属性赋值时也给draw...

weixin_34200628的博客 169

3.6WorldWind利用opengl绘制地球模型

对模型进行绘制核心还是进行坐标变换,将模型坐标最终变换为屏幕像素坐标,而变换主要有三种模式,模型视图变换,投影变换和纹理变换!模型视图变换细分为模型变换和视图变换,模型变换方法就是设置平移,旋转,缩放矩阵,视图变换可以通过方法gluLookAt来设置相机的方位,从而得到视图变换矩阵用于视图变换,当然本质上是得到了视图变换矩阵,内部也是利用参数计算出了矩阵左乘当前矩阵模式的变换矩阵,所以,world...

upcdxlq的博客 1155

WorldWind学习系列十二:Measure插件学习

原文转自:http://www.cnblogs.com/wuhenke/archive/2009/12/28/1634464.html 我在写自己的WorldWind插件时,遇到很大挫折,上周本来想写个简单的画线的插件,费了九牛二虎之力终于画出了,如何以动画效果画出线的问题没解决。Direct3D中画线本来是个简单的事,画到球面上也不难,但是实践告诉我:我前期学习WW,又犯了眼高手低的毛病!改

aijingyi的专栏 1499

蓝天采集器winds系统页面渲染设置教程

页面渲染设置 页面渲染功能开启后能自动加载出网页中的ajax内容 服务器中需要安装谷歌浏览器,支持linux、win系统 centos7安装chrome的命令: wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm yum localinstall google-chrome-stable_current_x86_64.rpm 安装后的chrome路径为:/usr/bin/google

sr8899的博客 1484

WorldWind学习系列:2、基本流程

介绍WorldWind的基本运行流程和地球球体创建过程

1270

WorldWind学习系列十四:DEM数据加载和应用——以SRTM为例

原文转自:http://www.cnblogs.com/wuhenke/archive/2010/01/01/1637544.html 今天是2010的第一天,总想把它过得充实点,为我自己新的一年开个好头吧!首先,向关注我博客的网友道声:“元旦快乐!”,其次,接着跟大家分享一下我学习WW中DEM数据的加载和应用心得,希望大家从中有所收获!   DEM应用在WW的三维表现中占有很重要的位置,跟影

aijingyi的专栏 1985

WorldWind学习系列十一:Virtual Earth插件学习

原文转自:http://www.cnblogs.com/wuhenke/archive/2009/12/24/1631739.html   学习WorldWind有很长时间了,理论学习算是基本完成了。我体会是WW的学习主要分为两大步:WW框架体系学习和WW插件学习学习WW插件逐步深入后,必然要首先学习Direct3D编程,这也算是我的经验之谈吧。今天Virtual Earth插件学习完成,也

aijingyi的专栏 1846

转载 WorldWind学习总结三

WorldWind学习总结三 转载自:http://blog.csdn.net/paul_xj/article/details/1792486           可能学习过程中给自己制造压力太大,有时候一天没有收获就会很难受,但是像WW这样的项目到一定程度会有个难过的坎而几天没有进步是很正常的,对自己要求太多而实现不了常有很坏的影响,待调整好再理清思路又过了不少时间,用一个好的心态来稳步进

wsh6759的CGIS专栏 1083

WorldWind 学习笔记 五、添加模型

World Wind 中添加模型后的一些问题和解决思路 其中就由于大型游戏世界坐标的精度而产生的抖动问题,本文采取了相对中心的解决方案

4204

WorldWind源码剖析系列:星球球体的加载与渲染

WorldWind源码剖析系列:星球球体的加载与渲染 WorldWind中主函数Main()的分析 在文件WorldWind.cs中主函数Main()阐明了WorldWind的初始化运行机制(如图1所示 ): 图1 WorldWind的初始化运行机制 1.  使用System.Version在内部,读取软件版本信息,并格式化输出。我们在外面配置软件版本,“关于”部分中版本自动更改。 ...

weixin_34259232的博客 224

WorldWind学习系列十三:地形数据(DEM)加载和应用(入门

原文转自:http://www.cnblogs.com/wuhenke/archive/2009/12/30/1636421.html   学习WW中DEM的加载和应用对于基于WW搞三维GIS插件开发很重要。我一直也想关注和搜集相关学习资料,之前没有开始研究它,主要是自己没能在WW看到高程应用功能,感觉没法切入。我昨天下午和今天上午的时间就花在找研究切入点啦!实质上就是找如何在WW查看高程的功

aijingyi的专栏 1798

worldwind java加载3ds_WorldWind Java 版学习:3、配置文件的读取

1、在 WorldWindow 启动过程中,直接读取的配置文件有三个:一个是在程序启动前,使用静态模块配置程序的配置文件System.setProperty("gov.nasa.worldwind.app.config.document","gov/nasa/worldwindx/applications/worldwindow/config/worldwindow.worldwind.xml")...

weixin_35600779的博客 226

WorldWind学习系列:5、摄像机类

WorldWind的坐标系以地心为原点,地心到0度经线与赤道的交点为X轴,地心到北极点为Z轴,地心到东经90度经线与赤道的交点为Y轴,三坐标轴构成一个右手坐标系。

700

WorldWind学习系列:4、空闲处理OnApplicationIdle流程

在程序没有要处理的消息时,会调用WorldWindow.OnApplicationIdle函数,更新渲染场景,重绘整个场景,本简要介绍主要流程。

219

WorldWind源码剖析系列WorldWind实时确定、更新、初始化和渲染地形和纹理数据...

WorldWind实时确定、更新、初始化和渲染地形和纹理数据 当用户点击WorldWind中的地球时,首先响应的是WorldWindow.OnPaint()函数,后续程序的调用流程如下图所示。 零散知识点: 1、 地形瓦片类TerrainTile引用了地形瓦片服务类TerrainTileService,在TerrainTile的Initialize()函...

weixin_30321449的博客 156
上一篇: WorldWind学习系列五:插件加载过程全解析
下一篇: WorldWind学习系列七:Load/Unload Plugins——投石问路篇
aijingyi
博客等级 码龄16年 33粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值