Magnum::Shaders::Phong class

Phong shader.

Uses ambient, diffuse and specular color or texture. For a colored mesh you need to provide the Position and Normal attributes in your triangle mesh. By default, the shader renders the mesh with a white color in an identity transformation. Use setTransformationMatrix(), setNormalMatrix(), setProjectionMatrix(), setLightPosition() and others to configure the shader.

Image

Colored rendering

Common mesh setup:

struct Vertex {
    Vector3 position;
    Vector3 normal;
};
Vertex data[60]{
    // ...
};

GL::Buffer vertices;
vertices.setData(data, GL::BufferUsage::StaticDraw);

GL::Mesh mesh;
mesh.addVertexBuffer(vertices, 0,
    Shaders::Phong::Position{},
    Shaders::Phong::Normal{});

Common rendering setup:

Matrix4 transformationMatrix = Matrix4::translation(Vector3::zAxis(-5.0f));
Matrix4 projectionMatrix =
    Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.001f, 100.0f);

Shaders::Phong shader;
shader.setDiffuseColor(0x2f83cc_rgbf)
    .setShininess(200.0f)
    .setLightPosition({5.0f, 5.0f, 7.0f})
    .setTransformationMatrix(transformationMatrix)
    .setNormalMatrix(transformationMatrix.normalMatrix())
    .setProjectionMatrix(projectionMatrix)
    .draw(mesh);

Textured rendering

If you want to use textures, you need to provide also the TextureCoordinates attribute. Pass appropriate Flag combination to the constructor and then at render time don't forget to also call appropriate subset of bindAmbientTexture(), bindDiffuseTexture() and bindSpecularTexture() (or the combined bindTextures()). The texture is multipled by the color, which is by default set to fully opaque white for enabled textures. Mesh setup with a diffuse and a specular texture:

struct Vertex {
    Vector3 position;
    Vector3 normal;
    Vector2 textureCoordinates;
};
Vertex data[60]{
    // ...
};

GL::Buffer vertices;
vertices.setData(data, GL::BufferUsage::StaticDraw);

GL::Mesh mesh;
mesh.addVertexBuffer(vertices, 0,
    Shaders::Phong::Position{},
    Shaders::Phong::Normal{},
    Shaders::Phong::TextureCoordinates{});

Common rendering setup:

Matrix4 transformationMatrix, projectionMatrix;
GL::Texture2D diffuseTexture, specularTexture;

Shaders::Phong shader{Shaders::Phong::Flag::DiffuseTexture|
                      Shaders::Phong::Flag::SpecularTexture};
shader.bindTextures(nullptr, &diffuseTexture, &specularTexture, nullptr)
    .setLightPosition({5.0f, 5.0f, 7.0f})
    .setTransformationMatrix(transformationMatrix)
    .setNormalMatrix(transformationMatrix.normalMatrix())
    .setProjectionMatrix(projectionMatrix)
    .draw(mesh);

Alpha blending and masking

Enable Flag::AlphaMask and tune setAlphaMask() for simple binary alpha-masked drawing that doesn't require depth sorting or blending enabled. Note that this feature is implemented using the GLSL discard operation which is known to have considerable performance impact on some platforms. With proper depth sorting and blending you'll usually get much better performance and output quality.

For general alpha-masked drawing you need to provide an ambient texture with alpha channel and set alpha channel of the diffuse/specular color to 0.0f so only ambient alpha will be taken into account. If you have a diffuse texture combined with the alpha mask, you can use that texture for both ambient and diffuse part and then separate the alpha like this:

Shaders::Phong shader{Shaders::Phong::Flag::AmbientTexture|
                      Shaders::Phong::Flag::DiffuseTexture};
shader.bindTextures(&diffuseAlphaTexture, &diffuseAlphaTexture, nullptr, nullptr)
    .setAmbientColor(0x000000ff_rgbaf)
    .setDiffuseColor(Color4{diffuseRgb, 0.0f})
    .setSpecularColor(Color4{specularRgb, 0.0f});

Object ID output

The shader supports writing object ID to the framebuffer for object picking or other annotation purposes. Enable it using Flag::ObjectId and set up an integer buffer attached to the ObjectIdOutput attachment. If you have a batch of meshes with different object IDs, enable Flag::InstancedObjectId and supply per-vertex IDs to the ObjectId attribute. The output will contain a sum of the per-vertex ID and ID coming from setObjectId().

