Browse Source

Shaders: add normal texture support to Phong.

Note -- since there are no visual tests for Phong yet, this is done in
the least intrusive manner to avoid breaking current functionality. It's
likely very underperforming due to the matric calculation per fragment,
it'll get optimized once I have proper tests.
pull/344/head
Vladimír Vondruš 7 years ago
parent
commit
0cb4ded506
  1. 1
      doc/changelog.dox
  2. 4
      doc/snippets/MagnumShaders.cpp
  3. 23
      src/Magnum/Shaders/Phong.cpp
  4. 23
      src/Magnum/Shaders/Phong.frag
  5. 39
      src/Magnum/Shaders/Phong.h
  6. 15
      src/Magnum/Shaders/Phong.vert
  7. 11
      src/Magnum/Shaders/Test/PhongGLTest.cpp

1
doc/changelog.dox

@ -162,6 +162,7 @@ See also:
@subsubsection changelog-latest-new-shaders Shaders library @subsubsection changelog-latest-new-shaders Shaders library
- Normal texture support in @ref Shaders::Phong
- Added @ref Shaders::Generic3D::Tangent generic vertex attribute definition - Added @ref Shaders::Generic3D::Tangent generic vertex attribute definition
@subsubsection changelog-latest-new-text Text library @subsubsection changelog-latest-new-text Text library

4
doc/snippets/MagnumShaders.cpp

@ -342,7 +342,7 @@ GL::Texture2D diffuseTexture, specularTexture;
Shaders::Phong shader{Shaders::Phong::Flag::DiffuseTexture| Shaders::Phong shader{Shaders::Phong::Flag::DiffuseTexture|
Shaders::Phong::Flag::SpecularTexture}; Shaders::Phong::Flag::SpecularTexture};
shader.bindTextures(nullptr, &diffuseTexture, &specularTexture) shader.bindTextures(nullptr, &diffuseTexture, &specularTexture, nullptr)
.setLightPosition({5.0f, 5.0f, 7.0f}) .setLightPosition({5.0f, 5.0f, 7.0f})
.setTransformationMatrix(transformationMatrix) .setTransformationMatrix(transformationMatrix)
.setNormalMatrix(transformationMatrix.rotation()) .setNormalMatrix(transformationMatrix.rotation())
@ -359,7 +359,7 @@ Color3 diffuseRgb, specularRgb;
/* [Phong-usage-alpha] */ /* [Phong-usage-alpha] */
Shaders::Phong shader{Shaders::Phong::Flag::AmbientTexture| Shaders::Phong shader{Shaders::Phong::Flag::AmbientTexture|
Shaders::Phong::Flag::DiffuseTexture}; Shaders::Phong::Flag::DiffuseTexture};
shader.bindTextures(&diffuseAlphaTexture, &diffuseAlphaTexture, nullptr) shader.bindTextures(&diffuseAlphaTexture, &diffuseAlphaTexture, nullptr, nullptr)
.setAmbientColor(0x000000ff_rgbaf) .setAmbientColor(0x000000ff_rgbaf)
.setDiffuseColor(Color4{diffuseRgb, 0.0f}) .setDiffuseColor(Color4{diffuseRgb, 0.0f})
.setSpecularColor(Color4{specularRgb, 0.0f}); .setSpecularColor(Color4{specularRgb, 0.0f});

23
src/Magnum/Shaders/Phong.cpp

