Magnum::GL::Mesh class

Mesh.

Wraps an OpenGL vertex array object, or a collection of buffers and attribute bindings in case vertex array objects are not available or are disabled.

Quick usage with MeshTools::compile()

If you have a Trade::MeshData instance that you got for example from Trade::AbstractImporter::mesh() or from the Primitives library, the simplest possible way is to use MeshTools::compile():

Trade::MeshData data = ;

GL::Mesh mesh = MeshTools::compile(data);

This one-liner uploads the data and configures the mesh for all attributes known by Magnum that are present in it, making it suitable to be drawn by builtin shaders. It's however rather opaque and the Trade::MeshData may be an overly generic abstraction if you already have your vertex data in known types. Continue below to see how to configure a mesh for builtin shaders with lower-level APIs.

Mesh configuration

A mesh is, at the very least, a MeshPrimitive and associated vertex/index count. To prevent accidentally drawing empty meshes, you're required to call setCount() always, the primitive is however implicitly MeshPrimitive::Triangles and you can change it either in the constructor or via setPrimitive(). If setCount() (or setInstanceCount()) is zero, the mesh is considered empty and no draw commands are issued when calling AbstractShaderProgram::draw().

While a mesh can be attribute-less and rely on a specialized vertex shader to generate positions and other data, in most cases it has one or more associated vertex buffers and corresponding attribute bindings added using addVertexBuffer(). In the following snippet, a single position attribute is specified, making it suitable to be rendered with the Shaders::FlatGL shader. The Vector3 type we use for the data matches the type expected by Shaders::FlatGL3D::Position, so the default constructor is sufficient for it. The Advanced formats of vertex data section below shows cases where the types don't match.

const Vector3 positions[]{
    
};
GL::Buffer vertices{positions};

GL::Mesh mesh;
mesh.setCount(Containers::arraySize(positions))
    .addVertexBuffer(vertices, 0, Shaders::FlatGL3D::Position{});

Here's a mesh with a position and a normal interleaved together, as is needed for Shaders::PhongGL. See the docs of addVertexBuffer() for detailed description how particular attributes, offsets and paddings are specified. Note that Shaders::FlatGL::Position and Shaders::PhongGL::Position are both aliases to Shaders::GenericGL::Position, meaning you can render a mesh configured for the Phong shader with the Flat shader as well:

struct Vertex {
    Vector3 position;
    Vector3 normal;
};
const Vertex vertexData[]{
    
};
GL::Buffer vertices{vertexData};

GL::Mesh mesh;
mesh.setCount(Containers::arraySize(vertexData))
    .addVertexBuffer(vertices, 0,
        Shaders::PhongGL::Position{},
        Shaders::PhongGL::Normal{});

Indexed meshes have the index buffer and corresponding index type set using setIndexBuffer().

const UnsignedInt indexData[]{
    
};
GL::Buffer indices{indexData};


mesh.setIndexBuffer(indices, 0, MeshIndexType::UnsignedInt);

Using MeshTools

Real-world use cases rarely have a statically defined struct with the desired vertex attribute layout. If you have loose attribute arrays, you can use MeshTools::interleave() to interleave them together. The usage including the padding specification, is similar to addVertexBuffer(). The above vertex buffer setup but with separate position and normal arrays that get interleaved can be expressed like this:

Containers::ArrayView<const Vector3> positions = ;
Containers::ArrayView<const Vector3> normals = ;
GL::Buffer vertices{MeshTools::interleave(positions, normals)};


mesh.addVertexBuffer(vertices, 0,
    Shaders::PhongGL::Position{},
    Shaders::PhongGL::Normal{});

For indices it's often beneficial to store them in a 16-bit type if they don't need the full 32-bit range. That's what MeshTools::compressIndices() is for:

Containers::Pair<Containers::Array<char>, MeshIndexType> compressed =
    MeshTools::compressIndices(indexData);
GL::Buffer indices{compressed.first()};


