Browse Source

Shaders: implement instancing in Flat.

pull/433/head
Vladimír Vondruš 6 years ago
parent
commit
a1f1f66c04
  1. 1
      doc/changelog.dox
  2. 20
      doc/snippets/MagnumShaders.cpp
  3. 13
      src/Magnum/Shaders/Flat.cpp
  4. 95
      src/Magnum/Shaders/Flat.h
  5. 38
      src/Magnum/Shaders/Flat.vert
  6. 2
      src/Magnum/Shaders/Test/CMakeLists.txt
  7. 195
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  8. 32
      src/Magnum/Shaders/Test/FlatTest.cpp
  9. BIN
      src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga
  10. BIN
      src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga

1
doc/changelog.dox

@ -233,6 +233,7 @@ See also:
@ref Shaders::Generic::TransformationMatrix, @ref Shaders::Generic::TransformationMatrix,
@ref Shaders::Generic::NormalMatrix and @ref Shaders::Generic::NormalMatrix and
@ref Shaders::Generic::TextureOffset for instancing @ref Shaders::Generic::TextureOffset for instancing
- Instancing in @ref Shaders::Flat
@subsubsection changelog-latest-new-trade Trade library @subsubsection changelog-latest-new-trade Trade library

20
doc/snippets/MagnumShaders.cpp

@ -249,6 +249,26 @@ framebuffer.mapForDraw({
} }
#endif #endif
{
GL::Mesh mesh;
/* [Flat-usage-instancing] */
struct {
Matrix4 transformation;
Color3 color;
} instanceData[] {
{Matrix4::translation({1.0f, 2.0f, 0.0f}), 0xff3333_rgbf},
{Matrix4::translation({2.0f, 1.0f, 0.0f}), 0x33ff33_rgbf},
{Matrix4::translation({3.0f, 0.0f, 1.0f}), 0x3333ff_rgbf},
// ...
};
mesh.setInstanceCount(Containers::arraySize(instanceData))
.addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0,
Shaders::Flat3D::TransformationMatrix{},
Shaders::Flat3D::Color3{});
/* [Flat-usage-instancing] */
}
{ {
/* [MeshVisualizer-usage-geom1] */ /* [MeshVisualizer-usage-geom1] */
struct Vertex { struct Vertex {

13
src/Magnum/Shaders/Flat.cpp

@ -72,6 +72,8 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(const Flags flags): _fla
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
.addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") .addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
#endif #endif
.addSource(flags & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : "")
.addSource(flags >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "")
.addSource(rs.get("generic.glsl")) .addSource(rs.get("generic.glsl"))
.addSource(rs.get("Flat.vert")); .addSource(rs.get("Flat.vert"));
frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "")
@ -107,6 +109,10 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(const Flags flags): _fla
} }
if(flags >= Flag::InstancedObjectId) if(flags >= Flag::InstancedObjectId)
bindAttributeLocation(ObjectId::Location, "instanceObjectId"); bindAttributeLocation(ObjectId::Location, "instanceObjectId");
if(flags & Flag::InstancedTransformation)
bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix");
if(flags >= Flag::InstancedTextureOffset)
bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset");
#endif #endif
} }
#endif #endif
@ -203,6 +209,8 @@ Debug& operator<<(Debug& debug, const FlatFlag value) {
_c(ObjectId) _c(ObjectId)
_c(InstancedObjectId) _c(InstancedObjectId)
#endif #endif
_c(InstancedTransformation)
_c(InstancedTextureOffset)
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
@ -215,12 +223,13 @@ Debug& operator<<(Debug& debug, const FlatFlags value) {
FlatFlag::Textured, FlatFlag::Textured,
FlatFlag::AlphaMask, FlatFlag::AlphaMask,
FlatFlag::VertexColor, FlatFlag::VertexColor,
FlatFlag::InstancedTextureOffset, /* Superset of TextureTransformation */
FlatFlag::TextureTransformation, FlatFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
FlatFlag::InstancedObjectId, /* Superset of ObjectId */ FlatFlag::InstancedObjectId, /* Superset of ObjectId */
FlatFlag::ObjectId FlatFlag::ObjectId,
#endif #endif
}); FlatFlag::InstancedTransformation});
} }
} }

95
src/Magnum/Shaders/Flat.h

