Mesh Construction

<< Click to Display Table of Contents >>

Navigation:  XStream® HDVR® SDK > Advanced Functionality > 3D Polygon Meshes >

Mesh Construction

Previous pageReturn to chapter overviewNext page

C++ C++ Java Java .NET .NET

Summary

 

The XStream® HDVR® SDK allows polygon based mesh objects to be dynamically constructed at runtime, using utility functions in the C++ based IVertexCallListContext or the Java/.NET based hdrcVertexCallListContext class. This class supports triangular polygons and line based objects only. Each vertex in the object must have a coordinate, normal vector, RGB color, and shading state applied. Texture mapping data is also supported, as described in the Texture Mapping section. Additionally, a vertex index list may also be specified as in the example below.

 

Creating the Vertex Call List

 

In C++, a polygon object is created using the IServerContext::CreateVertexCallList() method.

 

IVertexCallListContext *pVertexCallList;

pServer->CreateVertexCallList(&pVertexCallList);

 

In Java/.NET, a polygon object is created using the hdrcServerContext.createVertexCallList() method.

 

hdrcVertexCallListContext vertexCallList;

vertexCallList = serverContext->createVertexCallList();

 

Setting the Vertex Count

 

In C++, the next step is to set the number of vertices that make up the object. IVertexCallListContext::SetNumVertices() will then allocate memory for the arrays making up the vertices, normal vectors, colors, texture coordinates, and shading state.

 

pVertexCallList->SetNumVertices( vertexCount );

 

In Java/.NET, the next step is to set the number of vertices that make up the object. hdrcVertexCallListContext.setNumVertices() will then to allocate memory for the arrays making up the vertices, normal vectors, colors, texture coordinates, and shading state.

 

vertexCallList.setNumVertices(vertexCount);

 

Setting Vertex Data

 

Once the vertex count is set, the geometry data in the array may be modified.

 

In C++, this is done with various Get/Set functions such as IVertexCallListContext::GetVertices(), IVertexCallListContext::GetNormals(), IVertexCallListContext::GetIndices, etc. After each data array has been modified, the corresponding Set(type)Modified methods are called, such as IVertexCallListContext::SetVerticesModified(), IVertexCallListContext::SetNormalsModified(), IVertexCallListContext::SetIndicesModified(), etc. The Set(type)Modified methods take as input parameters the range of values in the array that have been changed. The range of values is inclusive of the starting value and exclusive of the ending value. For example, if the array has 10 elements and all have been modified, the starting value is 0 and the ending value is 10.

 

// Get the number of vertices in this object

unsigned int vertexCount;

pVertexCallList->GetNumVertices(&vertexCount);

 

// This vertex call list is made of triangles (3 vertices per triangle only).

pVertexCallList->SetType(VCL_TYPE_TRIANGLES);

 

// Set vertex data for this object

VECTOR3D *pVertices = NULL;

pVertexCallList->GetVertices(&pVertices);

for(int i = 0; i < vertexCount; i++) {

    pVertices[i].x = 0;

    pVertices[i].y = 0;

    pVertices[i].z = 0;

}

pVertexCallList->SetVerticesModified(true, 0, vertexCount);

 

// Set vertex normal values.

// Normal vectors must be of unit length (use normalize function if necessary).

VECTOR3D *pNormals = NULL;

pVertexCallList->GetNormals(&pNormals);

for(int i = 0; i < vertexCount; i++) {

    pNormals[i].x = 0;

    pNormals[i].y = 1;

    pNormals[i].z = 0;

    pNormals[i].normalize();

}

pVertexCallList->SetNormalsModified(true, 0, vertexCount);

 

// Set vertex color values. 

// Color components are in the range of 0 to 255.

COLOR_RGBA *pColors = NULL;

pVertexCallList->GetColors(&pColors);

for(int i = 0; i < vertexCount; i++) {

   pColors[i].r = 0;

   pColors[i].g = 128;

   pColors[i].b = 255;

   pColors[i].a = 128;

}

pVertexCallList->SetColorsModified(true, 0, vertexCount);

 

// Set shading flags. 

// This flag determines if shading is to be applied to this vertex

h_uint8 *pShading = NULL;

pVertexCallList->GetShadingEnabled(&pShading);

for(int i = 0; i < vertexCount; i++) {

   pShading[i] = H_TRUE;

}

pVertexCallList->SetShadingEnabledModified(true, 0, vertexCount);

 

// Set texture mapping UV coordinates. 

// Texture UV coordinates are in the range of 0 to 1.

// Texture coordinates are only necessary if texture mapping is used.

VECTOR2F textureCoords;

pVertexCallList->GetTextureCoords(&textureCoords);

for( int i = 0; i < vertexCount; i++ ) {

   textureCoords.x = 1;

   textureCoords.y = 0;

}

pVertexCallList->SetTextureCoordsModified(true, 0, vertexCount);

 