The functionality is practically the same as in the Flat shader, see its documentation for more information and usage example.

Instanced rendering

Enabling Flag::InstancedTransformation will turn the shader into an instanced one. It'll take per-instance transformation and normal matrix from the TransformationMatrix and NormalMatrix attributes, applying those before the matrix set by setTransformationMatrix() and setNormalMatrix(). Besides that, Flag::VertexColor (and the Color3 / Color4) attributes can work as both per-vertex and per-instance, and for texturing it's possible to have per-instance texture offset taken from TextureOffset when Flag::InstancedTextureOffset is enabled (similarly to transformation, applied before setTextureMatrix()). The snippet below shows adding a buffer with per-instance transformation to a mesh — note how a normal matrix attribute has to be populated and supplied as well to ensure lighting works:

struct {
    Matrix4 transformation;
    Matrix3x3 normal;
} instanceData[] {
    {Matrix4::translation({1.0f, 2.0f, 0.0f})*Matrix4::rotationX(90.0_degf), {}},
    {Matrix4::translation({2.0f, 1.0f, 0.0f})*Matrix4::rotationY(90.0_degf), {}},
    {Matrix4::translation({3.0f, 0.0f, 1.0f})*Matrix4::rotationZ(90.0_degf), {}},
    // ...
};
for(auto& instance: instanceData)
    instance.normal = instance.transformation.normalMatrix();

mesh.setInstanceCount(Containers::arraySize(instanceData))
    .addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0,
        Shaders::Phong::TransformationMatrix{},
        Shaders::Phong::NormalMatrix{});

Zero lights

Creating this shader with zero lights makes its output equivalent to the Flat3D shader — only setAmbientColor() and bindAmbientTexture() (if Flag::AmbientTexture is enabled) are taken into account, which correspond to Flat::setColor() and Flat::bindTexture(). This is useful to reduce complexity in apps that render models with pre-baked lights. For instanced workflows using zero lights means the NormalMatrix instance attribute doesn't need to be supplied either. In addition, enabling Flag::VertexColor and using a default ambient color with no texturing makes this shader equivalent to VertexColor.

Base classes

class Magnum::GL::AbstractShaderProgram
Base for shader program implementations.

Public types

enum (anonymous): UnsignedInt { ColorOutput = Generic3D::ColorOutput new in 2019.10, ObjectIdOutput = Generic3D::ObjectIdOutput new in 2019.10 }
enum class Flag: UnsignedShort { AmbientTexture = 1 << 0, DiffuseTexture = 1 << 1, SpecularTexture = 1 << 2, NormalTexture = 1 << 4 new in 2019.10, AlphaMask = 1 << 3, VertexColor = 1 << 5 new in 2019.10, TextureTransformation = 1 << 6 new in Git master, ObjectId = 1 << 7 new in 2019.10, InstancedObjectId = (1 << 8)|ObjectId new in Git master, InstancedTransformation = 1 << 9 new in Git master, InstancedTextureOffset = (1 << 10)|TextureTransformation new in Git master }
Flag.
using Position = Generic3D::Position
Vertex position.
using Normal = Generic3D::Normal
Normal direction.
using Tangent = Generic3D::Tangent new in 2019.10
Tangent direction.
using TextureCoordinates = Generic3D::TextureCoordinates
2D texture coordinates
using Color3 = Generic3D::Color3 new in 2019.10
Three-component vertex color.
using Color4 = Generic3D::Color4 new in 2019.10
Four-component vertex color.
using ObjectId = Generic3D::ObjectId new in Git master
(Instanced) object ID
using TransformationMatrix = Generic3D::TransformationMatrix new in Git master
(Instanced) transformation matrix
using NormalMatrix = Generic3D::NormalMatrix new in Git master
(Instanced) normal matrix
using TextureOffset = Generic3D::TextureOffset new in Git master
(Instanced) texture offset
using Flags = Containers::EnumSet<Flag>
Flags.

Constructors, destructors, conversion operators

Phong(Flags flags = {}, UnsignedInt lightCount = 1) explicit
Constructor.
Phong(NoCreateT) explicit noexcept
Construct without creating the underlying OpenGL object.
Phong(const Phong&) deleted
Copying is not allowed.
Phong(Phong&&) defaulted noexcept
Move constructor.

Public functions