mesh.setIndexBuffer(indices, 0, compressed.second());

The ultimate generic tool is the already-shown MeshTools::compile(), together with all MeshTools APIs that operate on Trade::MeshData instances. See the class documentation for additional ways of accessing and processing the data contained there.

Advanced formats of vertex data

Even though a shader accepts, say, a 32-bit floating-point vector, the actual mesh data don't need to match that and can be in a smaller type to save on memory bandwidth. The GPU vertex fetching hardware will then unpack them as necessary. The following snippet shows a setup similar to the above position + normal mesh, except that the position is a Vector3h and the normal is a packed normalized Vector3s, together with padding for having vertex boundaries aligned to four bytes to make the GPU happier:

struct Packed {
    Vector3h position;
    Short:16;
    Vector3s normal;
    Short:16;
};
const Packed vertexData[]{
    
};
GL::Buffer vertices{vertexData};


mesh.addVertexBuffer(vertices, 0,
    Shaders::PhongGL::Position{Shaders::PhongGL::Position::Components::Three,
                               Shaders::PhongGL::Position::DataType::Half},
    2,
    Shaders::PhongGL::Normal{Shaders::PhongGL::Normal::Components::Three,
                             Shaders::PhongGL::Normal::DataType::Short,
                             Shaders::PhongGL::Normal::DataOption::Normalized},
    2);

Dynamically specified attributes

In some cases, for example when the shader code is fully generated at runtime, it's not possible to know attribute locations and types at compile time. In that case, there are overloads of addVertexBuffer() and addVertexBufferInstanced() that take a DynamicAttribute instead of the Attribute typedefs, however then you're responsible for explicitly specifying also the stride. Adding a RGB attribute at location 3 normalized from unsigned byte to float with one byte padding at the end (or, in other words, stride of four bytes) could then look like this:

mesh.addVertexBuffer(colorBuffer, 0, 4, GL::DynamicAttribute{
    GL::DynamicAttribute::Kind::GenericNormalized, 3,
    GL::DynamicAttribute::Components::Three,
    GL::DynamicAttribute::DataType::UnsignedByte});

The DynamicAttribute also allows VertexFormat to be used for specifying attribute types instead of the rather verbose GL::Attribute::Components, DataType and DataOptions tuple that GL itself accepts. The above packed position + normal attribute specification would then look like this:

mesh.addVertexBuffer(vertices, offsetof(Packed, position), sizeof(Packed),
    GL::DynamicAttribute{Shaders::PhongGL::Position{},
                         VertexFormat::Vector3h});
mesh.addVertexBuffer(vertices, offsetof(Packed, normal), sizeof(Packed),
    GL::DynamicAttribute{Shaders::PhongGL::Normal{},
                         VertexFormat::Vector3sNormalized});

Transferring buffer ownership

If a vertex/index buffer is used only by a single mesh, it's possible to transfer its ownership to the mesh itself to simplify resource management on the application side. Simply use the addVertexBuffer() / addVertexBufferInstanced() and setIndexBuffer() overloads that take a Buffer as a rvalue. While this allows you to discard the buffer instances and pass just the mesh around, it also means you lose a way to access or update the buffers afterwards.

GL::Buffer vertices, indices;

mesh.addVertexBuffer(std::move(vertices), 0,
        Shaders::PhongGL::Position{},
        Shaders::PhongGL::Normal{})
    .setIndexBuffer(std::move(indices), 0, MeshIndexType::UnsignedInt);

If adding the same buffer multiple times or using it for both vertex and index data, be sure to transfer the ownership last to avoid the other functions getting only a moved-out instance. For example:

mesh.addVertexBuffer(vertices, 0, Shaders::PhongGL::Position{}, 20)
    .addVertexBuffer(std::move(vertices), 0, 20, Shaders::PhongGL::Normal{});

Rendering meshes

With a framebuffer bound and a compatible shader set up, it's only a matter of calling AbstractShaderProgram::draw():

Shaders::PhongGL shader{};