In Java/.NET, this is done with various lock/unlock functions such as hdrcVertexCallListContext.lockVertices(), hdrcVertexCallListContext.lockNormals(), hdrcVertexCallListContext.lockIndices() etc. After each data array has been modified, the corresponding unlock methods are called, such as hdrcVertexCallListContext.unlockVertices(), hdrcVertexCallListContext.unlockNormals(), hdrcVertexCallListContext.unlockIndices() etc. The lock/unlock functions take as input parameters the range of values in the array that will be changed. The range of values is inclusive of the starting value and exclusive of the ending value. For example, if the array has 10 elements and all have been modified, the starting value is 0 and the ending value is 10.

 

// Get the number of vertices in this object

int vertexCount = vertexCallList.getNumVertices();

 

// This vertex call list is made of triangles (3 vertices per triangle only).

vertexCallList.setType(hdrcDefines.VCL_TYPE_TRIANGLES);

 

// Set vertex data for this object

float[] vertices;

vertices = vertexCallList.lockVertices(0, vertexCount);

for(int i = 0; i < vertexCount * 3; i += 3) {

    vertices[i]   = 0;

    vertices[i+1] = 0;

    vertices[i+2] = 0;

}

vertexCallList.unlockVertices(true, 0, vertexCount);

 

// Set vertex normal values.

// Normal vectors must be of unit length (use normalize function if necessary).

float[] normals;

normals = vertexCallList.lockNormals(0, vertexCount);

for(int i = 0; i < vertexCount * 3; i += 3) {

    normals[i]   = 0;

    normals[i+1] = 1;

    normals[i+2] = 0;

}

vertexCallList.unlockNormals(true, 0, vertexCount);

 

// Set vertex color values. 

// Color components are in the range of 0 to 255.

byte[] colors;

colors = vertexCallList.lockColors(0, vertexCount);

for(int i = 0; i < vertexCount * 4; i += 4) {

   colors[i]   = 0;

   colors[i+1] = 128;

   colors[i+2] = 255;

   colors[i+3] = 128;

}

vertexCallList.unlockColors(true, 0, vertexCount);

 

// Set shading flags. 

// This flag determines if shading is to be applied to this vertex

byte[] shading;

vertexCallList.lockShadingEnabled(0, vertexCount);

for( int i = 0; i < vertexCount; i++) {

   shading[i] = 1;

}

vertexCallList.unlockShadingEnabled(true, 0, vertexCount);

 

// Set texture mapping UV coordinates. 

// Texture UV coordinates are in the range of 0 to 1.

// Texture coordinates are only necessary if texture mapping is used.

float[] textureCoords;

vertexCallList.lockTextureCoords(0, vertexCount);

for( int i = 0; i < vertexCount * 2; i += 2) {

   textureCoords[i] = 1;

   textureCoords[i+1] = 0;

}

vertexCallList.unlockTextureCoords(true, 0, vertexCount);

 

The .NET example code is below:

 

// Get the number of vertices in this object

int vertexCount = vertexCallList.getNumVertices();

 

// This vertex call list is made of triangles (3 vertices per triangle only).

vertexCallList.setType(hdrcDefines.VCL_TYPE_TRIANGLES);

 

// Set vertex data for this object

float[] vertices;

vertices = vertexCallList.lockVertices(0, vertexCount);

for(int i = 0; i < vertexCount * 3; i += 3) {

    vertices[i]   = 0;

    vertices[i+1] = 0;

    vertices[i+2] = 0;

}

vertexCallList.unlockVertices(true, 0, vertexCount);

 

// Set vertex normal values.

// Normal vectors must be of unit length (use normalize function if necessary).

float[] normals;

normals = vertexCallList.lockNormals(0, vertexCount);

for(int i = 0; i < vertexCount * 3; i += 3) {

    normals[i]   = 0;

    normals[i+1] = 1;

    normals[i+2] = 0;

}

vertexCallList.unlockNormals(true, 0, vertexCount);

 

// Set vertex color values. 

// Color components are in the range of 0 to 255.

byte[] colors;

colors = vertexCallList.lockColors(0, vertexCount);

for(int i = 0; i < vertexCount * 4; i += 4) {

   colors[i]   = 0;

   colors[i+1] = 128;

   colors[i+2] = 255;

   colors[i+3] = 128;

}

vertexCallList.unlockColors(true, 0, vertexCount);

 

// Set shading flags. 

// This flag determines if shading is to be applied to this vertex

byte[] shading;

vertexCallList.lockShadingEnabled(0, vertexCount);

for( int i = 0; i < vertexCount; i++) {

   shading[i] = 1;

}

vertexCallList.unlockShadingEnabled(true, 0, vertexCount);

 

// Set texture mapping UV coordinates. 

// Texture UV coordinates are in the range of 0 to 1.

// Texture coordinates are only necessary if texture mapping is used.

float[] textureCoords;

vertexCallList.lockTextureCoords(0, vertexCount);

for( int i = 0; i < vertexCount * 2; i += 2) {

   textureCoords[i] = 1;

   textureCoords[i+1] = 0;

}

vertexCallList.unlockTextureCoords(true, 0, vertexCount);

 

Creating an Index Buffer

 

