今天主要是分析学习了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学习系列一:顺利起航篇
转载于:https://www.cnblogs.com/wuhenke/archive/2009/12/14/1624122.html
相关资源:数据结构—成绩单生成器