Browse Source

MeshTools: ability to generate smooth normals in compile().

pull/229/head
Vladimír Vondruš 7 years ago
parent
commit
5d2cf7ef93
  1. 17
      src/Magnum/MeshTools/Compile.cpp
  2. 12
      src/Magnum/MeshTools/Compile.h
  3. 6
      src/Magnum/MeshTools/GenerateNormals.h
  4. 41
      src/Magnum/MeshTools/Test/CompileGLTest.cpp
  5. BIN
      src/Magnum/MeshTools/Test/CompileTestFiles/phong-smooth.tga

17
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<Vector2> textureCoords2DStorage;
Containers::Array<Color4> 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<UnsignedInt>(meshData.indices(), positions);
useIndices = true;
}
normals = Containers::arrayView(normalStorage);
useIndices = false;
} else {
positions = meshData.positions(0);

12
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
};
/**

6
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<Vector3> generateFlatNormals(const Containers::StridedArrayView1D<const Vector3>& 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<class T> MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions);

41
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<Flag> 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 */

BIN
src/Magnum/MeshTools/Test/CompileTestFiles/phong-smooth.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Loading…
Cancel
Save