auto operator=(const Phong&) -> Phong& deleted
Copying is not allowed.
auto operator=(Phong&&) -> Phong& defaulted noexcept
Move assignment.
auto flags() const -> Flags
Flags.
auto lightCount() const -> UnsignedInt
Light count.
auto setAmbientColor(const Magnum::Color4& color) -> Phong&
Set ambient color.
auto bindAmbientTexture(GL::Texture2D& texture) -> Phong&
Bind an ambient texture.
auto setDiffuseColor(const Magnum::Color4& color) -> Phong&
Set diffuse color.
auto bindDiffuseTexture(GL::Texture2D& texture) -> Phong&
Bind a diffuse texture.
auto bindNormalTexture(GL::Texture2D& texture) -> Phong& new in 2019.10
Bind a normal texture.
auto setSpecularColor(const Magnum::Color4& color) -> Phong&
Set specular color.
auto bindSpecularTexture(GL::Texture2D& texture) -> Phong&
Bind a specular texture.
auto bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular, GL::Texture2D* normal = nullptr) -> Phong&
Bind textures.
auto setShininess(Float shininess) -> Phong&
Set shininess.
auto setAlphaMask(Float mask) -> Phong&
Set alpha mask value.
auto setObjectId(UnsignedInt id) -> Phong&
Set object ID.
auto setTransformationMatrix(const Matrix4& matrix) -> Phong&
Set transformation matrix.
auto setNormalMatrix(const Matrix3x3& matrix) -> Phong&
Set normal matrix.
auto setProjectionMatrix(const Matrix4& matrix) -> Phong&
Set projection matrix.
auto setTextureMatrix(const Matrix3& matrix) -> Phong& new in Git master
Set texture coordinate transformation matrix.
auto setLightPositions(Containers::ArrayView<const Vector3> lights) -> Phong&
Set light positions.
auto setLightPositions(std::initializer_list<Vector3> lights) -> Phong&
auto setLightPosition(UnsignedInt id, const Vector3& position) -> Phong&
Set position for given light.
auto setLightPosition(const Vector3& position) -> Phong&
Set light position.
auto setLightColors(Containers::ArrayView<const Magnum::Color4> colors) -> Phong&
Set light colors.
auto setLightColors(std::initializer_list<Magnum::Color4> colors) -> Phong&
auto setLightColor(UnsignedInt id, const Magnum::Color4& color) -> Phong&
Set position for given light.
auto setLightColor(const Magnum::Color4& color) -> Phong&
Set light color.

Enum documentation

enum Magnum::Shaders::Phong::(anonymous): UnsignedInt

Enumerators
ColorOutput new in 2019.10

Color shader output. Generic output, present always. Expects three- or four-component floating-point or normalized buffer attachment.

ObjectIdOutput new in 2019.10

Object ID shader output. Generic output, present only if Flag::ObjectId is set. Expects a single-component unsigned integral attachment. Writes the value set in setObjectId() there, see Object ID output for more information.

enum class Magnum::Shaders::Phong::Flag: UnsignedShort

Flag.

Enumerators
AmbientTexture

Multiply ambient color with a texture.

DiffuseTexture

Multiply diffuse color with a texture.

SpecularTexture

Multiply specular color with a texture.

NormalTexture new in 2019.10

Modify normals according to a texture. Requires the Tangent attribute to be present.

AlphaMask

Enable alpha masking. If the combined fragment color has an alpha less than the value specified with setAlphaMask(), given fragment is discarded.

This uses the discard operation which is known to have considerable performance impact on some platforms. While useful for cheap alpha masking that doesn't require depth sorting, with proper depth sorting and blending you'll usually get much better performance and output quality.

VertexColor new in 2019.10

Multiply diffuse color with a vertex color. Requires either the Color3 or Color4 attribute to be present.

TextureTransformation new in Git master

Enable texture coordinate transformation. If this flag is set, the shader expects that at least one of Flag::AmbientTexture, Flag::DiffuseTexture, Flag::SpecularTexture or Flag::NormalTexture is enabled as well.

ObjectId new in 2019.10

Enable object ID output. See Object ID output for more information.

InstancedObjectId new in Git master

Instanced object ID. Retrieves a per-instance / per-vertex object ID from the ObjectId attribute, outputting a sum of the per-vertex ID and ID coming from setObjectId(). Implicitly enables Flag::ObjectId. See Object ID output for more information.

