Browse Source

Primitives: added a wireframe icosphere.

catastrophic-cross
Vladimír Vondruš 6 years ago
parent
commit
56cade15ca
  1. 1
      doc/changelog.dox
  2. 6
      doc/generated/primitives.cpp
  3. BIN
      doc/primitives-icospherewireframe.png
  4. 76
      src/Magnum/Primitives/Icosphere.cpp
  5. 23
      src/Magnum/Primitives/Icosphere.h
  6. 16
      src/Magnum/Primitives/Test/IcosphereTest.cpp

1
doc/changelog.dox

@ -210,6 +210,7 @@ See also:
@ref Primitives::coneSolid(), @ref Primitives::cylinderSolid(), @ref Primitives::coneSolid(), @ref Primitives::cylinderSolid(),
@ref Primitives::grid3DSolid(), @ref Primitives::planeSolid() and @ref Primitives::grid3DSolid(), @ref Primitives::planeSolid() and
@ref Primitives::uvSphereSolid() can now have tangents as well @ref Primitives::uvSphereSolid() can now have tangents as well
- Added @ref Primitives::icosphereWireframe()
@subsubsection changelog-latest-new-scenegraph SceneGraph library @subsubsection changelog-latest-new-scenegraph SceneGraph library

6
doc/generated/primitives.cpp