shader.draw(mesh);

WebGL restrictions

WebGL puts some restrictions on vertex buffer layout, see addVertexBuffer() documentation for details.

A WebGL restriction that allows Buffers to be bound only to one unique target transitively affects meshes as well, requiring Buffer::TargetHint::ElementArray to be used for index buffers. To simplify dealing with this restriction, the addVertexBuffer() and setIndexBuffer() functions check proper target hint when adding vertex and index buffers under WebGL.

Performance optimizations

If ARB_vertex_array_object (part of OpenGL 3.0), OpenGL ES 3.0, WebGL 2.0, OES_vertex_array_object in OpenGL ES 2.0 or OES_vertex_array_object in WebGL 1.0 is supported, VAOs are used instead of binding the buffers and specifying vertex attribute pointers in each AbstractShaderProgram::draw() call. The engine tracks currently bound VAO and currently active shader program to avoid unnecessary calls to glBindVertexArray() and glUseProgram(). Mesh limits and implementation-defined values (such as maxElementIndex()) are cached, so repeated queries don't result in repeated glGet() calls.

If ARB_direct_state_access desktop extension and VAOs are available, DSA functions are used for specifying attribute locations to avoid unnecessary calls to glBindBuffer() and glBindVertexArray(). See documentation of addVertexBuffer() for more information.

If index range is specified in setIndexBuffer(), range-based version of drawing commands are used on desktop OpenGL and OpenGL ES 3.0. See also AbstractShaderProgram::draw() for more information.

Base classes

class AbstractObject
Base for all OpenGL objects.

Public static functions

static auto maxVertexAttributeStride() -> UnsignedInt
Max vertex attribute stride.
static auto maxElementIndex() -> Long
Max supported index value.
static auto maxElementsIndices() -> Int
Max recommended index count.
static auto maxElementsVertices() -> Int
Max recommended vertex count.
static auto wrap(GLuint id, MeshPrimitive primitive = MeshPrimitive::Triangles, ObjectFlags flags = {}) -> Mesh
Wrap existing OpenGL vertex array object.
static auto wrap(GLuint id, ObjectFlags flags) -> Mesh

Constructors, destructors, conversion operators

Mesh(MeshPrimitive primitive = MeshPrimitive::Triangles) explicit
Constructor.
Mesh(Magnum::MeshPrimitive primitive) explicit
Construct with a generic primitive type.
Mesh(NoCreateT) explicit noexcept
Construct without creating the underlying OpenGL object.
Mesh(const Mesh&) deleted
Copying is not allowed.
Mesh(Mesh&& other) noexcept
Move constructor.
~Mesh()
Destructor.

Public functions

