Use Mesh::CreateInfo to describe and create meshes.
Vertex and index listings define meshes. Indices refer to vertices which define the faces of a mesh.
To define a mesh, you need:
- Vertex format definition. This definition describes the components that define a vertex. This includes information about the vertex position, texture coordinates, normal, and tangent.
- List of vertices. Each vertex contains components that the format definition describes.
- List of indices. Indices describe polygons by referring to each vertex by index. When triangles describe a polygon, three indices describe a triangle. You can use several index listings, each of which uses a material.
When you render a large number of copies of the same mesh, performing a draw call for each copy consumes GPU time and decreases application performance. Instancing makes it possible to draw multiple copies of a mesh with different attributes, such as position, size, and color, with a single render call. For an example of how to render multiple instances of a cube mesh at different locations and with different colors, see Creating a mesh with instancing.
To enable the Kanzi Studio Preview to visualize the bounding volume of a mesh, set the bounding box for that mesh.
Examples
Creating a mesh
To create a cube mesh:
Mesh::CreateInfo createInfo;
createInfo.memoryType = GPUResource::GpuOnly;
MeshVertexAttribute position("kzPosition", VertexAttribute::SemanticPosition, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(position);
MeshVertexAttribute textureCoordinate("kzTextureCoordinate0", VertexAttribute::SemanticTextureCoordinate, 0, GraphicsDataTypeSFLOAT32, 2, ~0u);
createInfo.vertexFormat.push_back(textureCoordinate);
MeshVertexAttribute normal("kzNormal", VertexAttribute::SemanticNormal, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(normal);
MeshVertexAttribute tangent("kzTangent", VertexAttribute::SemanticTangent, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(tangent);
Mesh::CreateInfo::Cluster cluster(GraphicsPrimitiveTypeTriangles, 36, IndexBufferTypeUInt16, material, materialUrl);
createInfo.clusters.push_back(cluster);
{
createInfo.vertexCount = 24;
size_t dataSize = createInfo.vertexCount * createInfo.vertexSize;
createInfo.vertexData.resize(dataSize);
const Vector3 cornerPositions[] =
{
Vector3(1.0f, 1.0f, 1.0f),
Vector3(-1.0f, 1.0f, 1.0f),
Vector3(-1.0f, -1.0f, 1.0f),
Vector3(1.0f, -1.0f, 1.0f),
Vector3(1.0f, -1.0f, -1.0f),
Vector3(1.0f, 1.0f, -1.0f),
Vector3(-1.0f, 1.0f, -1.0f),
Vector3(-1.0f, -1.0f, -1.0f)
};
const Vector2 UVs[] =
{
Vector2(1.0f, 1.0f),
Vector2(0.0f, 1.0f),
Vector2(0.0f, 0.0f),
Vector2(1.0f, 0.0f)
};
const unsigned int faceIndices[][4] =
{
{ 0, 1, 2, 3 },
{ 5, 0, 3, 4 },
{ 6, 5, 4, 7 },
{ 1, 6, 7, 2 },
{ 5, 6, 1, 0 },
{ 3, 2, 7, 4 }
};
const Vector3 faceNormals[] =
{
Vector3(0.0f, 0.0f, 1.0f),
Vector3(1.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, -1.0f),
Vector3(-1.0f, 0.0f, 0.0f),
Vector3(0.0f, 1.0f, 0.0f),
Vector3(0.0f, -1.0f, 0.0f)
};
const Vector3 faceTangent[] =
{
Vector3(1.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, -1.0f),
Vector3(-1.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, 1.0f),
Vector3(1.0f, 0.0f, 0.0f),
Vector3(1.0f, 0.0f, 0.0f)
};
uint16_t vertexIndex = 0;
for (unsigned int face = 0; face < 6; ++face)
{
uint16_t* indexData = reinterpret_cast<uint16_t*>(&createInfo.clusters[0].indexData[0]);
unsigned int faceBaseIndex = face * 6;
indexData[faceBaseIndex + 0] = vertexIndex + 0;
indexData[faceBaseIndex + 1] = vertexIndex + 1;
indexData[faceBaseIndex + 2] = vertexIndex + 2;
indexData[faceBaseIndex + 3] = vertexIndex + 2;
indexData[faceBaseIndex + 4] = vertexIndex + 3;
indexData[faceBaseIndex + 5] = vertexIndex + 0;
for (unsigned int faceCorner = 0; faceCorner < 4; ++faceCorner, ++vertexIndex)
{
unsigned int boxCorner = faceIndices[face][faceCorner];
}
}
}
createInfo.boundingBox = Box::fromCenterAndSize(Vector3(0.0f, 0.0f, 0.0f), Vector3(2.0f, 2.0f, 2.0f));
Creating a mesh from native handles
To create a mesh from native handles:
Mesh::CreateInfo createInfo;
GPUBuffer::NativeHandle bufferHandles[2];
kzsGlGenBuffers(2, bufferHandles);
createInfo.vertexBufferHandle = bufferHandles[0];
createInfo.takeOwnership = true;
MeshVertexAttribute position("kzPosition", VertexAttribute::SemanticPosition, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(position);
MeshVertexAttribute textureCoordinate("kzTextureCoordinate0", VertexAttribute::SemanticTextureCoordinate, 0, GraphicsDataTypeSFLOAT32, 2, ~0u);
createInfo.vertexFormat.push_back(textureCoordinate);
MeshVertexAttribute normal("kzNormal", VertexAttribute::SemanticNormal, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(normal);
MeshVertexAttribute tangent("kzTangent", VertexAttribute::SemanticTangent, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(tangent);
Mesh::CreateInfo::Cluster cluster(GraphicsPrimitiveTypeTriangles, 36, IndexBufferTypeUInt16, bufferHandles[1], material, materialUrl);
createInfo.clusters.push_back(cluster);
{
createInfo.vertexCount = 24;
size_t dataSize = createInfo.vertexCount * createInfo.vertexSize;
const Vector3 cornerPositions[] = {
Vector3(1.0f, 1.0f, 1.0f),
Vector3(-1.0f, 1.0f, 1.0f),
Vector3(-1.0f, -1.0f, 1.0f),
Vector3(1.0f, -1.0f, 1.0f),
Vector3(1.0f, -1.0f, -1.0f),
Vector3(1.0f, 1.0f, -1.0f),
Vector3(-1.0f, 1.0f, -1.0f),
Vector3(-1.0f, -1.0f, -1.0f)
};
const Vector2 UVs[] = {
Vector2(1.0f, 1.0f),
Vector2(0.0f, 1.0f),
Vector2(0.0f, 0.0f),
Vector2(1.0f, 0.0f)
};
const unsigned int faceIndices[][4] = {
{ 0, 1, 2, 3 },
{ 5, 0, 3, 4 },
{ 6, 5, 4, 7 },
{ 1, 6, 7, 2 },
{ 5, 6, 1, 0 },
{ 3, 2, 7, 4 }
};
const Vector3 faceNormals[] = {
Vector3(0.0f, 0.0f, 1.0f),
Vector3(1.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, -1.0f),
Vector3(-1.0f, 0.0f, 0.0f),
Vector3(0.0f, 1.0f, 0.0f),
Vector3(0.0f, -1.0f, 0.0f)
};
const Vector3 faceTangent[] = {
Vector3(1.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, -1.0f),
Vector3(-1.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, 1.0f),
Vector3(1.0f, 0.0f, 0.0f),
Vector3(1.0f, 0.0f, 0.0f)
};
uint16_t vertexIndex = 0;
vector<uint16_t> indexBuffer;
indexBuffer.resize(createInfo.clusters[0].indexCount);
vector<uint8_t> vertexBuffer;
vertexBuffer.resize(dataSize);
uint8_t* vertexPtr = vertexBuffer.data();
for (unsigned int face = 0; face < 6; ++face)
{
uint16_t* indexData = indexBuffer.data();
unsigned int faceBaseIndex = face * 6;
indexData[faceBaseIndex + 0] = vertexIndex + 0;
indexData[faceBaseIndex + 1] = vertexIndex + 1;
indexData[faceBaseIndex + 2] = vertexIndex + 2;
indexData[faceBaseIndex + 3] = vertexIndex + 2;
indexData[faceBaseIndex + 4] = vertexIndex + 3;
indexData[faceBaseIndex + 5] = vertexIndex + 0;
for (unsigned int faceCorner = 0; faceCorner < 4; ++faceCorner, ++vertexIndex)
{
unsigned int boxCorner = faceIndices[face][faceCorner];
float* floatPtr = reinterpret_cast<float*>(vertexPtr);
*floatPtr++ = cornerPositions[boxCorner].getX();
*floatPtr++ = cornerPositions[boxCorner].getY();
*floatPtr++ = cornerPositions[boxCorner].getZ();
*floatPtr++ = UVs[faceCorner].getX();
*floatPtr++ = UVs[faceCorner].getY();
*floatPtr++ = faceNormals[face].getX();
*floatPtr++ = faceNormals[face].getY();
*floatPtr++ = faceNormals[face].getZ();
*floatPtr++ = faceTangent[face].getX();
*floatPtr++ = faceTangent[face].getY();
*floatPtr++ = faceTangent[face].getZ();
vertexPtr += createInfo.vertexSize;
}
}
}
createInfo.boundingBox = Box::fromCenterAndSize(Vector3(0.0f, 0.0f, 0.0f), Vector3(2.0f, 2.0f, 2.0f));
Creating a mesh with instancing
To create a mesh with instancing:
const char* vertexSource =
"#version 100\n"
"attribute vec3 kzPosition;\n"
"attribute vec3 InstancePosition;\n"
"attribute vec4 InstanceColor;\n"
"uniform highp mat4 kzProjectionCameraWorldMatrix;\n"
"varying vec4 outColor;\n"
"void main() {\n"
"precision mediump float;\n"
"vec3 position = kzPosition + InstancePosition;\n"
"gl_Position = kzProjectionCameraWorldMatrix * vec4(position, 1.0);\n"
"outColor = InstanceColor;\n"
"}\n";
const char* fragmentSource =
"#version 100\n"
"varying vec4 outColor;\n"
"void main() {\n"
"precision lowp float;\n"
"gl_FragColor = outColor;\n"
"}\n";
ShaderProgram::CreateInfoShaderSources shaderCreateInfo(vertexSource, fragmentSource);
static const ShaderVertexAttribute kzPosition = ShaderVertexAttribute("kzPosition", VertexAttribute::SemanticPosition,
0, GraphicsElementTypeFLOAT, 0, 3, 0, 0);
static const ShaderVertexAttribute InstancePosition = ShaderVertexAttribute("InstancePosition", VertexAttribute::SemanticPosition,
1, GraphicsElementTypeFLOAT, 0, 3, 1, 0);
static const ShaderVertexAttribute InstanceColor = ShaderVertexAttribute("InstanceColor", VertexAttribute::SemanticColor,
0, GraphicsElementTypeFLOAT, 0, 4, 2, 0);
shaderCreateInfo.vertexFormat.push_back(kzPosition);
shaderCreateInfo.vertexFormat.push_back(InstancePosition);
shaderCreateInfo.vertexFormat.push_back(InstanceColor);
shaderCreateInfo.addFixedUniform("kzProjectionCameraWorldMatrix");
auto shader = ShaderProgram::create(domain, shaderCreateInfo, "CustomShader");
auto material = Material::create(domain, "CustomMaterial", shader);
Mesh::CreateInfo createInfo;
createInfo.memoryType = GPUResource::GpuOnly;
MeshVertexAttribute position("kzPosition", VertexAttribute::SemanticPosition, 0, GraphicsDataTypeSFLOAT32, 3, ~0u);
createInfo.vertexFormat.push_back(position);
MeshVertexAttribute instancePosition("InstancePosition", VertexAttribute::SemanticPosition, 1, GraphicsDataTypeSFLOAT32, 3, 0);
instancePosition.divisor = 1;
createInfo.vertexFormat.push_back(instancePosition);
MeshVertexAttribute instanceColor("InstanceColor", VertexAttribute::SemanticColor, 0, GraphicsDataTypeUNORM8, 4, 3 * sizeof(float));
instanceColor.divisor = 1;
createInfo.vertexFormat.push_back(instanceColor);
Mesh::CreateInfo::Cluster cluster(GraphicsPrimitiveTypeTriangles, 36, IndexBufferTypeUInt16, material, "");
createInfo.clusters.push_back(cluster);
{
createInfo.vertexCount = 8;
size_t dataSize = createInfo.vertexCount * createInfo.vertexSize;
createInfo.vertexData.resize(dataSize);
const Vector3 cornerPositions[] = {
Vector3(1.0f, 1.0f, 1.0f),
Vector3(-1.0f, 1.0f, 1.0f),
Vector3(-1.0f, -1.0f, 1.0f),
Vector3(1.0f, -1.0f, 1.0f),
Vector3(1.0f, -1.0f, -1.0f),
Vector3(1.0f, 1.0f, -1.0f),
Vector3(-1.0f, 1.0f, -1.0f),
Vector3(-1.0f, -1.0f, -1.0f)
};
const uint16_t faceIndices[][4] = {
{ 0, 1, 2, 3 },
{ 5, 0, 3, 4 },
{ 6, 5, 4, 7 },
{ 1, 6, 7, 2 },
{ 5, 6, 1, 0 },
{ 3, 2, 7, 4 }
};
for (unsigned int face = 0; face < 6; ++face)
{
uint16_t* indexData = reinterpret_cast<uint16_t*>(&createInfo.clusters[0].indexData[0]);
unsigned int faceBaseIndex = face * 6;
indexData[faceBaseIndex + 0] = faceIndices[face][0];
indexData[faceBaseIndex + 1] = faceIndices[face][1];
indexData[faceBaseIndex + 2] = faceIndices[face][2];
indexData[faceBaseIndex + 3] = faceIndices[face][2];
indexData[faceBaseIndex + 4] = faceIndices[face][3];
indexData[faceBaseIndex + 5] = faceIndices[face][0];
}
for (unsigned int vertexIndex = 0; vertexIndex < 8; ++vertexIndex)
{
}
}
{
createInfo.instanceCount = 4;
createInfo.instanceData.resize(createInfo.instanceCount * createInfo.instanceSize);
const Vector3 instancePositions[] = {
Vector3(-1.0f, -1.0f, 0.0f),
Vector3(-1.0f, 1.0f, 0.0f),
Vector3(1.0f, 1.0f, 0.0f),
Vector3(1.0f, -1.0f, 0.0f)
};
const uint32_t instanceColors[] = {
0xffffffff,
0xffff0000,
0xff00ff00,
0xff0000ff
};
byte* instanceBuffer = createInfo.instanceData.data();
for (unsigned instance = 0; instance < createInfo.instanceCount; ++instance)
{
auto pos = reinterpret_cast<float*>(instanceBuffer + instance * createInfo.instanceSize);
*pos++ = instancePositions[instance].getX();
*pos++ = instancePositions[instance].getY();
*pos++ = instancePositions[instance].getZ();
auto color = reinterpret_cast<uint32_t*>(pos);
*color = instanceColors[instance];
}
}
createInfo.boundingBox = Box::fromCenterAndSize(Vector3(0.0f, 0.0f, 0.0f), Vector3(4.0f, 4.0f, 2.0f));
MeshSharedPtr mesh = Mesh::create(domain, createInfo,
"instancedBox");
- See also
- Mesh