AGI Components with Insight3D Alpha 2008 r8
Surface Mesh Primitive

The surface mesh is similar to the triangle mesh, but it only renders meshes on the surface of a globe. Arbitrary mesh or meshes at altitude cannot be rendered with the surface mesh. The main advantage of the surface mesh over the triangle mesh is it will conform to terrain as shown below.

In addition to conforming to terrain, the surface mesh can have a texture applied to it as shown below.

Given the advantages of the surface mesh, you may wonder why you would ever use the generic triangle mesh to render meshes on the surface. There are two reasons.

  • The surface mesh requires a video card and drivers that support OpenGL 2.0. This has been available since 2004 but you may still want to call AgGxPrimitiveSurfaceMesh.Supported before assuming the surface mesh is supported.
  • Performance. Although the surface mesh is highly optimized, including use of geometry shaders when ran on Shader Model 4 video cards, it is still slower then the triangle mesh. Early alpha performance tests showed the triangle mesh to be 55-75% faster then the surface mesh on a GeForce 8800 GTX.
The following example from the HowTo adds terrain to the globe then creates a surface mesh representing the 925 zip code that conforms to the terrain.
CopyC#
IAgGxCentralBody earth = sceneManager.CentralBodies("Earth");
IAgGxGlobeInlay inlay = scene.GlobeInlayManager.AddURI(earth,
    Program.uriLocalDataPath + "TerrainAndImagery/925.pdtt",
    AgGxInlayRole.InlayRoleNormal,
    true);

Array pointsAry = STKUtil.ReadAreaTargetPoints(Program.localDataPath + "AreaTargets/925.at");

IAgGxTriangulatorSurfacePolygon triangles = new AgGxTriangulatorSurfacePolygon();
triangles.Initialize(earth, ref pointsAry);

IAgGxPrimitiveSurfaceMesh mesh = new AgGxPrimitiveSurfaceMesh();
mesh.InitializeFromTriangulator(earth, 
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    triangles, null);
mesh.Color = (uint)ColorTranslator.ToOle(Color.Purple);
sceneManager.Primitives.Add(mesh);

The following example from the HowTo shows how to apply a texture to a surface mesh.

CopyC#
IAgGxConstantExtent extent = inlay.Extent;
double deltaLatitude = (extent.North - extent.South) * 0.2;
double deltaLongitude = (extent.East - extent.West) * 0.2;
IAgGxTriangulatorSurfaceExtent triangles = new AgGxTriangulatorSurfaceExtent();
triangles.Initialize(earth, 
    extent.West + deltaLongitude,
    extent.South + deltaLatitude,
    extent.East - deltaLongitude,
    extent.North - deltaLatitude);

IAgGxRendererTexture2D texture = sceneManager.Textures.LoadFromURI(Program.uriLocalDataPath + "Markers/originalLogo.png");
IAgGxPrimitiveSurfaceMesh mesh = new AgGxPrimitiveSurfaceMesh();
mesh.InitializeFromTriangulator(earth,
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    triangles, texture);
mesh.Translucency = 30;
sceneManager.Primitives.Add(mesh);

The extent triangulator is used to compute a mesh on the surface. As shown in the previous two examples, both the extent and polygon triangulator can be input to the surface mesh. The wall triangulator cannot be input since it does not provide meshes on the surface. A texture is created, in the same way it is created for markers, and passed along with the triangulator to initialize the surface mesh. The texture in this example has an alpha channel, which is why the entire extent is not filled.

The surface mesh provides SetFromTriangulator to allow dynamic updates.

Texture Matrix (Advanced)

When a texture is applied to a surface mesh, the texture is aligned north and encompasses the bounding extent of the surface mesh. It is possible to scale, translate, and rotate the texture using a texture matrix. Performing transformations, like these, over time can create effects such as water movement.

When a surface mesh is rendered, texels in the texture are mapped to pixels on the screen. Texture coordinates are used to lookup a texel. The texture lies on a plane between zero and one in the u and v direction (assuming the texture's width and height are powers of two) as shown below.

This is texture space. The texture repeats for values outside [0, 1]. The 2D texture coordinates, u and v, used to lookup a texel are multiplied by the 3x3 texture matrix before a lookup. Modifying this matrix changes the way texels are mapped to pixels.

The upper left 2x2 matrix is used for scaling and rotation. The upper right two elements are used for translation. When going through the following examples, you my find it helpful to refer to the texture space image.

By default, the texture matrix is the identity matrix; the u and v coordinates are not changed when multiplied by the matrix.

CopyC#
mesh.SetTextureMatrix(
    1, 0, 0,
    0, 1, 0,
    0, 0, 1);

Use a scaling matrix to tile the texture. The first example below scales textures coordinates so they fall within [0, 2] so 4 copies of the texture are rendered. In the second example, the texture coordinates only range within [0.5, 0.5] so only a quarter of the texture is rendered.

CopyC#
mesh.SetTextureMatrix(
    2, 0, 0,
    0, 2, 0,
    0, 0, 1);

CopyC#
mesh.SetTextureMatrix(
    0.5, 0, 0,
    0, 0.5, 0,
    0, 0, 1);

The following example constructs a translation matrix so texture coordinates will fall within [0.5, 1.5]. Translation can be used to create texture animation effects.

CopyC#
mesh.SetTextureMatrix(
    1, 0, 0.5,
    0, 1, 0.5,
    0, 0, 1);

The following example constructs a rotation matrix to rotate texture coordinates 30 degrees from north.

CopyC#
double theta = Trig.DegreesToRadians(30);
double cosTheta = Math.Cos(theta);
double sinTheta = Math.Sin(theta);

mesh.SetTextureMatrix(
    cosTheta, sinTheta, 0,
    -sinTheta, cosTheta, 0,
    0, 0, 1);

This final example first translates [-0.5, -0.5], then rotates 30 degrees, and finally translates [0.5, 0.5]. This has the effect of rotating around the center of the texture. This matrix was computed by post-multiplying a translation matrix by a rotation/translation matrix.

CopyC#
double theta = Trig.DegreesToRadians(30);
double cosTheta = Math.Cos(theta);
double sinTheta = Math.Sin(theta);
double translateU = -(0.5 * cosTheta) + -(0.5 * sinTheta) + 0.5;
double translateV = (0.5 * sinTheta) + -(0.5 * cosTheta) + 0.5;

mesh.SetTextureMatrix(
    cosTheta, sinTheta, translateU,
    -sinTheta, cosTheta, translateV,
    0, 0, 1);

To avoid the texture repeating, as seen in the lower left corner of the above screen shot, make a boundary around the image when it is created. In the future, the surface mesh will provide a texture filter that can be used to avoid modifying the source image itself.