From 80c6fef7bff966f44f509c75846616ba5c1cdf5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 21 Mar 2020 21:19:40 +0100 Subject: [PATCH] MeshTools: handle generic Tangent and Bitangent attributes in compile(). A bit unfortunate that the test needs ES3.2 and GS, but I got nothing better right now. Not handling ObjectId yet, for that I need to implement instancing first (so yes, GCC/Clang will still warn about an unhandled switch case). --- src/Magnum/MeshTools/Compile.cpp | 14 +- src/Magnum/MeshTools/Test/CompileGLTest.cpp | 144 ++++++++++++++++-- .../MeshTools/Test/CompileTestFiles/tbn.tga | Bin 0 -> 1611 bytes 3 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 src/Magnum/MeshTools/Test/CompileTestFiles/tbn.tga diff --git a/src/Magnum/MeshTools/Compile.cpp b/src/Magnum/MeshTools/Compile.cpp index cf10ffb75..5eebf0a92 100644 --- a/src/Magnum/MeshTools/Compile.cpp +++ b/src/Magnum/MeshTools/Compile.cpp @@ -85,9 +85,6 @@ GL::Mesh compileInternal(const Trade::MeshData& meshData, GL::Buffer&& indices, to a 2-component version if needed */ attribute.emplace(Shaders::Generic3D::Position{}, format); break; - case Trade::MeshAttribute::Normal: - attribute.emplace(Shaders::Generic3D::Normal{}, format); - break; case Trade::MeshAttribute::TextureCoordinates: /** @todo have Generic2D derived from Generic that has all attribute definitions common for 2D and 3D */ @@ -100,6 +97,17 @@ GL::Mesh compileInternal(const Trade::MeshData& meshData, GL::Buffer&& indices, 3-component version if needed */ attribute.emplace(Shaders::Generic2D::Color4{}, format); break; + case Trade::MeshAttribute::Tangent: + /* Pick Tangent4 always, the format will properly reduce it to + a 3-component version if needed */ + attribute.emplace(Shaders::Generic3D::Tangent4{}, format); + break; + case Trade::MeshAttribute::Bitangent: + attribute.emplace(Shaders::Generic3D::Bitangent{}, format); + break; + case Trade::MeshAttribute::Normal: + attribute.emplace(Shaders::Generic3D::Normal{}, format); + break; /* So it doesn't yell that we didn't handle a known attribute */ case Trade::MeshAttribute::Custom: break; /* LCOV_EXCL_LINE */ diff --git a/src/Magnum/MeshTools/Test/CompileGLTest.cpp b/src/Magnum/MeshTools/Test/CompileGLTest.cpp index 9a489d21f..848fc7db4 100644 --- a/src/Magnum/MeshTools/Test/CompileGLTest.cpp +++ b/src/Magnum/MeshTools/Test/CompileGLTest.cpp @@ -35,6 +35,8 @@ #include "Magnum/Mesh.h" #include "Magnum/PixelFormat.h" #include "Magnum/DebugTools/CompareImage.h" +#include "Magnum/GL/Context.h" +#include "Magnum/GL/Extensions.h" #include "Magnum/GL/Mesh.h" #include "Magnum/GL/OpenGLTester.h" #include "Magnum/GL/Framebuffer.h" @@ -49,6 +51,7 @@ #include "Magnum/Shaders/Flat.h" #include "Magnum/Shaders/Phong.h" #include "Magnum/Shaders/VertexColor.h" +#include "Magnum/Shaders/MeshVisualizer.h" #include "Magnum/Trade/AbstractImporter.h" #include "Magnum/Trade/MeshData.h" @@ -65,11 +68,14 @@ namespace Magnum { namespace MeshTools { namespace Test { namespace { enum class Flag { NonIndexed = 1 << 0, - Normals = 1 << 1, - GeneratedFlatNormals = 1 << 2, - GeneratedSmoothNormals = 1 << 3, - TextureCoordinates2D = 1 << 4, - Colors = 1 << 5 + Tangents = 1 << 1, + Bitangents = 1 << 2, + BitangentsFromTangents = 1 << 3, + Normals = 1 << 4, + GeneratedFlatNormals = 1 << 5, + GeneratedSmoothNormals = 1 << 6, + TextureCoordinates2D = 1 << 7, + Colors = 1 << 8 }; typedef Containers::EnumSet Flags; @@ -112,6 +118,10 @@ struct CompileGLTest: GL::OpenGLTester { Shaders::VertexColor2D _color2D; Shaders::VertexColor3D _color3D; Shaders::Phong _phong; + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + Shaders::MeshVisualizer3D _meshVisualizer3D{NoCreate}; + Shaders::MeshVisualizer3D _meshVisualizerBitangentsFromTangents3D{NoCreate}; + #endif GL::Renderbuffer _color; GL::Framebuffer _framebuffer{{{}, {32, 32}}}; @@ -157,6 +167,8 @@ constexpr struct { {"positions, gen smooth normals + texcoords", Flag::GeneratedSmoothNormals|Flag::TextureCoordinates2D}, {"positions, gen smooth normals + texcoords + colors", Flag::GeneratedSmoothNormals|Flag::TextureCoordinates2D|Flag::Colors}, {"positions, nonindexed + gen smooth normals", Flag::NonIndexed|Flag::GeneratedSmoothNormals}, + {"positions, tangents, bitangents, normals", Flag::Tangents|Flag::Bitangents|Flag::Normals}, + {"positions, tangents, bitangents from tangents, normals", Flag::Tangents|Flag::BitangentsFromTangents|Flag::Normals} }; constexpr struct { @@ -257,6 +269,25 @@ CompileGLTest::CompileGLTest() { #endif {4, 4}) .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA8Unorm, {4, 4}, ImageData}); + + /* Mesh visualizer shaders only if we have a GS */ + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + #ifndef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + #else + if(GL::Context::current().isExtensionSupported()) + #endif + { + _meshVisualizer3D = Shaders::MeshVisualizer3D{ + Shaders::MeshVisualizer3D::Flag::TangentDirection| + Shaders::MeshVisualizer3D::Flag::BitangentDirection| + Shaders::MeshVisualizer3D::Flag::NormalDirection}; + _meshVisualizerBitangentsFromTangents3D = Shaders::MeshVisualizer3D{ + Shaders::MeshVisualizer3D::Flag::TangentDirection| + Shaders::MeshVisualizer3D::Flag::BitangentFromTangentDirection| + Shaders::MeshVisualizer3D::Flag::NormalDirection}; + } + #endif } template struct MeshTypeName; @@ -401,6 +432,13 @@ template void CompileGLTest::threeDimensions() { auto&& data = Data3D[testCaseInstanceId()]; setTestCaseDescription(data.name); + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH /** @todo remove once MeshDataXD is gone */ + if(std::is_same::value && data.flags & (Flag::Tangents|Flag::Bitangents|Flag::BitangentsFromTangents)) + CORRADE_SKIP("Not possible with MeshData3D."); + CORRADE_IGNORE_DEPRECATED_POP + #endif + /* 6-----7-----8 | /| /| @@ -412,39 +450,73 @@ template void CompileGLTest::threeDimensions() { |/ |/ | 0-----1-----2 */ - const struct Vertex { + struct Vertex { Vector3 position; + Vector4 tangent; + Vector3 bitangent; Vector3 normal; Vector2 textureCoordinates; Color4 color; } vertexData[]{ - {{-0.75f, -0.75f, -0.35f}, Vector3{-0.5f, -0.5f, 1.0f}.normalized(), + {{-0.75f, -0.75f, -0.35f}, + Vector4{Vector3{1.0f, 0.5f, 0.5f}.normalized(), -1.0f}, {}, + Vector3{-0.5f, -0.5f, 1.0f}.normalized(), {0.0f, 0.0f}, 0x00ff00_rgbf}, - {{ 0.00f, -0.75f, -0.25f}, Vector3{ 0.0f, -0.5f, 1.0f}.normalized(), + {{ 0.00f, -0.75f, -0.25f}, + Vector4{Vector3{1.0f, 0.0f, 0.5f}.normalized(), 1.0f}, {}, + Vector3{ 0.0f, -0.5f, 1.0f}.normalized(), {0.5f, 0.0f}, 0x808000_rgbf}, - {{ 0.75f, -0.75f, -0.35f}, Vector3{ 0.5f, -0.5f, 1.0f}.normalized(), + {{ 0.75f, -0.75f, -0.35f}, + Vector4{Vector3{1.0f, -0.5f, 0.5f}.normalized(), 1.0f}, {}, + Vector3{ 0.5f, -0.5f, 1.0f}.normalized(), {1.0f, 0.0f}, 0xff0000_rgbf}, - {{-0.75f, 0.00f, -0.25f}, Vector3{-0.5f, 0.0f, 1.0f}.normalized(), + {{-0.75f, 0.00f, -0.25f}, + Vector4{Vector3{1.0f, 0.5f, 0.0f}.normalized(), -1.0f}, {}, + Vector3{-0.5f, 0.0f, 1.0f}.normalized(), {0.0f, 0.5f}, 0x00ff80_rgbf}, - {{ 0.00f, 0.00f, 0.00f}, Vector3{ 0.0f, 0.0f, 1.0f}.normalized(), + {{ 0.00f, 0.00f, 0.00f}, + Vector4{Vector3{1.0f, 0.0f, 0.0f}.normalized(), 1.0f}, {}, + Vector3{ 0.0f, 0.0f, 1.0f}.normalized(), {0.5f, 0.5f}, 0x808080_rgbf}, - {{ 0.75f, 0.00f, -0.25f}, Vector3{ 0.5f, 0.0f, 1.0f}.normalized(), + {{ 0.75f, 0.00f, -0.25f}, + Vector4{Vector3{1.0f, -0.5f, 0.0f}.normalized(), 1.0f}, {}, + Vector3{ 0.5f, 0.0f, 1.0f}.normalized(), {1.0f, 0.5f}, 0xff0080_rgbf}, - {{-0.75f, 0.75f, -0.35f}, Vector3{-0.5f, 0.5f, 1.0f}.normalized(), + {{-0.75f, 0.75f, -0.35f}, + Vector4{Vector3{1.0f, -0.5f, 0.0f}.normalized(), -1.0f}, {}, + Vector3{-0.5f, 0.5f, 1.0f}.normalized(), {0.0f, 1.0f}, 0x00ffff_rgbf}, - {{ 0.0f, 0.75f, -0.25f}, Vector3{ 0.0f, 0.5f, 1.0f}.normalized(), + {{ 0.0f, 0.75f, -0.25f}, + Vector4{Vector3{1.0f, -0.5f, 0.0f}.normalized(), -1.0f}, {}, + Vector3{ 0.0f, 0.5f, 1.0f}.normalized(), {0.5f, 1.0f}, 0x8080ff_rgbf}, - {{ 0.75f, 0.75f, -0.35f}, Vector3{ 0.5f, 0.5f, 1.0f}.normalized(), + {{ 0.75f, 0.75f, -0.35f}, + Vector4{Vector3{1.0f, -0.5f, 0.0f}.normalized(), -1.0f}, {}, + Vector3{ 0.5f, 0.5f, 1.0f}.normalized(), {1.0f, 1.0f}, 0xff00ff_rgbf} }; + /* Calculate bitangents from normal+tangent */ + for(Vertex& i: vertexData) + i.bitangent = Math::cross(i.normal, i.tangent.xyz())*i.tangent.w(); + Containers::Array attributeData; arrayAppend(attributeData, Trade::MeshAttributeData{ Trade::MeshAttribute::Position, Containers::stridedArrayView(vertexData, &vertexData[0].position, Containers::arraySize(vertexData), sizeof(Vertex))}); + if(data.flags & Flag::Tangents || data.flags & Flag::BitangentsFromTangents) + arrayAppend(attributeData, Trade::MeshAttributeData{ + Trade::MeshAttribute::Tangent, + Containers::stridedArrayView(vertexData, &vertexData[0].tangent, + Containers::arraySize(vertexData), sizeof(Vertex))}); + if(data.flags & Flag::Bitangents) + arrayAppend(attributeData, Trade::MeshAttributeData{ + Trade::MeshAttribute::Bitangent, + Containers::stridedArrayView(vertexData, &vertexData[0].bitangent, + Containers::arraySize(vertexData), sizeof(Vertex))}); if(data.flags & Flag::Normals) arrayAppend(attributeData, Trade::MeshAttributeData{ Trade::MeshAttribute::Normal, @@ -597,6 +669,48 @@ template void CompileGLTest::threeDimensions() { /* SwiftShader has some minor off-by-one precision differences */ (DebugTools::CompareImageToFile{_manager, 1.0f, 0.0948f})); } + + /* Check with the mesh visualizer shader for TBN direction. This has to be + last, as it gets skipped on WebGL / ES2. */ + if(data.flags >= (Flag::Tangents|Flag::Bitangents|Flag::Normals) || + data.flags >= (Flag::Tangents|Flag::BitangentsFromTangents|Flag::Normals)) { + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported")); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() + std::string(" is not supported")); + #endif + + _framebuffer.clear(GL::FramebufferClear::Color); + + if(data.flags >= (Flag::Tangents|Flag::Bitangents|Flag::Normals)) + _meshVisualizer3D + .setTransformationMatrix(transformation) + .setProjectionMatrix(projection) + .setViewportSize({32, 32}) + .setSmoothness(0.0f) /* To avoid perspective artifacts */ + .draw(mesh); + else if(data.flags >= (Flag::Tangents|Flag::BitangentsFromTangents|Flag::Normals)) + _meshVisualizerBitangentsFromTangents3D + .setTransformationMatrix(transformation) + .setProjectionMatrix(projection) + .setViewportSize({32, 32}) + .setSmoothness(0.0f) /* To avoid perspective artifacts */ + .draw(mesh); + else CORRADE_VERIFY(false); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE_WITH( + _framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), + Utility::Directory::join(COMPILEGLTEST_TEST_DIR, "tbn.tga"), + /* SwiftShader has some minor off-by-one precision differences */ + (DebugTools::CompareImageToFile{_manager, 1.0f, 0.0948f})); + #else + CORRADE_SKIP("Geometry shaders not available on ES2 or WebGL."); + #endif + } } void CompileGLTest::packedAttributes() { diff --git a/src/Magnum/MeshTools/Test/CompileTestFiles/tbn.tga b/src/Magnum/MeshTools/Test/CompileTestFiles/tbn.tga new file mode 100644 index 0000000000000000000000000000000000000000..4692545bcd4b6fc73d95f1f95e8ed48382e77965 GIT binary patch literal 1611 zcma)+2~q*})JMN#^A6-_r%yKKVq@eILoqL zQ>s0X#Z}PnP@7^Rf7WF+4VhIwn4Ij#W@R)R|7cNXqY|t{e1b4&u_=5KNX8e8JeU(k zxq{``>dDmG)6ynO>nIkv-qFBhcNxQG6C=isede_C)p0q7i_lxLf}K_TrDMaJ(20up z{vZF5baP*YlM~ioWUH?o?i2WJbW2_wEPTJQ{2^R`5V^QyQMrArPoPcPGL-OzXcD9> zQYN*e7O7=fCjT;jRD4=X&0j0a+42ph>j68Z}HBzIk5F@Sf<#6JmW7y zl|8@?15n literal 0 HcmV?d00001