auto operator=(const Mesh&) -> Mesh& deleted
Copying is not allowed.
auto operator=(Mesh&& other) -> Mesh& noexcept
Move assignment.
auto id() const -> GLuint
OpenGL vertex array ID.
auto release() -> GLuint
Release OpenGL object.
auto label() -> Containers::String
Mesh label.
auto setLabel(Containers::StringView label) -> Mesh&
Set mesh label.
auto isIndexed() const -> bool
Whether the mesh is indexed.
auto indexType() const -> MeshIndexType
Index type.
auto indexTypeSize() const -> UnsignedInt deprecated in Git master
Index type size.
auto primitive() const -> MeshPrimitive
Primitive type.
auto setPrimitive(MeshPrimitive primitive) -> Mesh&
Set primitive type.
auto setPrimitive(Magnum::MeshPrimitive primitive) -> Mesh&
Set a generic primitive type.
auto count() const -> Int
Vertex/index count.
auto setCount(Int count) -> Mesh&
Set vertex/index count.
auto baseVertex() const -> Int
Base vertex.
auto setBaseVertex(Int baseVertex) -> Mesh&
Set base vertex.
auto indexOffset() const -> GLintptr new in Git master
Index offset.
auto setIndexOffset(GLintptr offset, UnsignedInt start, UnsignedInt end) -> Mesh& new in Git master
Set index offset.
auto setIndexOffset(GLintptr offset) -> Mesh& new in Git master
Set index offset.
auto instanceCount() const -> Int
Instance count.
auto setInstanceCount(Int count) -> Mesh&
Set instance count.
auto baseInstance() const -> UnsignedInt
Base instance.
auto setBaseInstance(UnsignedInt baseInstance) -> Mesh&
Set base instance.
template<class ... T>
auto addVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes) -> Mesh&
Add buffer with (interleaved) vertex attributes for use with given shader.
template<class ... T>
auto addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes) -> Mesh&
Add instanced vertex buffer.
auto addVertexBuffer(Buffer& buffer, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute) -> Mesh&
Add vertex buffer with dynamic vertex attributes.
auto addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute) -> Mesh&
Add instanced vertex buffer with dynamic vertex attributes.
template<class ... T>
auto addVertexBuffer(Buffer&& buffer, GLintptr offset, const T&... attributes) -> Mesh&
Add vertex buffer with ownership transfer.
template<class ... T>
auto addVertexBufferInstanced(Buffer&& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes) -> Mesh&
Add instanced vertex buffer with ownership transfer.
auto addVertexBuffer(Buffer&& buffer, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute) -> Mesh&
Add vertex buffer with dynamic vertex attributes with ownership transfer.
auto addVertexBufferInstanced(Buffer&& buffer, UnsignedInt divisor, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute) -> Mesh&
Add instanced vertex buffer with dynamic vertex attributes with ownership transfer.
auto setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end) -> Mesh&
Set index buffer.
auto setIndexBuffer(Buffer& buffer, GLintptr offset, Magnum::MeshIndexType type, UnsignedInt start, UnsignedInt end) -> Mesh&
auto setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type) -> Mesh&
Set index buffer.
auto setIndexBuffer(Buffer& buffer, GLintptr offset, Magnum::MeshIndexType type) -> Mesh&
Set index buffer with a generic index type.
auto setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end) -> Mesh&
Set index buffer with ownership transfer.
auto setIndexBuffer(Buffer&& buffer, GLintptr offset, Magnum::MeshIndexType type, UnsignedInt start, UnsignedInt end) -> Mesh&
Set index buffer with a generic index type and ownership transfer.
auto setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type) -> Mesh&
Set index buffer with ownership transfer.
auto setIndexBuffer(Buffer&& buffer, GLintptr offset, Magnum::MeshIndexType type) -> Mesh&
Set index buffer with a generic index type and ownership transfer.
auto draw(AbstractShaderProgram& shader) -> Mesh& deprecated in 2020.06
Draw the mesh.
auto draw(AbstractShaderProgram&& shader) -> Mesh& deprecated in 2020.06
auto draw(AbstractShaderProgram& shader, TransformFeedback& xfb, UnsignedInt stream = 0) -> Mesh& deprecated in 2020.06
Draw the mesh with vertices coming out of transform feedback.
auto draw(AbstractShaderProgram&& shader, TransformFeedback& xfb, UnsignedInt stream = 0) -> Mesh& deprecated in 2020.06

Function documentation

static UnsignedInt Magnum::GL::Mesh::maxVertexAttributeStride()

Max vertex attribute stride.

The result is cached, repeated queries don't result in repeated OpenGL calls. If OpenGL 4.4 or OpenGL 3.1 supporting this query isn't available, returns max representable 32-bit value (0xffffffffu). On WebGL 1 and 2 the max stride is specified to be 255 with no corresponding limit query.

static Long Magnum::GL::Mesh::maxElementIndex()

Max supported index value.

The result is cached, repeated queries don't result in repeated OpenGL calls. If extension ARB_ES3_compatibility (part of OpenGL 4.3) is not available, returns max representable 32-bit value (0xffffffffu).

static Int Magnum::GL::Mesh::maxElementsIndices()

Max recommended index count.

