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/cylinder.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'assetFactory/cylinder.cpp') 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}), -- 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/cylinder.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'assetFactory/cylinder.cpp') 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; -- 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(-) (limited to 'assetFactory/cylinder.cpp') 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