From 0cb4ded5069f4db9e7e6c713344385b7d06d3754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 28 May 2019 12:26:55 +0200 Subject: [PATCH] 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. --- doc/changelog.dox | 1 + doc/snippets/MagnumShaders.cpp | 4 +-- src/Magnum/Shaders/Phong.cpp | 23 +++++++++++---- src/Magnum/Shaders/Phong.frag | 23 ++++++++++++++- src/Magnum/Shaders/Phong.h | 39 +++++++++++++++++++++---- src/Magnum/Shaders/Phong.vert | 15 +++++++++- src/Magnum/Shaders/Test/PhongGLTest.cpp | 11 +++++-- 7 files changed, 99 insertions(+), 17 deletions(-) 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"); }