The result is cached, repeated queries don't result in repeated OpenGL calls.

static Int Magnum::GL::Mesh::maxElementsVertices()

Max recommended vertex count.

The result is cached, repeated queries don't result in repeated OpenGL calls.

static Mesh Magnum::GL::Mesh::wrap(GLuint id, MeshPrimitive primitive = MeshPrimitive::Triangles, ObjectFlags flags = {})

Wrap existing OpenGL vertex array object.

Parameters
id OpenGL vertex array ID
primitive Primitive type
flags Object creation flags

The id is expected to be of an existing OpenGL vertex array object. Unlike vertex array created using constructor, the OpenGL object is by default not deleted on destruction, use flags for different behavior.

static Mesh Magnum::GL::Mesh::wrap(GLuint id, ObjectFlags flags)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Magnum::GL::Mesh::Mesh(MeshPrimitive primitive = MeshPrimitive::Triangles) explicit

Constructor.

Parameters
primitive Primitive type

If ARB_vertex_array_object (part of OpenGL 3.0), OpenGL ES 3.0, WebGL 2.0, OES_vertex_array_object in OpenGL ES 2.0 or OES_vertex_array_object in WebGL 1.0 is available, vertex array object is created. If ARB_direct_state_access (part of OpenGL 4.5) is not available, the vertex array object is created on first use.

Magnum::GL::Mesh::Mesh(Magnum::MeshPrimitive primitive) explicit

Construct with a generic primitive type.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Note that implementation-specific values are passed as-is with meshPrimitiveUnwrap(). It's the user responsibility to ensure an implementation-specific value actually represents a valid OpenGL primitive type.

Magnum::GL::Mesh::Mesh(NoCreateT) explicit noexcept

Construct without creating the underlying OpenGL object.

The constructed instance is equivalent to moved-from state. Useful in cases where you will overwrite the instance later anyway. Move another object over it to make it useful.

This function can be safely used for constructing (and later destructing) objects even without any OpenGL context being active. However note that this is a low-level and a potentially dangerous API, see the documentation of NoCreate for alternatives.

Magnum::GL::Mesh::~Mesh()

Destructor.

If ARB_vertex_array_object (part of OpenGL 3.0), OpenGL ES 3.0, WebGL 2.0, OES_vertex_array_object in OpenGL ES 2.0 or OES_vertex_array_object in WebGL 1.0 is available, associated vertex array object is deleted.

GLuint Magnum::GL::Mesh::id() const

OpenGL vertex array ID.

If neither ARB_vertex_array_object (part of OpenGL 3.0) nor OpenGL ES 3.0 / WebGL 2.0 nor OES_vertex_array_object in OpenGL ES 2.0 / OES_vertex_array_object in WebGL 1.0 is available, returns 0.

GLuint Magnum::GL::Mesh::release()

Release OpenGL object.

Releases ownership of OpenGL vertex array object and returns its ID so it is not deleted on destruction. The internal state is then equivalent to moved-from state.

Containers::String Magnum::GL::Mesh::label()

Mesh label.

The result is not cached, repeated queries will result in repeated OpenGL calls. If OpenGL 4.3 / OpenGL ES 3.2 is not supported and neither KHR_debug (covered also by ANDROID_extension_pack_es31a) nor EXT_debug_label desktop or ES extension is available, this function returns empty string.

Mesh& Magnum::GL::Mesh::setLabel(Containers::StringView label)

Set mesh label.

Returns Reference to self (for method chaining)

Default is empty string. If OpenGL 4.3 / OpenGL ES 3.2 is not supported and neither KHR_debug (covered also by ANDROID_extension_pack_es31a) nor EXT_debug_label desktop or ES extension is available, this function does nothing.

bool Magnum::GL::Mesh::isIndexed() const

Whether the mesh is indexed.

MeshIndexType Magnum::GL::Mesh::indexType() const

Index type.

Expects that the mesh is indexed.

UnsignedInt Magnum::GL::Mesh::indexTypeSize() const

