From 5d2cf7ef9376b7cd93e84425bf270526b7713b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 28 May 2019 00:39:34 +0200 Subject: [PATCH] MeshTools: ability to generate smooth normals in compile(). --- src/Magnum/MeshTools/Compile.cpp | 17 +++++--- src/Magnum/MeshTools/Compile.h | 12 ++++- src/Magnum/MeshTools/GenerateNormals.h | 6 ++- src/Magnum/MeshTools/Test/CompileGLTest.cpp | 41 +++++++++++++++--- .../Test/CompileTestFiles/phong-smooth.tga | Bin 0 -> 4114 bytes 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 src/Magnum/MeshTools/Test/CompileTestFiles/phong-smooth.tga diff --git a/src/Magnum/MeshTools/Compile.cpp b/src/Magnum/MeshTools/Compile.cpp index 99d3c2ac9..c4c5d5b80 100644 --- a/src/Magnum/MeshTools/Compile.cpp +++ b/src/Magnum/MeshTools/Compile.cpp @@ -130,7 +130,7 @@ GL::Mesh compile(const Trade::MeshData3D& meshData, CompileFlags flags) { GL::Mesh mesh; mesh.setPrimitive(meshData.primitive()); - const bool generateNormals = flags & CompileFlag::GenerateFlatNormals && meshData.primitive() == MeshPrimitive::Triangles; + const bool generateNormals = flags & (CompileFlag::GenerateFlatNormals|CompileFlag::GenerateSmoothNormals) && meshData.primitive() == MeshPrimitive::Triangles; /* Decide about stride and offsets */ UnsignedInt stride = sizeof(Shaders::Generic3D::Position::Type); @@ -169,8 +169,9 @@ GL::Mesh compile(const Trade::MeshData3D& meshData, CompileFlags flags) { Containers::Array textureCoords2DStorage; Containers::Array colorStorage; if(generateNormals) { - /* If the mesh is indexed, duplicate all attributes */ - if(meshData.isIndexed()) { + /* If we want flat normals and the mesh is indexed, duplicate all + attributes */ + if(flags & CompileFlag::GenerateFlatNormals && meshData.isIndexed()) { positionStorage = duplicate( Containers::stridedArrayView(meshData.indices()), Containers::stridedArrayView(meshData.positions(0))); positions = Containers::arrayView(positionStorage); @@ -194,9 +195,15 @@ GL::Mesh compile(const Trade::MeshData3D& meshData, CompileFlags flags) { colors = meshData.colors(0); } - normalStorage = generateFlatNormals(positions); + if(flags & CompileFlag::GenerateFlatNormals || !meshData.isIndexed()) { + normalStorage = generateFlatNormals(positions); + useIndices = false; + } else { + normalStorage = generateSmoothNormals(meshData.indices(), positions); + useIndices = true; + } + normals = Containers::arrayView(normalStorage); - useIndices = false; } else { positions = meshData.positions(0); diff --git a/src/Magnum/MeshTools/Compile.h b/src/Magnum/MeshTools/Compile.h index 23aec67f2..2f70bd714 100644 --- a/src/Magnum/MeshTools/Compile.h +++ b/src/Magnum/MeshTools/Compile.h @@ -59,7 +59,17 @@ enum class CompileFlag: UnsignedByte { * mesh or doesn't have 3D positions, this flag does nothing. If the mesh * already has its own normals, these get replaced. */ - GenerateFlatNormals = 1 << 0 + GenerateFlatNormals = 1 << 0, + + /** + * If the mesh @ref MeshPrimitive::Triangles, generates normals using + * @ref MeshTools::generateSmoothNormals() based on triangle adjacency + * information from the index buffer. If the mesh is not indexed, this + * behaves the same as @ref CompileFlag::GenerateFlatNormals. If the mesh + * is not a triangle mesh or doesn't have 3D positions, this flag does + * nothing. If the mesh already has its own normals, these get replaced. + */ + GenerateSmoothNormals = 1 << 1 }; /** diff --git a/src/Magnum/MeshTools/GenerateNormals.h b/src/Magnum/MeshTools/GenerateNormals.h index 1dbfc9c41..7d45d660f 100644 --- a/src/Magnum/MeshTools/GenerateNormals.h +++ b/src/Magnum/MeshTools/GenerateNormals.h @@ -52,7 +52,8 @@ Example usage: @snippet MagnumMeshTools.cpp generateFlatNormals -@see @ref generateFlatNormalsInto(), @ref generateSmoothNormals() +@see @ref generateFlatNormalsInto(), @ref generateSmoothNormals(), + @ref MeshTools::CompileFlag::GenerateFlatNormals */ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateFlatNormals(const Containers::StridedArrayView1D& positions); @@ -102,7 +103,8 @@ vertex; hard edges are preserved where adjacent triangles don't share vertices. Implementation is based on the article [Weighted Vertex Normals](http://www.bytehazard.com/articles/vertnorm.html) by Martijn Buijs. -@see @ref generateSmoothNormalsInto(), @ref generateFlatNormals() +@see @ref generateSmoothNormalsInto(), @ref generateFlatNormals(), + @ref MeshTools::CompileFlag::GenerateSmoothNormals */ template MAGNUM_MESHTOOLS_EXPORT Containers::Array generateSmoothNormals(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& positions); diff --git a/src/Magnum/MeshTools/Test/CompileGLTest.cpp b/src/Magnum/MeshTools/Test/CompileGLTest.cpp index 491bb591c..171ae4728 100644 --- a/src/Magnum/MeshTools/Test/CompileGLTest.cpp +++ b/src/Magnum/MeshTools/Test/CompileGLTest.cpp @@ -56,8 +56,9 @@ enum class Flag { NonIndexed = 1 << 0, Normals = 1 << 1, GeneratedFlatNormals = 1 << 2, - TextureCoordinates2D = 1 << 3, - Colors = 1 << 4 + GeneratedSmoothNormals = 1 << 3, + TextureCoordinates2D = 1 << 4, + Colors = 1 << 5 }; typedef Containers::EnumSet Flags; @@ -118,7 +119,12 @@ constexpr struct { {"positions, nonindexed + gen flat normals", Flag::NonIndexed|Flag::GeneratedFlatNormals}, {"positions, nonindexed + gen flat normals + colors", Flag::NonIndexed|Flag::GeneratedFlatNormals|Flag::Colors}, {"positions, nonindexed + gen flat normals + texcoords", Flag::NonIndexed|Flag::GeneratedFlatNormals|Flag::TextureCoordinates2D}, - {"positions, nonindexed + gen flat normals + texcoords + colors", Flag::NonIndexed|Flag::GeneratedFlatNormals|Flag::TextureCoordinates2D|Flag::Colors} + {"positions, nonindexed + gen flat normals + texcoords + colors", Flag::NonIndexed|Flag::GeneratedFlatNormals|Flag::TextureCoordinates2D|Flag::Colors}, + {"positions, gen smooth normals", Flag::GeneratedSmoothNormals}, + {"positions, gen smooth normals + colors", Flag::GeneratedSmoothNormals|Flag::Colors}, + {"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}, }; using namespace Math::Literals; @@ -394,8 +400,12 @@ void CompileGLTest::threeDimensions() { MAGNUM_VERIFY_NO_GL_ERROR(); - GL::Mesh mesh = compile(Trade::MeshData3D{MeshPrimitive::Triangles, indices, {positions}, normals, textureCoordinates2D, colors}, - data.flags & Flag::GeneratedFlatNormals ? CompileFlag::GenerateFlatNormals : CompileFlags{}); + CompileFlags flags; + if(data.flags & Flag::GeneratedFlatNormals) + flags |= CompileFlag::GenerateFlatNormals; + else if(data.flags & Flag::GeneratedSmoothNormals) + flags |= CompileFlag::GenerateSmoothNormals; + GL::Mesh mesh = compile(Trade::MeshData3D{MeshPrimitive::Triangles, indices, {positions}, normals, textureCoordinates2D, colors}, flags); MAGNUM_VERIFY_NO_GL_ERROR(); @@ -439,8 +449,10 @@ void CompileGLTest::threeDimensions() { (DebugTools::CompareImageToFile{_manager, 0.5f, 0.0113f})); } - /* Check generated flat normals with the phong shader */ - if(data.flags & Flag::GeneratedFlatNormals) { + /* Check generated flat / smooth normals with the phong shader. If smooth + normals are requested but the mesh is not indexed, it should behave the + same as flat normals. */ + if(data.flags & Flag::GeneratedFlatNormals || (data.flags & Flag::GeneratedSmoothNormals && data.flags & Flag::NonIndexed)) { _framebuffer.clear(GL::FramebufferClear::Color); _phong .setDiffuseColor(0x33ff66_rgbf) @@ -455,6 +467,21 @@ void CompileGLTest::threeDimensions() { Utility::Directory::join(COMPILEGLTEST_TEST_DIR, "phong-flat.tga"), /* SwiftShader has some minor off-by-one precision differences */ (DebugTools::CompareImageToFile{_manager, 0.25f, 0.0079f})); + } else if(data.flags & Flag::GeneratedSmoothNormals) { + _framebuffer.clear(GL::FramebufferClear::Color); + _phong + .setDiffuseColor(0x33ff66_rgbf) + .setTransformationMatrix(transformation) + .setNormalMatrix(transformation.rotationScaling()) + .setProjectionMatrix(projection); + mesh.draw(_phong); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE_WITH( + _framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), + Utility::Directory::join(COMPILEGLTEST_TEST_DIR, "phong-smooth.tga"), + /* SwiftShader has some minor off-by-one precision differences */ + (DebugTools::CompareImageToFile{_manager, 0.25f, 0.0059f})); } /* Check with the colored shader, if we have colors */ diff --git a/src/Magnum/MeshTools/Test/CompileTestFiles/phong-smooth.tga b/src/Magnum/MeshTools/Test/CompileTestFiles/phong-smooth.tga new file mode 100644 index 0000000000000000000000000000000000000000..ddc81ed349947ea38b6b56e135039b658d42fc6e GIT binary patch literal 4114 zcmeH~xpLG{5Jji>5t9Kn-fbY_7YukE?+eBSB=8H6kdTw|5k$l!1TGe{@4MNGeW%>q z(|S*q21_yo6oH58^30R;?(N&R`-xg@Q!Rcr*Z9}e)MOj+|7x&rahvsDY_@^R%{I8C zxYA-nSCim-Zta@Zv!VO`w6=Zcw%FeDTMgWSO94-N4&P|8kz3nsL2&E#=h64NmY-4sfW# zCvSLqzS?W_eu6drq|L^kw%NpTKE|JEUDx2my>&u->UR^~=tT~ZLlr)nlQ;R0+ZedQ zn0Vf9lP}wC>XqX4YE0_)zeodmj5@&?Ezz9396R97ed)BhuU)I5-?N_+J~Qvd6Ar40bHEcB zf6^c1SA>u6(1~a88o98a=dGN<-TzJTz02l*5Z(TrHF%+mYY}unKm33v@lz$fYL8Al z1An|mebJo#!2xq&rN<80PCIP7?4a$i13!D52mG9abnsf>2Ryk>eC8TFslDR|?b*|F zSKeSBvE6pe`s}2Q+Hu=sNA-JQr8nUabZ|fD`B;ZE{}TVLg^$l8KAMv^*k|p8E!!De zveS0T=ADDS!@w;7f@&-G8;D8R)0&ln%R5NOa7u^T) z6y7SE!8!lYdyVzi-e77Su10ARZnv*x!J`dt72=%9j=>dA0-Y(Oh*%a}a89Wnba9Rg?G0XyZfQjaO_c;`2 z05dtxA$1368s64XtBM0h@=Hv}F@Ag&rjn|o1?3D|x bvA1*8U%w}_Mvvk1_2}J*xAFVm{$KPLYM?dI literal 0 HcmV?d00001