diff --git a/doc/changelog.dox b/doc/changelog.dox index bf83773c6..943d14824 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -231,6 +231,7 @@ See also: - Normal texture support in @ref Shaders::Phong - Added @ref Shaders::Generic3D::Tangent generic vertex attribute definition - Object ID output in @ref Shaders::Flat and @ref Shaders::Phong +- Vertex color support in @ref Shaders::Flat and @ref Shaders::Phong @subsubsection changelog-latest-new-text Text library diff --git a/src/Magnum/Shaders/Flat.cpp b/src/Magnum/Shaders/Flat.cpp index ce0855174..74ee895aa 100644 --- a/src/Magnum/Shaders/Flat.cpp +++ b/src/Magnum/Shaders/Flat.cpp @@ -64,10 +64,12 @@ template Flat::Flat(const Flags flags): _fla GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); vert.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") + .addSource(flags & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "") .addSource(rs.get("generic.glsl")) .addSource(rs.get(vertexShaderName())); frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") .addSource(flags & Flag::AlphaMask ? "#define ALPHA_MASK\n" : "") + .addSource(flags & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "") #ifndef MAGNUM_TARGET_GLES2 .addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "") #endif @@ -86,7 +88,10 @@ template Flat::Flat(const Flags flags): _fla #endif { bindAttributeLocation(Position::Location, "position"); - if(flags & Flag::Textured) bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + if(flags & Flag::Textured) + bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + if(flags & Flag::VertexColor) + bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ #ifndef MAGNUM_TARGET_GLES2 if(flags & Flag::ObjectId) { bindFragmentDataLocation(ColorOutput, "color"); @@ -120,7 +125,7 @@ template Flat::Flat(const Flags flags): _fla /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES setTransformationProjectionMatrix({}); - setColor(Color4{1.0f}); + setColor(Magnum::Color4{1.0f}); if(flags & Flag::AlphaMask) setAlphaMask(0.5f); /* Object ID is zero by default */ #endif @@ -160,6 +165,7 @@ Debug& operator<<(Debug& debug, const FlatFlag value) { #define _c(v) case FlatFlag::v: return debug << "Shaders::Flat::Flag::" #v; _c(Textured) _c(AlphaMask) + _c(VertexColor) #ifndef MAGNUM_TARGET_GLES2 _c(ObjectId) #endif @@ -174,6 +180,7 @@ Debug& operator<<(Debug& debug, const FlatFlags value) { return Containers::enumSetDebugOutput(debug, value, "Shaders::Flat::Flags{}", { FlatFlag::Textured, FlatFlag::AlphaMask, + FlatFlag::VertexColor, #ifndef MAGNUM_TARGET_GLES2 FlatFlag::ObjectId #endif diff --git a/src/Magnum/Shaders/Flat.frag b/src/Magnum/Shaders/Flat.frag index 61a576970..ae2f759e9 100644 --- a/src/Magnum/Shaders/Flat.frag +++ b/src/Magnum/Shaders/Flat.frag @@ -68,6 +68,10 @@ uniform highp uint objectId; /* defaults to zero */ in mediump vec2 interpolatedTextureCoordinates; #endif +#ifdef VERTEX_COLOR +in lowp vec4 interpolatedVertexColor; +#endif + #ifdef NEW_GLSL #ifdef EXPLICIT_ATTRIB_LOCATION layout(location = COLOR_OUTPUT_ATTRIBUTE_LOCATION) @@ -87,6 +91,9 @@ void main() { #ifdef TEXTURED texture(textureData, interpolatedTextureCoordinates)* #endif + #ifdef VERTEX_COLOR + interpolatedVertexColor* + #endif color; #ifdef ALPHA_MASK diff --git a/src/Magnum/Shaders/Flat.h b/src/Magnum/Shaders/Flat.h index 9d82dd7cc..9eb66ee8d 100644 --- a/src/Magnum/Shaders/Flat.h +++ b/src/Magnum/Shaders/Flat.h @@ -43,8 +43,9 @@ namespace Implementation { enum class FlatFlag: UnsignedByte { Textured = 1 << 0, AlphaMask = 1 << 1, + VertexColor = 1 << 2, #ifndef MAGNUM_TARGET_GLES2 - ObjectId = 1 << 2 + ObjectId = 1 << 3 #endif }; typedef Containers::EnumSet FlatFlags; @@ -71,6 +72,8 @@ 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. +Conversely, enabling @ref Flag::VertexColor and using a default color with no +texturing makes this shader equivalent to @ref VertexColor. @section Shaders-Flat-usage Example usage @@ -139,6 +142,24 @@ template class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab */ typedef typename Generic::TextureCoordinates TextureCoordinates; + /** + * @brief Three-component vertex color + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Color3. Use + * either this or the @ref Color4 attribute. Used only if + * @ref Flag::VertexColor is set. + */ + typedef typename Generic::Color3 Color3; + + /** + * @brief Four-component vertex color + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Color4. Use + * either this or the @ref Color3 attribute. Used only if + * @ref Flag::VertexColor is set. + */ + typedef typename Generic::Color4 Color4; + enum: UnsignedInt { /** * Color shader output. Present always, expects three- or @@ -187,6 +208,12 @@ template class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab */ AlphaMask = 1 << 1, + /** + * Multiply diffuse color with a vertex color. Requires either + * the @ref Color3 or @ref Color4 attribute to be present. + */ + VertexColor = 1 << 2, + #ifndef MAGNUM_TARGET_GLES2 /** * Enable object ID output. See @ref Shaders-Flat-usage-object-id @@ -195,7 +222,7 @@ template class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab * attachments, which are not available in OpenGL ES 2.0 or * WebGL 1.0. */ - ObjectId = 1 << 2 + ObjectId = 1 << 3 #endif }; @@ -265,7 +292,7 @@ template class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab * texture. * @see @ref bindTexture() */ - Flat& setColor(const Color4& color){ + Flat& setColor(const Magnum::Color4& color) { setUniform(_colorUniform, color); return *this; } diff --git a/src/Magnum/Shaders/Flat2D.vert b/src/Magnum/Shaders/Flat2D.vert index 6a6cc9ed0..f8c8a1bc1 100644 --- a/src/Magnum/Shaders/Flat2D.vert +++ b/src/Magnum/Shaders/Flat2D.vert @@ -51,6 +51,15 @@ in mediump vec2 textureCoordinates; out mediump vec2 interpolatedTextureCoordinates; #endif +#ifdef VERTEX_COLOR +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = COLOR_ATTRIBUTE_LOCATION) +#endif +in lowp vec4 vertexColor; + +out lowp vec4 interpolatedVertexColor; +#endif + void main() { gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); @@ -58,4 +67,9 @@ void main() { /* Texture coordinates, if needed */ interpolatedTextureCoordinates = textureCoordinates; #endif + + #ifdef VERTEX_COLOR + /* Vertex colors, if enabled */ + interpolatedVertexColor = vertexColor; + #endif } diff --git a/src/Magnum/Shaders/Flat3D.vert b/src/Magnum/Shaders/Flat3D.vert index c79a1897c..eda843c6b 100644 --- a/src/Magnum/Shaders/Flat3D.vert +++ b/src/Magnum/Shaders/Flat3D.vert @@ -51,6 +51,15 @@ in mediump vec2 textureCoordinates; out mediump vec2 interpolatedTextureCoordinates; #endif +#ifdef VERTEX_COLOR +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = COLOR_ATTRIBUTE_LOCATION) +#endif +in lowp vec4 vertexColor; + +out lowp vec4 interpolatedVertexColor; +#endif + void main() { gl_Position = transformationProjectionMatrix*position; @@ -58,4 +67,9 @@ void main() { /* Texture coordinates, if needed */ interpolatedTextureCoordinates = textureCoordinates; #endif + + #ifdef VERTEX_COLOR + /* Vertex colors, if enabled */ + interpolatedVertexColor = vertexColor; + #endif } diff --git a/src/Magnum/Shaders/Phong.cpp b/src/Magnum/Shaders/Phong.cpp index 148042a14..94f05e138 100644 --- a/src/Magnum/Shaders/Phong.cpp +++ b/src/Magnum/Shaders/Phong.cpp @@ -92,6 +92,7 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l vert.addSource(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture) ? "#define TEXTURED\n" : "") .addSource(flags & Flag::NormalTexture ? "#define NORMAL_TEXTURE\n" : "") + .addSource(flags & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "") .addSource(Utility::formatString("#define LIGHT_COUNT {}\n", lightCount)) .addSource(rs.get("generic.glsl")) .addSource(rs.get("Phong.vert")); @@ -99,6 +100,7 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l .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::VertexColor ? "#define VERTEX_COLOR\n" : "") .addSource(flags & Flag::AlphaMask ? "#define ALPHA_MASK\n" : "") #ifndef MAGNUM_TARGET_GLES2 .addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "") @@ -128,6 +130,8 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l bindAttributeLocation(Normal::Location, "normal"); if((flags & Flag::NormalTexture) && lightCount) bindAttributeLocation(Tangent::Location, "tangent"); + if(flags & Flag::VertexColor) + bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ if(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture)) bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); #ifndef MAGNUM_TARGET_GLES2 @@ -177,17 +181,17 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES /* Default to fully opaque white so we can see the textures */ - if(flags & Flag::AmbientTexture) setAmbientColor(Color4{1.0f}); - else setAmbientColor(Color4{0.0f}); + if(flags & Flag::AmbientTexture) setAmbientColor(Magnum::Color4{1.0f}); + else setAmbientColor(Magnum::Color4{0.0f}); setTransformationMatrix({}); setProjectionMatrix({}); if(lightCount) { - setDiffuseColor(Color4{1.0f}); - setSpecularColor(Color4{1.0f}); + setDiffuseColor(Magnum::Color4{1.0f}); + setSpecularColor(Magnum::Color4{1.0f}); setShininess(80.0f); if(flags & Flag::AlphaMask) setAlphaMask(0.5f); /* Object ID is zero by default */ - setLightColors(Containers::Array{Containers::DirectInit, lightCount, Color4{1.0f}}); + setLightColors(Containers::Array{Containers::DirectInit, lightCount, Magnum::Color4{1.0f}}); /* Light position is zero by default */ setNormalMatrix({}); } @@ -259,14 +263,14 @@ Phong& Phong::setLightPosition(UnsignedInt id, const Vector3& position) { return *this; } -Phong& Phong::setLightColors(const Containers::ArrayView colors) { +Phong& Phong::setLightColors(const Containers::ArrayView colors) { CORRADE_ASSERT(_lightCount == colors.size(), "Shaders::Phong::setLightColors(): expected" << _lightCount << "items but got" << colors.size(), *this); if(_lightCount) setUniform(_lightColorsUniform, colors); return *this; } -Phong& Phong::setLightColor(UnsignedInt id, const Color4& color) { +Phong& Phong::setLightColor(UnsignedInt id, const Magnum::Color4& color) { CORRADE_ASSERT(id < _lightCount, "Shaders::Phong::setLightColor(): light ID" << id << "is out of bounds for" << _lightCount << "lights", *this); setUniform(_lightColorsUniform + id, color); @@ -282,6 +286,7 @@ Debug& operator<<(Debug& debug, const Phong::Flag value) { _c(SpecularTexture) _c(NormalTexture) _c(AlphaMask) + _c(VertexColor) #ifndef MAGNUM_TARGET_GLES2 _c(ObjectId) #endif @@ -299,6 +304,7 @@ Debug& operator<<(Debug& debug, const Phong::Flags value) { Phong::Flag::SpecularTexture, Phong::Flag::NormalTexture, Phong::Flag::AlphaMask, + Phong::Flag::VertexColor, #ifndef MAGNUM_TARGET_GLES2 Phong::Flag::ObjectId #endif diff --git a/src/Magnum/Shaders/Phong.frag b/src/Magnum/Shaders/Phong.frag index 84e3233f5..a89b52b4d 100644 --- a/src/Magnum/Shaders/Phong.frag +++ b/src/Magnum/Shaders/Phong.frag @@ -149,6 +149,10 @@ in highp vec3 cameraDirection; in mediump vec2 interpolatedTextureCoords; #endif +#ifdef VERTEX_COLOR +in lowp vec4 interpolatedVertexColor; +#endif + #ifdef NEW_GLSL #ifdef EXPLICIT_ATTRIB_LOCATION layout(location = COLOR_OUTPUT_ATTRIBUTE_LOCATION) @@ -174,6 +178,9 @@ void main() { #ifdef DIFFUSE_TEXTURE texture(diffuseTexture, interpolatedTextureCoords)* #endif + #ifdef VERTEX_COLOR + interpolatedVertexColor* + #endif diffuseColor; lowp const vec4 finalSpecularColor = #ifdef SPECULAR_TEXTURE diff --git a/src/Magnum/Shaders/Phong.h b/src/Magnum/Shaders/Phong.h index cdeb7da8b..d7ca7a1ff 100644 --- a/src/Magnum/Shaders/Phong.h +++ b/src/Magnum/Shaders/Phong.h @@ -115,6 +115,7 @@ Creating this shader with zero lights makes its output equivalent to the (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. +In addition, enabling @ref Flag::VertexColor and using a default ambient color with no texturing makes this shader equivalent to @ref VertexColor. @see @ref shaders */ @@ -155,6 +156,24 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { */ typedef Generic3D::TextureCoordinates TextureCoordinates; + /** + * @brief Three-component vertex color + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Color3. Use + * either this or the @ref Color4 attribute. Used only if + * @ref Flag::VertexColor is set. + */ + typedef Generic3D::Color3 Color3; + + /** + * @brief Four-component vertex color + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Color4. Use + * either this or the @ref Color3 attribute. Used only if + * @ref Flag::VertexColor is set. + */ + typedef Generic3D::Color4 Color4; + enum: UnsignedInt { /** * Color shader output. @ref shaders-generic "Generic output", @@ -221,6 +240,12 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { */ AlphaMask = 1 << 3, + /** + * Multiply diffuse color with a vertex color. Requires either + * the @ref Color3 or @ref Color4 attribute to be present. + */ + VertexColor = 1 << 5, + #ifndef MAGNUM_TARGET_GLES2 /** * Enable object ID output. See @ref Shaders-Phong-usage-object-id @@ -229,7 +254,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * attachments, which are not available in OpenGL ES 2.0 or * WebGL 1.0. */ - ObjectId = 1 << 5 + ObjectId = 1 << 6 #endif }; @@ -286,7 +311,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * ambient texture, otherwise default value is @cpp 0x00000000_rgbaf @ce. * @see @ref bindAmbientTexture() */ - Phong& setAmbientColor(const Color4& color) { + Phong& setAmbientColor(const Magnum::Color4& color) { setUniform(_ambientColorUniform, color); return *this; } @@ -319,7 +344,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * to the output in that case. * @see @ref bindDiffuseTexture() */ - Phong& setDiffuseColor(const Color4& color) { + Phong& setDiffuseColor(const Magnum::Color4& color) { if(_lightCount) setUniform(_diffuseColorUniform, color); return *this; } @@ -368,7 +393,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * output in that case. * @see @ref bindSpecularTexture() */ - Phong& setSpecularColor(const Color4& color) { + Phong& setSpecularColor(const Magnum::Color4& color) { if(_lightCount) setUniform(_specularColorUniform, color); return *this; } @@ -550,10 +575,10 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * Initial values are @cpp 0xffffffff_rgbaf @ce. Expects that the size * of the @p colors array is the same as @ref lightCount(). */ - Phong& setLightColors(Containers::ArrayView colors); + Phong& setLightColors(Containers::ArrayView colors); /** @overload */ - Phong& setLightColors(std::initializer_list colors) { + Phong& setLightColors(std::initializer_list colors) { return setLightColors({colors.begin(), colors.size()}); } @@ -563,9 +588,9 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * * Unlike @ref setLightColors() updates just a single light color. * Expects that @p id is less than @ref lightCount(). - * @see @ref setLightColor(const Color4&) + * @see @ref setLightColor(const Magnum::Color4&) */ - Phong& setLightColor(UnsignedInt id, const Color4& color); + Phong& setLightColor(UnsignedInt id, const Magnum::Color4& color); /** * @brief Set light color @@ -573,9 +598,9 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * * Convenience alternative to @ref setLightColors() when there is just * one light. - * @see @ref setLightColor(UnsignedInt, const Color4&) + * @see @ref setLightColor(UnsignedInt, const Magnum::Color4&) */ - Phong& setLightColor(const Color4& color) { + Phong& setLightColor(const Magnum::Color4& color) { return setLightColors({&color, 1}); } diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index e57662ec0..84bbfa5e3 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -93,6 +93,15 @@ in mediump vec2 textureCoords; out mediump vec2 interpolatedTextureCoords; #endif +#ifdef VERTEX_COLOR +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = COLOR_ATTRIBUTE_LOCATION) +#endif +in lowp vec4 vertexColor; + +out lowp vec4 interpolatedVertexColor; +#endif + #if LIGHT_COUNT out mediump vec3 transformedNormal; #ifdef NORMAL_TEXTURE @@ -129,4 +138,9 @@ void main() { /* Texture coordinates, if needed */ interpolatedTextureCoords = textureCoords; #endif + + #ifdef VERTEX_COLOR + /* Vertex colors, if enabled */ + interpolatedVertexColor = vertexColor; + #endif } diff --git a/src/Magnum/Shaders/Test/CMakeLists.txt b/src/Magnum/Shaders/Test/CMakeLists.txt index 91fc643bc..8bcfc27b1 100644 --- a/src/Magnum/Shaders/Test/CMakeLists.txt +++ b/src/Magnum/Shaders/Test/CMakeLists.txt @@ -94,7 +94,9 @@ if(BUILD_GL_TESTS) FlatTestFiles/textured2D-alpha.tga FlatTestFiles/textured3D-alpha.tga FlatTestFiles/textured2D-alpha-mask0.5.tga - FlatTestFiles/textured3D-alpha-mask0.5.tga) + FlatTestFiles/textured3D-alpha-mask0.5.tga + FlatTestFiles/vertexColor2D.tga + FlatTestFiles/vertexColor3D.tga) if(NOT BUILD_PLUGINS_STATIC) target_include_directories(ShadersFlatGLTest PRIVATE $) else() @@ -140,6 +142,7 @@ if(BUILD_GL_TESTS) PhongTestFiles/textured-normal.tga PhongTestFiles/textured-specular.tga PhongTestFiles/textured.tga + PhongTestFiles/vertexColor.tga # For zero lights test (equivalency to Flat3D) FlatTestFiles/textured3D-alpha-mask0.5.tga) diff --git a/src/Magnum/Shaders/Test/FlatGLTest.cpp b/src/Magnum/Shaders/Test/FlatGLTest.cpp index b0d1502b1..c4a91c841 100644 --- a/src/Magnum/Shaders/Test/FlatGLTest.cpp +++ b/src/Magnum/Shaders/Test/FlatGLTest.cpp @@ -80,6 +80,9 @@ struct FlatGLTest: GL::OpenGLTester { void renderTextured2D(); void renderTextured3D(); + template void renderVertexColor2D(); + template void renderVertexColor3D(); + void renderAlphaSetup(); void renderAlphaTeardown(); @@ -127,6 +130,8 @@ constexpr struct { {"textured", Flat2D::Flag::Textured}, {"alpha mask", Flat2D::Flag::AlphaMask}, {"alpha mask + textured", Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured}, + {"vertex colors", Flat2D::Flag::VertexColor}, + {"vertex colors + textured", Flat2D::Flag::VertexColor|Flat2D::Flag::Textured}, #ifndef MAGNUM_TARGET_GLES2 {"object ID", Flat2D::Flag::ObjectId}, {"object ID + alpha mask + textured", Flat2D::Flag::ObjectId|Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured} @@ -182,7 +187,11 @@ FlatGLTest::FlatGLTest() { &FlatGLTest::renderSinglePixelTextured2D, &FlatGLTest::renderSinglePixelTextured3D, &FlatGLTest::renderTextured2D, - &FlatGLTest::renderTextured3D}, + &FlatGLTest::renderTextured3D, + &FlatGLTest::renderVertexColor2D, + &FlatGLTest::renderVertexColor2D, + &FlatGLTest::renderVertexColor3D, + &FlatGLTest::renderVertexColor3D}, &FlatGLTest::renderSetup, &FlatGLTest::renderTeardown); @@ -603,6 +612,118 @@ void FlatGLTest::renderTextured3D() { (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); } +template void FlatGLTest::renderVertexColor2D() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + Trade::MeshData2D circleData = Primitives::circle2DSolid(32, + Primitives::CircleTextureCoords::Generate); + + /* Highlight a quarter */ + Containers::Array colorData{Containers::DirectInit, circleData.positions(0).size(), 0x999999_rgbf}; + for(std::size_t i = 8; i != 16; ++i) + colorData[i + 1] = 0xffff99_rgbf*1.5f; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh circle = MeshTools::compile(circleData); + circle.addVertexBuffer(colors, 0, GL::Attribute{}); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + Flat2D shader{Flat2D::Flag::Textured|Flat2D::Flag::VertexColor}; + shader.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f})) + .setColor(0x9999ff_rgbf) + .bindTexture(texture); + circle.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has minor rounding errors. ARM Mali slightly more */ + const Float maxThreshold = 1.334f, meanThreshold = 0.015f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's worse */ + const Float maxThreshold = 1.334f, meanThreshold = 0.013f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/vertexColor2D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +template void FlatGLTest::renderVertexColor3D() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + Trade::MeshData3D sphereData = Primitives::uvSphereSolid(16, 32, + Primitives::UVSphereTextureCoords::Generate); + + /* Highlight the middle rings */ + Containers::Array colorData{Containers::DirectInit, sphereData.positions(0).size(), 0x999999_rgbf}; + for(std::size_t i = 6*33; i != 9*33; ++i) + colorData[i + 1] = 0xffff99_rgbf*1.5f; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh sphere = MeshTools::compile(sphereData); + sphere.addVertexBuffer(colors, 0, GL::Attribute{}); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + Flat3D shader{Flat3D::Flag::Textured|Flat3D::Flag::VertexColor}; + shader.setTransformationProjectionMatrix( + Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(-15.0_degf)* + Matrix4::rotationX(15.0_degf)) + .setColor(0x9999ff_rgbf) + .bindTexture(texture); + sphere.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has some minor differences on the edges */ + const Float maxThreshold = 76.67f, meanThreshold = 0.072f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's worse */ + const Float maxThreshold = 76.67f, meanThreshold = 0.072f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/vertexColor3D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + void FlatGLTest::renderAlphaSetup() { renderSetup(); if(RenderAlphaData[testCaseInstanceId()].blending) diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/vertexColor2D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/vertexColor2D.tga new file mode 100644 index 000000000..c857c9b7a Binary files /dev/null and b/src/Magnum/Shaders/Test/FlatTestFiles/vertexColor2D.tga differ diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/vertexColor3D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/vertexColor3D.tga new file mode 100644 index 000000000..db357fc74 Binary files /dev/null and b/src/Magnum/Shaders/Test/FlatTestFiles/vertexColor3D.tga differ diff --git a/src/Magnum/Shaders/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index 76e2cd299..b0c96dcce 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/src/Magnum/Shaders/Test/PhongGLTest.cpp @@ -81,6 +81,8 @@ struct PhongGLTest: GL::OpenGLTester { void renderTextured(); void renderTexturedNormal(); + template void renderVertexColor(); + void renderShininess(); void renderAlphaSetup(); @@ -137,6 +139,8 @@ constexpr struct { {"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}, + {"vertex colors", Phong::Flag::VertexColor, 1}, + {"vertex colors + diffuse texture", Phong::Flag::VertexColor|Phong::Flag::DiffuseTexture, 1}, #ifndef MAGNUM_TARGET_GLES2 {"object ID", Phong::Flag::ObjectId, 1}, {"object ID + alpha mask + specular texture", Phong::Flag::ObjectId|Phong::Flag::AlphaMask|Phong::Flag::SpecularTexture, 1}, @@ -286,6 +290,11 @@ PhongGLTest::PhongGLTest() { &PhongGLTest::renderSetup, &PhongGLTest::renderTeardown); + addTests({&PhongGLTest::renderVertexColor, + &PhongGLTest::renderVertexColor}, + &PhongGLTest::renderSetup, + &PhongGLTest::renderTeardown); + addInstancedTests({&PhongGLTest::renderShininess}, Containers::arraySize(RenderShininessData), &PhongGLTest::renderSetup, @@ -817,6 +826,69 @@ void PhongGLTest::renderTexturedNormal() { (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); } +template void PhongGLTest::renderVertexColor() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + Trade::MeshData3D sphereData = Primitives::uvSphereSolid(16, 32, + Primitives::UVSphereTextureCoords::Generate); + + /* Highlight the middle rings */ + Containers::Array colorData{Containers::DirectInit, sphereData.positions(0).size(), 0x999999_rgbf}; + for(std::size_t i = 6*33; i != 9*33; ++i) + colorData[i + 1] = 0xffff99_rgbf*1.5f; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh sphere = MeshTools::compile(sphereData); + sphere.addVertexBuffer(colors, 0, GL::Attribute{}); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D diffuse; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + diffuse.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + Phong shader{Phong::Flag::DiffuseTexture|Phong::Flag::VertexColor, 2}; + shader.setLightPositions({{-3.0f, -3.0f, 0.0f}, + { 3.0f, -3.0f, 0.0f}}) + .setTransformationMatrix( + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(-15.0_degf)* + Matrix4::rotationX(15.0_degf)) + /** @todo use normalMatrix() instead */ + .setNormalMatrix((Matrix4::rotationY(-15.0_degf)* + Matrix4::rotationX(15.0_degf)).rotationScaling()) + .setProjectionMatrix(Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)) + .setDiffuseColor(0x9999ff_rgbf) + .bindDiffuseTexture(diffuse); + sphere.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has some minor differences on the edges */ + const Float maxThreshold = 105.4f, meanThreshold = 0.075f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's worse */ + const Float maxThreshold = 105.4f, meanThreshold = 0.075f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "PhongTestFiles/vertexColor.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + void PhongGLTest::renderShininess() { auto&& data = RenderShininessData[testCaseInstanceId()]; setTestCaseDescription(data.name); diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/vertexColor.tga b/src/Magnum/Shaders/Test/PhongTestFiles/vertexColor.tga new file mode 100644 index 000000000..1f044cab8 Binary files /dev/null and b/src/Magnum/Shaders/Test/PhongTestFiles/vertexColor.tga differ diff --git a/src/Magnum/Shaders/VertexColor.h b/src/Magnum/Shaders/VertexColor.h index 1fb6c9367..c6edeed30 100644 --- a/src/Magnum/Shaders/VertexColor.h +++ b/src/Magnum/Shaders/VertexColor.h @@ -49,6 +49,11 @@ configure the shader. @image html shaders-vertexcolor.png width=256px +This shader is equivalent to @ref Flat with @ref Flat::Flag::VertexColor +enabled; the 3D version of this shader is equivalent to @ref Phong with +@ref Phong::Flag::VertexColor enabled. In both cases this implementation is +much simpler and thus likely also faster. + @section Shaders-VertexColor-example Example usage Common mesh setup. The shader accepts either three- or four-component color