Index type size.

Expects that the mesh is indexed.

Mesh& Magnum::GL::Mesh::setPrimitive(MeshPrimitive primitive)

Set primitive type.

Returns Reference to self (for method chaining)

Default is MeshPrimitive::Triangles.

Mesh& Magnum::GL::Mesh::setPrimitive(Magnum::MeshPrimitive primitive)

Set a generic primitive type.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Note that implementation-specific values are passed as-is with meshPrimitiveUnwrap(). It's the user responsibility to ensure an implementation-specific value actually represents a valid OpenGL primitive type.

Mesh& Magnum::GL::Mesh::setCount(Int count)

Set vertex/index count.

Returns Reference to self (for method chaining)

If the mesh is indexed, the value is treated as index count, otherwise the value is vertex count. If set to 0, no draw commands are issued when calling AbstractShaderProgram::draw(). Ignored when calling AbstractShaderProgram::drawTransformFeedback().

Mesh& Magnum::GL::Mesh::setBaseVertex(Int baseVertex)

Set base vertex.

Returns Reference to self (for method chaining)

Sets number of vertices of which the vertex buffer will be offset when drawing. Ignored when calling AbstractShaderProgram::drawTransformFeedback(). Default is 0.

Mesh& Magnum::GL::Mesh::setIndexOffset(GLintptr offset, UnsignedInt start, UnsignedInt end) new in Git master

Set index offset.

Parameters
offset First index
start Minimum array index contained in the buffer
end Maximum array index contained in the buffer
Returns Reference to self (for method chaining)

The offset gets multiplied by index type size and added to the base offset that was specified in Mesh::setIndexBuffer(). The start and end parameters may help to improve memory access performance, as only a portion of vertex buffer needs to be acccessed. On OpenGL ES 2.0 this function behaves the same as setIndexOffset(GLintptr), as index range functionality is not available there. Ignored when calling AbstractShaderProgram::drawTransformFeedback().

Expects that the mesh is indexed.

Mesh& Magnum::GL::Mesh::setIndexOffset(GLintptr offset) new in Git master

Set index offset.

Returns Reference to self (for method chaining)

The offset gets multiplied by index type size and added to the base offset that was specified in Mesh::setIndexBuffer(). Prefer to use setIndexOffset(GLintptr, UnsignedInt, UnsignedInt) for potential better performance on certain drivers. Ignored when calling AbstractShaderProgram::drawTransformFeedback().

Expects that the mesh is indexed.

Mesh& Magnum::GL::Mesh::setInstanceCount(Int count)

Set instance count.

Returns Reference to self (for method chaining)

If set to 1, non-instanced draw commands are issued when calling AbstractShaderProgram::draw() or AbstractShaderProgram::drawTransformFeedback(). If set to 0, no draw commands are issued at all. Default is 1.

Mesh& Magnum::GL::Mesh::setBaseInstance(UnsignedInt baseInstance)

Set base instance.

Returns Reference to self (for method chaining)

Ignored when calling AbstractShaderProgram::drawTransformFeedback(). Default is 0.

template<class ... T>
Mesh& Magnum::GL::Mesh::addVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes)

Add buffer with (interleaved) vertex attributes for use with given shader.

Returns Reference to self (for method chaining)

Parameter offset is offset of the array from the beginning, attribute list is combination of attribute definitions (specified in implementation of given shader) and offsets between interleaved attributes.

See class documentation for simple usage example. For more involved example imagine that you have a buffer with 76 bytes of some other data at the beginning (possibly material configuration) and then the interleaved vertex array. Each vertex consists of a weight, position, texture coordinate and a normal. You want to draw it with Shaders::PhongGL, but it accepts only a position and a normal, so you have to skip the weight and the texture coordinate in each vertex:

GL::Buffer buffer;
GL::Mesh mesh;
mesh.addVertexBuffer(buffer, 76,    /* initial array offset */
    4,                              /* skip vertex weight (Float) */
    Shaders::PhongGL::Position(),   /* vertex position */
    8,                              /* skip texture coordinates (Vector2) */
    Shaders::PhongGL::Normal());    /* vertex normal */

