http://cg.iit.bme.hu/portal/node/312 https://portal.vik.bme.hu/kepzes/targyak/VIIIMA25
Dr. Várady Tamás, Dr. Salvi Péter BME, Villamosmérnöki és Informatikai Kar Irányítástechnika és Informatika Tanszék
Object
BaseMesh
Mesh
Bezier
T1Ax, T1Ay, T1Az, T1Bx, T1By, T1Bz, T1Cx, T1Cy, T1Cz T2Ax, T2Ay, T2Az, T2Bx, T2By, T2Bz, T2Cx, T2Cy, T2Cz ... TnAx, TnAy, TnAz, TnBx, TnBy, TnBz, TnCx, TnCy, TnCz
[...header...] P1x P1y P1z P2x P2y P2z ... Pmx Pmy Pmz 3 T1A T1B T1C 3 T2A T2B T2C ... 3 TnA TnB TnC
Hol vannak az alábbi sokszöghálón a fél-élek? (satírozás → lyuk)
Egy fél-él adatstruktúra alapján...
Hogyan gyűjtjük össze egy csúcs körüli szomszédos csúcsokat?
Hogyan gyűjtjük össze egy csúcs körüli szomszédos lapokat?
Hogyan találjuk meg, és hogyan megyünk végig a mesh határán? (ha nincsenek lyukak)
ArrayKernel
base-mesh.hh
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh> struct BaseTraits : public OpenMesh::DefaultTraits { using Point = OpenMesh::Vec3d; // the default would be Vec3f using Normal = OpenMesh::Vec3d; VertexTraits { double mean; // approximated mean curvature }; }; using BaseMesh = OpenMesh::TriMesh_ArrayKernelT<BaseTraits>; using Vector = OpenMesh::VectorT<double,3>;
VertexFaceIter
faces()
vertices()
OpenMesh::IO::read_mesh(mesh, filename)
request_face_normals
request_vertex_normals
update_face_normals
update_vertex_normals
Viewer
class Window : public QMainWindow { // ... private slots: void open(bool clear_others); // ... private: QString last_directory; // ... };
window.cc
Window::Window(QApplication *parent) : QMainWindow(), parent(parent), last_directory(".") { // ... auto openAction = new QAction(tr("&Open"), this); openAction->setShortcut(tr("Ctrl+O")); openAction->setStatusTip(tr("Load a model from a file")); connect(openAction, &QAction::triggered, [this](){ open(true); }); auto importAction = new QAction(tr("&Import"), this); importAction->setShortcut(tr("Ctrl+I")); importAction->setStatusTip(tr("Import a model from a file")); connect(importAction, &QAction::triggered, this, [this](){ open(false); }); auto fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(openAction); fileMenu->addAction(importAction); fileMenu->addAction(quitAction); }
void Window::open(bool clear_others) { auto filename = QFileDialog::getOpenFileName(this, tr("Open File"), last_directory, tr("Readable files (*.obj *.ply *.stl);;" "Mesh (*.obj *.ply *.stl);;" "All files (*.*)")); if (filename.isEmpty()) return; last_directory = QFileInfo(filename).absolutePath(); if (clear_others) viewer->deleteObjects(); if (!viewer->open(filename.toUtf8().data())) QMessageBox::warning(this, tr("Cannot open file"), tr("Could not open file: ") + filename + "."); }
#include "object.hh" class Viewer : public QGLViewer { Q_OBJECT public: void deleteObjects(); bool open(std::string filename); // ... private: void setupCamera(); std::vector<std::shared_ptr<Object>> objects; Visualization vis; };
visualization.hh
#pragma once #include <GL/gl.h> struct Visualization { Visualization(); bool show_solid, show_wireframe; };
visualization.cc
#include "visualization.hh" Visualization::Visualization() : show_solid(true), show_wireframe(false) { }
viewer.cc
void Viewer::keyPressEvent(QKeyEvent *e) { if (e->modifiers() == Qt::NoModifier) switch (e->key()) { case Qt::Key_S: vis.show_solid = !vis.show_solid; update(); break; case Qt::Key_W: vis.show_wireframe = !vis.show_wireframe; update(); break; default: QGLViewer::keyPressEvent(e); } else QGLViewer::keyPressEvent(e); }
object.hh
#pragma once #include "base-mesh.hh" #include "visualization.hh" class Object { public: explicit Object(std::string filename); virtual ~Object(); const BaseMesh &baseMesh() const; virtual void draw(const Visualization &vis) const; virtual void updateBaseMesh(); virtual bool reload() = 0; bool valid() const; protected: BaseMesh mesh; std::string filename; };
object.cc
#include "object.hh" Object::Object(std::string filename) : filename(filename) { } Object::~Object() { } const BaseMesh &Object::baseMesh() const { return mesh; } bool Object::valid() const { return mesh.n_vertices() > 0; } void Object::draw(const Visualization &vis) const { // simple version for (auto f : mesh.faces()) { glBegin(GL_POLYGON); for (auto v : f.vertices()) { glNormal3dv(mesh.normal(v).data()); glVertex3dv(mesh.point(v).data()); } glEnd(); } } void Object::updateBaseMesh() { mesh.request_face_normals(); mesh.request_vertex_normals(); mesh.update_face_normals(); mesh.update_vertex_normals(); }
mesh.hh
#pragma once #include "object.hh" class Mesh : public Object { public: Mesh(std::string filename); virtual ~Mesh(); virtual bool reload() override; };
mesh.cc
#include <OpenMesh/Core/IO/MeshIO.hh> #include "mesh.hh" Mesh::Mesh(std::string filename) : Object(filename) { reload(); } Mesh::~Mesh() { } bool Mesh::reload() { if (!OpenMesh::IO::read_mesh(mesh, filename)) return false; updateBaseMesh(); return true; }
#include "mesh.hh" void Viewer::draw() { for (auto o : objects) o->draw(vis); } void Viewer::deleteObjects() { objects.clear(); } bool Viewer::open(std::string filename) { std::shared_ptr<Object> surface; surface = std::make_shared<Mesh>(filename); if (!surface->valid()) return false; objects.push_back(surface); setupCamera(); return true; }
void Viewer::setupCamera() { double large = std::numeric_limits<double>::max(); Vector box_min(large, large, large), box_max(-large, -large, -large); for (auto o : objects) { const auto &mesh = o->baseMesh(); for (auto v : mesh.vertices()) { box_min.minimize(mesh.point(v)); box_max.maximize(mesh.point(v)); } } using qglviewer::Vec; camera()->setSceneBoundingBox(Vec(box_min.data()), Vec(box_max.data())); camera()->showEntireScene(); update(); }
glPolygonMode
GL_FRONT_AND_BACK
GL_LINE
GL_FILL
glEnable(GL_POLYGON_OFFSET_FILL)
glPolygonOffset(1, 1)
draw()
void Object::draw(const Visualization &vis) const { glPolygonMode(GL_FRONT_AND_BACK, !vis.show_solid && vis.show_wireframe ? GL_LINE : GL_FILL); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1, 1); glColor3d(1.0, 1.0, 1.0); if (vis.show_solid || vis.show_wireframe) { for (auto f : mesh.faces()) { glBegin(GL_POLYGON); for (auto v : f.vertices()) { glNormal3dv(mesh.normal(v).data()); glVertex3dv(mesh.point(v).data()); } glEnd(); } } if (vis.show_solid && vis.show_wireframe) { glPolygonMode(GL_FRONT, GL_LINE); glColor3d(0.0, 0.0, 0.0); glDisable(GL_LIGHTING); for (auto f : mesh.faces()) { glBegin(GL_POLYGON); for (auto v : f.vertices()) glVertex3dv(mesh.point(v).data()); glEnd(); } glEnable(GL_LIGHTING); } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); }
![bg 50%](halfedge-legend.png)