diff --git a/CMakeLists.txt b/CMakeLists.txt index 7555615..a59c4bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,9 @@ add_library( Threedim/Ply.hpp Threedim/Ply.cpp + Threedim/ArrayToGeometry.hpp + Threedim/ArrayToGeometry.cpp + Threedim/StructureSynth.hpp Threedim/StructureSynth.cpp diff --git a/Threedim/ArrayToGeometry.cpp b/Threedim/ArrayToGeometry.cpp new file mode 100644 index 0000000..dec8013 --- /dev/null +++ b/Threedim/ArrayToGeometry.cpp @@ -0,0 +1,150 @@ +#include "ArrayToGeometry.hpp" + +#include +#include +#include +#include + +#include +#include + +namespace Threedim +{ +static thread_local TMesh array_to_mesh; + +void loadPoints(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs) +{ + vcg::tri::Clean::RemoveZeroAreaFace(mesh); + vcg::tri::UpdateTopology::FaceFace(mesh); + vcg::tri::Clean::RemoveNonManifoldFace(mesh); + vcg::tri::UpdateTopology::FaceFace(mesh); + vcg::tri::UpdateNormal::PerVertexNormalized(mesh); + vcg::tri::UpdateTexture::WedgeTexFromPlane( + mesh, vcg::Point3f{0., 0., 0.}, vcg::Point3f{1., 1., 1.}, 1.); + + vcg::tri::RequirePerVertexNormal(mesh); + vcg::tri::RequirePerVertexTexCoord(mesh); + + complete.clear(); + const auto vertices = mesh.vert.size(); + const auto floats + = vertices * (3 + 3 + 2); // 3 float for pos, 3 float for normal, 2 float for UV + complete.resize(floats); + float* pos_start = complete.data(); + float* norm_start = complete.data() + vertices * 3; + float* uv_start = complete.data() + vertices * 3 + vertices * 3; + + for (auto& fi : mesh.face) + { // iterate each faces + + auto v0 = fi.V(0); + auto v1 = fi.V(1); + auto v2 = fi.V(2); + + auto p0 = v0->P(); + (*pos_start++) = p0.X(); + (*pos_start++) = p0.Y(); + (*pos_start++) = p0.Z(); + + auto p1 = v1->P(); + (*pos_start++) = p1.X(); + (*pos_start++) = p1.Y(); + (*pos_start++) = p1.Z(); + + auto p2 = v2->P(); + (*pos_start++) = p2.X(); + (*pos_start++) = p2.Y(); + (*pos_start++) = p2.Z(); + + auto n0 = v0->N(); + (*norm_start++) = n0.X(); + (*norm_start++) = n0.Y(); + (*norm_start++) = n0.Z(); + + auto n1 = v1->N(); + (*norm_start++) = n1.X(); + (*norm_start++) = n1.Y(); + (*norm_start++) = n1.Z(); + + auto n2 = v2->N(); + (*norm_start++) = n2.X(); + (*norm_start++) = n2.Y(); + (*norm_start++) = n2.Z(); + +#if 0 + auto uv0 = fi.WT(0); + (*uv_start++) = uv0.U(); + (*uv_start++) = uv0.V(); + + auto uv1 = fi.WT(1); + (*uv_start++) = uv1.U(); + (*uv_start++) = uv1.V(); + + auto uv2 = fi.WT(2); + (*uv_start++) = uv2.U(); + (*uv_start++) = uv2.V(); +#endif + (*uv_start++) = p0.X(); + (*uv_start++) = p0.Y(); + + (*uv_start++) = p1.X(); + (*uv_start++) = p1.Y(); + + (*uv_start++) = p2.X(); + (*uv_start++) = p2.Y(); + } + outputs.geometry.mesh.buffers.main_buffer.data = complete.data(); + outputs.geometry.mesh.buffers.main_buffer.size = complete.size(); + outputs.geometry.mesh.buffers.main_buffer.dirty = true; + + outputs.geometry.mesh.input.input0.offset = 0; + outputs.geometry.mesh.input.input1.offset = sizeof(float) * vertices * 3; + outputs.geometry.mesh.input.input2.offset = sizeof(float) * vertices * (3 + 3); + outputs.geometry.mesh.vertices = vertices; + outputs.geometry.dirty_mesh = true; +} +void ArrayToMesh::create_mesh(std::span v) +{ + if (v.size() < 3) + return; + + if (inputs.triangulate) + { + auto& m = array_to_mesh; + m.Clear(); + vcg::tri::Allocator::AddVertices(m, v.size() / 3); + + for (std::size_t i = 0; i < v.size(); i += 3) + { + auto& vtx = m.vert[i / 3].P(); + vtx.X() = v[i + 0]; + vtx.Y() = v[i + 1]; + vtx.Z() = v[i + 2]; + } + vcg::tri::UpdateBounding::Box(m); + vcg::tri::UpdateNormal::PerFace(m); + + vcg::tri::BallPivoting pivot(m, 0.01, 0.05); + pivot.BuildMesh(); + loadTriMesh(m, complete, outputs); + } + else + { + std::size_t vertices = v.size() / 3; + + this->complete.clear(); + this->complete.resize(std::ceil((v.size() / 3.) * (3 + 3 + 2))); + std::copy_n(v.begin(), v.size(), complete.begin()); + + outputs.geometry.mesh.buffers.main_buffer.data = complete.data(); + outputs.geometry.mesh.buffers.main_buffer.size = complete.size(); + outputs.geometry.mesh.buffers.main_buffer.dirty = true; + + outputs.geometry.mesh.input.input0.offset = 0; + outputs.geometry.mesh.input.input1.offset = sizeof(float) * vertices * 3; + outputs.geometry.mesh.input.input2.offset = sizeof(float) * vertices * (3 + 3); + outputs.geometry.mesh.vertices = vertices; + outputs.geometry.dirty_mesh = true; + } +} +} diff --git a/Threedim/ArrayToGeometry.hpp b/Threedim/ArrayToGeometry.hpp new file mode 100644 index 0000000..18d3807 --- /dev/null +++ b/Threedim/ArrayToGeometry.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Threedim +{ + +class ArrayToMesh +{ +public: + halp_meta(name, "Array to mesh") + halp_meta(category, "Visuals/3D") + halp_meta(c_name, "array_to_mesh") + halp_meta(manual_url, "https://ossia.io/score-docs/processes/array-to-mesh.html") + halp_meta(uuid, "dfc5bae9-c75c-4180-b4e8-be3063c8d8f2") + + struct ins + { + struct : halp::val_port<"Input", std::vector> + { + void update(ArrayToMesh& self) { self.create_mesh(value); } + } in; + PositionControl position; + RotationControl rotation; + ScaleControl scale; + + halp::toggle<"Triangulate"> triangulate; + } inputs; + + PrimitiveOutputs outputs; + void create_mesh(std::span v); + + std::vector complete; +}; + +} diff --git a/Threedim/MeshHelpers.hpp b/Threedim/MeshHelpers.hpp new file mode 100644 index 0000000..2ead716 --- /dev/null +++ b/Threedim/MeshHelpers.hpp @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace Threedim +{ +using namespace vcg; +class TFace; +class TVertex; + +struct TUsedTypes + : public vcg::UsedTypes::AsVertexType, vcg::Use::AsFaceType> +{ +}; + +class TVertex + : public Vertex< + TUsedTypes, + vertex::BitFlags, + vertex::Coord3f, + vertex::Normal3f, + vertex::TexCoord2f, + vertex::Mark> +{ +}; + +class TFace + : public Face< + TUsedTypes, + face::VertexRef, + face::Normal3f, + face::WedgeTexCoord2f, + face::BitFlags, + face::FFAdj> +{ +}; + +class TMesh : public vcg::tri::TriMesh, std::vector> +{ +}; + +void loadTriMesh(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs); +} diff --git a/Threedim/Primitive.cpp b/Threedim/Primitive.cpp index 9ebda10..6b8b769 100644 --- a/Threedim/Primitive.cpp +++ b/Threedim/Primitive.cpp @@ -1,59 +1,15 @@ #include "Primitive.hpp" -#include -#include -#include +#include +#include #include #include -#include - -namespace -{ -using namespace vcg; -class TFace; -class TVertex; - -struct TUsedTypes - : public vcg::UsedTypes::AsVertexType, vcg::Use::AsFaceType> -{ -}; - -class TVertex - : public Vertex< - TUsedTypes, - vertex::BitFlags, - vertex::Coord3f, - vertex::Normal3f, - vertex::TexCoord2f, - vertex::Mark> -{ -}; - -class TFace - : public Face< - TUsedTypes, - face::VertexRef, - face::Normal3f, - face::WedgeTexCoord2f, - face::BitFlags, - face::FFAdj> -{ -}; - -class TMesh : public vcg::tri::TriMesh, std::vector> -{ -}; -} - namespace Threedim { -static thread_local TMesh mesh; - -static void -loadTriMesh(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs) +void loadTriMesh(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs) { vcg::tri::Clean::RemoveUnreferencedVertex(mesh); vcg::tri::Clean::RemoveZeroAreaFace(mesh); @@ -61,14 +17,16 @@ loadTriMesh(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs vcg::tri::Clean::RemoveNonManifoldFace(mesh); vcg::tri::UpdateTopology::FaceFace(mesh); vcg::tri::UpdateNormal::PerVertexNormalized(mesh); - vcg::tri::UpdateTexture::WedgeTexFromPlane(mesh,vcg::Point3f{0.,0.,0.},vcg::Point3f{1.,1.,1.},1.); + vcg::tri::UpdateTexture::WedgeTexFromPlane( + mesh, vcg::Point3f{0., 0., 0.}, vcg::Point3f{1., 1., 1.}, 1.); vcg::tri::RequirePerVertexNormal(mesh); vcg::tri::RequirePerVertexTexCoord(mesh); complete.clear(); - const auto vertices = mesh.face.size() * 3; - const auto floats = vertices * (3 + 3 + 2); // 3 float for pos, 3 float for normal, 2 float for UV + const auto vertices = mesh.vert.size(); + const auto floats + = vertices * (3 + 3 + 2); // 3 float for pos, 3 float for normal, 2 float for UV complete.resize(floats); float* pos_start = complete.data(); float* norm_start = complete.data() + vertices * 3; @@ -124,14 +82,14 @@ loadTriMesh(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs (*uv_start++) = uv2.U(); (*uv_start++) = uv2.V(); #endif - (*uv_start++) =p0.X(); - (*uv_start++) =p0.Y(); + (*uv_start++) = p0.X(); + (*uv_start++) = p0.Y(); - (*uv_start++) =p1.X(); - (*uv_start++) =p1.Y(); + (*uv_start++) = p1.X(); + (*uv_start++) = p1.Y(); - (*uv_start++) =p2.X(); - (*uv_start++) =p2.Y(); + (*uv_start++) = p2.X(); + (*uv_start++) = p2.Y(); } outputs.geometry.mesh.buffers.main_buffer.data = complete.data(); outputs.geometry.mesh.buffers.main_buffer.size = complete.size(); @@ -139,11 +97,12 @@ loadTriMesh(TMesh& mesh, std::vector& complete, PrimitiveOutputs& outputs outputs.geometry.mesh.input.input0.offset = 0; outputs.geometry.mesh.input.input1.offset = sizeof(float) * vertices * 3; - outputs.geometry.mesh.input.input2.offset = sizeof(float) * vertices * (3+3); + outputs.geometry.mesh.input.input2.offset = sizeof(float) * vertices * (3 + 3); outputs.geometry.mesh.vertices = vertices; outputs.geometry.dirty_mesh = true; } +static thread_local TMesh mesh; void Plane::update() { /* diff --git a/Threedim/Primitive.hpp b/Threedim/Primitive.hpp index 764652a..4de0be5 100644 --- a/Threedim/Primitive.hpp +++ b/Threedim/Primitive.hpp @@ -7,23 +7,6 @@ namespace Threedim { -struct Update -{ - void update(auto& obj) { obj.update(); } -}; - -struct PrimitiveOutputs -{ - struct - { - halp_meta(name, "Geometry"); - halp::position_normals_texcoords_geometry mesh; - float transform[16]{}; - bool dirty_mesh = false; - bool dirty_transform = false; - } geometry; -}; - struct Primitive { halp_meta(category, "Visuals/3D/Primitives") diff --git a/Threedim/TinyObj.hpp b/Threedim/TinyObj.hpp index 75f185a..e2f2f0b 100644 --- a/Threedim/TinyObj.hpp +++ b/Threedim/TinyObj.hpp @@ -1,12 +1,16 @@ #pragma once -#include -#include #include +#include +#include +#include +#include + #include -#include -#include #include +#include + +#include namespace Threedim { using float_vec = boost::container::vector>; @@ -69,4 +73,20 @@ struct ScaleControl : halp::xyz_spinboxes_f32<"Scale", halp::range{0.00001, 1000 void update(auto& o) { rebuild_transform(o.inputs, o.outputs); } }; +struct Update +{ + void update(auto& obj) { obj.update(); } +}; + +struct PrimitiveOutputs +{ + struct + { + halp_meta(name, "Geometry"); + halp::position_normals_texcoords_geometry mesh; + float transform[16]{}; + bool dirty_mesh = false; + bool dirty_transform = false; + } geometry; +}; } diff --git a/score_addon_threedim.cpp b/score_addon_threedim.cpp index 77e7f93..06de3d7 100644 --- a/score_addon_threedim.cpp +++ b/score_addon_threedim.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -166,6 +167,7 @@ std::vector score_addon_threedim::factories( { std::vector fx; Avnd::instantiate_fx< + Threedim::ArrayToMesh, Threedim::Noise, Threedim::StrucSynth, Threedim::ObjLoader,