@ -44,8 +44,10 @@ namespace Implementation {
TextureTransformation = 1 << 3, TextureTransformation = 1 << 3,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
ObjectId = 1 << 4, ObjectId = 1 << 4,
InstancedObjectId = (1 << 5)|ObjectId InstancedObjectId = (1 << 5)|ObjectId,
#endif #endif
InstancedTransformation = 1 << 6,
InstancedTextureOffset = (1 << 7)|TextureTransformation
}; };
typedef Containers::EnumSet<FlatFlag> FlatFlags; typedef Containers::EnumSet<FlatFlag> FlatFlags;
} }
@ -120,6 +122,28 @@ from @ref setObjectId().
@requires_gles30 Object ID output requires integer buffer attachments, which @requires_gles30 Object ID output requires integer buffer attachments, which
are not available in OpenGL ES 2.0 or WebGL 1.0. are not available in OpenGL ES 2.0 or WebGL 1.0.
@section Shaders-Flat-instancing Instanced rendering
Enabling @ref Flag::InstancedTransformation will turn the shader into an
instanced one. It'll take per-instance transformation from the
@ref TransformationMatrix attribute, applying it before the matrix set by
@ref setTransformationProjectionMatrix(). Besides that, @ref Flag::VertexColor
(and the @ref Color3 / @ref Color4) attributes can work as both per-vertex and
per-instance, and for texturing it's possible to have per-instance texture
offset taken from @ref TextureOffset when @ref Flag::InstancedTextureOffset is
enabled (similarly to transformation, applied before @ref setTextureMatrix()).
The snippet below shows adding a buffer with per-instance transformation and
color to a mesh:
@snippet MagnumShaders.cpp Flat-usage-instancing
@requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
@requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
@gl_extension{EXT,instanced_arrays} or @gl_extension{NV,instanced_arrays}
in OpenGL ES 2.0.
@requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays} in WebGL
1.0.
@see @ref shaders, @ref Flat2D, @ref Flat3D @see @ref shaders, @ref Flat2D, @ref Flat3D
*/ */
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::AbstractShaderProgram { template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::AbstractShaderProgram {
@ -176,6 +200,37 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
typedef typename Generic<dimensions>::ObjectId ObjectId; typedef typename Generic<dimensions>::ObjectId ObjectId;
#endif #endif
/**
* @brief (Instanced) transformation matrix
* @m_since_latest
*
* @ref shaders-generic "Generic attribute", @ref Magnum::Matrix3 in
* 2D, @ref Magnum::Matrix4 in 3D. Used only if
* @ref Flag::InstancedTransformation is set.
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
* @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
* @gl_extension{EXT,instanced_arrays} or
* @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0.
* @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays}
* in WebGL 1.0.
*/
typedef typename Generic<dimensions>::TransformationMatrix TransformationMatrix;
/**
* @brief (Instanced) texture offset
* @m_since_latest
*
* @ref shaders-generic "Generic attribute", @ref Magnum::Vector2. Used
* only if @ref Flag::InstancedTextureOffset is set.
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
* @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
* @gl_extension{EXT,instanced_arrays} or
* @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0.
* @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays}
* in WebGL 1.0.
*/
typedef typename Generic<dimensions>::TextureOffset TextureOffset;
enum: UnsignedInt { enum: UnsignedInt {
/** /**
* Color shader output. Present always, expects three- or * Color shader output. Present always, expects three- or
@ -263,8 +318,44 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
* WebGL 1.0. * WebGL 1.0.
* @m_since_latest * @m_since_latest
*/ */
InstancedObjectId = (1 << 5)|ObjectId InstancedObjectId = (1 << 5)|ObjectId,
#endif #endif
/**
* Instanced transformation. Retrieves a per-instance
* transformation matrix from the @ref TransformationMatrix
* attribute and uses it together with the matrix coming from
* @ref setTransformationProjectionMatrix() (first the
* per-instance, then the uniform matrix). See
* @ref Shaders-Flat-instancing for more information.
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
* @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
* @gl_extension{EXT,instanced_arrays} or
* @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0.
* @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays}
* in WebGL 1.0.
* @m_since_latest
*/
InstancedTransformation = 1 << 6,
/**
* Instanced texture offset. Retrieves a per-instance offset vector
* from the @ref TextureOffset attribute and uses it together with
* the matrix coming from @ref setTextureMatrix() (first the
* per-instance vector, then the uniform matrix). Instanced texture
* scaling and rotation is not supported at the moment, you can
* specify that only via the uniform @ref setTextureMatrix().
* Implicitly enables @ref Flag::TextureTransformation. See
* @ref Shaders-Flat-instancing for more information.
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
* @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
* @gl_extension{EXT,instanced_arrays} or
* @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0.
* @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays}
* in WebGL 1.0.
* @m_since_latest
*/
InstancedTextureOffset = (1 << 7)|TextureTransformation
}; };
/** /**

38
src/Magnum/Shaders/Flat.vert

@ -96,11 +96,39 @@ in highp uint instanceObjectId;
flat out highp uint interpolatedInstanceObjectId; flat out highp uint interpolatedInstanceObjectId;
#endif #endif
#ifdef INSTANCED_TRANSFORMATION
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = TRANSFORMATION_MATRIX_ATTRIBUTE_LOCATION)
#endif
#ifdef TWO_DIMENSIONS
in highp mat3 instancedTransformationMatrix;
#elif defined(THREE_DIMENSIONS)
in highp mat4 instancedTransformationMatrix;
#else
#error
#endif
#endif
#ifdef INSTANCED_TEXTURE_OFFSET
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = TEXTURE_OFFSET_ATTRIBUTE_LOCATION)
#endif
in mediump vec2 instancedTextureOffset;
#endif
void main() { void main() {
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); gl_Position.xywz = vec4(transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION
instancedTransformationMatrix*
#endif
vec3(position, 1.0), 0.0);
#elif defined(THREE_DIMENSIONS) #elif defined(THREE_DIMENSIONS)
gl_Position = transformationProjectionMatrix*position; gl_Position = transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION
instancedTransformationMatrix*
#endif
position;
#else #else
#error #error
#endif #endif
@ -109,7 +137,11 @@ void main() {
/* Texture coordinates, if needed */ /* Texture coordinates, if needed */
interpolatedTextureCoordinates = interpolatedTextureCoordinates =
#ifdef TEXTURE_TRANSFORMATION #ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy (textureMatrix*vec3(
#ifdef INSTANCED_TEXTURE_OFFSET
instancedTextureOffset +
#endif
textureCoordinates, 1.0)).xy
#else #else
textureCoordinates textureCoordinates
#endif #endif

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

