Browse Source

Shaders: allow Phong with zero lights.

Which makes it equivalent to Flat3D. Useful to reduce complexity in apps
that render models with pre-baked lighting.
pull/364/head
Vladimír Vondruš 7 years ago
parent
commit
a3c8d8ec63
  1. 3
      doc/changelog.dox
  2. 7
      src/Magnum/Shaders/Flat.h
  3. 100
      src/Magnum/Shaders/Phong.cpp
  4. 10
      src/Magnum/Shaders/Phong.frag
  5. 42
      src/Magnum/Shaders/Phong.h
  6. 10
      src/Magnum/Shaders/Phong.vert
  7. 5
      src/Magnum/Shaders/Test/CMakeLists.txt
  8. 108
      src/Magnum/Shaders/Test/PhongGLTest.cpp

3
doc/changelog.dox

@ -346,6 +346,9 @@ See also:
- @ref Shaders::Phong now clamps the specular factor to minimize artifacts
when shininess is near zero
- @ref Shaders::Phong can now handle zero lights, in which case its output is
equivalent to @ref Shaders::Flat3D. See @ref Shaders-Phong-zero-lights for
more information.
@subsubsection changelog-latest-changes-texturetools TextureTools library

7
src/Magnum/Shaders/Flat.h

@ -65,10 +65,13 @@ and then at render time don't forget to bind also the texture via
@ref bindTexture(). The texture is multipled by the color, which is by default
set to @cpp 0xffffffff_rgbaf @ce.
For coloring the texture based on intensity you can use the @ref Vector shader.
@image html shaders-flat.png width=256px
For coloring the texture based on intensity you can use the @ref Vector shader.
The 3D version of this shader is equivalent to @ref Phong with zero lights,
however this implementation is much simpler and thus likely also faster. See
@ref Shaders-Phong-zero-lights "its documentation" for more information.
@section Shaders-Flat-usage Example usage
@subsection Shaders-Flat-usage-colored Colored mesh

100
src/Magnum/Shaders/Phong.cpp