InstancedTransformation new in Git master

Instanced transformation. Retrieves a per-instance transformation and normal matrix from the TransformationMatrix / NormalMatrix attributes and uses them together with matrices coming from setTransformationMatrix() and setNormalMatrix() (first the per-instance, then the uniform matrix). See Instanced rendering for more information.

InstancedTextureOffset new in Git master

Instanced texture offset. Retrieves a per-instance offset vector from the TextureOffset attribute and uses it together with the matrix coming from setTextureMatrix() (first the per-instance vector, then the uniform matrix). Instanced texture scaling and rotation is not supported at the moment, you can specify that only via the uniform setTextureMatrix(). Implicitly enables Flag::TextureTransformation. See Instanced rendering for more information.

Typedef documentation

typedef Generic3D::Position Magnum::Shaders::Phong::Position

Vertex position.

Generic attribute, Vector3.

typedef Generic3D::Normal Magnum::Shaders::Phong::Normal

Normal direction.

Generic attribute, Vector3.

typedef Generic3D::Tangent Magnum::Shaders::Phong::Tangent new in 2019.10

Tangent direction.

Generic attribute, Vector3, used only if Flag::NormalTexture is set.

typedef Generic3D::TextureCoordinates Magnum::Shaders::Phong::TextureCoordinates

2D texture coordinates

Generic attribute, Vector2, used only if at least one of Flag::AmbientTexture, Flag::DiffuseTexture and Flag::SpecularTexture is set.

typedef Generic3D::Color3 Magnum::Shaders::Phong::Color3 new in 2019.10

Three-component vertex color.

Generic attribute, Magnum::Color3. Use either this or the Color4 attribute. Used only if Flag::VertexColor is set.

typedef Generic3D::Color4 Magnum::Shaders::Phong::Color4 new in 2019.10

Four-component vertex color.

Generic attribute, Magnum::Color4. Use either this or the Color3 attribute. Used only if Flag::VertexColor is set.

typedef Generic3D::ObjectId Magnum::Shaders::Phong::ObjectId new in Git master

(Instanced) object ID

Generic attribute, Magnum::UnsignedInt. Used only if Flag::InstancedObjectId is set.

typedef Containers::EnumSet<Flag> Magnum::Shaders::Phong::Flags

Flags.

Function documentation

Magnum::Shaders::Phong::Phong(Flags flags = {}, UnsignedInt lightCount = 1) explicit

Constructor.

Parameters
flags Flags
lightCount Count of light sources

Magnum::Shaders::Phong::Phong(NoCreateT) explicit noexcept

Construct without creating the underlying OpenGL object.

The constructed instance is equivalent to a 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.

Phong& Magnum::Shaders::Phong::setAmbientColor(const Magnum::Color4& color)

Set ambient color.

Returns Reference to self (for method chaining)

If Flag::AmbientTexture is set, default value is 0xffffffff_rgbaf and the color will be multiplied with ambient texture, otherwise default value is 0x00000000_rgbaf.

Phong& Magnum::Shaders::Phong::bindAmbientTexture(GL::Texture2D& texture)

Bind an ambient texture.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::AmbientTexture enabled.

Phong& Magnum::Shaders::Phong::setDiffuseColor(const Magnum::Color4& color)

Set diffuse color.

Returns Reference to self (for method chaining)

Initial value is 0xffffffff_rgbaf. If lightCount() is zero, this function is a no-op, as diffuse color doesn't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::bindDiffuseTexture(GL::Texture2D& texture)

Bind a diffuse texture.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::DiffuseTexture enabled. If lightCount() is zero, this function is a no-op, as diffuse color doesn't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::bindNormalTexture(GL::Texture2D& texture) new in 2019.10

Bind a normal texture.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::NormalTexture enabled and the Tangent attribute was supplied. If lightCount() is zero, this function is a no-op, as normals dosn't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::setSpecularColor(const Magnum::Color4& color)

Set specular color.

Returns Reference to self (for method chaining)

Initial value is 0xffffffff_rgbaf. Color will be multiplied with specular texture if Flag::SpecularTexture is set. If you want to have a fully diffuse material, set specular color to 0x000000ff_rgbaf. If lightCount() is zero, this function is a no-op, as specular color doesn't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::bindSpecularTexture(GL::Texture2D& texture)