@ -121,6 +121,8 @@ if(BUILD_GL_TESTS)
FlatTestFiles/colored2D.tga FlatTestFiles/colored2D.tga
FlatTestFiles/colored3D.tga FlatTestFiles/colored3D.tga
FlatTestFiles/defaults.tga FlatTestFiles/defaults.tga
FlatTestFiles/instanced2D.tga
FlatTestFiles/instanced3D.tga
FlatTestFiles/textured2D.tga FlatTestFiles/textured2D.tga
FlatTestFiles/textured3D.tga FlatTestFiles/textured3D.tga
FlatTestFiles/textured2D-alpha.tga FlatTestFiles/textured2D-alpha.tga

195
src/Magnum/Shaders/Test/FlatGLTest.cpp

@ -35,6 +35,8 @@
#include "Magnum/ImageView.h" #include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
#include "Magnum/DebugTools/CompareImage.h" #include "Magnum/DebugTools/CompareImage.h"
#include "Magnum/GL/Context.h"
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/Mesh.h" #include "Magnum/GL/Mesh.h"
#include "Magnum/GL/Framebuffer.h" #include "Magnum/GL/Framebuffer.h"
#include "Magnum/GL/Renderer.h" #include "Magnum/GL/Renderer.h"
@ -103,6 +105,9 @@ struct FlatGLTest: GL::OpenGLTester {
void renderObjectId3D(); void renderObjectId3D();
#endif #endif
void renderInstanced2D();
void renderInstanced3D();
private: private:
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"}; PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"};
std::string _testDir; std::string _testDir;
@ -120,12 +125,12 @@ struct FlatGLTest: GL::OpenGLTester {
- Mesa Intel - Mesa Intel
- Mesa AMD - Mesa AMD
- SwiftShader ES2/ES3 - SwiftShader ES2/ES3
- ARM Mali (Huawei P10) ES2/ES3 - ARM Mali (Huawei P10) ES2/ES3 (except instancing)
- WebGL 1 / 2 (on Mesa Intel) - WebGL 1 / 2 (on Mesa Intel) (except instancing)
- NVidia Windows - NVidia Windows (except instancing)
- Intel Windows - Intel Windows (except instancing)
- AMD on macOS - AMD on macOS (except instancing)
- iPhone 6 w/ iOS 12.4 - iPhone 6 w/ iOS 12.4 (except instancing)
*/ */
using namespace Math::Literals; using namespace Math::Literals;
@ -144,8 +149,10 @@ constexpr struct {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
{"object ID", Flat2D::Flag::ObjectId}, {"object ID", Flat2D::Flag::ObjectId},
{"instanced object ID", Flat2D::Flag::InstancedObjectId}, {"instanced object ID", Flat2D::Flag::InstancedObjectId},
{"object ID + alpha mask + textured", Flat2D::Flag::ObjectId|Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured} {"object ID + alpha mask + textured", Flat2D::Flag::ObjectId|Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured},
#endif #endif
{"instanced transformation", Flat2D::Flag::InstancedTransformation},
{"instanced texture offset", Flat2D::Flag::Textured|Flat2D::Flag::InstancedTextureOffset}
}; };
const struct { const struct {
@ -261,6 +268,11 @@ FlatGLTest::FlatGLTest() {
&FlatGLTest::renderObjectIdTeardown); &FlatGLTest::renderObjectIdTeardown);
#endif #endif
addTests({&FlatGLTest::renderInstanced2D,
&FlatGLTest::renderInstanced3D},
&FlatGLTest::renderSetup,
&FlatGLTest::renderTeardown);
/* Load the plugins directly from the build tree. Otherwise they're either /* Load the plugins directly from the build tree. Otherwise they're either
static and already loaded or not present in the build tree */ static and already loaded or not present in the build tree */
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME #ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME
@ -1107,6 +1119,175 @@ void FlatGLTest::renderObjectId3D() {
} }
#endif #endif
void FlatGLTest::renderInstanced2D() {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::instanced_arrays>())
CORRADE_SKIP(GL::Extensions::ARB::instanced_arrays::string() + std::string(" is not supported"));
#elif defined(MAGNUM_TARGET_GLES2)
#ifndef MAGNUM_TARGET_WEBGL
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>() &&
!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::instanced_arrays>() &&
!GL::Context::current().isExtensionSupported<GL::Extensions::NV::instanced_arrays>())
CORRADE_SKIP("GL_{ANGLE,EXT,NV}_instanced_arrays is not supported");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>())
CORRADE_SKIP(GL::Extensions::ANGLE::instanced_arrays::string() + std::string(" is not supported"));
#endif
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32,
Primitives::Circle2DFlag::TextureCoordinates));
/* Three circles, each in a different location */
struct {
Matrix3 transformation;
Color3 color;
Vector2 textureOffset;
} instanceData[] {
{Matrix3::translation({-1.25f, -1.25f}), 0xff3333_rgbf,
{0.0f, 0.0f}},
{Matrix3::translation({ 1.25f, -1.25f}), 0x33ff33_rgbf,
{1.0f, 0.0f}},
{Matrix3::translation({ 0.00f, 1.25f}), 0x9999ff_rgbf,
{0.5f, 1.0f}}
};
circle
.addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0,
Flat2D::TransformationMatrix{},
Flat2D::Color3{},
Flat2D::TextureOffset{})
.setInstanceCount(3);
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D texture;
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "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{Flat2D::Flag::Textured|
Flat2D::Flag::VertexColor|
Flat2D::Flag::InstancedTransformation|
Flat2D::Flag::InstancedTextureOffset}
.setColor(0xffff99_rgbf)
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f}))
.setTextureMatrix(Matrix3::scaling(Vector2{0.5f}))
.bindTexture(texture)
.draw(circle);
MAGNUM_VERIFY_NO_GL_ERROR();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* Minor differences on AMD, SwiftShader a bit more */
const Float maxThreshold = 3.0f, meanThreshold = 0.018f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage */
const Float maxThreshold = 3.0f, meanThreshold = 0.018f;
#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>()),
Utility::Directory::join(_testDir, "FlatTestFiles/instanced2D.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void FlatGLTest::renderInstanced3D() {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::instanced_arrays>())
CORRADE_SKIP(GL::Extensions::ARB::instanced_arrays::string() + std::string(" is not supported"));
#elif defined(MAGNUM_TARGET_GLES2)
#ifndef MAGNUM_TARGET_WEBGL
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>() &&
!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::instanced_arrays>() &&
!GL::Context::current().isExtensionSupported<GL::Extensions::NV::instanced_arrays>())
CORRADE_SKIP("GL_{ANGLE,EXT,NV}_instanced_arrays is not supported");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>())
CORRADE_SKIP(GL::Extensions::ANGLE::instanced_arrays::string() + std::string(" is not supported"));
#endif
#endif
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::UVSphereFlag::TextureCoordinates));
/* Three spheres, each in a different location */
struct {
Matrix4 transformation;
Color3 color;
Vector2 textureOffset;
} instanceData[] {
{Matrix4::translation({-1.25f, -1.25f, 0.0f}), 0xff3333_rgbf,
{0.0f, 0.0f}},
{Matrix4::translation({ 1.25f, -1.25f, 0.0f}), 0x33ff33_rgbf,
{1.0f, 0.0f}},
{Matrix4::translation({ 0.0f, 1.0f, 1.0f}), 0x9999ff_rgbf,
{0.5f, 1.0f}}
};
sphere
.addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0,
Flat3D::TransformationMatrix{},
Flat3D::Color3{},
Flat3D::TextureOffset{})
.setInstanceCount(3);
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D texture;
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "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{Flat3D::Flag::Textured|
Flat3D::Flag::VertexColor|
Flat3D::Flag::InstancedTransformation|
Flat3D::Flag::InstancedTextureOffset}
.setColor(0xffff99_rgbf)
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f}))
.setTextureMatrix(Matrix3::scaling(Vector2{0.5f}))
.bindTexture(texture)
.draw(sphere);
MAGNUM_VERIFY_NO_GL_ERROR();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* Minor differences on AMD, SwiftShader a bit more */
const Float maxThreshold = 67.67f, meanThreshold = 0.062f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage */
const Float maxThreshold = 67.67f, meanThreshold = 0.062f;
#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>()),
Utility::Directory::join(_testDir, "FlatTestFiles/instanced3D.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::FlatGLTest) CORRADE_TEST_MAIN(Magnum::Shaders::Test::FlatGLTest)

32
src/Magnum/Shaders/Test/FlatTest.cpp

@ -39,9 +39,7 @@ struct FlatTest: TestSuite::Tester {
void debugFlag(); void debugFlag();
void debugFlags(); void debugFlags();
#ifndef MAGNUM_TARGET_GLES2 void debugFlagsSupersets();
void debugFlagsInstancedObjectId();
#endif
}; };
FlatTest::FlatTest() { FlatTest::FlatTest() {
@ -53,10 +51,7 @@ FlatTest::FlatTest() {
&FlatTest::debugFlag, &FlatTest::debugFlag,
&FlatTest::debugFlags, &FlatTest::debugFlags,
#ifndef MAGNUM_TARGET_GLES2 &FlatTest::debugFlagsSupersets});
&FlatTest::debugFlagsInstancedObjectId
#endif
});
} }
template<UnsignedInt dimensions> void FlatTest::constructNoCreate() { template<UnsignedInt dimensions> void FlatTest::constructNoCreate() {
@ -94,16 +89,23 @@ void FlatTest::debugFlags() {
CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::Textured|Shaders::Flat::Flag::AlphaMask Shaders::Flat::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::Textured|Shaders::Flat::Flag::AlphaMask Shaders::Flat::Flags{}\n");
} }
#ifndef MAGNUM_TARGET_GLES2 void FlatTest::debugFlagsSupersets() {
void FlatTest::debugFlagsInstancedObjectId() { #ifndef MAGNUM_TARGET_GLES2
std::ostringstream out;
/* InstancedObjectId is a superset of ObjectId so only one should be /* InstancedObjectId is a superset of ObjectId so only one should be
*printed */ printed */
Debug{&out} << (Flat3D::Flag::ObjectId|Flat3D::Flag::InstancedObjectId); {
CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::InstancedObjectId\n"); std::ostringstream out;
Debug{&out} << (Flat3D::Flag::ObjectId|Flat3D::Flag::InstancedObjectId);
CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::InstancedObjectId\n");
}
#endif
/* InstancedTextureOffset is a superset of TextureTransformation so only
one should be printed */
std::ostringstream out;
Debug{&out} << (Flat3D::Flag::InstancedTextureOffset|Flat3D::Flag::TextureTransformation);
CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::InstancedTextureOffset\n");
} }
#endif
}}}} }}}}

BIN
src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga

Binary file not shown.
Loading…
Cancel
Save