@ -69,23 +69,25 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
#ifndef MAGNUM_TARGET_GLES
/* Initializer for the light color array -- we need a list of vec4(1.0)
joined by commas. For GLES we'll simply upload the values directly. */
constexpr const char lightInitializerPreamble[] = "#define LIGHT_COLOR_INITIALIZER ";
constexpr std::size_t lightInitializerPreambleSize =
Containers::arraySize(lightInitializerPreamble) - 1;
constexpr const char lightInitializerItem[] = "vec4(1.0), ";
constexpr std::size_t lightInitializerItemSize =
Containers::arraySize(lightInitializerItem) - 1;
std::string lightInitializer;
lightInitializer.reserve(Containers::arraySize(lightInitializerPreamble) - 1 + lightCount*lightInitializerItemSize);
lightInitializer.append(lightInitializerPreamble, lightInitializerPreambleSize);
for(std::size_t i = 0; i != lightCount; ++i)
lightInitializer.append(lightInitializerItem, lightInitializerItemSize);
/* Drop the last comma and add a newline at the end */
lightInitializer[lightInitializer.size() - 2] = '\n';
lightInitializer.resize(lightInitializer.size() - 1);
if(lightCount) {
/* Initializer for the light color array -- we need a list of vec4(1.0)
joined by commas. For GLES we'll simply upload the values directly. */
constexpr const char lightInitializerPreamble[] = "#define LIGHT_COLOR_INITIALIZER ";
constexpr std::size_t lightInitializerPreambleSize =
Containers::arraySize(lightInitializerPreamble) - 1;
constexpr const char lightInitializerItem[] = "vec4(1.0), ";
constexpr std::size_t lightInitializerItemSize =
Containers::arraySize(lightInitializerItem) - 1;
lightInitializer.reserve(Containers::arraySize(lightInitializerPreamble) - 1 + lightCount*lightInitializerItemSize);
lightInitializer.append(lightInitializerPreamble, lightInitializerPreambleSize);
for(std::size_t i = 0; i != lightCount; ++i)
lightInitializer.append(lightInitializerItem, lightInitializerItemSize);
/* Drop the last comma and add a newline at the end */
lightInitializer[lightInitializer.size() - 2] = '\n';
lightInitializer.resize(lightInitializer.size() - 1);
}
#endif
vert.addSource(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture) ? "#define TEXTURED\n" : "")
@ -103,11 +105,11 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
#endif
.addSource(Utility::formatString(
"#define LIGHT_COUNT {}\n"
"#define LIGHT_COLORS_LOCATION {}\n", lightCount, _lightPositionsUniform + lightCount))
#ifndef MAGNUM_TARGET_GLES
.addSource(std::move(lightInitializer))
#endif
.addSource(rs.get("generic.glsl"))
"#define LIGHT_COLORS_LOCATION {}\n", lightCount, _lightPositionsUniform + lightCount));
#ifndef MAGNUM_TARGET_GLES
if(lightCount) frag.addSource(std::move(lightInitializer));
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Phong.frag"));
CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag}));
@ -122,8 +124,9 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
#endif
{
bindAttributeLocation(Position::Location, "position");
bindAttributeLocation(Normal::Location, "normal");
if(flags & Flag::NormalTexture)
if(lightCount)
bindAttributeLocation(Normal::Location, "normal");
if((flags & Flag::NormalTexture) && lightCount)
bindAttributeLocation(Tangent::Location, "tangent");
if(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture))
bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates");
@ -144,17 +147,19 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
{
_transformationMatrixUniform = uniformLocation("transformationMatrix");
_projectionMatrixUniform = uniformLocation("projectionMatrix");
_normalMatrixUniform = uniformLocation("normalMatrix");
_ambientColorUniform = uniformLocation("ambientColor");
_diffuseColorUniform = uniformLocation("diffuseColor");
_specularColorUniform = uniformLocation("specularColor");
_shininessUniform = uniformLocation("shininess");
if(lightCount) {
_normalMatrixUniform = uniformLocation("normalMatrix");
_diffuseColorUniform = uniformLocation("diffuseColor");
_specularColorUniform = uniformLocation("specularColor");
_shininessUniform = uniformLocation("shininess");
_lightPositionsUniform = uniformLocation("lightPositions");
_lightColorsUniform = uniformLocation("lightColors");
}
if(flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask");
#ifndef MAGNUM_TARGET_GLES2
if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId");
#endif
_lightPositionsUniform = uniformLocation("lightPositions");
_lightColorsUniform = uniformLocation("lightColors");
}
#ifndef MAGNUM_TARGET_GLES
@ -162,9 +167,11 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
#endif
{
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);
if(lightCount) {
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) */
@ -172,17 +179,18 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
/* Default to fully opaque white so we can see the textures */
if(flags & Flag::AmbientTexture) setAmbientColor(Color4{1.0f});
else setAmbientColor(Color4{0.0f});
setDiffuseColor(Color4{1.0f});
setSpecularColor(Color4{1.0f});
setShininess(80.0f);
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
setLightColors(Containers::Array<Color4>{Containers::DirectInit, lightCount, Color4{1.0f}});
/* Light position is zero by default */
setTransformationMatrix({});
setProjectionMatrix({});
setNormalMatrix({});
if(lightCount) {
setDiffuseColor(Color4{1.0f});
setSpecularColor(Color4{1.0f});
setShininess(80.0f);
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
setLightColors(Containers::Array<Color4>{Containers::DirectInit, lightCount, Color4{1.0f}});
/* Light position is zero by default */
setNormalMatrix({});
}
#endif
}
@ -196,21 +204,21 @@ Phong& Phong::bindAmbientTexture(GL::Texture2D& texture) {
Phong& Phong::bindDiffuseTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(_flags & Flag::DiffuseTexture,
"Shaders::Phong::bindDiffuseTexture(): the shader was not created with diffuse texture enabled", *this);
texture.bind(DiffuseTextureLayer);
if(_lightCount) texture.bind(DiffuseTextureLayer);
return *this;
}
Phong& Phong::bindSpecularTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(_flags & Flag::SpecularTexture,
"Shaders::Phong::bindSpecularTexture(): the shader was not created with specular texture enabled", *this);
texture.bind(SpecularTextureLayer);
if(_lightCount) texture.bind(SpecularTextureLayer);
return *this;
}
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);
if(_lightCount) texture.bind(NormalTextureLayer);
return *this;
}
@ -240,7 +248,7 @@ Phong& Phong::setObjectId(UnsignedInt id) {
Phong& Phong::setLightPositions(const Containers::ArrayView<const Vector3> positions) {
CORRADE_ASSERT(_lightCount == positions.size(),
"Shaders::Phong::setLightPositions(): expected" << _lightCount << "items but got" << positions.size(), *this);
setUniform(_lightPositionsUniform, positions);
if(_lightCount) setUniform(_lightPositionsUniform, positions);
return *this;
}
@ -254,7 +262,7 @@ Phong& Phong::setLightPosition(UnsignedInt id, const Vector3& position) {
Phong& Phong::setLightColors(const Containers::ArrayView<const Color4> colors) {
CORRADE_ASSERT(_lightCount == colors.size(),
"Shaders::Phong::setLightColors(): expected" << _lightCount << "items but got" << colors.size(), *this);
setUniform(_lightColorsUniform, colors);
if(_lightCount) setUniform(_lightColorsUniform, colors);
return *this;
}

10
src/Magnum/Shaders/Phong.frag

@ -53,6 +53,7 @@ uniform lowp vec4 ambientColor
#endif
;
#if LIGHT_COUNT
#ifdef DIFFUSE_TEXTURE
#ifdef EXPLICIT_TEXTURE_LAYER
layout(binding = 1)
@ -100,6 +101,7 @@ uniform mediump float shininess
= 80.0
#endif
;
#endif
#ifdef ALPHA_MASK
#ifdef EXPLICIT_UNIFORM_LOCATION
@ -120,6 +122,7 @@ layout(location = 9)
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. */
@ -131,13 +134,16 @@ uniform lowp vec4 lightColors[LIGHT_COUNT]
= vec4[](LIGHT_COLOR_INITIALIZER)
#endif
;
#endif
#if LIGHT_COUNT
in mediump vec3 transformedNormal;
#ifdef NORMAL_TEXTURE
in mediump vec3 transformedTangent;
#endif
in highp vec3 lightDirections[LIGHT_COUNT];
in highp vec3 cameraDirection;
#endif
#if defined(AMBIENT_TEXTURE) || defined(DIFFUSE_TEXTURE) || defined(SPECULAR_TEXTURE) || defined(NORMAL_TEXTURE)
in mediump vec2 interpolatedTextureCoords;
@ -163,6 +169,7 @@ void main() {
texture(ambientTexture, interpolatedTextureCoords)*
#endif
ambientColor;
#if LIGHT_COUNT
lowp const vec4 finalDiffuseColor =
#ifdef DIFFUSE_TEXTURE
texture(diffuseTexture, interpolatedTextureCoords)*
@ -173,10 +180,12 @@ void main() {
texture(specularTexture, interpolatedTextureCoords)*
#endif
specularColor;
#endif
/* Ambient color */
fragmentColor = finalAmbientColor;
#if LIGHT_COUNT
/* Normal */
mediump vec3 normalizedTransformedNormal = normalize(transformedNormal);
#ifdef NORMAL_TEXTURE
@ -203,6 +212,7 @@ void main() {
fragmentColor += vec4(finalSpecularColor.rgb*specularity, finalSpecularColor.a);
}
}
#endif
#ifdef ALPHA_MASK
/* Using <= because if mask is set to 1.0, it should discard all, similarly

42
src/Magnum/Shaders/Phong.h

@ -107,6 +107,14 @@ example.
@requires_gles30 Object ID output requires integer buffer attachments, which
are not available in OpenGL ES 2.0 or WebGL 1.0.
@section Shaders-Phong-zero-lights Zero lights
Creating this shader with zero lights makes its output equivalent to the
@ref Flat3D shader --- only @ref setAmbientColor() and @ref bindAmbientTexture()
(if @ref Flag::AmbientTexture is enabled) are taken into account, which
correspond to @ref Flat::setColor() and @ref Flat::bindTexture(). This is
useful to reduce complexity in apps that render models with pre-baked lights.
@see @ref shaders
*/
class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
@ -305,11 +313,13 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* @brief Set diffuse color
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0xffffffff_rgbaf @ce.
* Initial value is @cpp 0xffffffff_rgbaf @ce. If @ref lightCount() is
* zero, this function is a no-op, as diffuse color doesn't contribute
* to the output in that case.
* @see @ref bindDiffuseTexture()
*/
Phong& setDiffuseColor(const Color4& color) {
setUniform(_diffuseColorUniform, color);
if(_lightCount) setUniform(_diffuseColorUniform, color);
return *this;
}
@ -318,7 +328,8 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* @return Reference to self (for method chaining)
*
* Expects that the shader was created with @ref Flag::DiffuseTexture
* enabled.
* enabled. If @ref lightCount() is zero, this function is a no-op, as
* diffuse color doesn't contribute to the output in that case.
* @see @ref bindTextures(), @ref setDiffuseColor()
*/
Phong& bindDiffuseTexture(GL::Texture2D& texture);
@ -337,7 +348,9 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* @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.
* 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()
*/
Phong& bindNormalTexture(GL::Texture2D& texture);
@ -349,11 +362,13 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* Initial value is @cpp 0xffffffff_rgbaf @ce. Color will be multiplied
* with specular texture if @ref Flag::SpecularTexture is set. If you
* want to have a fully diffuse material, set specular color to
* @cpp 0x000000ff_rgbaf @ce.
* @cpp 0x000000ff_rgbaf @ce. If @ref lightCount() is zero, this
* function is a no-op, as specular color doesn't contribute to the
* output in that case.
* @see @ref bindSpecularTexture()
*/
Phong& setSpecularColor(const Color4& color) {
setUniform(_specularColorUniform, color);
if(_lightCount) setUniform(_specularColorUniform, color);
return *this;
}
@ -362,7 +377,8 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* @return Reference to self (for method chaining)
*
* Expects that the shader was created with @ref Flag::SpecularTexture
* enabled.
* enabled. If @ref lightCount() is zero, this function is a no-op, as
* specular color doesn't contribute to the output in that case.
* @see @ref bindTextures(), @ref setSpecularColor()
*/
Phong& bindSpecularTexture(GL::Texture2D& texture);
@ -409,10 +425,12 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* @return Reference to self (for method chaining)
*
* The larger value, the harder surface (smaller specular highlight).
* Initial value is @cpp 80.0f @ce.
* Initial value is @cpp 80.0f @ce. If @ref lightCount() is zero, this
* function is a no-op, as specular color doesn't contribute to the
* output in that case.
*/
Phong& setShininess(Float shininess) {
setUniform(_shininessUniform, shininess);
if(_lightCount) setUniform(_shininessUniform, shininess);
return *this;
}
@ -462,10 +480,12 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* The matrix doesn't need to be normalized, as the renormalization
* must be done in the shader anyway. You need to set also
* @ref setTransformationMatrix() with a corresponding value. Initial
* value is an identity matrix.
* value is an identity matrix. If @ref lightCount() is zero, this
* function is a no-op, as normals don't contribute to the output in
* that case.
*/
Phong& setNormalMatrix(const Matrix3x3& matrix) {
setUniform(_normalMatrixUniform, matrix);
if(_lightCount) setUniform(_normalMatrixUniform, matrix);
return *this;
}

10
src/Magnum/Shaders/Phong.vert

@ -46,6 +46,7 @@ uniform highp mat4 projectionMatrix
#endif
;
#if LIGHT_COUNT
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
#endif
@ -54,18 +55,22 @@ uniform mediump mat3 normalMatrix
= mat3(1.0)
#endif
;
#endif
#if LIGHT_COUNT
/* Needs to be last because it uses locations 10 to 10 + LIGHT_COUNT - 1 */
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 10)
#endif
uniform highp vec3 lightPositions[LIGHT_COUNT]; /* defaults to zero */
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = POSITION_ATTRIBUTE_LOCATION)
#endif
in highp vec4 position;
#if LIGHT_COUNT
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = NORMAL_ATTRIBUTE_LOCATION)
#endif
@ -77,6 +82,7 @@ layout(location = TANGENT_ATTRIBUTE_LOCATION)
#endif
in mediump vec3 tangent;
#endif
#endif
#ifdef TEXTURED
#ifdef EXPLICIT_ATTRIB_LOCATION
@ -87,18 +93,21 @@ in mediump vec2 textureCoords;
out mediump vec2 interpolatedTextureCoords;
#endif
#if LIGHT_COUNT
out mediump vec3 transformedNormal;
#ifdef NORMAL_TEXTURE
out mediump vec3 transformedTangent;
#endif
out highp vec3 lightDirections[LIGHT_COUNT];
out highp vec3 cameraDirection;
#endif
void main() {
/* Transformed vertex position */
highp vec4 transformedPosition4 = transformationMatrix*position;
highp vec3 transformedPosition = transformedPosition4.xyz/transformedPosition4.w;
#if LIGHT_COUNT
/* Transformed normal and tangent vector */
transformedNormal = normalMatrix*normal;
#ifdef NORMAL_TEXTURE
@ -111,6 +120,7 @@ void main() {
/* Direction to the camera */
cameraDirection = -transformedPosition;
#endif
/* Transform the position */
gl_Position = projectionMatrix*transformedPosition4;

5
src/Magnum/Shaders/Test/CMakeLists.txt

@ -139,7 +139,10 @@ if(BUILD_GL_TESTS)
PhongTestFiles/textured-diffuse.tga
PhongTestFiles/textured-normal.tga
PhongTestFiles/textured-specular.tga
PhongTestFiles/textured.tga)
PhongTestFiles/textured.tga
# For zero lights test (equivalency to Flat3D)
FlatTestFiles/textured3D-alpha-mask0.5.tga)
if(NOT BUILD_PLUGINS_STATIC)
target_include_directories(ShadersPhongGLTest PRIVATE $<TARGET_FILE_DIR:ShadersPhongGLTest>)
else()

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