@ -46,7 +46,8 @@ namespace {
enum: Int { enum: Int {
AmbientTextureLayer = 0, AmbientTextureLayer = 0,
DiffuseTextureLayer = 1, DiffuseTextureLayer = 1,
SpecularTextureLayer = 2 SpecularTextureLayer = 2,
NormalTextureLayer = 3
}; };
} }
@ -87,13 +88,15 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
lightInitializer.resize(lightInitializer.size() - 1); lightInitializer.resize(lightInitializer.size() - 1);
#endif #endif
vert.addSource(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture) ? "#define TEXTURED\n" : "") vert.addSource(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture) ? "#define TEXTURED\n" : "")
.addSource(flags & Flag::NormalTexture ? "#define NORMAL_TEXTURE\n" : "")
.addSource(Utility::formatString("#define LIGHT_COUNT {}\n", lightCount)) .addSource(Utility::formatString("#define LIGHT_COUNT {}\n", lightCount))
.addSource(rs.get("generic.glsl")) .addSource(rs.get("generic.glsl"))
.addSource(rs.get("Phong.vert")); .addSource(rs.get("Phong.vert"));
frag.addSource(flags & Flag::AmbientTexture ? "#define AMBIENT_TEXTURE\n" : "") frag.addSource(flags & Flag::AmbientTexture ? "#define AMBIENT_TEXTURE\n" : "")
.addSource(flags & Flag::DiffuseTexture ? "#define DIFFUSE_TEXTURE\n" : "") .addSource(flags & Flag::DiffuseTexture ? "#define DIFFUSE_TEXTURE\n" : "")
.addSource(flags & Flag::SpecularTexture ? "#define SPECULAR_TEXTURE\n" : "") .addSource(flags & Flag::SpecularTexture ? "#define SPECULAR_TEXTURE\n" : "")
.addSource(flags & Flag::NormalTexture ? "#define NORMAL_TEXTURE\n" : "")
.addSource(flags & Flag::AlphaMask ? "#define ALPHA_MASK\n" : "") .addSource(flags & Flag::AlphaMask ? "#define ALPHA_MASK\n" : "")
.addSource(Utility::formatString( .addSource(Utility::formatString(
"#define LIGHT_COUNT {}\n" "#define LIGHT_COUNT {}\n"
@ -144,6 +147,7 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
if(flags & Flag::AmbientTexture) setUniform(uniformLocation("ambientTexture"), AmbientTextureLayer); if(flags & Flag::AmbientTexture) setUniform(uniformLocation("ambientTexture"), AmbientTextureLayer);
if(flags & Flag::DiffuseTexture) setUniform(uniformLocation("diffuseTexture"), DiffuseTextureLayer); if(flags & Flag::DiffuseTexture) setUniform(uniformLocation("diffuseTexture"), DiffuseTextureLayer);
if(flags & Flag::SpecularTexture) setUniform(uniformLocation("specularTexture"), SpecularTextureLayer); if(flags & Flag::SpecularTexture) setUniform(uniformLocation("specularTexture"), SpecularTextureLayer);
if(flags & Flag::NormalTexture) setUniform(uniformLocation("normalTexture"), NormalTextureLayer);
} }
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
@ -185,10 +189,17 @@ Phong& Phong::bindSpecularTexture(GL::Texture2D& texture) {
return *this; return *this;
} }
Phong& Phong::bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular) { Phong& Phong::bindNormalTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(_flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture), CORRADE_ASSERT(_flags & Flag::NormalTexture,
"Shaders::Phong::bindNormalTexture(): the shader was not created with normal texture enabled", *this);
texture.bind(NormalTextureLayer);
return *this;
}
Phong& Phong::bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular, GL::Texture2D* normal) {
CORRADE_ASSERT(_flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture, Flag::NormalTexture),
"Shaders::Phong::bindTextures(): the shader was not created with any textures enabled", *this); "Shaders::Phong::bindTextures(): the shader was not created with any textures enabled", *this);
GL::AbstractTexture::bind(AmbientTextureLayer, {ambient, diffuse, specular}); GL::AbstractTexture::bind(AmbientTextureLayer, {ambient, diffuse, specular, normal});
return *this; return *this;
} }
@ -234,6 +245,7 @@ Debug& operator<<(Debug& debug, const Phong::Flag value) {
_c(AmbientTexture) _c(AmbientTexture)
_c(DiffuseTexture) _c(DiffuseTexture)
_c(SpecularTexture) _c(SpecularTexture)
_c(NormalTexture)
_c(AlphaMask) _c(AlphaMask)
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -247,6 +259,7 @@ Debug& operator<<(Debug& debug, const Phong::Flags value) {
Phong::Flag::AmbientTexture, Phong::Flag::AmbientTexture,
Phong::Flag::DiffuseTexture, Phong::Flag::DiffuseTexture,
Phong::Flag::SpecularTexture, Phong::Flag::SpecularTexture,
Phong::Flag::NormalTexture,
Phong::Flag::AlphaMask}); Phong::Flag::AlphaMask});
} }

23
src/Magnum/Shaders/Phong.frag

