WorldWind源码剖析系列:大气层散射球类AtmosphericScatteringSphere
大气层散射球类AtmosphericScatteringSphere代表地球外面的大气层散射球模型,可以控制开启/关闭渲染该对象。该类的类图如下。
该类所包含的主要字段、属性和方法如下:
public float m_radius;//大气层散射球半径,默认为地球赤道半径的1.025倍
protected int m_numberSlices; //大气层散射球切片数目,默认为75
protected int m_numberSections; //大气层散射球半径分割段数,默认为75
public static float m_fInnerRadius = 0; //大气层散射球内半径
public static float m_fOuterRadius = 0; //大气层散射球外半径
public static int TilesHigh = 4; //大气层散射球瓦片高度
public static int TilesWide = 8; //大气层散射球瓦片宽度
System.Collections.Generic.List<MeshSubset> m_meshList = new System.Collections.Generic.List<MeshSubset>();//存储大气层散射球剖分的格网子集
Vector3 m_lastSunPosition = Vector3.Empty;//太阳位置
System.Threading.Thread m_backgroundThread = null;//渲染大气层散射球的后台线程
bool active = false;//是否激活大气层散射球
System.DateTime m_lastOpticalUpdate = System.DateTime.MinValue; //大气层散射球最后的不透明度更新时间
bool m_canDoShaders = false;//是否能够执行着色器
short[] m_indices = null;//剖分散射球时的顶点索引,用来构造索引缓冲区
short[] m_indicesHighResolution = null;//精细的顶点索引,实际是通过指定精细的格网顶点密度是前者的2倍来重新计算实现的,75/4=18.75,取整为18,则精细的格网顶点密度为36
float[] fCameraDepth = new float[4] { 0, 0, 0, 0 };//相机深度
float[] fLightDepth = new float[4];//光照深度
float[] fSampleDepth = new float[4];//采样深度
float[] fRayleighSum = new float[] { 0, 0, 0 };//瑞利散射和
float[] fMieSum = new float[] { 0, 0, 0 };//米尔散射和
Vector3 vPos = new Vector3();//光照位置
float[] fAttenuation = new float[3];//环境光
Vector3 vCamera = new Vector3();相机位置
public void Init(float radius, int slices, int sections)方法用来初始化大气层散射球,内部调用SunCalculator类、TimeKeeper类和BoundingBox类的静态函数,这两个类在本篇结束时附后讲解。将散射球切分成4行×8列=32块,每一步内部又按照指定的格网子集密度(如纵、横密度均为18)进一步剖分计算需要绘制的格网顶点。默认经度和纬度的分割间隔均为45度。内部又调用CustomVertex.PositionColored[] CreateMesh(double minLat, double maxLat, double minLon, double maxLon, int meshPointCount)函数根据输入的经纬度范围创建格网子集。
public void Update(DrawArgs drawArgs)方法用来更新大气散射球的光照、模型等渲染元素,内部实际上是发起后台线程backgroundThread来实现的,线程绑定的处理函数为private void Updater()。而Update函数是在World类的public override void Update(DrawArgs drawArgs)中被调用的。
CustomVertex.PositionColored[] CreateMesh(double minLat, double maxLat, double minLon, double maxLon, int meshPointCount) 函数根据输入的经、纬度范围和格网子集密度来创建格网子集的顶点数组。
short[] computeIndices(int meshPointCount)方法根据指定的格网子集密度来计算每个格网顶点的索引,以便渲染时索引缓冲区使用。其中,索引总数=纵向点数×横向点数×2×3。在数组中索引范围为[0,索引总数-1]。
void Interpolate(ref float[] p, float x, float y)被SetColor函数调用。
public void SetColor(ref CustomVertex.PositionColored pVertex, DrawArgs drawArgs)被UpdateColor和getAtmosphereColor函数调用。
int getAtmosphereColor(DrawArgs drawArgs,CustomVertex.PositionColored pVertex)被ColoredSpherePartial函数调用。
private void UpdateColor(DrawArgs drawArgs, MeshSubset meshSubset, bool doHighResolution)函数暂时未被调用,所以处理颜色函数可以暂时不用分析。
private Mesh ColoredSpherePartial(DrawArgs drawArgs, float radius, double startLat, double endLat, int slices, int stacks, double lonSpan, double heading) 被UpdateSkyMesh函数调用。
void UpdateLightVector(),根据太阳位置更新光照位置和方向,被Render()和Updater()函数调用。
private void UpdateSkyMesh(DrawArgs drawArgs, double horizonSpan)被Render()函数调用。
public void Render(DrawArgs drawArgs) 方法在World类的public override void Render(DrawArgs drawArgs)中被调用的。
void MakeOpticalDepthBuffer(float fInnerRadius, float fOuterRadius, float fRayleighScaleHeight, float fMieScaleHeight) 被Updater()函数调用。
实际上,大气散射球类只需要重点关注Update(DrawArgs drawArgs)和Render(DrawArgs drawArgs)两个方法,其余方法均直接或间接的被这两个方法调用。而这两个方法又分别被World类的Update(DrawArgs drawArgs)和Render(DrawArgs drawArgs)函数调用。