[WorldWind学习]17.视域调度(视域体裁剪)

视域调度(视域体裁剪)

  在WW中用户改变自己的的视角,纹理影像和高程会动态加载,在视野范围内的影像和DEM显示,超出视域范围的瓦片则不显示。不仅是瓦片,太阳、大气网格、三维模型ModelFeature等都会相应的进行剔除。

  看了ROAM相关的的视域体裁剪论文,有好多采用的是将视域体投影的简化算法。WW是否也是这样?我原来以为是,后来在群里和别人聊,说到了Frustum,才知道这个东西的作用。

  这里涉及的类主要是World_Wind_1.4.0_Source\PluginSDK\ViewFrustum.cs文件中的Frustum类。

  查看Frustum类,包含公有字段public Plane[] planes = new Plane[6];可以知道WW的视域裁剪采用的是六面体来实现的。

  1 using System;

  2 using Microsoft.DirectX;

  3 using Microsoft.DirectX.Direct3D;

  4 

  5 namespace WorldWind

  6 {

  7     /// <summary>

  8     /// The region of space in the modeled world that may appear on the screen; it is the field of view of the notional camera.

  9     /// Used to perform culling of invisible object (prior to rendering) to increase speed.

 10     /// See: http://en.wikipedia.org/wiki/Viewing_frustum

 11     /// </summary>

 12     public class Frustum

 13     {

 14         public Plane[] planes = new Plane[6];

 15 

 16         public void Update(Matrix m)

 17         {

 18             //bottom (down) plane

 19             this.planes[0] = new Plane(

 20                 m.M14 + m.M12, //a

 21                 m.M24 + m.M22, //b

 22                 m.M34 + m.M32, //c

 23                 m.M44 + m.M42 //d

 24                 );

 25             

 26             //far plane

 27             this.planes[1] = new Plane(

 28                 m.M14 - m.M13,

 29                 m.M24 - m.M23,

 30                 m.M34 - m.M33,

 31                 m.M44 - m.M43

 32                 );

 33 

 34             //right side plane

 35             this.planes[2] = new Plane(

 36                 m.M14 - m.M11, //a

 37                 m.M24 - m.M21, //b

 38                 m.M34 - m.M31, //c

 39                 m.M44 - m.M41 //d

 40                 );

 41 

 42             //left side plane

 43             this.planes[3] = new Plane(

 44                 m.M14 + m.M11,    //a

 45                 m.M24 + m.M21,    //b

 46                 m.M34 + m.M31,    //c

 47                 m.M44 + m.M41    //d

 48                 );

 49 

 50             //near plane

 51             this.planes[4] = new Plane(

 52                 m.M13,

 53                 m.M23,

 54                 m.M33,

 55                 m.M43);

 56 

 57             //top (up) plane

 58             this.planes[5] = new Plane(

 59                 m.M14 - m.M12, //a

 60                 m.M24 - m.M22, //b

 61                 m.M34 - m.M32, //c

 62                 m.M44 - m.M42 //d

 63                 );

 64 

 65             foreach(Plane p in this.planes)

 66                 p.Normalize();

 67         }

 68 

 69         /// <summary>

 70         /// Test if a sphere intersects or is completely inside the frustum.

 71         /// </summary>

 72         /// <returns>true when the sphere intersects.</returns>

 73         public bool Intersects(BoundingSphere c)

 74         {

 75             foreach(Plane p in this.planes)

 76             {

 77                 float distancePlaneToPoint = p.A * c.Center.X + p.B * c.Center.Y + p.C * c.Center.Z + p.D;

 78                 if(distancePlaneToPoint < -c.Radius)

 79                     // More than 1 radius outside the plane = outside

 80                     return false;

 81             }

 82 

 83             //else it's in view

 84             return true;

 85         }

 86 

 87         /// <summary>

 88         /// Test if a point is inside the frustum.

 89         /// </summary>

 90         /// <returns>true when the point is inside.</returns>

 91         /// <param name="v">XYZ in world coordinates of the point to test.</param>

 92         public bool ContainsPoint(Vector3 v)

 93         {

 94             foreach(Plane p in this.planes)

 95                 if(Vector3.Dot(new Vector3(p.A, p.B, p.C), v) + p.D < 0)

 96                     return false;

 97 

 98             return true;

 99         }

100 

101         /// <summary>

102         /// Tests if the view frustum fully contains the bounding box.

103         /// </summary>

104         /// <returns>true when the box is complete enclosed by the frustum.</returns>

105         public bool Contains(BoundingBox bb)

106         {

107             //Code taken from Flip Code Article:

108             // http://www.flipcode.com/articles/article_frustumculling.shtml

109             int iTotalIn = 0;

110             foreach(Plane p in this.planes)

111             {

112                 int iInCount = 8;

113                 int iPtIn = 1;

114                 // TODO: Modify bounding box and only check 2 corners.

115                 for(int i = 0; i < 8; i++)

116                 {

117                     if(Vector3.Dot(new Vector3(p.A,p.B,p.C), bb.corners[i]) + p.D < 0)

118                     {

119                         iPtIn = 0;

120                         --iInCount;

121                     }

122                 }

123 

124                 if(iInCount == 0)

125                     return false;

126 

127                 iTotalIn += iPtIn;

128             }

129 

130             if(iTotalIn == 6)

131                 return true;

132 

133             return false;

134         }

135 

136         /// <summary>

137         /// Tests if the bounding box specified intersects with or is fully contained in the frustum.

138         /// </summary>

139         /// <returns>true when the box intersects with the frustum.</returns>

140         public bool Intersects(BoundingBox bb)

141         {

142             foreach(Plane p in this.planes)

143             {

144                 Vector3 v = new Vector3(p.A,p.B,p.C);

145                 bool isInside = false;

146                 // TODO: Modify bounding box and only check 2 corners.

147                 for(int i = 0; i < 8; i++)

148                 {

149                     if(Vector3.Dot(v, bb.corners[i]) + p.D >= 0)

150                     {

151                         isInside = true;

152                         break;

153                     }

154                 }

155 

156                 if(!isInside)

157                     return false;

158             }

159 

160             return true;

161         }

162     

163         public override string ToString()

164         {

165             string res = string.Format("Near:\n{0}Far:\n{1}", planes[4], planes[1] );

166             return res;

167         }

168     }

169 }

该类实现的方法主要包括下面5个,后面四个主要是进行相交检测和包含检测:

public void Update(Matrix m);

public bool Intersects(BoundingSphere c);

public bool ContainsPoint(Vector3 v);

public bool Contains(BoundingBox bb);

public bool Intersects(BoundingBox bb);

调用了Frustum对象的类其实不多,不过Frustum的重要程度和CameraBase捆绑在一起。

  QuadTileSet类中的调用方式主要是通过调用camera.ViewFrustum来获取并进行相关的判断。在QuadTileSet中总共有3处地方可以查见camera.ViewFrustum,一个是在Update方法中,一个是在GetClosestDownloadRequest,还有一个是在ResetCacheForCurrentView方法中。

  QuadTile类中调用方式通过调用camera.ViewFrustum实现,主要在在Update方法中和Render方法中。

你可能感兴趣的:(学习)