You can also achieve the same effect by calling addVertexBuffer() more times with explicitly specified gaps before and after the attributes. This can be used for e.g. runtime-dependent configuration, as it isn't dependent on the variadic template:

mesh.addVertexBuffer(buffer, 76, 4, Shaders::PhongGL::Position{}, 20)
    .addVertexBuffer(buffer, 76, 24, Shaders::PhongGL::Normal{}, 0);

If specifying more than one attribute, the function assumes that the array is interleaved. Adding non-interleaved vertex buffer can be done by specifying one attribute at a time with specific offset. Above example with the position and normal arrays one after another (non-interleaved):

Int vertexCount = 352;
mesh.addVertexBuffer(buffer, 76 + 4*vertexCount, Shaders::PhongGL::Position{})
    .addVertexBuffer(buffer, 76 + 24*vertexCount, Shaders::PhongGL::Normal{});

If ARB_vertex_array_object (part of OpenGL 3.0), OpenGL ES 3.0, WebGL 2.0, OES_vertex_array_object in OpenGL ES 2.0 or OES_vertex_array_object in WebGL 1.0 is available, the vertex array object is used to hold the parameters.

template<class ... T>
Mesh& Magnum::GL::Mesh::addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes)

Add instanced vertex buffer.

Returns Reference to self (for method chaining)

Similar to the above function, the divisor parameter specifies number of instances that will pass until new data are fetched from the buffer. Setting it to 0 is equivalent to calling addVertexBuffer().

If ARB_vertex_array_object (part of OpenGL 3.0), OpenGL ES 3.0, WebGL 2.0, OES_vertex_array_object in OpenGL ES 2.0 or OES_vertex_array_object in WebGL 1.0 is available, the vertex array object is used to hold the parameters.

Mesh& Magnum::GL::Mesh::addVertexBuffer(Buffer& buffer, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute)

Add vertex buffer with dynamic vertex attributes.

Returns Reference to self (for method chaining)

Equivalent to addVertexBuffer(Buffer&, GLintptr, const T&... attributes) but with the possibility to fully specify the attribute properties at runtime, including base type and location. See class documentation for usage example.

Mesh& Magnum::GL::Mesh::addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute)

Add instanced vertex buffer with dynamic vertex attributes.

Returns Reference to self (for method chaining)

Equivalent to addVertexBufferInstanced(Buffer&, UnsignedInt, GLintptr, const T&... attributes) but with the possibility to fully specify the attribute properties at runtime, including base type and location. See class documentation for usage example.

template<class ... T>
Mesh& Magnum::GL::Mesh::addVertexBuffer(Buffer&& buffer, GLintptr offset, const T&... attributes)

Add vertex buffer with ownership transfer.

Returns Reference to self (for method chaining)

Unlike addVertexBuffer(Buffer&, GLintptr, const T&... attributes) this function takes ownership of buffer. See Transferring buffer ownership for more information.

template<class ... T>
Mesh& Magnum::GL::Mesh::addVertexBufferInstanced(Buffer&& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes)

Add instanced vertex buffer with ownership transfer.

Returns Reference to self (for method chaining)

Unlike addVertexBufferInstanced(Buffer&, UnsignedInt, GLintptr, const T&... attributes) this function takes ownership of buffer. See Transferring buffer ownership for more information.

Mesh& Magnum::GL::Mesh::addVertexBuffer(Buffer&& buffer, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute)

Add vertex buffer with dynamic vertex attributes with ownership transfer.

Returns Reference to self (for method chaining)

Unlike addVertexBuffer(Buffer&, GLintptr, GLsizei, const DynamicAttribute&) this function takes ownership of buffer. See Transferring buffer ownership for more information.

