diff --git a/doc/changelog.dox b/doc/changelog.dox index 54bdbf5dd..8126df9ed 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -162,6 +162,7 @@ See also: @subsubsection changelog-latest-new-shaders Shaders library +- Normal texture support in @ref Shaders::Phong - Added @ref Shaders::Generic3D::Tangent generic vertex attribute definition @subsubsection changelog-latest-new-text Text library diff --git a/doc/snippets/MagnumShaders.cpp b/doc/snippets/MagnumShaders.cpp index 4ebdcd8e1..b0737b522 100644 --- a/doc/snippets/MagnumShaders.cpp +++ b/doc/snippets/MagnumShaders.cpp @@ -342,7 +342,7 @@ GL::Texture2D diffuseTexture, specularTexture; Shaders::Phong shader{Shaders::Phong::Flag::DiffuseTexture| Shaders::Phong::Flag::SpecularTexture}; -shader.bindTextures(nullptr, &diffuseTexture, &specularTexture) +shader.bindTextures(nullptr, &diffuseTexture, &specularTexture, nullptr) .setLightPosition({5.0f, 5.0f, 7.0f}) .setTransformationMatrix(transformationMatrix) .setNormalMatrix(transformationMatrix.rotation()) @@ -359,7 +359,7 @@ Color3 diffuseRgb, specularRgb; /* [Phong-usage-alpha] */ Shaders::Phong shader{Shaders::Phong::Flag::AmbientTexture| Shaders::Phong::Flag::DiffuseTexture}; -shader.bindTextures(&diffuseAlphaTexture, &diffuseAlphaTexture, nullptr) +shader.bindTextures(&diffuseAlphaTexture, &diffuseAlphaTexture, nullptr, nullptr) .setAmbientColor(0x000000ff_rgbaf) .setDiffuseColor(Color4{diffuseRgb, 0.0f}) .setSpecularColor(Color4{specularRgb, 0.0f}); diff --git a/src/Magnum/Shaders/Phong.cpp b/src/Magnum/Shaders/Phong.cpp index b128afc91..e204c76f7 100644 --- a/src/Magnum/Shaders/Phong.cpp +++ b/src/Magnum/Shaders/Phong.cpp @@ -46,7 +46,8 @@ namespace { enum: Int { AmbientTextureLayer = 0, 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); #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(rs.get("generic.glsl")) .addSource(rs.get("Phong.vert")); frag.addSource(flags & Flag::AmbientTexture ? "#define AMBIENT_TEXTURE\n" : "") .addSource(flags & Flag::DiffuseTexture ? "#define DIFFUSE_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(Utility::formatString( "#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::DiffuseTexture) setUniform(uniformLocation("diffuseTexture"), DiffuseTextureLayer); 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) */ @@ -185,10 +189,17 @@ Phong& Phong::bindSpecularTexture(GL::Texture2D& texture) { return *this; } -Phong& Phong::bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, GL::Texture2D* specular) { - CORRADE_ASSERT(_flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture), +Phong& Phong::bindNormalTexture(GL::Texture2D& texture) { + 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); - GL::AbstractTexture::bind(AmbientTextureLayer, {ambient, diffuse, specular}); + GL::AbstractTexture::bind(AmbientTextureLayer, {ambient, diffuse, specular, normal}); return *this; } @@ -234,6 +245,7 @@ Debug& operator<<(Debug& debug, const Phong::Flag value) { _c(AmbientTexture) _c(DiffuseTexture) _c(SpecularTexture) + _c(NormalTexture) _c(AlphaMask) #undef _c /* LCOV_EXCL_STOP */ @@ -247,6 +259,7 @@ Debug& operator<<(Debug& debug, const Phong::Flags value) { Phong::Flag::AmbientTexture, Phong::Flag::DiffuseTexture, Phong::Flag::SpecularTexture, + Phong::Flag::NormalTexture, Phong::Flag::AlphaMask}); } diff --git a/src/Magnum/Shaders/Phong.frag b/src/Magnum/Shaders/Phong.frag index 6b654cc22..34e82be94 100644 --- a/src/Magnum/Shaders/Phong.frag +++ b/src/Magnum/Shaders/Phong.frag @@ -76,6 +76,13 @@ layout(binding = 2) uniform lowp sampler2D specularTexture; #endif +#ifdef NORMAL_TEXTURE +#ifdef EXPLICIT_TEXTURE_LAYER +layout(binding = 3) +#endif +uniform lowp sampler2D normalTexture; +#endif + #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 6) #endif @@ -118,10 +125,13 @@ uniform lowp vec4 lightColors[LIGHT_COUNT] ; in mediump vec3 transformedNormal; +#ifdef NORMAL_TEXTURE +in mediump vec3 transformedTangent; +#endif in highp vec3 lightDirections[LIGHT_COUNT]; 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; #endif @@ -149,7 +159,18 @@ void main() { /* Ambient color */ color = finalAmbientColor; + /* Normal */ 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 */ for(int i = 0; i < LIGHT_COUNT; ++i) { diff --git a/src/Magnum/Shaders/Phong.h b/src/Magnum/Shaders/Phong.h index 3a6e0b60f..b2ff117b3 100644 --- a/src/Magnum/Shaders/Phong.h +++ b/src/Magnum/Shaders/Phong.h @@ -115,6 +115,15 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { */ 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 * @@ -149,6 +158,12 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { */ 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 * alpha less than the value specified with @ref setAlphaMask(), @@ -271,6 +286,16 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { } #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 * @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 * @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 - * @ref Flag::AmbientTexture, @ref Flag::DiffuseTexture or - * @ref Flag::SpecularTexture enabled. More efficient than setting each - * texture separately. + * @ref Flag::AmbientTexture, @ref Flag::DiffuseTexture, + * @ref Flag::SpecularTexture or @ref Flag::NormalTexture enabled. More + * efficient than setting each texture separately. * @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 /** @brief @copybrief bindTextures() diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index b049c859a..082ce51f6 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -71,6 +71,13 @@ layout(location = NORMAL_ATTRIBUTE_LOCATION) #endif 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 EXPLICIT_ATTRIB_LOCATION layout(location = TEXTURECOORDINATES_ATTRIBUTE_LOCATION) @@ -81,6 +88,9 @@ out mediump vec2 interpolatedTextureCoords; #endif out mediump vec3 transformedNormal; +#ifdef NORMAL_TEXTURE +out mediump vec3 transformedTangent; +#endif out highp vec3 lightDirections[LIGHT_COUNT]; out highp vec3 cameraDirection; @@ -89,8 +99,11 @@ void main() { highp vec4 transformedPosition4 = transformationMatrix*position; highp vec3 transformedPosition = transformedPosition4.xyz/transformedPosition4.w; - /* Transformed normal vector */ + /* Transformed normal and tangent vector */ transformedNormal = normalMatrix*normal; + #ifdef NORMAL_TEXTURE + transformedTangent = normalMatrix*tangent; + #endif /* Direction to the light */ for(int i = 0; i < LIGHT_COUNT; ++i) diff --git a/src/Magnum/Shaders/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index ec10ec85d..b2966582e 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/src/Magnum/Shaders/Test/PhongGLTest.cpp @@ -61,10 +61,12 @@ constexpr struct { {"ambient texture", Phong::Flag::AmbientTexture, 1}, {"diffuse texture", Phong::Flag::DiffuseTexture, 1}, {"specular texture", Phong::Flag::SpecularTexture, 1}, + {"normal texture", Phong::Flag::NormalTexture, 1}, {"ambient + diffuse texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture, 1}, {"ambient + specular texture", Phong::Flag::AmbientTexture|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 + normal texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture|Phong::Flag::NormalTexture, 1}, {"alpha mask", Phong::Flag::AlphaMask, 1}, {"alpha mask + diffuse texture", Phong::Flag::AlphaMask|Phong::Flag::DiffuseTexture, 1}, {"five lights", {}, 5} @@ -135,11 +137,12 @@ void PhongGLTest::bindTextures() { MAGNUM_VERIFY_NO_GL_ERROR(); /* 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) .bindDiffuseTexture(texture) .bindSpecularTexture(texture) - .bindTextures(&texture, &texture, &texture); + .bindNormalTexture(texture) + .bindTextures(&texture, &texture, &texture, &texture); MAGNUM_VERIFY_NO_GL_ERROR(); } @@ -153,12 +156,14 @@ void PhongGLTest::bindTexturesNotEnabled() { shader.bindAmbientTexture(texture) .bindDiffuseTexture(texture) .bindSpecularTexture(texture) - .bindTextures(&texture, &texture, &texture); + .bindNormalTexture(texture) + .bindTextures(&texture, &texture, &texture, &texture); CORRADE_COMPARE(out.str(), "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::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"); }