Browse Source

Shaders: add a normal texture scale parameter to Phong.

It's needed to support the new material attributes supported by glTF.
The test output is slightly different as the normal coming from
the texture wasn't normalized before.
pull/470/head
Vladimír Vondruš 6 years ago
parent
commit
5285dcc986
  1. 8
      doc/changelog.dox
  2. 11
      src/Magnum/Shaders/Phong.cpp
  3. 23
      src/Magnum/Shaders/Phong.frag
  4. 31
      src/Magnum/Shaders/Phong.h
  5. 4
      src/Magnum/Shaders/Phong.vert
  6. 2
      src/Magnum/Shaders/Test/CMakeLists.txt
  7. 25
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  8. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/instanced-normal.tga
  9. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/textured-normal.tga
  10. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.0.tga
  11. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.5.tga

8
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

11
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<Magnum::Color4>{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);

23
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 */

31
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} */

4
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

2
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

25
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<GL::Extensions::EXT::gpu_shader4>())
@ -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

BIN
src/Magnum/Shaders/Test/PhongTestFiles/instanced-normal.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/PhongTestFiles/textured-normal.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.0.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/PhongTestFiles/textured-normal0.5.tga

Binary file not shown.
Loading…
Cancel
Save