Mesh& Magnum::GL::Mesh::addVertexBufferInstanced(Buffer&& buffer, UnsignedInt divisor, GLintptr offset, GLsizei stride, const DynamicAttribute& attribute)

Add instanced vertex buffer with dynamic vertex attributes with ownership transfer.

Returns Reference to self (for method chaining)

Unlike addVertexBufferInstanced(Buffer&, UnsignedInt, GLintptr, GLsizei, const DynamicAttribute&) this function takes ownership of buffer. See Transferring buffer ownership for more information.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end)

Set index buffer.

Parameters
buffer Index buffer
offset Offset into the buffer
type Index data type
start Minimum array index contained in the buffer
end Maximum array index contained in the buffer
Returns Reference to self (for method chaining)

The smaller range is specified with start and end the less memory operations are needed (and possibly some optimizations), improving draw performance. Specifying 0 for both parameters behaves the same as setIndexBuffer(Buffer&, GLintptr, MeshIndexType). On OpenGL ES 2.0 this function behaves always as setIndexBuffer(Buffer&, GLintptr, MeshIndexType), as this functionality is not available there.

If ARB_vertex_array_object (part of OpenGL 3.0), OpenGL ES 3.0, WebGL 2.0, OES_vertex_array_object in OpenGL ES 2.0 or OES_vertex_array_object in WebGL 1.0 is available, the vertex array object is used to hold the parameters.

Ignored when calling AbstractShaderProgram::drawTransformFeedback().

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, Magnum::MeshIndexType type, UnsignedInt start, UnsignedInt end)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, MeshIndexType type)

Set index buffer.

Parameters
buffer Index buffer
offset Offset into the buffer
type Index data type
Returns Reference to self (for method chaining)

Alternative to setIndexBuffer(Buffer&, GLintptr, MeshIndexType, UnsignedInt, UnsignedInt) with unspecified index limits, see its documentation for more information. Prefer to set index limits for better performance on certain drivers.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, Magnum::MeshIndexType type)

Set index buffer with a generic index type.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Note that implementation-specific values are passed as-is with meshIndexTypeUnwrap(). It's the user responsibility to ensure an implementation-specific value actually represents a valid OpenGL index type.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type, UnsignedInt start, UnsignedInt end)

Set index buffer with ownership transfer.

Unlike setIndexBuffer(Buffer&, GLintptr, MeshIndexType, UnsignedInt, UnsignedInt) this function takes ownership of buffer. See Transferring buffer ownership for more information.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer&& buffer, GLintptr offset, Magnum::MeshIndexType type, UnsignedInt start, UnsignedInt end)

Set index buffer with a generic index type and ownership transfer.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Note that implementation-specific values are passed as-is with meshIndexTypeUnwrap(). It's the user responsibility to ensure an implementation-specific value actually represents a valid OpenGL index type.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer&& buffer, GLintptr offset, MeshIndexType type)

Set index buffer with ownership transfer.

Unlike setIndexBuffer(Buffer&, GLintptr, MeshIndexType) this function takes ownership of buffer. See Transferring buffer ownership for more information.

Mesh& Magnum::GL::Mesh::setIndexBuffer(Buffer&& buffer, GLintptr offset, Magnum::MeshIndexType type)

Set index buffer with a generic index type and ownership transfer.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Note that implementation-specific values are passed as-is with meshIndexTypeUnwrap(). It's the user responsibility to ensure an implementation-specific value actually represents a valid OpenGL index type.

Mesh& Magnum::GL::Mesh::draw(AbstractShaderProgram& shader)

Draw the mesh.

Mesh& Magnum::GL::Mesh::draw(AbstractShaderProgram&& shader)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Mesh& Magnum::GL::Mesh::draw(AbstractShaderProgram& shader, TransformFeedback& xfb, UnsignedInt stream = 0)

Draw the mesh with vertices coming out of transform feedback.

Mesh& Magnum::GL::Mesh::draw(AbstractShaderProgram&& shader, TransformFeedback& xfb, UnsignedInt stream = 0)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.