The API provides for an optional vertex index list of an array of integers, where each value represents an index into the vertex array. A vertex index list allows vertices (and their associated normals, colors, and shading states) to be reused. Take the example of a cube. A cube has 6 faces, with 2 polygons each. If each vertex is individually specified, there will be 36 vertices (6 faces, 2 polygons per face, 3 vertices per polygon). Since a cube shares each corner with 3 faces, many of these vertices will be identical, requiring data duplication and extra memory use. Since the cube has only 8 unique corners, the cube can be defined with 8 vertices and a vertex index list of 36 entries, with each index list entry indexing one of the 8 vertices.

 

If the number of indices is set to 0, no index buffer will be used. Instead, each group of 3 vertices in the vertex buffer constitutes a single polygon. If IVertexCallListContext::SetNumIndices() is called with an input value of 0 when an index buffer has already been allocated, that index buffer will be deleted.

 

// Configure index buffer 

pVertexCallList->SetNumIndices(36);

 

h_uint32 *pIndices = NULL;

unsigned int numIndices; 

pVertexCallList->GetNumIndices(&numIndices);

 

pVertexCallList->GetIndices(&pIndices);

 

for(int i = 0; i < numIndices; i += 3) {

   pIndices[i]   = //integer index of vertex 1

   pIndices[i+1] = //integer index of vertex 2

   pIndices[i+2] = //integer index of vertex 3

}

pVertexCallList->SetIndicesModified(true, 0, numIndices);

 

If the number of indices is set to 0, no index buffer will be used. Instead, each group of 3 vertices in the vertex buffer constitutes a single polygon. If Java/.NET function hdrcVertexCallListContext.setNumIndices() is called with an input value of 0 when an index buffer has already been allocated, that index buffer will be deleted.

 

// Configure index buffer 

vertexCallList.setNumIndices(36);

 

int[] indices;

int numIndices = vertexCallList.getNumIndices();

 

numIndices = vertexCallList.lockIndices(0, numIndices);

for(int i = 0; i < numIndices; i += 3) {

   indices[i]   = //integer index of vertex 1

   indices[i+1] = //integer index of vertex 2

   indices[i+2] = //integer index of vertex 3

}

vertexCallList.unlockIndices(true, 0, numIndices);

 

Positioning the Mesh

 

Once a mesh has been created, it is added to a render engine and positioned in 3D space. This is done with the IRenderEngineContext::SetRenderParamsEx2() or IRenderQueue::SetRenderParamsEx2() methods. Whenever mesh properties, such as the transform matrix or vertex properties, are changed, the mesh must be re-applied using the SetRenderParamsEx2() method. A RENDER_PARAMS structure may be specified, or NULL if no new parameters are to be set.

 

// Create a vertex call list programmatically or load one from disk.

// See the sections on Mesh Construction, Volume Extraction, or Mesh File Import for details.

 

// Declare matrices for transform operation.

MATRIX44D transform1;

MATRIX44D transform2;

 

// Set position and orientation of mesh.

transform1.setIdentity();

transform1.setOffsetVector(0, 10, 0);

vertexCallList1->SetTransform(&transform1);

 

transform2.setIdentity();

transform2.setOffsetVector(0, 20, 0);

vertexCallList2->SetTransform(&transform2);

 

// Add vertex call lists pointers to an array.

IVertexCallListContext *vertexCallListArray[2];

vertexCallListArray[0] = vertexCallList1;

vertexCallListArray[1] = vertexCallList2;

 

// Assign vertex call lists to render engine.

// A RENDER_PARAMS structure or NULL may be passed to parameter 1.

pRenderEngine->SetRenderParamsEx2(NULL, 2, vertexCallListArray); 

 

 

Once a mesh has been created, it is added to a render engine and positioned in 3D space. This is done with the hdrcRenderEngineContext.setRenderParams() or hdrcRenderQueue.setRenderParams() methods. Whenever mesh properties, such as the transform matrix or vertex properties, are changed, the mesh must be re-applied using setRenderParams(). A RENDER_PARAMS structure may be specified, or NULL if no new parameters are to be set.

 

// Create a vertex call list programmatically or load one from disk

// See the sections on Mesh Construction, Volume Extraction, or Mesh File Import for details

 

// Declare matrices for transform operation.

MATRIX44D transform1 = new MATRIX44D();

MATRIX44D transform2 = new MATRIX44D();

 

// Set position and orientation of mesh

transform1.setIdentity();

transform1.setOffsetVector(0, 10, 0);

vertexCallList1.setTransform(transform1);

 

transform2.setIdentity();

transform2.setOffsetVector(0, 20, 0);

vertexCallList2.setTransform(transform2);

 

// Assign vertex call lists to render engine

POLYGON_PARAMS pp = new POLYGON_PARAMS();

pp.NumCallLists = 2;

pp.CallLists.add(vertexCallList1);

pp.CallLists.add(vertexCallList2);

pp.Mask = hdrcDefines.PPM_CALL_LISTS;

 

// Assign vertex call lists to render engine.

// A RENDER_PARAMS structure or null may be passed to parameter 1.

renderEngine.setRenderParams(null, pp);