@ -108,6 +108,7 @@ struct PrimitiveVisualizer: Platform::WindowlessApplication {
std::pair<Trade::MeshData, std::string> cubeWireframe(); std::pair<Trade::MeshData, std::string> cubeWireframe();
std::pair<Trade::MeshData, std::string> cylinderWireframe(); std::pair<Trade::MeshData, std::string> cylinderWireframe();
std::pair<Trade::MeshData, std::string> grid3DWireframe(); std::pair<Trade::MeshData, std::string> grid3DWireframe();
std::pair<Trade::MeshData, std::string> icosphereWireframe();
std::pair<Trade::MeshData, std::string> line3D(); std::pair<Trade::MeshData, std::string> line3D();
std::pair<Trade::MeshData, std::string> planeWireframe(); std::pair<Trade::MeshData, std::string> planeWireframe();
std::pair<Trade::MeshData, std::string> uvSphereWireframe(); std::pair<Trade::MeshData, std::string> uvSphereWireframe();
@ -257,6 +258,7 @@ int PrimitiveVisualizer::exec() {
&PrimitiveVisualizer::cubeWireframe, &PrimitiveVisualizer::cubeWireframe,
&PrimitiveVisualizer::cylinderWireframe, &PrimitiveVisualizer::cylinderWireframe,
&PrimitiveVisualizer::grid3DWireframe, &PrimitiveVisualizer::grid3DWireframe,
&PrimitiveVisualizer::icosphereWireframe,
&PrimitiveVisualizer::line3D, &PrimitiveVisualizer::line3D,
&PrimitiveVisualizer::planeWireframe, &PrimitiveVisualizer::planeWireframe,
&PrimitiveVisualizer::uvSphereWireframe}) &PrimitiveVisualizer::uvSphereWireframe})
@ -497,6 +499,10 @@ std::pair<Trade::MeshData, std::string> PrimitiveVisualizer::grid3DWireframe() {
return {Primitives::grid3DWireframe({5, 3}), "grid3dwireframe.png"}; return {Primitives::grid3DWireframe({5, 3}), "grid3dwireframe.png"};
} }
std::pair<Trade::MeshData, std::string> PrimitiveVisualizer::icosphereWireframe() {
return {Primitives::icosphereWireframe(), "icospherewireframe.png"};
}
std::pair<Trade::MeshData, std::string> PrimitiveVisualizer::line3D() { std::pair<Trade::MeshData, std::string> PrimitiveVisualizer::line3D() {
Trade::MeshData line = Primitives::line3D(); Trade::MeshData line = Primitives::line3D();
MeshTools::transformPointsInPlace(Matrix4::translation(Vector3::xAxis(-1.0f))*Matrix4::scaling(Vector3::xScale(2.0f)), MeshTools::transformPointsInPlace(Matrix4::translation(Vector3::xAxis(-1.0f))*Matrix4::scaling(Vector3::xScale(2.0f)),

BIN
doc/primitives-icospherewireframe.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

76
src/Magnum/Primitives/Icosphere.cpp

@ -42,16 +42,19 @@ constexpr UnsignedInt Indices[]{
3, 4, 5, 3, 4, 5,
4, 3, 8, 4, 3, 8,
6, 5, 11, 6, 5, 11,
5, 6, 10, 5, 6, 10,
9, 10, 2, 9, 10, 2,
10, 9, 3, 10, 9, 3,
7, 8, 9, 7, 8, 9,
8, 7, 0, 8, 7, 0,
11, 0, 1, 11, 0, 1,
0, 11, 4, 0, 11, 4,
6, 2, 10, 6, 2, 10,
1, 6, 11, 1, 6, 11,
3, 5, 10, 3, 5, 10,
5, 4, 11, 5, 4, 11,
2, 7, 9, 2, 7, 9,
7, 1, 0, 7, 1, 0,
@ -59,26 +62,30 @@ constexpr UnsignedInt Indices[]{
4, 8, 0 4, 8, 0
}; };
constexpr Vector3 Positions[]{ /* Can't be just an array of Vector3 because MSVC 2015 is special. See
{0.0f, -0.525731f, 0.850651f}, Crosshair.cpp for details. */
{0.850651f, 0.0f, 0.525731f}, constexpr struct VertexSolidStrip {
{0.850651f, 0.0f, -0.525731f}, Vector3 position;
{-0.850651f, 0.0f, -0.525731f}, } Vertices[]{
{-0.850651f, 0.0f, 0.525731f}, {{0.0f, -0.525731f, 0.850651f}},
{-0.525731f, 0.850651f, 0.0f}, {{0.850651f, 0.0f, 0.525731f}},
{0.525731f, 0.850651f, 0.0f}, {{0.850651f, 0.0f, -0.525731f}},
{0.525731f, -0.850651f, 0.0f}, {{-0.850651f, 0.0f, -0.525731f}},
{-0.525731f, -0.850651f, 0.0f}, {{-0.850651f, 0.0f, 0.525731f}},
{0.0f, -0.525731f, -0.850651f}, {{-0.525731f, 0.850651f, 0.0f}},
{0.0f, 0.525731f, -0.850651f}, {{0.525731f, 0.850651f, 0.0f}},
{0.0f, 0.525731f, 0.850651f} {{0.525731f, -0.850651f, 0.0f}},
{{-0.525731f, -0.850651f, 0.0f}},
{{0.0f, -0.525731f, -0.850651f}},
{{0.0f, 0.525731f, -0.850651f}},
{{0.0f, 0.525731f, 0.850651f}}
}; };
} }
Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) { Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) {
const std::size_t indexCount = Containers::arraySize(Indices)*(1 << subdivisions*2); const std::size_t indexCount = Containers::arraySize(Indices)*(1 << subdivisions*2);
const std::size_t vertexCount = Containers::arraySize(Positions) + ((indexCount - Containers::arraySize(Indices))/3); const std::size_t vertexCount = Containers::arraySize(Vertices) + ((indexCount - Containers::arraySize(Indices))/3);
Containers::Array<char> indexData{indexCount*sizeof(UnsignedInt)}; Containers::Array<char> indexData{indexCount*sizeof(UnsignedInt)};
auto indices = Containers::arrayCast<UnsignedInt>(indexData); auto indices = Containers::arrayCast<UnsignedInt>(indexData);
@ -96,12 +103,12 @@ Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) {
{ {
auto vertices = Containers::arrayCast<Vertex>(vertexData); auto vertices = Containers::arrayCast<Vertex>(vertexData);
Containers::StridedArrayView1D<Vector3> positions{vertices, &vertices[0].position, vertices.size(), sizeof(Vertex)}; Containers::StridedArrayView1D<Vector3> positions{vertices, &vertices[0].position, vertices.size(), sizeof(Vertex)};
for(std::size_t i = 0; i != Containers::arraySize(Positions); ++i) for(std::size_t i = 0; i != Containers::arraySize(Vertices); ++i)
positions[i] = Positions[i]; positions[i] = Vertices[i].position;
for(std::size_t i = 0; i != subdivisions; ++i) { for(std::size_t i = 0; i != subdivisions; ++i) {
const std::size_t iterationIndexCount = Containers::arraySize(Indices)*(1 << (i + 1)*2); const std::size_t iterationIndexCount = Containers::arraySize(Indices)*(1 << (i + 1)*2);
const std::size_t iterationVertexCount = Containers::arraySize(Positions) + ((iterationIndexCount - Containers::arraySize(Indices))/3); const std::size_t iterationVertexCount = Containers::arraySize(Vertices) + ((iterationIndexCount - Containers::arraySize(Indices))/3);
MeshTools::subdivideInPlace(indices.prefix(iterationIndexCount), positions.prefix(iterationVertexCount), [](const Vector3& a, const Vector3& b) { MeshTools::subdivideInPlace(indices.prefix(iterationIndexCount), positions.prefix(iterationVertexCount), [](const Vector3& a, const Vector3& b) {
return (a+b).normalized(); return (a+b).normalized();
}); });
@ -125,4 +132,39 @@ Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) {
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, normals}}}; Trade::MeshAttributeData{Trade::MeshAttribute::Normal, normals}}};
} }
namespace {
/* Taking the above, converting each triangle to three lines and leaving out
the duplicates. Because each edge is shared by two triangles and there was
20 triangles to begin with, there's 30 edges. */
constexpr UnsignedInt IndicesWireframe[]{
1, 2, 2, 6, 6, 1,
1, 7, 7, 2,
3, 4, 4, 5, 5, 3,
3, 8, 8, 4,
6, 5, 5, 11, 11, 6,
6, 10, 10, 5,
9, 10, 10, 2, 2, 9,
9, 3, 3, 10,
7, 8, 8, 9, 9, 7,
7, 0, 0, 8,
11, 0, 0, 1, 1, 11,
11, 4, 4, 0
};
constexpr Trade::MeshAttributeData AttributesWireframe[]{
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
Containers::stridedArrayView(Vertices, &Vertices[0].position,
Containers::arraySize(Vertices), sizeof(Vector3))}
};
}
Trade::MeshData icosphereWireframe() {
return Trade::MeshData{MeshPrimitive::Lines,
{}, IndicesWireframe, Trade::MeshIndexData{IndicesWireframe},
{}, Vertices, Trade::meshAttributeDataNonOwningArray(AttributesWireframe)};
}
}} }}

