diff --git a/doc/changelog.dox b/doc/changelog.dox index 39eef6aa9..bc33ca812 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -73,6 +73,11 @@ See also: - Added @ref MeshTools::generateQuadIndices() for quad triangulation including non-convex and non-planar quads +@subsubsection changelog-latest-new-shaders Shaders library + +- Added @ref Shaders::Phong::setNormalTextureScale(), consuming the recently + added @ref Trade::MaterialAttribute::NormalTextureScale material attribute + @subsubsection changelog-latest-new-scenegraph SceneGraph library - Added @ref SceneGraph::Object::move() @@ -148,6 +153,9 @@ See also: - @ref Shaders::Phong was normalizing light direction in vertex shader, causing the fragment-interpolated direction being incorrect with visible artifacts on long polygons under low light angle +- @ref Shaders::Phong wasn't normalizing normals coming from normal textures, + which may have caused slight artifacts due to limited precision of 8-bit + pixel formats @subsection changelog-latest-deprecated Deprecated APIs diff --git a/src/Magnum/Shaders/Phong.cpp b/src/Magnum/Shaders/Phong.cpp index dfdd6f915..18a10f990 100644 --- a/src/Magnum/Shaders/Phong.cpp +++ b/src/Magnum/Shaders/Phong.cpp @@ -178,6 +178,8 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l _diffuseColorUniform = uniformLocation("diffuseColor"); _specularColorUniform = uniformLocation("specularColor"); _shininessUniform = uniformLocation("shininess"); + if(flags & Flag::NormalTexture) + _normalTextureScaleUniform = uniformLocation("normalTextureScale"); _lightPositionsUniform = uniformLocation("lightPositions"); _lightColorsUniform = uniformLocation("lightColors"); } @@ -210,6 +212,8 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l setDiffuseColor(Magnum::Color4{1.0f}); setSpecularColor(Magnum::Color4{1.0f, 0.0f}); setShininess(80.0f); + if(flags & Flag::NormalTexture) + setNormalTextureScale(1.0f); setLightColors(Containers::Array{Containers::DirectInit, lightCount, Magnum::Color4{1.0f}}); /* Light position is zero by default */ setNormalMatrix({}); @@ -275,6 +279,13 @@ Phong& Phong::setShininess(Float shininess) { return *this; } +Phong& Phong::setNormalTextureScale(const Float scale) { + CORRADE_ASSERT(_flags & Flag::NormalTexture, + "Shaders::Phong::setNormalTextureScale(): the shader was not created with normal texture enabled", *this); + if(_lightCount) setUniform(_normalTextureScaleUniform, scale); + return *this; +} + Phong& Phong::setAlphaMask(Float mask) { CORRADE_ASSERT(_flags & Flag::AlphaMask, "Shaders::Phong::setAlphaMask(): the shader was not created with alpha mask enabled", *this); diff --git a/src/Magnum/Shaders/Phong.frag b/src/Magnum/Shaders/Phong.frag index 43a05e571..05e284e69 100644 --- a/src/Magnum/Shaders/Phong.frag +++ b/src/Magnum/Shaders/Phong.frag @@ -107,10 +107,21 @@ uniform mediump float shininess ; #endif -#ifdef ALPHA_MASK +#ifdef NORMAL_TEXTURE #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 8) #endif +uniform mediump float normalTextureScale + #ifndef GL_ES + = 1.0 + #endif + ; +#endif + +#ifdef ALPHA_MASK +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 9) +#endif uniform lowp float alphaMask #ifndef GL_ES = 0.5 @@ -120,16 +131,16 @@ uniform lowp float alphaMask #ifdef OBJECT_ID #ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 9) +layout(location = 10) #endif /* mediump is just 2^10, which might not be enough, this is 2^16 */ uniform highp uint objectId; /* defaults to zero */ #endif #if LIGHT_COUNT -/* Needs to be last because it uses locations 10 + LIGHT_COUNT to - 10 + 2*LIGHT_COUNT - 1. Location 10 is lightPositions. Also it can't be - specified as 10 + LIGHT_COUNT because that requires ARB_enhanced_layouts. */ +/* Needs to be last because it uses locations 11 + LIGHT_COUNT to + 11 + 2*LIGHT_COUNT - 1. Location 11 is lightPositions. Also it can't be + specified as 11 + LIGHT_COUNT because that requires ARB_enhanced_layouts. */ #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = LIGHT_COLORS_LOCATION) /* I fear this will blow up some drivers */ #endif @@ -214,7 +225,7 @@ void main() { normalizedTransformedTangent)), normalizedTransformedNormal ); - normalizedTransformedNormal = tbn*(texture(normalTexture, interpolatedTextureCoordinates).rgb*2.0 - vec3(1.0)); + normalizedTransformedNormal = tbn*(normalize((texture(normalTexture, interpolatedTextureCoordinates).rgb*2.0 - vec3(1.0))*vec3(normalTextureScale, normalTextureScale, 1.0))); #endif /* Add diffuse color for each light */ diff --git a/src/Magnum/Shaders/Phong.h b/src/Magnum/Shaders/Phong.h index fcd5b5557..6e03e6143 100644 --- a/src/Magnum/Shaders/Phong.h +++ b/src/Magnum/Shaders/Phong.h @@ -513,6 +513,24 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { */ Phong& bindDiffuseTexture(GL::Texture2D& texture); + /** + * @brief Set normal texture scale + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Affects strength of the normal mapping. Initial value is + * @cpp 1.0f @ce, meaning the normal texture is not changed in any way; + * a value of @cpp 0.0f @ce disables the normal texture effect + * altogether. + * + * Expects that the shader was created with @ref Flag::NormalTexture + * enabled. If @ref lightCount() is zero, this function is a no-op, as + * normals don't contribute to the output in that case. + * @see @ref bindNormalTexture(), + * @ref Trade::MaterialAttribute::NormalTextureScale + */ + Phong& setNormalTextureScale(Float scale); + /** * @brief Bind a normal texture * @return Reference to self (for method chaining) @@ -521,8 +539,8 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * Expects that the shader was created with @ref Flag::NormalTexture * enabled and the @ref Tangent attribute was supplied. If * @ref lightCount() is zero, this function is a no-op, as normals - * dosn't contribute to the output in that case. - * @see @ref bindTextures() + * don't contribute to the output in that case. + * @see @ref bindTextures(), @ref setNormalTextureScale() */ Phong& bindNormalTexture(GL::Texture2D& texture); @@ -743,12 +761,13 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { _diffuseColorUniform{5}, _specularColorUniform{6}, _shininessUniform{7}, - _alphaMaskUniform{8}; + _normalTextureScaleUniform{8}, + _alphaMaskUniform{9}; #ifndef MAGNUM_TARGET_GLES2 - Int _objectIdUniform{9}; + Int _objectIdUniform{10}; #endif - Int _lightPositionsUniform{10}, - _lightColorsUniform; /* 10 + lightCount, set in the constructor */ + Int _lightPositionsUniform{11}, + _lightColorsUniform; /* 11 + lightCount, set in the constructor */ }; /** @debugoperatorclassenum{Phong,Phong::Flag} */ diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index c89ee394a..981063770 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -73,9 +73,9 @@ uniform mediump mat3 textureMatrix #endif #if LIGHT_COUNT -/* Needs to be last because it uses locations 10 to 10 + LIGHT_COUNT - 1 */ +/* Needs to be last because it uses locations 11 to 11 + LIGHT_COUNT - 1 */ #ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 10) +layout(location = 11) #endif uniform highp vec3 lightPositions[LIGHT_COUNT]; /* defaults to zero */ #endif diff --git a/src/Magnum/Shaders/Test/CMakeLists.txt b/src/Magnum/Shaders/Test/CMakeLists.txt index 805405e70..83cd3f7e7 100644 --- a/src/Magnum/Shaders/Test/CMakeLists.txt +++ b/src/Magnum/Shaders/Test/CMakeLists.txt @@ -234,6 +234,8 @@ if(BUILD_GL_TESTS) PhongTestFiles/textured-diffuse.tga PhongTestFiles/textured-diffuse-transformed.tga PhongTestFiles/textured-normal.tga + PhongTestFiles/textured-normal0.0.tga + PhongTestFiles/textured-normal0.5.tga PhongTestFiles/textured-specular.tga PhongTestFiles/textured.tga PhongTestFiles/vertexColor.tga diff --git a/src/Magnum/Shaders/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index 50ce4718f..0e301e6ad 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/src/Magnum/Shaders/Test/PhongGLTest.cpp @@ -206,13 +206,17 @@ const struct { /* MSVC 2015 doesn't like constexpr here due to the angles */ const struct { const char* name; + const char* expected; bool multiBind; Deg rotation; + Float scale; } RenderTexturedNormalData[]{ - {"", false, {}}, - {"multi bind", true, {}}, - {"rotated 90°", false, 90.0_degf}, - {"rotated -90°", false, -90.0_degf} + {"", "textured-normal.tga", false, {}, 1.0f}, + {"multi bind", "textured-normal.tga", true, {}, 1.0f}, + {"rotated 90°", "textured-normal.tga", false, 90.0_degf, 1.0f}, + {"rotated -90°", "textured-normal.tga", false, -90.0_degf, 1.0f}, + {"0.5 scale", "textured-normal0.5.tga", false, {}, 0.5f}, + {"0.0 scale", "textured-normal0.0.tga", false, {}, 0.0f} }; const struct { @@ -490,6 +494,7 @@ void PhongGLTest::bindTexturesNotEnabled() { .bindDiffuseTexture(texture) .bindSpecularTexture(texture) .bindNormalTexture(texture) + .setNormalTextureScale(0.5f) .bindTextures(&texture, &texture, &texture, &texture); CORRADE_COMPARE(out.str(), @@ -497,6 +502,7 @@ void PhongGLTest::bindTexturesNotEnabled() { "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::setNormalTextureScale(): the shader was not created with normal texture enabled\n" "Shaders::Phong::bindTextures(): the shader was not created with any textures enabled\n"); } @@ -931,6 +937,10 @@ void PhongGLTest::renderTexturedNormal() { .setProjectionMatrix(Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)) .setDiffuseColor(0x999999_rgbf); + /* Verify the default is working properly */ + if(data.scale != 1.0f) + shader.setNormalTextureScale(data.scale); + if(data.multiBind) shader.bindTextures(nullptr, nullptr, nullptr, &normal); else @@ -965,7 +975,7 @@ void PhongGLTest::renderTexturedNormal() { const Float maxThreshold = 191.0f, meanThreshold = 3.017f; #endif CORRADE_COMPARE_WITH(pixels, - Utility::Directory::join(_testDir, "PhongTestFiles/textured-normal.tga"), + Utility::Directory::join({_testDir, "PhongTestFiles", data.expected}), (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); } @@ -1377,7 +1387,7 @@ void PhongGLTest::renderZeroLights() { Primitives::UVSphereFlag::TextureCoordinates)); /* Enable also Object ID, if supported */ - Phong::Flags flags = Phong::Flag::AmbientTexture|Phong::Flag::AlphaMask; + Phong::Flags flags = Phong::Flag::AmbientTexture|Phong::Flag::NormalTexture|Phong::Flag::AlphaMask; #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES if(GL::Context::current().isExtensionSupported()) @@ -1419,7 +1429,8 @@ void PhongGLTest::renderZeroLights() { .setNormalMatrix(Matrix3x3{Math::ZeroInit}) .setDiffuseColor(0xfa9922_rgbf) .setSpecularColor(0xfa9922_rgbf) - .setShininess(0.2f); + .setShininess(0.2f) + .setNormalTextureScale(-0.3f); #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/instanced-normal.tga b/src/Magnum/Shaders/Test/PhongTestFiles/instanced-normal.tga index ae238e262..7b2fe00b4 100644 Binary files a/src/Magnum/Shaders/Test/PhongTestFiles/instanced-normal.tga and b/src/Magnum/Shaders/Test/PhongTestFiles/instanced-normal.tga differ diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal.tga b/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal.tga index 87b5d7ea6..f6d72ad78 100644 Binary files a/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal.tga and b/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal.tga differ diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.0.tga b/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.0.tga new file mode 100644 index 000000000..e5aa174be Binary files /dev/null and b/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.0.tga differ diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.5.tga b/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.5.tga new file mode 100644 index 000000000..b85fd7aac Binary files /dev/null and b/src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.5.tga differ