Browse Source

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).
pull/430/head
Vladimír Vondruš 6 years ago
parent
commit
80c6fef7bf
  1. 14
      src/Magnum/MeshTools/Compile.cpp
  2. 144
      src/Magnum/MeshTools/Test/CompileGLTest.cpp
  3. BIN
      src/Magnum/MeshTools/Test/CompileTestFiles/tbn.tga

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

144
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<Flag> 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<GL::Extensions::ARB::geometry_shader4>())
#else
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>())
#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<class T> struct MeshTypeName;
@ -401,6 +432,13 @@ template<class T> 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<T, Trade::MeshData3D>::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<class T> 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<Trade::MeshAttributeData> 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<class T> 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<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>())
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() {

BIN
src/Magnum/MeshTools/Test/CompileTestFiles/tbn.tga

Binary file not shown.
Loading…
Cancel
Save