From f39019c7f12d2eaa90f8b56709df47bb35773e8e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Mar 2023 01:01:52 +0000 Subject: Hugely more detailed Brush47 model and revision to test case details Specifically, this includes the buffer block, which is a rotated cuboid with an extrusion. This feature breaks the current mesh creation code... Fix coming up. --- res/brush47.xml | 79 ++++++++++++++++++++++++++++++++++++++-------- test/test-assetFactory.cpp | 14 ++++---- 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/res/brush47.xml b/res/brush47.xml index 9c7d2a8..dbd3327 100644 --- a/res/brush47.xml +++ b/res/brush47.xml @@ -1,36 +1,89 @@ - + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + + + - + + + + + - + - + diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index ae5a88a..204ffb3 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -21,7 +21,7 @@ BOOST_GLOBAL_FIXTURE(ApplicationBase); BOOST_GLOBAL_FIXTURE(TestMainWindow); const std::filesystem::path TMP {"/tmp"}; -class FactoryFixture : public TestRenderOutputSize, public SceneProvider { +class FactoryFixture : public TestRenderOutputSize, public SceneProvider { public: FactoryFixture() : sceneRenderer {size, output} { } ~FactoryFixture() @@ -45,8 +45,8 @@ public: void environment(const SceneShader &, const SceneRenderer & sceneRenderer) const override { - sceneRenderer.setAmbientLight({.2, .2, .2}); - sceneRenderer.setDirectionalLight({.3, .3, .3}, east + south + south + down, *this); + sceneRenderer.setAmbientLight({.4, .4, .4}); + sceneRenderer.setDirectionalLight({.6, .6, .6}, east + south + south + down, *this); } void shadows(const ShadowMapper & mapper) const override @@ -57,7 +57,7 @@ public: void render(float dist = 10.f) { - sceneRenderer.camera.setView({dist, dist, dist}, south + west + down); + sceneRenderer.camera.setView({-dist, dist * 1.2f, dist * 1.2f}, south + east + down); sceneRenderer.render(*this); } Collection objects; @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(brush47xml) { auto mf = AssetFactory::loadXML(RESDIR "/brush47.xml"); BOOST_REQUIRE(mf); - BOOST_REQUIRE_EQUAL(6, mf->shapes.size()); + BOOST_REQUIRE_GE(mf->shapes.size(), 6); BOOST_CHECK(mf->shapes.at("plane")); BOOST_CHECK(mf->shapes.at("cylinder")); BOOST_CHECK(mf->shapes.at("cuboid")); @@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(brush47xml) auto bogie = mf->shapes.at("bogie"); BOOST_REQUIRE(bogie); auto bogieObj = std::dynamic_pointer_cast(bogie); - BOOST_CHECK_EQUAL(3, bogieObj->uses.size()); + BOOST_CHECK_GE(bogieObj->uses.size(), 3); BOOST_CHECK_EQUAL(1, mf->assets.size()); auto brush47 = mf->assets.at("brush-47"); BOOST_REQUIRE(brush47); @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(brush47xml) auto railVehicle = std::make_shared(brush47rvc); objects.objects.push_back(railVehicle); - render(20); + render(); } BOOST_AUTO_TEST_SUITE_END(); -- cgit v1.2.3 From a74580123fe36ba1227611c3703c1fe1a520719a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Mar 2023 01:41:26 +0000 Subject: Refactor of asset factory to address mutation/face controller logic Fixes issue where face controller extrusions applied to a rotated or scaled mesh would be applied incorrectly. Now we create the mesh at the origin, deform it as required (scale), apply face controllers and finally relocate it as required (position and rotation). A relative level of detail is cascade into the generation for shapes like cylinder, which generate fewer faces for small objects. --- assetFactory/cuboid.cpp | 4 ++-- assetFactory/cuboid.h | 2 +- assetFactory/cylinder.cpp | 27 ++++++++++++--------------- assetFactory/cylinder.h | 2 +- assetFactory/factoryMesh.cpp | 2 +- assetFactory/mutation.cpp | 19 +++++++++++++++++++ assetFactory/mutation.h | 4 ++++ assetFactory/object.cpp | 4 ++-- assetFactory/object.h | 2 +- assetFactory/plane.cpp | 4 ++-- assetFactory/plane.h | 2 +- assetFactory/shape.cpp | 6 ++---- assetFactory/shape.h | 8 ++++---- assetFactory/use.cpp | 26 ++++++++++++++++++++++++-- assetFactory/use.h | 2 +- 15 files changed, 77 insertions(+), 37 deletions(-) diff --git a/assetFactory/cuboid.cpp b/assetFactory/cuboid.cpp index 24fe4a4..03b1304 100644 --- a/assetFactory/cuboid.cpp +++ b/assetFactory/cuboid.cpp @@ -2,7 +2,7 @@ #include "modelFactoryMesh.h" Cuboid::CreatedFaces -Cuboid::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const +Cuboid::createMesh(ModelFactoryMesh & mesh, float) const { static constexpr std::array VERTICES {{ // bottom @@ -17,7 +17,7 @@ Cuboid::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) c {n, n, o}, }}; - const auto vhs = addMutatedToMesh(mesh, VERTICES, mutation); + const auto vhs = addToMesh(mesh, VERTICES); return { mesh.add_namedFace("top", {vhs[4], vhs[5], vhs[6], vhs[7]}), mesh.add_namedFace("bottom", {vhs[0], vhs[1], vhs[2], vhs[3]}), diff --git a/assetFactory/cuboid.h b/assetFactory/cuboid.h index 5a4072a..4e375a9 100644 --- a/assetFactory/cuboid.h +++ b/assetFactory/cuboid.h @@ -4,5 +4,5 @@ class Cuboid : public Shape { public: - CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override; + CreatedFaces createMesh(ModelFactoryMesh & mesh, float lodf) const override; }; diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp index cf0dbfb..e32ebcb 100644 --- a/assetFactory/cylinder.cpp +++ b/assetFactory/cylinder.cpp @@ -1,33 +1,30 @@ #include "cylinder.h" #include "maths.h" #include "modelFactoryMesh.h" +#include Cylinder::CreatedFaces -Cylinder::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const +Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const { - const glm::vec2 scale {std::accumulate(&mutation[0][0], &mutation[0][3], 0.f), - std::accumulate(&mutation[1][0], &mutation[1][3], 0.f)}; - const unsigned int P = static_cast(std::round(15.F * std::sqrt(glm::length(scale)))); + const unsigned int P = static_cast(std::round(15.F * std::sqrt(lodf))); std::vector bottom(P), top(P); - std::generate_n(bottom.begin(), P, [a = 0.f, step = two_pi / static_cast(P), &mesh, &mutation]() mutable { + std::generate_n(bottom.begin(), P, [a = 0.f, step = two_pi / static_cast(P), &mesh]() mutable { const auto xy = sincosf(a += step) * .5F; - const auto xyz = (xy ^ 0) % mutation; - return mesh.add_vertex({xyz.x, xyz.y, xyz.z}); + return mesh.add_vertex({xy.x, xy.y, 0.f}); }); - std::generate_n(top.begin(), P, [a = 0.f, step = two_pi / static_cast(P), &mesh, &mutation]() mutable { + std::generate_n(top.begin(), P, [a = 0.f, step = two_pi / static_cast(P), &mesh]() mutable { const auto xy = sincosf(a -= step) * .5F; - const auto xyz = (xy ^ 1) % mutation; - return mesh.add_vertex({xyz.x, xyz.y, xyz.z}); + return mesh.add_vertex({xy.x, xy.y, 1.f}); }); CreatedFaces surface; std::generate_n(std::inserter(surface, surface.end()), P, - [a = 0.f, step = two_pi / static_cast(P), &mesh, &mutation]() mutable { + [a = 0.f, step = two_pi / static_cast(P), &mesh]() mutable { const auto xy1 = sincosf(a) * .5F; const auto xy2 = sincosf(a -= step) * .5F; - const auto xyz1b = (xy1 ^ 0) % mutation; - const auto xyz2b = (xy2 ^ 0) % mutation; - const auto xyz1t = (xy1 ^ 1) % mutation; - const auto xyz2t = (xy2 ^ 1) % mutation; + const auto xyz1b = (xy1 ^ 0); + const auto xyz2b = (xy2 ^ 0); + const auto xyz1t = (xy1 ^ 1); + const auto xyz2t = (xy2 ^ 1); return mesh.add_namedFace("edge", { mesh.add_vertex({xyz1b.x, xyz1b.y, xyz1b.z}), diff --git a/assetFactory/cylinder.h b/assetFactory/cylinder.h index 65ca5e5..1d7b0e0 100644 --- a/assetFactory/cylinder.h +++ b/assetFactory/cylinder.h @@ -4,5 +4,5 @@ class Cylinder : public Shape { public: - CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override; + CreatedFaces createMesh(ModelFactoryMesh & mesh, float lodf) const override; }; diff --git a/assetFactory/factoryMesh.cpp b/assetFactory/factoryMesh.cpp index 0cfed85..1665b90 100644 --- a/assetFactory/factoryMesh.cpp +++ b/assetFactory/factoryMesh.cpp @@ -11,7 +11,7 @@ FactoryMesh::createMesh() const ModelFactoryMesh mesh; for (const auto & use : uses) { - use->createMesh(mesh, glm::identity()); + use->createMesh(mesh, 1); } mesh.garbage_collection(); diff --git a/assetFactory/mutation.cpp b/assetFactory/mutation.cpp index 21d2a24..9722dc3 100644 --- a/assetFactory/mutation.cpp +++ b/assetFactory/mutation.cpp @@ -1,4 +1,5 @@ #include "mutation.h" +#include #include #include @@ -8,3 +9,21 @@ Mutation::getMatrix() const return glm::translate(glm::identity(), position) * rotate_ypr(rotation) * glm::scale(glm::identity(), scale); } + +Mutation::Matrix +Mutation::getDeformationMatrix() const +{ + return glm::scale(glm::identity(), scale); +} + +Mutation::Matrix +Mutation::getLocationMatrix() const +{ + return glm::translate(glm::identity(), position) * rotate_ypr(rotation); +} + +float +Mutation::relativeLevelOfDetail() const +{ + return std::max({scale.x, scale.y, scale.z}); +} diff --git a/assetFactory/mutation.h b/assetFactory/mutation.h index 440fab0..e620955 100644 --- a/assetFactory/mutation.h +++ b/assetFactory/mutation.h @@ -7,6 +7,10 @@ struct Mutation { using Matrix = glm::mat4; Matrix getMatrix() const; + Matrix getDeformationMatrix() const; + Matrix getLocationMatrix() const; + + float relativeLevelOfDetail() const; glm::vec3 position {}; glm::vec3 rotation {}; diff --git a/assetFactory/object.cpp b/assetFactory/object.cpp index ae5a301..5c86f47 100644 --- a/assetFactory/object.cpp +++ b/assetFactory/object.cpp @@ -4,11 +4,11 @@ Object::Object(std::string i) : id {std::move(i)} { } Object::CreatedFaces -Object::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const +Object::createMesh(ModelFactoryMesh & mesh, float levelOfDetailFactor) const { CreatedFaces faces; for (const auto & use : uses) { - auto useFaces = use->createMesh(mesh, mutation); + auto useFaces = use->createMesh(mesh, levelOfDetailFactor); std::transform(useFaces.begin(), useFaces.end(), std::inserter(faces, faces.end()), [this](auto && face) { return std::make_pair(id + ":" + face.first, std::move(face.second)); }); diff --git a/assetFactory/object.h b/assetFactory/object.h index f3726c7..3f7b640 100644 --- a/assetFactory/object.h +++ b/assetFactory/object.h @@ -10,7 +10,7 @@ public: Object() = default; Object(std::string i); - CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override; + CreatedFaces createMesh(ModelFactoryMesh & mesh, float lodf) const override; Use::Collection uses; std::string id; diff --git a/assetFactory/plane.cpp b/assetFactory/plane.cpp index 563c4e9..c6e1b5a 100644 --- a/assetFactory/plane.cpp +++ b/assetFactory/plane.cpp @@ -2,7 +2,7 @@ #include "modelFactoryMesh.h" Plane::CreatedFaces -Plane::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const +Plane::createMesh(ModelFactoryMesh & mesh, float) const { static constexpr std::array VERTICES {{ {n, n, z}, @@ -11,5 +11,5 @@ Plane::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) co {n, y, z}, }}; - return {mesh.add_namedFace("plane", addMutatedToMesh(mesh, VERTICES, mutation))}; + return {mesh.add_namedFace("plane", addToMesh(mesh, VERTICES))}; } diff --git a/assetFactory/plane.h b/assetFactory/plane.h index 5e93ee4..f24e2c1 100644 --- a/assetFactory/plane.h +++ b/assetFactory/plane.h @@ -4,5 +4,5 @@ class Plane : public Shape { public: - CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const override; + CreatedFaces createMesh(ModelFactoryMesh & mesh, float lodf) const override; }; diff --git a/assetFactory/shape.cpp b/assetFactory/shape.cpp index f6e55e8..ec6594e 100644 --- a/assetFactory/shape.cpp +++ b/assetFactory/shape.cpp @@ -5,12 +5,10 @@ #include "shape.h" std::vector -Shape::addMutatedToMesh( - ModelFactoryMesh & mesh, const std::span vertices, const Mutation::Matrix & mutation) +Shape::addToMesh(ModelFactoryMesh & mesh, const std::span vertices) { std::vector vhs; - std::transform(vertices.begin(), vertices.end(), std::back_inserter(vhs), [&mesh, &mutation](const auto & v) { - const auto p = v % mutation; + std::transform(vertices.begin(), vertices.end(), std::back_inserter(vhs), [&mesh](const auto & p) { return mesh.add_vertex({p.x, p.y, p.z}); }); return vhs; diff --git a/assetFactory/shape.h b/assetFactory/shape.h index 5a2b59c..fe517c1 100644 --- a/assetFactory/shape.h +++ b/assetFactory/shape.h @@ -1,9 +1,9 @@ #pragma once #include "modelFactoryMesh_fwd.h" -#include "mutation.h" #include "stdTypeDefs.hpp" #include +#include #include #include #include @@ -18,8 +18,8 @@ public: virtual ~Shape() = default; - virtual CreatedFaces createMesh(ModelFactoryMesh &, const Mutation::Matrix & mutation) const = 0; + virtual CreatedFaces createMesh(ModelFactoryMesh &, float levelOfDetailFactor) const = 0; - static std::vector addMutatedToMesh( - ModelFactoryMesh & mesh, const std::span vertices, const Mutation::Matrix & mutation); + static std::vector addToMesh( + ModelFactoryMesh & mesh, const std::span vertices); }; diff --git a/assetFactory/use.cpp b/assetFactory/use.cpp index 708e310..898b736 100644 --- a/assetFactory/use.cpp +++ b/assetFactory/use.cpp @@ -1,14 +1,36 @@ #include "use.h" #include "assetFactory.h" +#include +#include +#include +#include +#include Shape::CreatedFaces -Use::createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const +Use::createMesh(ModelFactoryMesh & mesh, float levelOfDetailFactor) const { - auto faces = type->createMesh(mesh, mutation * getMatrix()); + auto apply = [&mesh](const auto & faces, const Mutation::Matrix & m) { + std::set vs; + for (const auto & f : faces) { + const auto fvr = mesh.fv_range(f.second); + for (const auto & v : fvr) { + if (!vs.contains(v)) { + glm::vec3 p = mesh.point(v); + p = p % m; + mesh.set_point(v, ModelFactoryMesh::Point(p.x, p.y, p.z)); + vs.insert(v); + } + } + } + }; + + auto faces = type->createMesh(mesh, levelOfDetailFactor * relativeLevelOfDetail()); applyStyle(mesh, {this}, faces); + apply(faces, getDeformationMatrix()); for (const auto & [name, faceController] : faceControllers) { faceController->apply(mesh, {this}, name, faces); } + apply(faces, getLocationMatrix()); return faces; } diff --git a/assetFactory/use.h b/assetFactory/use.h index 5e4c35f..9dbf382 100644 --- a/assetFactory/use.h +++ b/assetFactory/use.h @@ -11,7 +11,7 @@ class Use : public StdTypeDefs, public Mutation, public Style, public Persi public: using FaceControllers = std::map>; - Shape::CreatedFaces createMesh(ModelFactoryMesh & mesh, const Mutation::Matrix & mutation) const; + Shape::CreatedFaces createMesh(ModelFactoryMesh & mesh, float lodf) const; Shape::CPtr type; FaceControllers faceControllers; -- cgit v1.2.3 From 92c1aed7a471f34e18eb8d0077aad90fd8b7344b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Mar 2023 18:18:43 +0000 Subject: Make add_namedFace a thin template wrapper --- assetFactory/cuboid.cpp | 12 ++++++------ assetFactory/cylinder.cpp | 10 +++------- assetFactory/modelFactoryMesh.cpp | 8 -------- assetFactory/modelFactoryMesh.h | 9 ++++++++- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/assetFactory/cuboid.cpp b/assetFactory/cuboid.cpp index 03b1304..f200258 100644 --- a/assetFactory/cuboid.cpp +++ b/assetFactory/cuboid.cpp @@ -19,11 +19,11 @@ Cuboid::createMesh(ModelFactoryMesh & mesh, float) const const auto vhs = addToMesh(mesh, VERTICES); return { - mesh.add_namedFace("top", {vhs[4], vhs[5], vhs[6], vhs[7]}), - mesh.add_namedFace("bottom", {vhs[0], vhs[1], vhs[2], vhs[3]}), - mesh.add_namedFace("left", {vhs[0], vhs[7], vhs[6], vhs[1]}), - mesh.add_namedFace("right", {vhs[2], vhs[5], vhs[4], vhs[3]}), - mesh.add_namedFace("front", {vhs[0], vhs[3], vhs[4], vhs[7]}), - mesh.add_namedFace("back", {vhs[2], vhs[1], vhs[6], vhs[5]}), + mesh.add_namedFace("top", vhs[4], vhs[5], vhs[6], vhs[7]), + mesh.add_namedFace("bottom", vhs[0], vhs[1], vhs[2], vhs[3]), + mesh.add_namedFace("left", vhs[0], vhs[7], vhs[6], vhs[1]), + mesh.add_namedFace("right", vhs[2], vhs[5], vhs[4], vhs[3]), + mesh.add_namedFace("front", vhs[0], vhs[3], vhs[4], vhs[7]), + mesh.add_namedFace("back", vhs[2], vhs[1], vhs[6], vhs[5]), }; } diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp index e32ebcb..ca08bf8 100644 --- a/assetFactory/cylinder.cpp +++ b/assetFactory/cylinder.cpp @@ -25,13 +25,9 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const const auto xyz2b = (xy2 ^ 0); const auto xyz1t = (xy1 ^ 1); const auto xyz2t = (xy2 ^ 1); - return mesh.add_namedFace("edge", - { - mesh.add_vertex({xyz1b.x, xyz1b.y, xyz1b.z}), - mesh.add_vertex({xyz2b.x, xyz2b.y, xyz2b.z}), - mesh.add_vertex({xyz2t.x, xyz2t.y, xyz2t.z}), - mesh.add_vertex({xyz1t.x, xyz1t.y, xyz1t.z}), - }); + return mesh.add_namedFace("edge", mesh.add_vertex({xyz1b.x, xyz1b.y, xyz1b.z}), + mesh.add_vertex({xyz2b.x, xyz2b.y, xyz2b.z}), mesh.add_vertex({xyz2t.x, xyz2t.y, xyz2t.z}), + mesh.add_vertex({xyz1t.x, xyz1t.y, xyz1t.z})); }); for (const auto & [name, face] : surface) { mesh.property(mesh.smoothFaceProperty, face) = true; diff --git a/assetFactory/modelFactoryMesh.cpp b/assetFactory/modelFactoryMesh.cpp index f9ee6a0..806ac3b 100644 --- a/assetFactory/modelFactoryMesh.cpp +++ b/assetFactory/modelFactoryMesh.cpp @@ -5,11 +5,3 @@ ModelFactoryMesh::ModelFactoryMesh() add_property(smoothFaceProperty); add_property(nameFaceProperty); } - -std::pair -ModelFactoryMesh::add_namedFace(std::string name, std::vector p) -{ - const auto handle = add_face(std::move(p)); - property(nameFaceProperty, handle) = name; - return std::make_pair(name, handle); -} diff --git a/assetFactory/modelFactoryMesh.h b/assetFactory/modelFactoryMesh.h index 258913b..ea5f011 100644 --- a/assetFactory/modelFactoryMesh.h +++ b/assetFactory/modelFactoryMesh.h @@ -35,5 +35,12 @@ struct ModelFactoryMesh : public OpenMesh::PolyMesh_ArrayKernelT smoothFaceProperty; OpenMesh::FPropHandleT nameFaceProperty; - std::pair add_namedFace(std::string name, std::vector p); + template + std::pair + add_namedFace(std::string name, Vs &&... vs) + { + const auto handle = add_face(std::forward(vs)...); + property(nameFaceProperty, handle) = name; + return std::make_pair(name, handle); + } }; -- cgit v1.2.3 From 262407324e49d55629d7dd73e8eb50a3d10e9a3f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Mar 2023 18:20:53 +0000 Subject: Rewrite asset factory cylinder generator Fixes duplication of sincos to get circumference and vertex duplication breaking smooth edge shading. --- assetFactory/cylinder.cpp | 66 ++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp index ca08bf8..0803369 100644 --- a/assetFactory/cylinder.cpp +++ b/assetFactory/cylinder.cpp @@ -1,39 +1,53 @@ #include "cylinder.h" #include "maths.h" #include "modelFactoryMesh.h" -#include Cylinder::CreatedFaces Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const { - const unsigned int P = static_cast(std::round(15.F * std::sqrt(lodf))); - std::vector bottom(P), top(P); - std::generate_n(bottom.begin(), P, [a = 0.f, step = two_pi / static_cast(P), &mesh]() mutable { - const auto xy = sincosf(a += step) * .5F; - return mesh.add_vertex({xy.x, xy.y, 0.f}); - }); - std::generate_n(top.begin(), P, [a = 0.f, step = two_pi / static_cast(P), &mesh]() mutable { - const auto xy = sincosf(a -= step) * .5F; - return mesh.add_vertex({xy.x, xy.y, 1.f}); + const auto P = static_cast(std::round(15.F * std::sqrt(lodf))); + const auto step = two_pi / static_cast(P); + + // Generate 2D circumference points + std::vector circumference(P); + std::generate(circumference.begin(), circumference.end(), [a = 0.f, step]() mutable { + return sincosf(a += step) * .5F; }); + CreatedFaces surface; - std::generate_n(std::inserter(surface, surface.end()), P, - [a = 0.f, step = two_pi / static_cast(P), &mesh]() mutable { - const auto xy1 = sincosf(a) * .5F; - const auto xy2 = sincosf(a -= step) * .5F; - const auto xyz1b = (xy1 ^ 0); - const auto xyz2b = (xy2 ^ 0); - const auto xyz1t = (xy1 ^ 1); - const auto xyz2t = (xy2 ^ 1); - return mesh.add_namedFace("edge", mesh.add_vertex({xyz1b.x, xyz1b.y, xyz1b.z}), - mesh.add_vertex({xyz2b.x, xyz2b.y, xyz2b.z}), mesh.add_vertex({xyz2t.x, xyz2t.y, xyz2t.z}), - mesh.add_vertex({xyz1t.x, xyz1t.y, xyz1t.z})); - }); - for (const auto & [name, face] : surface) { - mesh.property(mesh.smoothFaceProperty, face) = true; + { + // Generate bottom face vertices + std::vector bottom(P); + std::transform(circumference.begin(), circumference.end(), bottom.begin(), [&mesh](const auto & xy) { + return mesh.add_vertex({xy.x, xy.y, 0.f}); + }); + surface.insert(mesh.add_namedFace("bottom", bottom)); + } + { + // Generate top face vertices + std::vector top(P); + std::transform(circumference.rbegin(), circumference.rend(), top.begin(), [&mesh](const auto & xy) { + return mesh.add_vertex({xy.x, xy.y, 1.f}); + }); + surface.insert(mesh.add_namedFace("top", top)); + } + { + // Generate edge vertices + std::vector> edge(P + 1); + std::transform(circumference.begin(), circumference.end(), edge.begin(), [&mesh](const auto & xy) { + return std::make_pair(mesh.add_vertex({xy.x, xy.y, 0.f}), mesh.add_vertex({xy.x, xy.y, 1.f})); + }); + // Wrap around + edge.back() = edge.front(); + // Transform adjacent pairs of top/bottom pairs to faces + std::adjacent_find(edge.begin(), edge.end(), [&mesh, &surface](const auto & first, const auto & second) { + const auto fh + = surface.insert(mesh.add_namedFace("edge", first.first, first.second, second.second, second.first)) + ->second; + mesh.property(mesh.smoothFaceProperty, fh) = true; + return false; + }); } - surface.insert(mesh.add_namedFace("bottom", bottom)); - surface.insert(mesh.add_namedFace("top", top)); return surface; } -- cgit v1.2.3