Bind a specular texture.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::SpecularTexture enabled. If lightCount() is zero, this function is a no-op, as specular color doesn't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular, GL::Texture2D* normal = nullptr)

Bind textures.

Returns Reference to self (for method chaining)

A particular texture has effect only if particular texture flag from Flag is set, you can use nullptr for the rest. Expects that the shader was created with at least one of Flag::AmbientTexture, Flag::DiffuseTexture, Flag::SpecularTexture or Flag::NormalTexture enabled. More efficient than setting each texture separately.

Phong& Magnum::Shaders::Phong::setShininess(Float shininess)

Set shininess.

Returns Reference to self (for method chaining)

The larger value, the harder surface (smaller specular highlight). Initial value is 80.0f. If lightCount() is zero, this function is a no-op, as specular color doesn't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::setAlphaMask(Float mask)

Set alpha mask value.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::AlphaMask enabled. Fragments with alpha values smaller than the mask value will be discarded. Initial value is 0.5f. See the flag documentation for further information.

Phong& Magnum::Shaders::Phong::setObjectId(UnsignedInt id)

Set object ID.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::ObjectId enabled. Value set here is written to the ObjectIdOutput, see Object ID output for more information. Default is 0.

Phong& Magnum::Shaders::Phong::setTransformationMatrix(const Matrix4& matrix)

Set transformation matrix.

Returns Reference to self (for method chaining)

You need to set also setNormalMatrix() with a corresponding value. Initial value is an identity matrix.

Phong& Magnum::Shaders::Phong::setNormalMatrix(const Matrix3x3& matrix)

Set normal matrix.

Returns Reference to self (for method chaining)

The matrix doesn't need to be normalized, as renormalization is done per-fragment anyway. You need to set also setTransformationMatrix() with a corresponding value. Initial value is an identity matrix. If lightCount() is zero, this function is a no-op, as normals don't contribute to the output in that case.

Phong& Magnum::Shaders::Phong::setProjectionMatrix(const Matrix4& matrix)

Set projection matrix.

Returns Reference to self (for method chaining)

Initial value is an identity matrix (i.e., an orthographic projection of the default $ [ -\boldsymbol{1} ; \boldsymbol{1} ] $ cube).

Phong& Magnum::Shaders::Phong::setTextureMatrix(const Matrix3& matrix) new in Git master

Set texture coordinate transformation matrix.

Returns Reference to self (for method chaining)

Expects that the shader was created with Flag::TextureTransformation enabled. Initial value is an identity matrix.

Phong& Magnum::Shaders::Phong::setLightPositions(Containers::ArrayView<const Vector3> lights)

Set light positions.

Returns Reference to self (for method chaining)

Initial values are zero vectors — that will in most cases cause the object to be rendered black (or in the ambient color), as the lights are is inside of it. Expects that the size of the lights array is the same as lightCount().

Phong& Magnum::Shaders::Phong::setLightPositions(std::initializer_list<Vector3> lights)

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

Phong& Magnum::Shaders::Phong::setLightPosition(UnsignedInt id, const Vector3& position)

Set position for given light.

Returns Reference to self (for method chaining)

Unlike setLightPosition() updates just a single light position. Expects that id is less than lightCount().

Phong& Magnum::Shaders::Phong::setLightPosition(const Vector3& position)

Set light position.

Returns Reference to self (for method chaining)

Convenience alternative to setLightPositions() when there is just one light.

Phong& Magnum::Shaders::Phong::setLightColors(Containers::ArrayView<const Magnum::Color4> colors)

Set light colors.

Returns Reference to self (for method chaining)

Initial values are 0xffffffff_rgbaf. Expects that the size of the colors array is the same as lightCount().

Phong& Magnum::Shaders::Phong::setLightColors(std::initializer_list<Magnum::Color4> colors)

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

Phong& Magnum::Shaders::Phong::setLightColor(UnsignedInt id, const Magnum::Color4& color)

Set position for given light.

Returns Reference to self (for method chaining)

Unlike setLightColors() updates just a single light color. Expects that id is less than lightCount().

Phong& Magnum::Shaders::Phong::setLightColor(const Magnum::Color4& color)

Set light color.

Returns Reference to self (for method chaining)

Convenience alternative to setLightColors() when there is just one light.

Debug& operator<<(Debug& debug, Phong::Flag value)

Debug output operator.

Debug& operator<<(Debug& debug, Phong::Flags value)

Debug output operator.