23
src/Magnum/Primitives/Icosphere.h

@ -47,14 +47,29 @@ normals.
The @p subdivisions parameter describes how many times is each icosphere The @p subdivisions parameter describes how many times is each icosphere
triangle subdivided, recursively. Specifying @cpp 0 @ce will result in an triangle subdivided, recursively. Specifying @cpp 0 @ce will result in an
icosphere with 20 faces, saying @cpp 1 @ce will result in an icosphere with 80 icosphere with 12 vertices and 20 faces, saying @cpp 1 @ce will result in an
faces (each triangle subdivided into four smaller), saying @cpp 2 @ce will icosphere with 80 faces (each triangle subdivided into four smaller), saying
result in 320 faces and so on. In particular, this is different from the @cpp 2 @ce will result in 320 faces and so on. In particular, this is different
`subdivisions` parameter in @ref grid3DSolid() or @ref grid3DWireframe(). from the `subdivisions` parameter in @ref grid3DSolid() or @ref grid3DWireframe().
@see @ref uvSphereSolid(), @ref uvSphereWireframe() @see @ref uvSphereSolid(), @ref uvSphereWireframe()
*/ */
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData icosphereSolid(UnsignedInt subdivisions); MAGNUM_PRIMITIVES_EXPORT Trade::MeshData icosphereSolid(UnsignedInt subdivisions);
/**
@brief Wireframe 3D icosphere
@m_since_latest
Sphere of radius @cpp 1.0f @ce with 12 vertices and 30 edges, centered at
origin. @ref MeshPrimitive::Lines with @ref MeshIndexType::UnsignedShort
indices and @ref VertexFormat::Vector3 positions. The returned instance
references data stored in constant memory.
@image html primitives-icospherewireframe.png width=256px
@see @ref icosphereWireframe()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData icosphereWireframe();
}} }}
#endif #endif

16
src/Magnum/Primitives/Test/IcosphereTest.cpp

@ -38,12 +38,16 @@ struct IcosphereTest: TestSuite::Tester {
void count0(); void count0();
void data1(); void data1();
void count2(); void count2();
void wireframe();
}; };
IcosphereTest::IcosphereTest() { IcosphereTest::IcosphereTest() {
addTests({&IcosphereTest::count0, addTests({&IcosphereTest::count0,
&IcosphereTest::data1, &IcosphereTest::data1,
&IcosphereTest::count2}); &IcosphereTest::count2,
&IcosphereTest::wireframe});
} }
void IcosphereTest::count0() { void IcosphereTest::count0() {
@ -146,6 +150,16 @@ void IcosphereTest::count2() {
CORRADE_COMPARE(icosphere.attributeCount(), 2); CORRADE_COMPARE(icosphere.attributeCount(), 2);
} }
void IcosphereTest::wireframe() {
Trade::MeshData icosphere = Primitives::icosphereWireframe();
CORRADE_COMPARE(icosphere.primitive(), MeshPrimitive::Lines);
CORRADE_VERIFY(icosphere.isIndexed());
CORRADE_COMPARE(icosphere.indexCount(), 60);
CORRADE_COMPARE(icosphere.vertexCount(), 12);
CORRADE_COMPARE(icosphere.attributeCount(), 1);
}
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Primitives::Test::IcosphereTest) CORRADE_TEST_MAIN(Magnum::Primitives::Test::IcosphereTest)

Loading…
Cancel
Save