@ -76,6 +76,13 @@ layout(binding = 2)
uniform lowp sampler2D specularTexture; uniform lowp sampler2D specularTexture;
#endif #endif
#ifdef NORMAL_TEXTURE
#ifdef EXPLICIT_TEXTURE_LAYER
layout(binding = 3)
#endif
uniform lowp sampler2D normalTexture;
#endif
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 6) layout(location = 6)
#endif #endif
@ -118,10 +125,13 @@ uniform lowp vec4 lightColors[LIGHT_COUNT]
; ;
in mediump vec3 transformedNormal; in mediump vec3 transformedNormal;
#ifdef NORMAL_TEXTURE
in mediump vec3 transformedTangent;
#endif
in highp vec3 lightDirections[LIGHT_COUNT]; in highp vec3 lightDirections[LIGHT_COUNT];
in highp vec3 cameraDirection; in highp vec3 cameraDirection;
#if defined(AMBIENT_TEXTURE) || defined(DIFFUSE_TEXTURE) || defined(SPECULAR_TEXTURE) #if defined(AMBIENT_TEXTURE) || defined(DIFFUSE_TEXTURE) || defined(SPECULAR_TEXTURE) || defined(NORMAL_TEXTURE)
in mediump vec2 interpolatedTextureCoords; in mediump vec2 interpolatedTextureCoords;
#endif #endif
@ -149,7 +159,18 @@ void main() {
/* Ambient color */ /* Ambient color */
color = finalAmbientColor; color = finalAmbientColor;
/* Normal */
mediump vec3 normalizedTransformedNormal = normalize(transformedNormal); mediump vec3 normalizedTransformedNormal = normalize(transformedNormal);
#ifdef NORMAL_TEXTURE
mediump vec3 normalizedTransformedTangent = normalize(transformedTangent);
mediump mat3 tbn = mat3(
normalizedTransformedTangent,
normalize(cross(normalizedTransformedNormal,
normalizedTransformedTangent)),
normalizedTransformedNormal
);
normalizedTransformedNormal = tbn*(texture(normalTexture, interpolatedTextureCoords).rgb*2.0 - vec3(1.0));
#endif
/* Add diffuse color for each light */ /* Add diffuse color for each light */
for(int i = 0; i < LIGHT_COUNT; ++i) { for(int i = 0; i < LIGHT_COUNT; ++i) {

39
src/Magnum/Shaders/Phong.h

@ -115,6 +115,15 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
*/ */
typedef Generic3D::Normal Normal; typedef Generic3D::Normal Normal;
/**
* @brief Tangent direction
*
* @ref shaders-generic "Generic attribute",
* @ref Magnum::Vector3 "Vector3", used only if
* @ref Flag::NormalTexture is set.
*/
typedef Generic3D::Tangent Tangent;
/** /**
* @brief 2D texture coordinates * @brief 2D texture coordinates
* *
@ -149,6 +158,12 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
*/ */
SpecularTexture = 1 << 2, SpecularTexture = 1 << 2,
/**
* Modify normals according to a texture. Requires the
* @ref Tangent attribute to be present.
*/
NormalTexture = 1 << 4,
/** /**
* Enable alpha masking. If the combined fragment color has an * Enable alpha masking. If the combined fragment color has an
* alpha less than the value specified with @ref setAlphaMask(), * alpha less than the value specified with @ref setAlphaMask(),
@ -271,6 +286,16 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
} }
#endif #endif
/**
* @brief Bind a normal texture
* @return Reference to self (for method chaining)
*
* Expects that the shader was created with @ref Flag::NormalTexture
* enabled and the @ref Tangent attribute was supplied.
* @see @ref bindTextures()
*/
Phong& bindNormalTexture(GL::Texture2D& texture);
/** /**
* @brief Set specular color * @brief Set specular color
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
@ -312,13 +337,17 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* A particular texture has effect only if particular texture flag from * A particular texture has effect only if particular texture flag from
* @ref Phong::Flag "Flag" is set, you can use @cpp nullptr @ce for the * @ref Phong::Flag "Flag" is set, you can use @cpp nullptr @ce for the
* rest. Expects that the shader was created with at least one of * rest. Expects that the shader was created with at least one of
* @ref Flag::AmbientTexture, @ref Flag::DiffuseTexture or * @ref Flag::AmbientTexture, @ref Flag::DiffuseTexture,
* @ref Flag::SpecularTexture enabled. More efficient than setting each * @ref Flag::SpecularTexture or @ref Flag::NormalTexture enabled. More
* texture separately. * efficient than setting each texture separately.
* @see @ref bindAmbientTexture(), @ref bindDiffuseTexture(), * @see @ref bindAmbientTexture(), @ref bindDiffuseTexture(),
* @ref bindSpecularTexture() * @ref bindSpecularTexture(), @ref bindNormalTexture()
*/ */
Phong& bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular); Phong& bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular, GL::Texture2D* normal
#ifdef MAGNUM_BUILD_DEPRECATED
= nullptr
#endif
);
#ifdef MAGNUM_BUILD_DEPRECATED #ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief bindTextures() /** @brief @copybrief bindTextures()

15
src/Magnum/Shaders/Phong.vert

@ -71,6 +71,13 @@ layout(location = NORMAL_ATTRIBUTE_LOCATION)
#endif #endif
in mediump vec3 normal; in mediump vec3 normal;
#ifdef NORMAL_TEXTURE
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = TANGENT_ATTRIBUTE_LOCATION)
#endif
in mediump vec3 tangent;
#endif
#ifdef TEXTURED #ifdef TEXTURED
#ifdef EXPLICIT_ATTRIB_LOCATION #ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = TEXTURECOORDINATES_ATTRIBUTE_LOCATION) layout(location = TEXTURECOORDINATES_ATTRIBUTE_LOCATION)
@ -81,6 +88,9 @@ out mediump vec2 interpolatedTextureCoords;
#endif #endif
out mediump vec3 transformedNormal; out mediump vec3 transformedNormal;
#ifdef NORMAL_TEXTURE
out mediump vec3 transformedTangent;
#endif
out highp vec3 lightDirections[LIGHT_COUNT]; out highp vec3 lightDirections[LIGHT_COUNT];
out highp vec3 cameraDirection; out highp vec3 cameraDirection;
@ -89,8 +99,11 @@ void main() {
highp vec4 transformedPosition4 = transformationMatrix*position; highp vec4 transformedPosition4 = transformationMatrix*position;
highp vec3 transformedPosition = transformedPosition4.xyz/transformedPosition4.w; highp vec3 transformedPosition = transformedPosition4.xyz/transformedPosition4.w;
/* Transformed normal vector */ /* Transformed normal and tangent vector */
transformedNormal = normalMatrix*normal; transformedNormal = normalMatrix*normal;
#ifdef NORMAL_TEXTURE
transformedTangent = normalMatrix*tangent;
#endif
/* Direction to the light */ /* Direction to the light */
for(int i = 0; i < LIGHT_COUNT; ++i) for(int i = 0; i < LIGHT_COUNT; ++i)

11
src/Magnum/Shaders/Test/PhongGLTest.cpp

@ -61,10 +61,12 @@ constexpr struct {
{"ambient texture", Phong::Flag::AmbientTexture, 1}, {"ambient texture", Phong::Flag::AmbientTexture, 1},
{"diffuse texture", Phong::Flag::DiffuseTexture, 1}, {"diffuse texture", Phong::Flag::DiffuseTexture, 1},
{"specular texture", Phong::Flag::SpecularTexture, 1}, {"specular texture", Phong::Flag::SpecularTexture, 1},
{"normal texture", Phong::Flag::NormalTexture, 1},
{"ambient + diffuse texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture, 1}, {"ambient + diffuse texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture, 1},
{"ambient + specular texture", Phong::Flag::AmbientTexture|Phong::Flag::SpecularTexture, 1}, {"ambient + specular texture", Phong::Flag::AmbientTexture|Phong::Flag::SpecularTexture, 1},
{"diffuse + specular texture", Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture, 1}, {"diffuse + specular texture", Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture, 1},
{"ambient + diffuse + specular texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture, 1}, {"ambient + diffuse + specular texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture, 1},
{"ambient + diffuse + specular + normal texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture|Phong::Flag::NormalTexture, 1},
{"alpha mask", Phong::Flag::AlphaMask, 1}, {"alpha mask", Phong::Flag::AlphaMask, 1},
{"alpha mask + diffuse texture", Phong::Flag::AlphaMask|Phong::Flag::DiffuseTexture, 1}, {"alpha mask + diffuse texture", Phong::Flag::AlphaMask|Phong::Flag::DiffuseTexture, 1},
{"five lights", {}, 5} {"five lights", {}, 5}
@ -135,11 +137,12 @@ void PhongGLTest::bindTextures() {
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
/* Test just that no assertion is fired */ /* Test just that no assertion is fired */
Phong shader{Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture}; Phong shader{Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture|Phong::Flag::NormalTexture};
shader.bindAmbientTexture(texture) shader.bindAmbientTexture(texture)
.bindDiffuseTexture(texture) .bindDiffuseTexture(texture)
.bindSpecularTexture(texture) .bindSpecularTexture(texture)
.bindTextures(&texture, &texture, &texture); .bindNormalTexture(texture)
.bindTextures(&texture, &texture, &texture, &texture);
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
} }
@ -153,12 +156,14 @@ void PhongGLTest::bindTexturesNotEnabled() {
shader.bindAmbientTexture(texture) shader.bindAmbientTexture(texture)
.bindDiffuseTexture(texture) .bindDiffuseTexture(texture)
.bindSpecularTexture(texture) .bindSpecularTexture(texture)
.bindTextures(&texture, &texture, &texture); .bindNormalTexture(texture)
.bindTextures(&texture, &texture, &texture, &texture);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Shaders::Phong::bindAmbientTexture(): the shader was not created with ambient texture enabled\n" "Shaders::Phong::bindAmbientTexture(): the shader was not created with ambient texture enabled\n"
"Shaders::Phong::bindDiffuseTexture(): the shader was not created with diffuse texture enabled\n" "Shaders::Phong::bindDiffuseTexture(): the shader was not created with diffuse texture enabled\n"
"Shaders::Phong::bindSpecularTexture(): the shader was not created with specular texture enabled\n" "Shaders::Phong::bindSpecularTexture(): the shader was not created with specular texture enabled\n"
"Shaders::Phong::bindNormalTexture(): the shader was not created with normal texture enabled\n"
"Shaders::Phong::bindTextures(): the shader was not created with any textures enabled\n"); "Shaders::Phong::bindTextures(): the shader was not created with any textures enabled\n");
} }

Loading…
Cancel
Save