World中有两个渲染器类对象,分别是地球表面渲染器WorldSurfaceRenderer和投影矢量渲染器ProjectedVectorRenderer。World分别调用WorldSurfaceRenderer的Update和RenderSurfaceImages函数,ProjectedVectorRenderer的Update和Render函数进行状态更新和渲染。
一、WorldSurfaceRenderer类
地球表面渲染器类在 RenderableObject 可渲染对象ImageLayer中应用, 图如下所示:
主要属性:
public const int RenderSurfaceSize = 256; //表面的大小
RenderToSurface m_Rts = null;
const int m_NumberRootTilesHigh = 5;
uint m_SamplesPerTile; //the samples per tile.
//Also can be considered the Vertex Density or
//Mesh Density of each SurfaceTile
WorldWind.World m_ParentWorld;
SurfaceTile[] m_RootSurfaceTiles; //覆盖地球的顶层瓦片
double m_DistanceAboveSeaLevel = 0;
bool m_Initialized = false;
System.Collections.ArrayList m_SurfaceImages = new System.Collections.ArrayList();
System.Collections.Queue m_TextureLoadQueue = new System.Collections.Queue();
public System.DateTime LastChange = System.DateTime.Now; //最后一次更新时间
public int NumberTilesUpdated = 0;
包含1个表面图片链表m_SurfaceImages和1个纹理待加载队列m_TextureLoadQueue 。
m_RootSurfaceTiles 是 SurfaceTile 表面瓦片数组。
主要函数:
1、构造函数,初始化表面0级瓦片数组m_RootSurfaceTiles。默认瓦片为5度,纬度方向36片,经度方向72片,目前看world里还没有创建WorldSurfaceRenderer类对象的代码。
public WorldSurfaceRenderer(uint samplesPerTile,
double distanceAboveSeaLevel,
WorldWind.World parentWorld
)
2、public void AddSurfaceImage(SurfaceImage surfaceImage), 如果SurfaceImage对象surfaceImage已经加载纹理,则将其添加到m_SurfaceImages链表,否则添加到纹理待加载队列。
3、public void RemoveSurfaceImage(string imageResource):根据ImageFilePath属性比较是否为同一个SurfaceImage对象,如果imageResource为SurfaceImage对象图形文件路径,则将该对象从m_SurfaceImages链表中删除。
4、private void OnDeviceReset(object sender, EventArgs e):设备重置时调用,重新创建RenderToSurface对象。
5、public void Initialize(DrawArgs drawArgs):初始化对象,初始化所有的表面瓦片对象。
6、public void Dispose():销毁对象,需要销毁所有的表面瓦片对象和RenderToSurface这个D3D Com对象。
7、public void Update(DrawArgs drawArgs):更新对象,如果对象没有初始化,先进行初始化。然后更新所有的表面瓦片对象(调用瓦片的update函数)。
8、public void RenderSurfaceImages(DrawArgs drawArgs):先将纹理待加载队列m_TextureLoadQueue 中的所有SurfaceImage对象加载纹理。然后添加到m_SurfaceImages链表中。然后渲染所有的表面瓦片对象(调用瓦片的Render函数)。
1.1 SurfaceTile
表面瓦片的主要属性:
int m_Level; //瓦片的层级,第0层开始
double m_North;
double m_South;
double m_West;
double m_East;
bool m_Initialized = false;
Device m_Device = null;
Texture m_RenderTexture = null;
// Surface m_RenderSurface = null;
// bool m_InitTexture = true;
// bool m_DeviceBindingMade = false;
float[,] m_HeightData = null; //高程数据
CustomVertex.TransformedColoredTextured[] m_RenderToTextureVertices = new CustomVertex.TransformedColoredTextured[4]; //带纹理的四个角的顶点
DynamicTexture m_DynamicTexture = null;
bool m_RequiresUpdate = false;
float m_VerticalExaggeration = float.NaN;
System.DateTime m_LastUpdate = System.DateTime.Now;
WorldSurfaceRenderer m_ParentWorldSurfaceRenderer;
BoundingBox m_BoundingBox;
short[] m_NwIndices = null;
short[] m_NeIndices = null;
short[] m_SwIndices = null;
short[] m_SeIndices = null;
//四个孩子节点瓦片
SurfaceTile m_NorthWestChild;
SurfaceTile m_NorthEastChild;
SurfaceTile m_SouthWestChild;
SurfaceTile m_SouthEastChild;
short[] m_IndicesElevated; //加上高程的索引
最主要函数包括构造函数、初始化函数Initialize,更新函数update和渲染函数Render。
1、构造函数,初始化瓦片的层级、经纬度范围,计算瓦片的包围盒BoundingBox。最后计算瓦片三角形的顶点索引,每个三角形包含6个点。三角形的数量为,每个顶点属于2个三角形,包含6个索引号。
2、初始化函数Initialize:当层级大于2时读取高程数据,
public class SurfaceTile : IDisposable
{
public SurfaceTile(double north, double south, double west, double east, int level,
WorldSurfaceRenderer parentWorldSurfaceRenderer)
{
m_North = north;
m_South = south;
m_West = west;
m_East = east;
m_Level = level;
m_ParentWorldSurfaceRenderer = parentWorldSurfaceRenderer;
float scale = 1.1f;
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(south),
Angle.FromDegrees(west),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel);
Vector3 v0 = new Vector3((float)v.X, (float)v.Y, (float)v.Z);
Vector3 v1 = Vector3.Scale(v0, scale);
v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(south),
Angle.FromDegrees(east),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel);
Vector3 v2 = new Vector3((float)v.X, (float)v.Y, (float)v.Z);
Vector3 v3 = Vector3.Scale(v2, scale);
v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(north),
Angle.FromDegrees(west),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel);
Vector3 v4 = new Vector3((float)v.X, (float)v.Y, (float)v.Z);
Vector3 v5 = Vector3.Scale(v4, scale);
v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(north),
Angle.FromDegrees(east),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel);
Vector3 v6 = new Vector3((float)v.X, (float)v.Y, (float)v.Z);
Vector3 v7 = Vector3.Scale(v6, scale);
m_BoundingBox = new BoundingBox(v0, v1, v2, v3, v4, v5, v6, v7);
int thisVertexDensityElevatedPlus2 = ((int)m_ParentWorldSurfaceRenderer.SamplesPerTile / 2 + 2);
m_IndicesElevated = new short[2 * thisVertexDensityElevatedPlus2 * thisVertexDensityElevatedPlus2 * 3];
for (int i = 0; i < thisVertexDensityElevatedPlus2; i++)
{
int elevated_idx = (2 * 3 * i * thisVertexDensityElevatedPlus2);
for (int j = 0; j < thisVertexDensityElevatedPlus2; j++)
{
m_IndicesElevated[elevated_idx] = (short)(i * (thisVertexDensityElevatedPlus2 + 1) + j);
m_IndicesElevated[elevated_idx + 1] = (short)((i + 1) * (thisVertexDensityElevatedPlus2 + 1) + j);
m_IndicesElevated[elevated_idx + 2] = (short)(i * (thisVertexDensityElevatedPlus2 + 1) + j + 1);
m_IndicesElevated[elevated_idx + 3] = (short)(i * (thisVertexDensityElevatedPlus2 + 1) + j + 1);
m_IndicesElevated[elevated_idx + 4] = (short)((i + 1) * (thisVertexDensityElevatedPlus2 + 1) + j);
m_IndicesElevated[elevated_idx + 5] = (short)((i + 1) * (thisVertexDensityElevatedPlus2 + 1) + j + 1);
elevated_idx += 6;
}
}
}
/// <summary>
/// Gets the render texture.
/// </summary>
/// <value></value>
public Texture RenderTexture
{
get
{
return m_RenderTexture;
}
}
private void OnDeviceReset(object sender, EventArgs e)
{
Device dev = (Device)sender;
m_Device = dev;
m_RenderTexture = new Texture(
dev,
WorldSurfaceRenderer.RenderSurfaceSize,
WorldSurfaceRenderer.RenderSurfaceSize,
1,
Usage.RenderTarget,
Format.X8R8G8B8,
Pool.Default);
m_RequiresUpdate = true;
}
private void OnDeviceDispose(object sender, EventArgs e)
{
if (m_RenderTexture != null && !m_RenderTexture.Disposed)
{
m_RenderTexture.Dispose();
}
/* if(m_RenderSurface != null && !m_RenderSurface.Disposed)
{
m_RenderSurface.Dispose();
}*/
}
/// <summary>
/// Initializes the specified draw args.
/// </summary>
/// <param name="drawArgs">DrawArgs.</param>
public void Initialize(DrawArgs drawArgs)
{
try
{
if (m_HeightData == null)
{
if (m_Level > 2)
{
Terrain.TerrainTile tt =
m_ParentWorldSurfaceRenderer.ParentWorld.TerrainAccessor.GetElevationArray(
m_North,
m_South,
m_West,
m_East,
(int)m_ParentWorldSurfaceRenderer.SamplesPerTile + 1);
if (tt.ElevationData != null)
{
m_HeightData = tt.ElevationData;
}
else
{
m_HeightData = new float[(uint)m_ParentWorldSurfaceRenderer.SamplesPerTile + 1, (uint)m_ParentWorldSurfaceRenderer.SamplesPerTile + 1];
}
}
else
{
m_HeightData = new float[(uint)m_ParentWorldSurfaceRenderer.SamplesPerTile + 1, (uint)m_ParentWorldSurfaceRenderer.SamplesPerTile + 1];
}
}
if (m_DynamicTexture == null)
{
m_DynamicTexture = new DynamicTexture();
buildTerrainMesh();
}
}
catch (Exception ex)
{
Log.Write(ex);
}
m_Initialized = true;
}
/// <summary>
/// Updates the render surface.
/// </summary>
/// <param name="drawArgs">Draw args.</param>
public void UpdateRenderSurface(DrawArgs drawArgs)
{
if (m_RenderTexture == null)
{
drawArgs.device.DeviceReset += new EventHandler(OnDeviceReset);
OnDeviceReset(drawArgs.device, null);
}
Viewport view = new Viewport();
view.Width = WorldSurfaceRenderer.RenderSurfaceSize;
view.Height = WorldSurfaceRenderer.RenderSurfaceSize;
if (drawArgs.RenderWireFrame)
{
drawArgs.device.RenderState.FillMode = FillMode.Solid;
}
using (Surface renderSurface = m_RenderTexture.GetSurfaceLevel(0))
{
m_ParentWorldSurfaceRenderer.RenderToSurface.BeginScene(renderSurface, view);
drawArgs.device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Black, 1.0f, 0);
drawArgs.device.VertexFormat = CustomVertex.TransformedColoredTextured.Format;
drawArgs.device.RenderState.ZBufferEnable = false;
double latRange = m_North - m_South;
double lonRange = m_East - m_West;
lock (m_ParentWorldSurfaceRenderer.SurfaceImages.SyncRoot)
{
for (int i = 0; i < m_ParentWorldSurfaceRenderer.SurfaceImages.Count; i++)
{
SurfaceImage currentSurfaceImage = m_ParentWorldSurfaceRenderer.SurfaceImages[i] as SurfaceImage;
if (currentSurfaceImage == null ||
currentSurfaceImage.ImageTexture == null ||
currentSurfaceImage.ImageTexture.Disposed ||
!currentSurfaceImage.Enabled ||
(currentSurfaceImage.North > m_North && currentSurfaceImage.South >= m_North) ||
(currentSurfaceImage.North <= m_South && currentSurfaceImage.South < m_South) ||
(currentSurfaceImage.West < m_West && currentSurfaceImage.East <= m_West) ||
(currentSurfaceImage.West >= m_East && currentSurfaceImage.East > m_East)
)
{
continue;
}
currentSurfaceImage.Opacity = currentSurfaceImage.ParentRenderable.Opacity;
Vector2 tex = currentSurfaceImage.GetTextureCoordinate(m_North, m_West);
m_RenderToTextureVertices[0].X = 0;
m_RenderToTextureVertices[0].Y = 0;
m_RenderToTextureVertices[0].Z = 0.0f;
m_RenderToTextureVertices[0].Tu = tex.Y;
m_RenderToTextureVertices[0].Tv = tex.X;
m_RenderToTextureVertices[0].Color = System.Drawing.Color.FromArgb(
currentSurfaceImage.ParentRenderable.Opacity,
0, 0, 0).ToArgb();
tex = currentSurfaceImage.GetTextureCoordinate(m_South, m_West);
m_RenderToTextureVertices[1].X = 0;
m_RenderToTextureVertices[1].Y = WorldSurfaceRenderer.RenderSurfaceSize;
m_RenderToTextureVertices[1].Z = 0.0f;
m_RenderToTextureVertices[1].Tu = tex.Y;
m_RenderToTextureVertices[1].Tv = tex.X;
m_RenderToTextureVertices[1].Color = System.Drawing.Color.FromArgb(
currentSurfaceImage.ParentRenderable.Opacity,
0, 0, 0).ToArgb();
tex = currentSurfaceImage.GetTextureCoordinate(m_North, m_East);
m_RenderToTextureVertices[2].X = WorldSurfaceRenderer.RenderSurfaceSize;
m_RenderToTextureVertices[2].Y = 0;
m_RenderToTextureVertices[2].Z = 0.0f;
m_RenderToTextureVertices[2].Tu = tex.Y;
m_RenderToTextureVertices[2].Tv = tex.X;
m_RenderToTextureVertices[2].Color = System.Drawing.Color.FromArgb(
currentSurfaceImage.ParentRenderable.Opacity,
0, 0, 0).ToArgb();
tex = currentSurfaceImage.GetTextureCoordinate(m_South, m_East);
m_RenderToTextureVertices[3].X = WorldSurfaceRenderer.RenderSurfaceSize;
m_RenderToTextureVertices[3].Y = WorldSurfaceRenderer.RenderSurfaceSize;
m_RenderToTextureVertices[3].Z = 0.0f;
m_RenderToTextureVertices[3].Tu = tex.Y;
m_RenderToTextureVertices[3].Tv = tex.X;
m_RenderToTextureVertices[3].Color = System.Drawing.Color.FromArgb(
currentSurfaceImage.ParentRenderable.Opacity,
0, 0, 0).ToArgb();
drawArgs.device.RenderState.AlphaBlendEnable = true;
drawArgs.device.RenderState.SourceBlend = Blend.SourceAlpha;
drawArgs.device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
drawArgs.device.SamplerState[0].BorderColor = System.Drawing.Color.FromArgb(0, 0, 0, 0);
drawArgs.device.SamplerState[1].BorderColor = System.Drawing.Color.FromArgb(0, 0, 0, 0);
drawArgs.device.SetTexture(0, currentSurfaceImage.ImageTexture);
drawArgs.device.SetTexture(1, currentSurfaceImage.ImageTexture);
drawArgs.device.TextureState[1].TextureCoordinateIndex = 0;
drawArgs.device.SamplerState[0].MinFilter = TextureFilter.Linear;
drawArgs.device.SamplerState[0].MagFilter = TextureFilter.Linear;
drawArgs.device.SamplerState[0].AddressU = TextureAddress.Clamp;
drawArgs.device.SamplerState[0].AddressV = TextureAddress.Clamp;
drawArgs.device.SamplerState[1].MinFilter = TextureFilter.Point;
drawArgs.device.SamplerState[1].MagFilter = TextureFilter.Point;
drawArgs.device.SamplerState[1].AddressU = TextureAddress.Border;
drawArgs.device.SamplerState[1].AddressV = TextureAddress.Border;
drawArgs.device.TextureState[0].ColorOperation = TextureOperation.SelectArg1;
drawArgs.device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
drawArgs.device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
drawArgs.device.TextureState[0].AlphaOperation = TextureOperation.Modulate;
drawArgs.device.TextureState[0].AlphaArgument1 = TextureArgument.Diffuse;
drawArgs.device.TextureState[0].AlphaArgument2 = TextureArgument.TextureColor;
drawArgs.device.TextureState[1].ColorOperation = TextureOperation.SelectArg1;
drawArgs.device.TextureState[1].ColorArgument1 = TextureArgument.Current;
drawArgs.device.TextureState[1].AlphaOperation = TextureOperation.Modulate;
drawArgs.device.TextureState[1].AlphaArgument1 = TextureArgument.TextureColor;
drawArgs.device.TextureState[1].AlphaArgument2 = TextureArgument.Diffuse;
drawArgs.device.TextureState[2].ColorOperation = TextureOperation.Disable;
drawArgs.device.TextureState[2].AlphaOperation = TextureOperation.Disable;
drawArgs.device.DrawUserPrimitives(
PrimitiveType.TriangleStrip,
2,
m_RenderToTextureVertices);
drawArgs.device.SetTexture(0, null);
drawArgs.device.SetTexture(1, null);
drawArgs.device.SetTextureStageState(1, TextureStageStates.TextureCoordinateIndex, 1);
}
m_ParentWorldSurfaceRenderer.RenderToSurface.EndScene(Filter.Box);
drawArgs.device.RenderState.ZBufferEnable = true;
}
}
if (drawArgs.RenderWireFrame)
{
drawArgs.device.RenderState.FillMode = FillMode.WireFrame;
}
m_LastUpdate = System.DateTime.Now;
m_RequiresUpdate = false;
}
private void ComputeChildrenTiles(DrawArgs drawArgs)
{
if (m_NorthWestChild == null)
{
SurfaceTile nwc = new SurfaceTile(
m_North,
0.5f * (m_South + m_North),
m_West,
0.5f * (m_West + m_East),
m_Level + 1,
m_ParentWorldSurfaceRenderer
);
nwc.Initialize(drawArgs);
m_NorthWestChild = nwc;
}
if (m_NorthEastChild == null)
{
SurfaceTile nec = new SurfaceTile(
m_North,
0.5f * (m_South + m_North),
0.5f * (m_West + m_East),
m_East,
m_Level + 1,
m_ParentWorldSurfaceRenderer
);
nec.Initialize(drawArgs);
m_NorthEastChild = nec;
}
if (m_SouthWestChild == null)
{
SurfaceTile swc = new SurfaceTile(
0.5f * (m_South + m_North),
m_South,
m_West,
0.5f * (m_West + m_East),
m_Level + 1,
m_ParentWorldSurfaceRenderer
);
swc.Initialize(drawArgs);
m_SouthWestChild = swc;
}
if (m_SouthEastChild == null)
{
SurfaceTile sec = new SurfaceTile(
0.5f * (m_South + m_North),
m_South,
0.5f * (m_West + m_East),
m_East,
m_Level + 1,
m_ParentWorldSurfaceRenderer
);
sec.Initialize(drawArgs);
m_SouthEastChild = sec;
}
}
private Vector2 GetTextureCoordinate(SurfaceImage surfaceImage, double latitude, double longitude)
{
double deltaLat = surfaceImage.North - latitude;
double deltaLon = longitude - surfaceImage.West;
double latRange = surfaceImage.North - surfaceImage.South;
double lonRange = surfaceImage.East - surfaceImage.West;
Vector2 v = new Vector2(
(float)(deltaLat / latRange),
(float)(deltaLon / lonRange));
return v;
}
/// <summary>
/// Builds the terrain mesh. Also re-builds the terrain mesh, such as when vertical exaggeration has changed.
/// </summary>
private void buildTerrainMesh()
{
int thisVertexDensityElevatedPlus3 = ((int)m_ParentWorldSurfaceRenderer.SamplesPerTile / 2 + 3);
double scaleFactor = (float)1 / (m_ParentWorldSurfaceRenderer.SamplesPerTile);
double latrange = (float)Math.Abs(m_North - m_South);
double lonrange = (float)Math.Abs(m_East - m_West);
m_DynamicTexture.nwVerts = new CustomVertex.PositionNormalTextured[thisVertexDensityElevatedPlus3 * thisVertexDensityElevatedPlus3];
m_DynamicTexture.neVerts = new CustomVertex.PositionNormalTextured[thisVertexDensityElevatedPlus3 * thisVertexDensityElevatedPlus3];
m_DynamicTexture.swVerts = new CustomVertex.PositionNormalTextured[thisVertexDensityElevatedPlus3 * thisVertexDensityElevatedPlus3];
m_DynamicTexture.seVerts = new CustomVertex.PositionNormalTextured[thisVertexDensityElevatedPlus3 * thisVertexDensityElevatedPlus3];
int base_idx;
for (int i = 0; i < thisVertexDensityElevatedPlus3; i++)
{
base_idx = i * thisVertexDensityElevatedPlus3;
for (int j = 0; j < thisVertexDensityElevatedPlus3; j++)
{
float height = -30000;
if (i == 0 || j == 0 || i == thisVertexDensityElevatedPlus3 - 1 || j == thisVertexDensityElevatedPlus3 - 1)
{
double latitude = 0;
double longitude = 0;
float tu = 0.0f;
float tv = 0.0f;
if (j == 0)
{
longitude = m_West;
tu = 0.0f;
}
else if (j == thisVertexDensityElevatedPlus3 - 1)
{
longitude = 0.5 * (m_West + m_East);
tu = 0.5f;
}
else
{
longitude = m_West + (float)scaleFactor * lonrange * (j - 1);
tu = (float)(scaleFactor * (j - 1));
}
if (i == 0)
{
latitude = m_North;
tv = 0.0f;
}
else if (i == thisVertexDensityElevatedPlus3 - 1)
{
latitude = 0.5 * (m_North + m_South);
tv = 0.5f;
}
else
{
latitude = m_North - scaleFactor * latrange * (i - 1);
tv = (float)(scaleFactor * (i - 1));
}
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(latitude),
Angle.FromDegrees(longitude),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.nwVerts[base_idx].X = v.X;
m_DynamicTexture.nwVerts[base_idx].Y = v.Y;
m_DynamicTexture.nwVerts[base_idx].Z = v.Z;
m_DynamicTexture.nwVerts[base_idx].Tu = tu;
m_DynamicTexture.nwVerts[base_idx].Tv = tv;
}
else
{
height = (float)m_HeightData[(i - 1), (j - 1)];
height *= World.Settings.VerticalExaggeration;
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(m_North - scaleFactor * latrange * (i - 1)),
Angle.FromDegrees(m_West + scaleFactor * lonrange * (j - 1)),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.nwVerts[base_idx].X = v.X;
m_DynamicTexture.nwVerts[base_idx].Y = v.Y;
m_DynamicTexture.nwVerts[base_idx].Z = v.Z;
m_DynamicTexture.nwVerts[base_idx].Tu = (float)(scaleFactor * (j - 1));
m_DynamicTexture.nwVerts[base_idx].Tv = (float)(scaleFactor * (i - 1));
}
base_idx += 1;
}
}
for (int i = 0; i < thisVertexDensityElevatedPlus3; i++)
{
base_idx = i * thisVertexDensityElevatedPlus3;
for (int j = 0; j < thisVertexDensityElevatedPlus3; j++)
{
float height = -30000;
if (i == 0 || j == 0 || i == thisVertexDensityElevatedPlus3 - 1 || j == thisVertexDensityElevatedPlus3 - 1)
{
double latitude = 0;
double longitude = 0;
float tu = 0.0f;
float tv = 0.0f;
if (j == 0)
{
longitude = 0.5 * (m_West + m_East);
tu = 0.5f;
}
else if (j == thisVertexDensityElevatedPlus3 - 1)
{
longitude = m_East;
tu = 1.0f;
}
else
{
longitude = 0.5 * (m_West + m_East) + (float)scaleFactor * lonrange * (j - 1);
tu = (float)(0.5f + scaleFactor * (j - 1));
}
if (i == 0)
{
latitude = m_North;
tv = 0.0f;
}
else if (i == thisVertexDensityElevatedPlus3 - 1)
{
latitude = 0.5 * (m_North + m_South);
tv = 0.5f;
}
else
{
latitude = m_North - scaleFactor * latrange * (i - 1);
tv = (float)(scaleFactor * (i - 1));
}
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(latitude),
Angle.FromDegrees(longitude),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.neVerts[base_idx].X = v.X;
m_DynamicTexture.neVerts[base_idx].Y = v.Y;
m_DynamicTexture.neVerts[base_idx].Z = v.Z;
m_DynamicTexture.neVerts[base_idx].Tu = tu;
m_DynamicTexture.neVerts[base_idx].Tv = tv;
}
else
{
height = (float)m_HeightData[(i - 1), (j - 1) + (m_ParentWorldSurfaceRenderer.SamplesPerTile / 2)];
height *= World.Settings.VerticalExaggeration;
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(m_North - scaleFactor * latrange * (i - 1)),
Angle.FromDegrees(0.5f * (m_West + m_East) + (float)scaleFactor * lonrange * (j - 1)),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.neVerts[base_idx].X = v.X;
m_DynamicTexture.neVerts[base_idx].Y = v.Y;
m_DynamicTexture.neVerts[base_idx].Z = v.Z;
m_DynamicTexture.neVerts[base_idx].Tu = (float)(0.5f + scaleFactor * (j - 1));
m_DynamicTexture.neVerts[base_idx].Tv = (float)(scaleFactor * (i - 1));
}
base_idx += 1;
}
}
for (int i = 0; i < thisVertexDensityElevatedPlus3; i++)
{
base_idx = i * thisVertexDensityElevatedPlus3;
for (int j = 0; j < thisVertexDensityElevatedPlus3; j++)
{
float height = -30000;
if (i == 0 || j == 0 || i == thisVertexDensityElevatedPlus3 - 1 || j == thisVertexDensityElevatedPlus3 - 1)
{
double latitude = 0;
double longitude = 0;
float tu = 0.0f;
float tv = 0.0f;
if (j == 0)
{
longitude = m_West;
tu = 0.0f;
}
else if (j == thisVertexDensityElevatedPlus3 - 1)
{
longitude = 0.5 * (m_West + m_East);
tu = 0.5f;
}
else
{
longitude = m_West + (float)scaleFactor * lonrange * (j - 1);
tu = (float)(scaleFactor * (j - 1));
}
if (i == 0)
{
latitude = 0.5 * (m_North + m_South);
tv = 0.5f;
}
else if (i == thisVertexDensityElevatedPlus3 - 1)
{
latitude = m_South;
tv = 1.0f;
}
else
{
latitude = 0.5 * (m_North + m_South) - scaleFactor * latrange * (i - 1);
tv = (float)(0.5f * scaleFactor * (i - 1));
}
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(latitude),
Angle.FromDegrees(longitude),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.swVerts[base_idx].X = v.X;
m_DynamicTexture.swVerts[base_idx].Y = v.Y;
m_DynamicTexture.swVerts[base_idx].Z = v.Z;
m_DynamicTexture.swVerts[base_idx].Tu = tu;
m_DynamicTexture.swVerts[base_idx].Tv = tv;
}
else
{
height = (float)m_HeightData[m_ParentWorldSurfaceRenderer.SamplesPerTile / 2 + (i - 1), (j - 1)];
height *= World.Settings.VerticalExaggeration;
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(0.5 * (m_North + m_South) - scaleFactor * latrange * (i - 1)),
Angle.FromDegrees(m_West + (float)scaleFactor * lonrange * (j - 1)),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.swVerts[base_idx].X = v.X;
m_DynamicTexture.swVerts[base_idx].Y = v.Y;
m_DynamicTexture.swVerts[base_idx].Z = v.Z;
m_DynamicTexture.swVerts[base_idx].Tu = (float)(scaleFactor * (j - 1));
m_DynamicTexture.swVerts[base_idx].Tv = (float)(0.5f + scaleFactor * (i - 1));
}
base_idx += 1;
}
}
for (int i = 0; i < thisVertexDensityElevatedPlus3; i++)
{
base_idx = i * thisVertexDensityElevatedPlus3;
for (int j = 0; j < thisVertexDensityElevatedPlus3; j++)
{
float height = -30000;
if (i == 0 || j == 0 || i == thisVertexDensityElevatedPlus3 - 1 || j == thisVertexDensityElevatedPlus3 - 1)
{
double latitude = 0;
double longitude = 0;
float tu = 0.0f;
float tv = 0.0f;
if (j == 0)
{
longitude = 0.5 * (m_West + m_East);
tu = 0.5f;
}
else if (j == thisVertexDensityElevatedPlus3 - 1)
{
longitude = m_East;
tu = 1.0f;
}
else
{
longitude = 0.5 * (m_West + m_East) + (float)scaleFactor * lonrange * (j - 1);
tu = (float)(0.5f + scaleFactor * (j - 1));
}
if (i == 0)
{
latitude = 0.5 * (m_North + m_South);
tv = 0.5f;
}
else if (i == thisVertexDensityElevatedPlus3 - 1)
{
latitude = m_South;
tv = 1.0f;
}
else
{
latitude = 0.5 * (m_North + m_South) - scaleFactor * latrange * (i - 1);
tv = (float)(0.5f + scaleFactor * (i - 1));
}
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(latitude),
Angle.FromDegrees(longitude),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.seVerts[base_idx].X = v.X;
m_DynamicTexture.seVerts[base_idx].Y = v.Y;
m_DynamicTexture.seVerts[base_idx].Z = v.Z;
m_DynamicTexture.seVerts[base_idx].Tu = tu;
m_DynamicTexture.seVerts[base_idx].Tv = tv;
}
else
{
height = (float)m_HeightData[m_ParentWorldSurfaceRenderer.SamplesPerTile / 2 + (i - 1), (j - 1) + (m_ParentWorldSurfaceRenderer.SamplesPerTile / 2)];
height *= World.Settings.VerticalExaggeration;
Vector3 v = MathEngine.SphericalToCartesian(
Angle.FromDegrees(0.5 * (m_North + m_South) - scaleFactor * latrange * (i - 1)),
Angle.FromDegrees(0.5 * (m_West + m_East) + (float)scaleFactor * lonrange * (j - 1)),
m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius + m_ParentWorldSurfaceRenderer.DistanceAboveSeaLevel + height);
m_DynamicTexture.seVerts[base_idx].X = v.X;
m_DynamicTexture.seVerts[base_idx].Y = v.Y;
m_DynamicTexture.seVerts[base_idx].Z = v.Z;
m_DynamicTexture.seVerts[base_idx].Tu = (float)(0.5f + scaleFactor * (j - 1));
m_DynamicTexture.seVerts[base_idx].Tv = (float)(0.5f + scaleFactor * (i - 1));
}
base_idx += 1;
}
}
double equatoralRadius = m_ParentWorldSurfaceRenderer.ParentWorld.EquatorialRadius;
try
{
if (m_VerticalExaggeration != World.Settings.VerticalExaggeration)
{
// m_NwIndices = CreateTriangleIndicesBTT(m_DynamicTexture.nwVerts, (int)m_ParentWorldSurfaceRenderer.SamplesPerTile/2, 1, equatoralRadius);
// m_NeIndices = CreateTriangleIndicesBTT(m_DynamicTexture.neVerts, (int)m_ParentWorldSurfaceRenderer.SamplesPerTile/2, 1, equatoralRadius);
// m_SwIndices = CreateTriangleIndicesBTT(m_DynamicTexture.swVerts, (int)m_ParentWorldSurfaceRenderer.SamplesPerTile/2, 1, equatoralRadius);
// m_SeIndices = CreateTriangleIndicesBTT(m_DynamicTexture.seVerts, (int)m_ParentWorldSurfaceRenderer.SamplesPerTile/2, 1, equatoralRadius);
// calculate_normals(ref m_DynamicTexture.nwVerts, m_IndicesElevated);
// calculate_normals(ref m_DynamicTexture.neVerts, m_IndicesElevated);
// calculate_normals(ref m_DynamicTexture.swVerts, m_IndicesElevated);
// calculate_normals(ref m_DynamicTexture.seVerts, m_IndicesElevated);
m_VerticalExaggeration = World.Settings.VerticalExaggeration;
}
}
catch (Exception ex)
{
Log.Write(ex);
}
}
// Create indice list (PM)
private short[] CreateTriangleIndicesBTT(CustomVertex.PositionTextured[] ElevatedVertices, int VertexDensity, int Margin, double LayerRadius)
{
BinaryTriangleTree Tree = new BinaryTriangleTree(ElevatedVertices, VertexDensity, Margin, LayerRadius);
Tree.BuildTree(7); // variance 0 = best fit
Tree.BuildIndices();
return Tree.Indices;
}
private short[] CreateTriangleIndicesRegular(CustomVertex.PositionTextured[] ElevatedVertices, int VertexDensity, int Margin, double LayerRadius)
{
short[] indices;
int thisVertexDensityElevatedPlus2 = (VertexDensity + (Margin * 2));
indices = new short[2 * thisVertexDensityElevatedPlus2 * thisVertexDensityElevatedPlus2 * 3];
for (int i = 0; i < thisVertexDensityElevatedPlus2; i++)
{
int elevated_idx = (2 * 3 * i * thisVertexDensityElevatedPlus2);
for (int j = 0; j < thisVertexDensityElevatedPlus2; j++)
{
indices[elevated_idx] = (short)(i * (thisVertexDensityElevatedPlus2 + 1) + j);
indices[elevated_idx + 1] = (short)((i + 1) * (thisVertexDensityElevatedPlus2 + 1) + j);
indices[elevated_idx + 2] = (short)(i * (thisVertexDensityElevatedPlus2 + 1) + j + 1);
indices[elevated_idx + 3] = (short)(i * (thisVertexDensityElevatedPlus2 + 1) + j + 1);
indices[elevated_idx + 4] = (short)((i + 1) * (thisVertexDensityElevatedPlus2 + 1) + j);
indices[elevated_idx + 5] = (short)((i + 1) * (thisVertexDensityElevatedPlus2 + 1) + j + 1);
elevated_idx += 6;
}
}
return indices;
}
/// <summary>
/// Updates the specified draw args.
/// </summary>
/// <param name="drawArgs">Draw args.</param>
public void Update(DrawArgs drawArgs)
{
try
{
if (!m_Initialized)
Initialize(drawArgs);
float scaleFactor = 1f / (m_ParentWorldSurfaceRenderer.SamplesPerTile);
float latrange = (float)Math.Abs(m_North - m_South);
float lonrange = (float)Math.Abs(m_East - m_West);
int thisVertexDensityElevatedPlus3 = ((int)m_ParentWorldSurfaceRenderer.SamplesPerTile / 2 + 3);
scaleFactor = (float)1 / (m_ParentWorldSurfaceRenderer.SamplesPerTile);
latrange = (float)Math.Abs(m_North - m_South);
lonrange = (float)Math.Abs(m_East - m_West);
double centerLatitude = 0.5 * (m_North + m_South);
double centerLongitude = 0.5 * (m_East + m_West);
double tileSize = (m_North - m_South);
if (m_VerticalExaggeration != World.Settings.VerticalExaggeration)
{
// buildTerrainMesh();
}
if (drawArgs.WorldCamera.TrueViewRange < Angle.FromDegrees(3.0f * tileSize)
&& MathEngine.SphericalDistance(Angle.FromDegrees(centerLatitude), Angle.FromDegrees(centerLongitude),
drawArgs.WorldCamera.Latitude, drawArgs.WorldCamera.Longitude) < Angle.FromDegrees(2.9f * tileSize)
&& drawArgs.WorldCamera.ViewFrustum.Intersects(m_BoundingBox))
{
if (m_NorthWestChild == null || m_NorthEastChild == null || m_SouthWestChild == null || m_SouthEastChild == null)
{
ComputeChildrenTiles(drawArgs);
}
else
{
if (m_NorthEastChild != null)
{
m_NorthEastChild.Update(drawArgs);
}
if (m_NorthWestChild != null)
{
m_NorthWestChild.Update(drawArgs);
}
if (m_SouthEastChild != null)
{
m_SouthEastChild.Update(drawArgs);
}
if (m_SouthWestChild != null)
{
m_SouthWestChild.Update(drawArgs);
}
}
}
else
{
if (m_NorthWestChild != null)
{
m_NorthWestChild.Dispose();
m_NorthWestChild = null;
}
if (m_NorthEastChild != null)
{
m_NorthEastChild.Dispose();
m_NorthEastChild = null;
}
if (m_SouthEastChild != null)
{
m_SouthEastChild.Dispose();
m_SouthEastChild = null;
}
if (m_SouthWestChild != null)
{
m_SouthWestChild.Dispose();
m_SouthWestChild = null;
}
}
}
catch (System.Threading.ThreadAbortException)
{
}
catch (Exception ex)
{
Log.Write(ex);
}
}
/// <summary>
/// Disposes this instance. Releases any resources from the graphics device, also disposes of "child" surface tiles.
/// </summary>
public void Dispose()
{
m_Initialized = false;
m_BoundingBox = null;
if (m_Device != null)
{
m_Device.DeviceReset -= new EventHandler(OnDeviceReset);
m_Device.Disposing -= new EventHandler(OnDeviceDispose);
OnDeviceDispose(m_Device, null);
}
if (m_NorthWestChild != null)
{
m_NorthWestChild.Dispose();
m_NorthWestChild = null;
}
if (m_NorthEastChild != null)
{
m_NorthEastChild.Dispose();
m_NorthEastChild = null;
}
if (m_SouthWestChild != null)
{
m_SouthWestChild.Dispose();
m_SouthWestChild = null;
}
if (m_SouthEastChild != null)
{
m_SouthEastChild.Dispose();
m_SouthEastChild = null;
}
}
private void calculate_normals(ref CustomVertex.PositionNormalTextured[] vertices, short[] indices)
{
System.Collections.ArrayList[] normal_buffer = new System.Collections.ArrayList[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
normal_buffer[i] = new System.Collections.ArrayList();
}
for (int i = 0; i < m_IndicesElevated.Length; i += 3)
{
Vector3 p1 = vertices[indices[i + 0]].Position;
Vector3 p2 = vertices[indices[i + 1]].Position;
Vector3 p3 = vertices[indices[i + 2]].Position;
Vector3 v1 = p2 - p1;
Vector3 v2 = p3 - p1;
Vector3 normal = Vector3.Cross(v1, v2);
normal.Normalize();
// Store the face's normal for each of the vertices that make up the face.
normal_buffer[indices[i + 0]].Add(normal);
normal_buffer[indices[i + 1]].Add(normal);
normal_buffer[indices[i + 2]].Add(normal);
}
// Now loop through each vertex vector, and avarage out all the normals stored.
for (int i = 0; i < vertices.Length; ++i)
{
for (int j = 0; j < normal_buffer[i].Count; ++j)
{
Vector3 curNormal = (Vector3)normal_buffer[i][j];
if (vertices[i].Normal == Vector3.Empty)
vertices[i].Normal = curNormal;
else
vertices[i].Normal += curNormal;
}
vertices[i].Normal.Multiply(1.0f / normal_buffer[i].Count);
}
}
/// <summary>
/// Determines whether this surface tile is renderable.
/// </summary>
/// <param name="drawArgs">Draw args.</param>
/// <returns>
/// <c>true</c> if the surface tile is renderable; otherwise, <c>false</c>.
/// </returns>
public bool IsRenderable(DrawArgs drawArgs)
{
double _centerLat = 0.5 * (m_North + m_South);
double _centerLon = 0.5 * (m_East + m_West);
double m_DynamicTextureSize = (m_North - m_South);
if (!m_Initialized ||
drawArgs.WorldCamera.TrueViewRange / 2 > Angle.FromDegrees(3.0 * m_DynamicTextureSize * 1.5f) ||
MathEngine.SphericalDistance(Angle.FromDegrees(_centerLat), Angle.FromDegrees(_centerLon),
drawArgs.WorldCamera.Latitude, drawArgs.WorldCamera.Longitude) > Angle.FromDegrees(3.0 * m_DynamicTextureSize * 1.5f) ||
m_BoundingBox == null ||
!drawArgs.WorldCamera.ViewFrustum.Intersects(m_BoundingBox) ||
m_DynamicTexture == null //||
//m_RenderTexture == null ||
//m_RenderTexture.Disposed
)
{
// if(m_Level == 0)
// {
// return true;
// }
// else
// {
return false;
// }
}
else
{
return true;
}
}
private bool checkSurfaceImageChange()
{
//TODO: Make this smart enough to check only *this* surface tile
if (m_ParentWorldSurfaceRenderer.LastChange > m_LastUpdate)
{
return true;
}
lock (m_ParentWorldSurfaceRenderer.SurfaceImages.SyncRoot)
{
for (int i = 0; i < m_ParentWorldSurfaceRenderer.SurfaceImages.Count; i++)
{
SurfaceImage currentSurfaceImage = m_ParentWorldSurfaceRenderer.SurfaceImages[i] as SurfaceImage;
if (currentSurfaceImage.LastUpdate > m_LastUpdate || currentSurfaceImage.Opacity != currentSurfaceImage.ParentRenderable.Opacity)
{
if (currentSurfaceImage == null ||
currentSurfaceImage.ImageTexture == null ||
currentSurfaceImage.ImageTexture.Disposed ||
!currentSurfaceImage.Enabled ||
(currentSurfaceImage.North > m_North && currentSurfaceImage.South >= m_North) ||
(currentSurfaceImage.North <= m_South && currentSurfaceImage.South < m_South) ||
(currentSurfaceImage.West < m_West && currentSurfaceImage.East <= m_West) ||
(currentSurfaceImage.West >= m_East && currentSurfaceImage.East > m_East)
)
{
continue;
}
else
{
return true;
}
}
else
{
continue;
}
}
}
return false;
}
int m_FramesSinceLastUpdate = 0;
public static int SurfaceTileRefreshHz = 35;
/// <summary>
/// Renders the surface tile.
/// </summary>
/// <param name="drawArgs">Draw args.</param>
public void Render(DrawArgs drawArgs)
{
try
{
if (!IsRenderable(drawArgs))
{
if (m_RenderTexture != null)
{
return;
}
}
bool nwRendered = false;
bool neRendered = false;
bool swRendered = false;
bool seRendered = false;
if (m_NorthWestChild != null &&
m_NorthWestChild.m_Initialized &&
m_NorthWestChild.IsRenderable(drawArgs))
{
if (m_NorthWestChild.RenderTexture != null ||
(m_NorthWestChild.RenderTexture == null && this.m_ParentWorldSurfaceRenderer.NumberTilesUpdated < 2))
{
m_NorthWestChild.Render(drawArgs);
nwRendered = true;
}
}
if (m_NorthEastChild != null &&
m_NorthEastChild.m_Initialized &&
m_NorthEastChild.IsRenderable(drawArgs))
{
if (m_NorthEastChild.RenderTexture != null ||
(m_NorthEastChild.RenderTexture == null && this.m_ParentWorldSurfaceRenderer.NumberTilesUpdated < 2))
{
m_NorthEastChild.Render(drawArgs);
neRendered = true;
}
}
if (m_SouthWestChild != null &&
m_SouthWestChild.m_Initialized &&
m_SouthWestChild.IsRenderable(drawArgs))
{
if (m_SouthWestChild.RenderTexture != null ||
(m_SouthWestChild.RenderTexture == null && this.m_ParentWorldSurfaceRenderer.NumberTilesUpdated < 2))
{
m_SouthWestChild.Render(drawArgs);
swRendered = true;
}
}
if (m_SouthEastChild != null && m_SouthEastChild.m_Initialized && m_SouthEastChild.IsRenderable(drawArgs))
{
if (m_SouthEastChild.RenderTexture != null ||
(m_SouthEastChild.RenderTexture == null && this.m_ParentWorldSurfaceRenderer.NumberTilesUpdated < 2))
{
m_SouthEastChild.Render(drawArgs);
seRendered = true;
}
}
if (nwRendered && neRendered && swRendered && seRendered)
return;
if (m_RenderTexture == null || m_RequiresUpdate || checkSurfaceImageChange() || m_FramesSinceLastUpdate++ > SurfaceTileRefreshHz)
{
drawArgs.device.EndScene();
UpdateRenderSurface(drawArgs);
drawArgs.device.BeginScene();
m_FramesSinceLastUpdate = 0;
m_ParentWorldSurfaceRenderer.NumberTilesUpdated++;
}
if (m_RenderTexture == null)
return;
drawArgs.device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
drawArgs.device.TextureState[0].AlphaOperation = TextureOperation.SelectArg1;
drawArgs.device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
drawArgs.device.TextureState[0].ColorOperation = TextureOperation.SelectArg1;
drawArgs.device.TextureState[1].ColorOperation = TextureOperation.Disable;
drawArgs.device.TextureState[1].AlphaOperation = TextureOperation.Disable;
drawArgs.device.RenderState.ZBufferEnable = true;
drawArgs.device.SetTexture(0, m_RenderTexture);
drawArgs.device.SamplerState[0].MinFilter = TextureFilter.Linear;
drawArgs.device.SamplerState[0].MagFilter = TextureFilter.Linear;
drawArgs.device.SamplerState[0].AddressU = TextureAddress.Clamp;
drawArgs.device.SamplerState[0].AddressV = TextureAddress.Clamp;
if (!nwRendered && m_DynamicTexture.nwVerts != null)
{
drawArgs.device.DrawIndexedUserPrimitives(
PrimitiveType.TriangleList,
0,
m_DynamicTexture.nwVerts.Length,
(m_NwIndices != null ? m_NwIndices.Length / 3 : m_IndicesElevated.Length / 3),
(m_NwIndices != null ? m_NwIndices : m_IndicesElevated),
true,
m_DynamicTexture.nwVerts);
}
if (!neRendered && m_DynamicTexture.neVerts != null)
{
drawArgs.device.DrawIndexedUserPrimitives(
PrimitiveType.TriangleList,
0,
m_DynamicTexture.neVerts.Length,
(m_NeIndices != null ? m_NeIndices.Length / 3 : m_IndicesElevated.Length / 3),
(m_NeIndices != null ? m_NeIndices : m_IndicesElevated),
true,
m_DynamicTexture.neVerts);
}
if (!swRendered && m_DynamicTexture.swVerts != null)
{
drawArgs.device.DrawIndexedUserPrimitives(
PrimitiveType.TriangleList,
0,
m_DynamicTexture.nwVerts.Length,
(m_SwIndices != null ? m_SwIndices.Length / 3 : m_IndicesElevated.Length / 3),
(m_SwIndices != null ? m_SwIndices : m_IndicesElevated),
true,
m_DynamicTexture.swVerts);
}
if (!seRendered && m_DynamicTexture.seVerts != null)
{
drawArgs.device.DrawIndexedUserPrimitives(
PrimitiveType.TriangleList,
0,
m_DynamicTexture.seVerts.Length,
(m_SeIndices != null ? m_SeIndices.Length / 3 : m_IndicesElevated.Length / 3),
(m_SeIndices != null ? m_SeIndices : m_IndicesElevated),
true,
m_DynamicTexture.seVerts);
}
}
catch (System.Threading.ThreadAbortException)
{
}
catch (Exception ex)
{
//TODO: Remove this
Log.Write(ex);
}
}
}
class DynamicTexture : System.IDisposable
{
public CustomVertex.PositionNormalTextured[] nwVerts;
public CustomVertex.PositionNormalTextured[] neVerts;
public CustomVertex.PositionNormalTextured[] swVerts;
public CustomVertex.PositionNormalTextured[] seVerts;
public DynamicTexture()
{
}
#region IDisposable Members
public void Dispose()
{
}
#endregion
}
1.2 SurfaceImage
表面图片有图片路径、纹理对象、四角点坐标等属性,类图如下所示:
主要函数:
1、构造函数
public SurfaceImage(
string imageFilePath,
double north,
double south,
double west,
double east,
Texture texture,
WorldWind.Renderable.RenderableObject parentRenderable)
2、public Vector2 GetTextureCoordinate(double latitude, double longitude) 根据经纬度返回纹理坐标。
二、ProjectedVectorRenderer
投影矢量渲染器类图如下所示:
投影矢量渲染器类在两种 RenderableObject 可渲染对象中应用。在 LineFeature 类的 UpdateTexturedVertices() 函数中将LineString 对象、 PolygonFeature 类的 UpdateVertices()函数中将 Polygon对象添加到m_lineStrings和m_polygons数组。
主要成员:
ProjectedVectorTile[] m_rootTiles = null; //0层瓦片数组
double m_lzts = 36.0; //0层瓦片的大小
public bool EnableCaching = false;
public World World = null;
public System.Drawing.Size TileSize = new System.Drawing.Size(256, 256);
System.Collections.ArrayList m_polygons = new System.Collections.ArrayList();
System.Collections.ArrayList m_lineStrings = new System.Collections.ArrayList();
public System.DateTime LastUpdate = System.DateTime.Now;
默认情况下,0层瓦片36度,瓦片大小为256*256。0层瓦片数组m_rootTiles。
主要函数:
private void UpdateRootTiles():在构造函数里调用。创建和更新0层瓦片数组。创建一个ProjectedVectorTile 矢量瓦片对象,设置瓦片的经纬度范围、层级、所在行和列,添加到m_rootTiles数组中。创建瓦片时并未对瓦片进行初始化。
public void Add(LineString lineString), public void Add(Polygon polygon):将线、多边形对象添加到数组中。
private static bool IsRenderableVisible(WorldWind.Renderable.RenderableObject renderable):私有静态成员函数,判断一个可渲染对象是否可见。
public void Update(DrawArgs drawArgs):更新线、多边形图元数组的状态,调用m_rootTiles的Update函数,更新每个瓦片的状态。
public void Render(DrawArgs drawArgs):调用m_rootTiles的Render函数,渲染每个瓦片。
1.1 ProjectedVectorTile
投影矢量瓦片类图如下所示:
主要属性:
public static string CachePath ; //瓦片缓存目录
bool m_Initialized = false;
bool m_Initializing = false;
bool m_Disposing = false;
public int Level = 0; //瓦片所在层级
public int Row = 0;
public int Col = 0;
ProjectedVectorRenderer m_parentProjectedLayer = null; //渲染器父对象
每个瓦片有四个上层瓦片ProjectedVectorTile 的子节点 ,以及四个子节点对应的可渲染图像层ImageLayer对象,按方位(东南西北)进行命名。
Renderable.ImageLayer m_NwImageLayer;
Renderable.ImageLayer m_NeImageLayer;
Renderable.ImageLayer m_SwImageLayer;
Renderable.ImageLayer m_SeImageLayer;
ProjectedVectorTile m_NorthWestChild;
ProjectedVectorTile m_NorthEastChild;
ProjectedVectorTile m_SouthWestChild;
ProjectedVectorTile m_SouthEastChild;
瓦片的覆盖范围属性:
public GeographicBoundingBox m_geographicBoundingBox = null; //经纬度范围
public BoundingBox BoundingBox; //瓦片在三维中的包围盒
主要方法:
1、 public ProjectedVectorTile( GeographicBoundingBox geographicBoundingBox, ProjectedVectorRenderer parentLayer ):构造函数,创建了瓦片的包围盒BoundingBox对象。
2、public void Initialize(DrawArgs drawArgs):初始化矢量瓦片对象,主要调用UpdateImageLayers更新四个ImageLayer图层对象。
3、private void UpdateImageLayers(DrawArgs drawArgs):调用CreateImageLayer 创建四个ImageLayer图层对象,并进行初始化。
4、 private Renderable.ImageLayer CreateImageLayer(double north, double south, double west, double east, DrawArgs drawArgs, string imagePath):创建一个ImageLayer可渲染对象,imagePath为图片路径(dds格式),如果不能缓存,或者路径对应的文件不存在,则在内存中绘制,生成图片。分别绘制m_parentProjectedLayer 父对象中的线、多边形两个数组对象中与当前瓦片范围有相交区域的对象。所有的线和多边形在父类对象中。线形使用drawLineString绘制,多边形使用drawPolygon绘制。如果绘制的内容不为空,则生成一个ImageLayer对象。
5、private void drawLineString(LineString lineString, Graphics g, GeographicBoundingBox dstBB, Size imageSize):使用gdi+的DrawLines函数在内存中绘制直线。
6、private void drawPolygon(Polygon polygon, Graphics g, GeographicBoundingBox dstBB, Size imageSize):使用gdi+的FillPolygon绘制填充多边形,使用DrawPolygon绘制线框。
7、private System.Drawing.Point[] getScreenPoints(Point3d[] sourcePoints, int offset, int length, GeographicBoundingBox dstBB, Size dstImageSize):将点数组的坐标由经纬度坐标转换到图片中的屏幕坐标。
8、public virtual void ComputeChildren(DrawArgs drawArgs):生成四个上层子节点对象,并完成初始化。
9、private ProjectedVectorTile ComputeChild(DrawArgs drawArgs, double childSouth, double childNorth, double childWest, double childEast, double tileSize):生成一个上层子节点对象。
10、 public void Update(DrawArgs drawArgs):更新投影瓦片的参数,调用UpdateImageLayers生成和初始化四个图像层对象,然后调用每个图像层对象的update函数进行更新。调用四个孩子节点的update函数,更新子节点对象。
11、public void Render(DrawArgs drawArgs):渲染投影瓦片,实际是渲染四个子节点,如果子节点已创建并初始化,则调用它的Render函数,否则渲染对应的图像层对象。
12、protected virtual void CreateMesh(GeographicBoundingBox geographicBoundingBox, int meshPointCount, ref CustomVertex.PositionColoredTextured[] vertices, ref short[] indices):创建瓦片的mesh使用的顶点和索引数组。目前,函数没有使用。
13、public static System.Drawing.Drawing2D.HatchStyle getGDIHatchStyle(WorldWind.ShapeFillStyle shapeFillStyle):根据shape文件填充样式,返回对应的GDI填充样。
1.2 Polygon
多边形对象Polygon是可渲染类PolygonFeature的组成部分,表示一个多边形(可以带孔)。
public LinearRing outerBoundary = null;
public LinearRing[] innerBoundaries = null;
public Color PolgonColor = Color.Red;
public Color OutlineColor = Color.Black;
public float LineWidth = 1.0f;
public bool Outline = true;
public bool Fill = true;
public bool Visible = true;
public bool Remove = false;
public WorldWind.Renderable.RenderableObject ParentRenderable = null;
public class LinearRing
{
public Point3d[] Points = null;
}
public GeographicBoundingBox GetGeographicBoundingBox():返回多边形对象的经纬度范围。
1.3 LineString
线形对象LineString是可渲染类LineFeature的组成部分,表示了一系列的点构成的线形图。
public Point3d[] Coordinates = null;
public Color Color = Color.Yellow;
public float LineWidth = 1.0f;
public bool Visible = true;
public bool Remove = false;
public RenderableObject ParentRenderable = null;
public GeographicBoundingBox GetGeographicBoundingBox():返回线形对象的经纬度范围。