@ -95,6 +95,8 @@ struct PhongGLTest: GL::OpenGLTester {
void renderObjectId();
#endif
void renderZeroLights();
private:
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"};
@ -139,7 +141,8 @@ constexpr struct {
{"object ID", Phong::Flag::ObjectId, 1},
{"object ID + alpha mask + specular texture", Phong::Flag::ObjectId|Phong::Flag::AlphaMask|Phong::Flag::SpecularTexture, 1},
#endif
{"five lights", {}, 5}
{"five lights", {}, 5},
{"zero lights", {}, 0}
};
using namespace Math::Literals;
@ -299,6 +302,16 @@ PhongGLTest::PhongGLTest() {
&PhongGLTest::renderObjectIdTeardown);
#endif
addTests({&PhongGLTest::renderZeroLights},
#ifndef MAGNUM_TARGET_GLES2
&PhongGLTest::renderObjectIdSetup,
&PhongGLTest::renderObjectIdTeardown
#else
&PhongGLTest::renderSetup,
&PhongGLTest::renderTeardown
#endif
);
/* Load the plugins directly from the build tree. Otherwise they're either
static and already loaded or not present in the build tree */
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME
@ -1065,6 +1078,99 @@ void PhongGLTest::renderObjectId() {
}
#endif
void PhongGLTest::renderZeroLights() {
CORRADE_COMPARE(_framebuffer.checkStatus(GL::FramebufferTarget::Draw), GL::Framebuffer::Status::Complete);
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Phong shader{
Phong::Flag::AmbientTexture|Phong::Flag::AlphaMask
#ifndef MAGNUM_TARGET_GLES2
|Phong::Flag::ObjectId
#endif
, 0};
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D ambient;
Containers::Optional<Trade::ImageData2D> ambientImage;
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/diffuse-alpha-texture.tga")) && (ambientImage = importer->image2D(0)));
ambient.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, TextureFormatRGBA, ambientImage->size())
.setSubImage(0, {}, *ambientImage);
GL::Texture2D bogus;
shader
.bindAmbientTexture(ambient)
.setAmbientColor(0x9999ff_rgbf)
.setTransformationMatrix(
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationX(15.0_degf))
.setProjectionMatrix(Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f))
.setAlphaMask(0.5f)
#ifndef MAGNUM_TARGET_GLES2
.setObjectId(65534)
#endif
/* Passing a zero-sized light position / color array, shouldn't assert */
.setLightPositions({})
.setLightColors({})
/* Using a bogus normal matrix -- it's not used so it should be okay.
Same for all other unused values, they should get ignored. */
.setNormalMatrix(Matrix3x3{Math::ZeroInit})
.setDiffuseColor(0xfa9922_rgbf)
.setSpecularColor(0xfa9922_rgbf)
.setShininess(0.2f);
/* For proper Z order draw back faces first and then front faces */
GL::Renderer::setFaceCullingMode(GL::Renderer::PolygonFacing::Front);
sphere.draw(shader);
GL::Renderer::setFaceCullingMode(GL::Renderer::PolygonFacing::Back);
sphere.draw(shader);
MAGNUM_VERIFY_NO_GL_ERROR();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* Compared to FlatGLTest::renderAlpha3D(0.5), there's a bit more different
pixels on the edges, caused by matrix multiplication being done in the
shader and not on the CPU side. */
const Float maxThreshold = 139.0f, meanThreshold = 0.122f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 139.0f, meanThreshold = 2.896f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
/* Should be equivalent to masked Flat3D */
Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/textured3D-alpha-mask0.5.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
#ifndef MAGNUM_TARGET_GLES2
/* Object ID -- no need to verify the whole image, just check that pixels
on known places have expected values. SwiftShader insists that the read
format has to be 32bit, so the renderbuffer format is that too to make
it the same (ES3 Mesa complains if these don't match). */
_framebuffer.mapForRead(GL::Framebuffer::ColorAttachment{1});
CORRADE_COMPARE(_framebuffer.checkStatus(GL::FramebufferTarget::Read), GL::Framebuffer::Status::Complete);
Image2D image = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::R32UI});
MAGNUM_VERIFY_NO_GL_ERROR();
/* Outside of the object, cleared to 27 */
CORRADE_COMPARE(image.pixels<UnsignedInt>()[10][10], 27);
/* Inside of the object. Verify that it can hold 16 bits at least. */
CORRADE_COMPARE(image.pixels<UnsignedInt>()[40][46], 65534);
#endif
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::PhongGLTest)

Loading…
Cancel
Save