Browse Source

GL: refresh Mesh and Buffer docs to be less shit.

Looking at the snippets, these seem to have been written back when there
was no builtin shaders yet, it seems, not to mention
MeshTools::compile(), Trade::MeshData or any of the other high-level
APIs. Rather overwhelming to just throw huge code snippets at the user,
explaining a workflow with a custom-made mesh that's going to be drawn
with a custom-made shader, which is like level 999 of using the GL
library.
pull/525/head
Vladimír Vondruš 5 years ago
parent
commit
491b724a86
  1. 258
      doc/snippets/MagnumGL.cpp
  2. 1
      doc/snippets/MagnumTrade.cpp
  3. 45
      src/Magnum/GL/Buffer.h
  4. 170
      src/Magnum/GL/Mesh.h
  5. 6
      src/Magnum/Trade/MeshData.h

258
doc/snippets/MagnumGL.cpp

@ -47,11 +47,14 @@
#include "Magnum/GL/Texture.h"
#include "Magnum/GL/TextureFormat.h"
#include "Magnum/GL/Version.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Half.h"
#include "Magnum/Math/Matrix4.h"
#include "Magnum/MeshTools/Interleave.h"
#include "Magnum/MeshTools/CompressIndices.h"
#include "Magnum/Primitives/Cube.h"
#include "Magnum/Primitives/Plane.h"
#include "Magnum/Shaders/FlatGL.h"
#include "Magnum/Shaders/PhongGL.h"
#include "Magnum/Trade/MeshData.h"
@ -82,6 +85,8 @@
#include "Magnum/GL/RectangleTexture.h"
#endif
#define DOXYGEN_IGNORE(...) __VA_ARGS__
using namespace Magnum;
using namespace Magnum::Math::Literals;
@ -446,9 +451,12 @@ GL::BufferImage2D image = framebuffer.read(framebuffer.viewport(),
#endif
{
GL::Buffer buffer;
/* [Buffer-setdata] */
Containers::ArrayView<Vector3> data;
const Vector3 data[]{
DOXYGEN_IGNORE({})
};
GL::Buffer buffer;
buffer.setData(data);
GL::Buffer buffer2{data}; // or construct & fill in a single step
@ -458,10 +466,23 @@ GL::Buffer buffer2{data}; // or construct & fill in a single step
{
GL::Buffer buffer;
/* [Buffer-setdata-stl] */
std::vector<Vector3> data;
std::vector<Vector3> data = DOXYGEN_IGNORE({});
buffer.setData(data);
/* [Buffer-setdata-stl] */
}
#ifndef MAGNUM_TARGET_GLES
{
Containers::ArrayView<const void> data;
/* [Buffer-setstorage] */
GL::Buffer buffer;
buffer.setStorage(data, {});
/* [Buffer-setstorage] */
}
#endif
{
GL::Buffer buffer;
/* [Buffer-setdata-allocate] */
buffer.setData({nullptr, 200*sizeof(Vector3)});
/* [Buffer-setdata-allocate] */
@ -471,8 +492,9 @@ buffer.setData({nullptr, 200*sizeof(Vector3)});
{
GL::Buffer buffer;
/* [Buffer-map] */
Containers::ArrayView<Vector3> data = Containers::arrayCast<Vector3>(buffer.map(0,
200*sizeof(Vector3), GL::Buffer::MapFlag::Write|GL::Buffer::MapFlag::InvalidateBuffer));
Containers::ArrayView<Vector3> data = Containers::arrayCast<Vector3>(
buffer.map(0, 200*sizeof(Vector3),
GL::Buffer::MapFlag::Write|GL::Buffer::MapFlag::InvalidateBuffer));
CORRADE_INTERNAL_ASSERT(data);
for(Vector3& d: data)
d = {/*...*/};
@ -483,8 +505,9 @@ CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap());
{
GL::Buffer buffer;
/* [Buffer-flush] */
Containers::ArrayView<Vector3> data = Containers::arrayCast<Vector3>(buffer.map(0,
200*sizeof(Vector3), GL::Buffer::MapFlag::Write|GL::Buffer::MapFlag::FlushExplicit));
Containers::ArrayView<Vector3> data = Containers::arrayCast<Vector3>(
buffer.map(0, 200*sizeof(Vector3),
GL::Buffer::MapFlag::Write|GL::Buffer::MapFlag::FlushExplicit));
CORRADE_INTERNAL_ASSERT(data);
for(std::size_t i: {7, 27, 56, 128}) {
data[i] = {/*...*/};
@ -497,14 +520,15 @@ CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap());
{
/* [Buffer-webgl-nope] */
GL::Buffer vertices, indices;
GL::Buffer vertices;
GL::Buffer indices;
/* [Buffer-webgl-nope] */
}
{
/* [Buffer-webgl] */
GL::Buffer vertices{GL::Buffer::TargetHint::Array},
indices{GL::Buffer::TargetHint::ElementArray};
GL::Buffer vertices{GL::Buffer::TargetHint::Array};
GL::Buffer indices{GL::Buffer::TargetHint::ElementArray};
/* [Buffer-webgl] */
}
@ -1016,156 +1040,112 @@ framebuffer.mapForDraw({
#endif
{
/* [Mesh-nonindexed] */
/* Custom shader, needing only position data */
class MyShader: public GL::AbstractShaderProgram {
public:
typedef GL::Attribute<0, Vector3> Position;
// ...
};
/* Fill vertex buffer with position data */
Vector3 positions[30]{
// ...
/* [Mesh-vertices] */
const Vector3 positions[]{
DOXYGEN_IGNORE({})
};
GL::Buffer vertexBuffer;
vertexBuffer.setData(positions, GL::BufferUsage::StaticDraw);
GL::Buffer vertices{positions};
/* Configure the mesh, add vertex buffer */
GL::Mesh mesh;
mesh.setPrimitive(MeshPrimitive::Triangles)
.addVertexBuffer(vertexBuffer, 0, MyShader::Position{})
.setCount(30);
/* [Mesh-nonindexed] */
mesh.setCount(Containers::arraySize(positions))
.addVertexBuffer(vertices, 0, Shaders::FlatGL3D::Position{});
/* [Mesh-vertices] */
}
{
/* [Mesh-interleaved] */
/* Non-indexed primitive with positions and normals */
Trade::MeshData plane = Primitives::planeSolid();
/* Fill a vertex buffer with interleaved position and normal data */
GL::Buffer buffer;
buffer.setData(MeshTools::interleave(plane.positions3DAsArray(),
plane.normalsAsArray()));
/* [Mesh-vertices-interleaved] */
struct Vertex {
Vector3 position;
Vector3 normal;
};
const Vertex vertexData[]{
DOXYGEN_IGNORE({})
};
GL::Buffer vertices{vertexData};
/* Configure the mesh, add the vertex buffer */
GL::Mesh mesh;
mesh.setPrimitive(plane.primitive())
.setCount(plane.vertexCount())
.addVertexBuffer(buffer, 0, Shaders::PhongGL::Position{}, Shaders::PhongGL::Normal{});
/* [Mesh-interleaved] */
mesh.setCount(Containers::arraySize(vertexData))
.addVertexBuffer(vertices, 0,
Shaders::PhongGL::Position{},
Shaders::PhongGL::Normal{});
/* [Mesh-vertices-interleaved] */
}
{
/* [Mesh-indexed] */
/* Custom shader */
class MyShader: public GL::AbstractShaderProgram {
public:
typedef GL::Attribute<0, Vector3> Position;
// ...
};
/* Fill vertex buffer with position data */
Vector3 positions[240]{
// ...
};
GL::Buffer vertexBuffer;
vertexBuffer.setData(positions);
/* Fill index buffer with index data */
UnsignedByte indices[75]{
// ...
GL::Mesh mesh;
/* [Mesh-indices] */
const UnsignedInt indexData[]{
DOXYGEN_IGNORE(0)
};
GL::Buffer indexBuffer;
indexBuffer.setData(indices);
GL::Buffer indices{indexData};
/* Configure the mesh, add both vertex and index buffer */
GL::Mesh mesh;
mesh.setPrimitive(MeshPrimitive::Triangles)
.setCount(75)
.addVertexBuffer(vertexBuffer, 0, MyShader::Position{})
.setIndexBuffer(indexBuffer, 0, GL::MeshIndexType::UnsignedByte, 176, 229);
/* [Mesh-indexed] */
DOXYGEN_IGNORE()
mesh.setIndexBuffer(indices, 0, MeshIndexType::UnsignedInt);
/* [Mesh-indices] */
}
{
/* [Mesh-indexed-tools] */
// Indexed primitive
Trade::MeshData cube = Primitives::cubeSolid();
// Fill vertex buffer with interleaved position and normal data
GL::Buffer vertexBuffer;
vertexBuffer.setData(MeshTools::interleave(cube.positions3DAsArray(),
cube.normalsAsArray()));
// Compress index data
Containers::Array<char> indexData;
MeshIndexType indexType;
std::tie(indexData, indexType) = MeshTools::compressIndices(cube.indices());
// Fill index buffer
GL::Buffer indexBuffer;
indexBuffer.setData(indexData);
// Configure the mesh, add both vertex and index buffer
GL::Mesh mesh;
mesh.setPrimitive(cube.primitive())
.setCount(cube.indexCount())
.addVertexBuffer(vertexBuffer, 0, Shaders::PhongGL::Position{}, Shaders::PhongGL::Normal{})
.setIndexBuffer(indexBuffer, 0, indexType);
/* [Mesh-indexed-tools] */
/* [Mesh-vertices-interleaved-tool] */
Containers::ArrayView<const Vector3> positions = DOXYGEN_IGNORE({});
Containers::ArrayView<const Vector3> normals = DOXYGEN_IGNORE({});
GL::Buffer vertices{MeshTools::interleave(positions, normals)};
DOXYGEN_IGNORE()
mesh.addVertexBuffer(vertices, 0,
Shaders::PhongGL::Position{},
Shaders::PhongGL::Normal{});
/* [Mesh-vertices-interleaved-tool] */
}
#ifndef MAGNUM_TARGET_GLES
{
/* [Mesh-formats] */
// Custom shader with colors specified as four floating-point values
class MyShader: public GL::AbstractShaderProgram {
public:
typedef GL::Attribute<0, Vector3> Position;
typedef GL::Attribute<1, Color4> Color;
GL::Mesh mesh;
const UnsignedInt indexData[1]{};
/* [Mesh-indices-tool] */
Containers::Array<char> compressed;
MeshIndexType type;
std::tie(compressed, type) = MeshTools::compressIndices(indexData);
GL::Buffer indices{compressed};
// ...
};
DOXYGEN_IGNORE()
mesh.setIndexBuffer(indices, 0, type);
/* [Mesh-indices-tool] */
}
/* Initial mesh configuration */
{
GL::Mesh mesh;
mesh.setPrimitive(MeshPrimitive::Triangles)
.setCount(30);
/* Fill position buffer with positions specified as two-component XY (i.e.,
no Z component, which is meant to be always 0) */
Vector2 positions[30]{
// ...
/* [Mesh-formats] */
struct Packed {
Vector3h position;
Short:16;
Vector3s normal;
Short:16;
};
GL::Buffer positionBuffer;
positionBuffer.setData(positions, GL::BufferUsage::StaticDraw);
/* Specify layout of positions buffer -- only two components, unspecified Z
component will be automatically set to 0 */
mesh.addVertexBuffer(positionBuffer, 0,
MyShader::Position{MyShader::Position::Components::Two});
/* Fill color buffer with colors specified as four-byte BGRA (i.e., directly
from a TGA file) */
UnsignedByte colors[4*30]{
// ...
const Packed vertexData[]{
DOXYGEN_IGNORE({})
};
GL::Buffer colorBuffer;
colorBuffer.setData(colors, GL::BufferUsage::StaticDraw);
/* Specify color buffer layout -- BGRA, each component unsigned byte and we
want to normalize them from [0, 255] to [0.0f, 1.0f] */
mesh.addVertexBuffer(colorBuffer, 0, MyShader::Color{
MyShader::Color::Components::BGRA,
MyShader::Color::DataType::UnsignedByte,
MyShader::Color::DataOption::Normalized});
GL::Buffer vertices{vertexData};
DOXYGEN_IGNORE()
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);
/* [Mesh-formats] */
/* [Mesh-formats-vertexformat] */
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});
/* [Mesh-formats-vertexformat] */
}
#endif
{
GL::Mesh mesh;
@ -1182,7 +1162,7 @@ mesh.addVertexBuffer(colorBuffer, 0, 4, GL::DynamicAttribute{
GL::Mesh mesh;
/* [Mesh-buffer-ownership] */
GL::Buffer vertices, indices;
// ...
DOXYGEN_IGNORE()
mesh.addVertexBuffer(std::move(vertices), 0,
Shaders::PhongGL::Position{},
Shaders::PhongGL::Normal{})
@ -1195,6 +1175,16 @@ mesh.addVertexBuffer(vertices, 0, Shaders::PhongGL::Position{}, 20)
/* [Mesh-buffer-ownership-multiple] */
}
{
GL::Mesh mesh;
/* [Mesh-draw] */
Shaders::PhongGL shader{DOXYGEN_IGNORE()};
DOXYGEN_IGNORE()
shader.draw(mesh);
/* [Mesh-draw] */
}
{
/* [Mesh-addVertexBuffer1] */
GL::Buffer buffer;

1
doc/snippets/MagnumTrade.cpp

@ -657,6 +657,7 @@ Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
#ifdef MAGNUM_TARGET_GL
{
/* This snippet is also used by GL::Mesh, bear that in mind when updating */
/* [MeshData-usage-compile] */
Trade::MeshData data = DOXYGEN_IGNORE(Trade::MeshData{MeshPrimitive::Points, 0});

45
src/Magnum/GL/Buffer.h

@ -135,23 +135,36 @@ namespace Implementation { struct BufferState; }
/**
@brief Buffer
Encapsulates one OpenGL buffer object and provides functions for convenient
data updates.
Wraps an OpenGL buffer object.
@section GL-Buffer-data-updating Data updating
@section GL-Buffer-data-upload Data upload
Default way to set or update buffer data with @ref setData(), @ref setSubData()
or the shorthand @ref Buffer() constructor is to use
@ref Corrade::Containers::ArrayView. See its documentation for more information
about automatic conversions etc.
Data can be uploaded to the buffer with @ref setData(), @ref setSubData() or
the shorthand @ref Buffer(Containers::ArrayView<const void>, BufferUsage) "Buffer()"
constructor. All these functions accept a @relativeref{Corrade,Containers::ArrayView}, which is among other things
implicitly convertible from statically sized C arrays or can be constructed
from a pair of a pointer and a size. You can optionally specify a usage hint
in the second argument, which defaults to @ref BufferUsage::StaticDraw.
@snippet MagnumGL.cpp Buffer-setdata
If you @cpp #include @ce @ref Corrade/Containers/ArrayViewStl.h, you can also
pass directly STL types such as @ref std::vector or @link std::array @endlink:
Furthermore, if you @cpp #include @ce @ref Corrade/Containers/ArrayViewStl.h,
you can also directly pass STL types such as a @ref std::vector or a
@ref std::array; with @ref Corrade/Containers/ArrayViewStlSpan.h the
@ref std::span is convertible to it as well:
@snippet MagnumGL.cpp Buffer-setdata-stl
An alternative to @ref setData() that provides more flexibility and better
performance guarantees is @ref setStorage(). It's similar in spirit to texture
storage, however as it's only available on desktop OpenGL 4.4
(@gl_extension{ARB,buffer_storage}), its usage isn't encouraged like with
textures. The minimal variant of the call shown below creates an immutable
buffer from given data in device memory, in the second argument you can specify
@ref StorageFlags that make it CPU-accessible, (persistently) mappable etc.
@snippet MagnumGL.cpp Buffer-setstorage
@section GL-Buffer-data-mapping Memory mapping
Buffer data can be also updated asynchronously. First you need to allocate
@ -178,19 +191,19 @@ Buffers in @ref MAGNUM_TARGET_WEBGL "WebGL" need to be bound only to one unique
target, i.e., @ref Buffer bound to @ref Buffer::TargetHint::Array cannot be
later rebound to @ref Buffer::TargetHint::ElementArray. However, Magnum by
default uses any sufficient target when binding the buffer internally (e.g. for
setting data). To avoid GL errors, the following, while completely fine on
desktop, is not sufficient on WebGL:
setting data). Which means the following, while completely fine on desktop and
OpenGL ES, is not sufficient on WebGL:
@snippet MagnumGL.cpp Buffer-webgl-nope
You have to set target hint to desired target, either in constructor or using
@ref Buffer::setTargetHint() like this (and similarly for other bufffer types
such as UBOs):
To avoid GL errors, you have to set target hint to desired target, either in
the constructor or using @ref setTargetHint(). A similar care needs to be taken
for uniform buffers and other types of buffers.
@snippet MagnumGL.cpp Buffer-webgl
To simplify debugging, @ref Mesh checks proper target hint when adding vertex
and index buffers in WebGL.
To simplify debugging, the @ref Mesh class checks proper target hint when
adding vertex and index buffers under WebGL.
@section GL-Buffer-performance-optimizations Performance optimizations

170
src/Magnum/GL/Mesh.h

@ -213,81 +213,155 @@ template<class T> struct IsDynamicAttribute<T, DynamicAttribute>: std::true_type
/**
@brief 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.
@section GL-Mesh-configuration-compile Quick usage with MeshTools::compile()
If you have a @ref Trade::MeshData instance that you got for example from
@ref Trade::AbstractImporter::mesh() or from the @ref Primitives library, the
simplest possible way is to use @ref MeshTools::compile():
@snippet MagnumTrade.cpp MeshData-usage-compile
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 @ref 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.
@m_class{m-note m-success}
@par
A generic mesh setup using the high-level utility is used in the
@ref examples-primitives and @ref examples-viewer examples.
@section GL-Mesh-configuration Mesh configuration
You have to specify at least primitive and vertex/index count using
@ref setPrimitive() and @ref setCount(). Then fill your vertex buffers with
data, add them to the mesh and specify @ref Attribute "shader attribute" layout
inside the buffers using @ref addVertexBuffer(). You can also use
@ref MeshTools::interleave() to conveniently interleave vertex data.
A mesh is, at the very least, a @ref MeshPrimitive and associated vertex/index
count. To prevent accidentally drawing empty meshes, you're required to call
@ref setCount() always, the primitive is however implicitly
@ref MeshPrimitive::Triangles and you can change it either in the constructor
or via @ref setPrimitive(). If @ref setCount() (or @ref setInstanceCount()) is
zero, the mesh is considered empty and no draw commands are issued when calling
@ref 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
@ref addVertexBuffer(). In the following snippet, a single position attribute
is specified, making it suitable to be rendered with the @ref Shaders::FlatGL
shader. The @relativeref{Magnum,Vector3} type we use for the data matches the
type expected by @ref Shaders::FlatGL3D::Position, so the default constructor
is sufficient for it. The @ref GL-Mesh-configuration-formats section below
shows cases where the types don't match.
If you want indexed mesh, fill your index buffer with data and specify its
layout using @ref setIndexBuffer(). You can also use @ref MeshTools::compressIndices()
to conveniently compress the indices based on the range used.
@snippet MagnumGL.cpp Mesh-vertices
There is also @ref MeshTools::compile() function which operates directly on
@ref Trade::MeshData and returns fully configured mesh and vertex/index buffers
for use with stock shaders.
Here's a mesh with a position and a normal interleaved together, as is needed
for @ref Shaders::PhongGL. See the docs of @ref addVertexBuffer() for
detailed description how particular attributes, offsets and paddings are
specified. Note that @ref Shaders::FlatGL::Position and
@ref Shaders::PhongGL::Position are both aliases to
@ref Shaders::GenericGL::Position, meaning you can render a mesh configured for
the Phong shader with the Flat shader as well:
@attention Note that, by default, neither vertex buffers nor index buffer is
managed (e.g. deleted on destruction) by the mesh, so you have to manage
them on your own and ensure that they are available for whole mesh
lifetime. See @ref GL-Mesh-buffer-ownership for a way to transfer buffer
ownership to the mesh.
@snippet MagnumGL.cpp Mesh-vertices-interleaved
If vertex/index count or instance count is zero, the mesh is empty and no draw
commands are issued when calling @ref AbstractShaderProgram::draw().
Indexed meshes have the index buffer and corresponding index type set using
@ref setIndexBuffer().
@subsection GL-Mesh-configuration-example Example mesh configuration
@snippet MagnumGL.cpp Mesh-indices
@subsubsection GL-Mesh-configuration-example-basic Basic non-indexed mesh
<b></b>
@snippet MagnumGL.cpp Mesh-nonindexed
@m_class{m-note m-warning}
@subsubsection GL-Mesh-configuration-interleaved Interleaved vertex data
@par
Note that, by default, the mesh doesn't deal with buffer ownership. You
have to ensure the index and vertex buffers stay in scope for as long as
the mesh is used, otherwise you'll end up with broken rendering or driver
crashes. See @ref GL-Mesh-buffer-ownership below for a way to transfer
buffer ownership to the mesh.
@snippet MagnumGL.cpp Mesh-interleaved
<b></b>
@subsubsection GL-Mesh-configuration-indexed Indexed mesh
@m_class{m-note m-success}
@snippet MagnumGL.cpp Mesh-indexed
@par
A basic non-indexed mesh setup using the low-level interface is shown in
the @ref examples-triangle "Triangle example", an indexed mesh then in the
following @ref examples-texturedquad "Textured Quad example".
Or using @ref MeshTools::interleave() and @ref MeshTools::compressIndices():
@subsection GL-Mesh-configuration-tools Using MeshTools
@snippet MagnumGL.cpp Mesh-indexed-tools
Real-world use cases rarely have a statically defined @cpp struct @ce with the
desired vertex attribute layout. If you have loose attribute arrays, you can
use @ref MeshTools::interleave() to interleave them together. The usage
including the padding specification, is similar to @ref addVertexBuffer(). The
above vertex buffer setup but with separate position and normal arrays that get interleaved can be expressed like this:
Or, if you plan to use the mesh with stock shaders, you can just use
@ref MeshTools::compile().
@snippet MagnumGL.cpp Mesh-vertices-interleaved-tool
@subsubsection GL-Mesh-configuration-formats Specific formats of vertex data
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 @ref MeshTools::compressIndices() is
for:
@snippet MagnumGL.cpp Mesh-indices-tool
The ultimate generic tool is the already-shown @ref MeshTools::compile(),
together with all @ref MeshTools APIs that operate on @ref Trade::MeshData
instances. See the class documentation for additional ways of accessing and
processing the data contained there.
@subsection GL-Mesh-configuration-formats 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 @relativeref{Magnum,Vector3h} and
the normal is a packed normalized @relativeref{Magnum,Vector3s}, together with
padding for having vertex boundaries aligned to four bytes to make the GPU
happier:
@snippet MagnumGL.cpp Mesh-formats
@subsubsection GL-Mesh-configuration-dynamic Dynamically specified attributes
@subsection GL-Mesh-configuration-dynamic 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 @ref addVertexBuffer() and
@ref addVertexBufferInstanced() that take @ref DynamicAttribute instead of
@ref Attribute typedefs. Adding a RGB attribute at location 3 normalized from
unsigned byte to float with one byte padding at the end could then look like
this:
@ref addVertexBufferInstanced() that take a @ref DynamicAttribute instead of
the @ref 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:
@snippet MagnumGL.cpp Mesh-dynamic
@section GL-Mesh-buffer-ownership Transferring buffer ownership
The @ref DynamicAttribute also allows @ref VertexFormat to be used for
specifying attribute types instead of the rather verbose
@ref GL::Attribute::Components, @relativeref{GL::Attribute,DataType} and
@relativeref{GL::Attribute,DataOptions} tuple that GL itself accepts. The above
packed position + normal attribute specification would then look like this:
@snippet MagnumGL.cpp Mesh-formats-vertexformat
@subsection GL-Mesh-buffer-ownership 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 user side. Simply use the @ref addVertexBuffer() /
the application side. Simply use the @ref addVertexBuffer() /
@ref addVertexBufferInstanced() and @ref setIndexBuffer() overloads that take
a @ref Buffer as a rvalue:
a @ref 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.
@snippet MagnumGL.cpp Mesh-buffer-ownership
While this allows you to destruct the buffer instances and pass just the mesh
around, this also means you lose a way to access or update the buffers. If
adding the same buffer multiple times or using it for both vertex and index
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:
@ -295,16 +369,22 @@ getting only a moved-out instance. For example:
@section GL-Mesh-rendering Rendering meshes
Basic workflow is: bind specific framebuffer for drawing (if needed), set up
respective shader (see
@ref GL-AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation"
for more information) and call @ref AbstractShaderProgram::draw().
With a framebuffer bound and a compatible shader set up, it's only a matter of
calling @ref AbstractShaderProgram::draw():
@snippet MagnumGL.cpp Mesh-draw
@section GL-Mesh-webgl-restrictions WebGL restrictions
@ref MAGNUM_TARGET_WEBGL "WebGL" puts some restrictions on vertex buffer
layout, see @ref addVertexBuffer() documentation for details.
The @ref Buffer binding restriction transitively affects meshes as well,
requiring @ref Buffer::TargetHint::ElementArray to be used for index buffers.
To simplify debugging, the @ref addVertexBuffer() and @ref setIndexBuffer()
functions checks proper target hint when adding vertex and index buffers under
WebGL.
@section GL-Mesh-performance-optimization Performance optimizations
If @gl_extension{ARB,vertex_array_object} (part of OpenGL 3.0), OpenGL ES 3.0,

6
src/Magnum/Trade/MeshData.h

@ -608,6 +608,12 @@ to the GPU. It also won't be able to deal with any custom attributes that the
mesh contains. Continue below to see how to achieve a similar effect with
lower-level APIs.
@m_class{m-note m-success}
@par
A generic mesh setup using the high-level utility is used in the
@ref examples-primitives and @ref examples-viewer examples.
@section Trade-MeshData-usage Basic usage
The second simplest usage is accessing attributes through the convenience

Loading…
Cancel
Save