基于Butterfly的细分
简介
即三角网格插值细分
参考文献
http://graphics.stanford.edu/courses/cs468-10-fall/LectureSlides/10_Subdivision.pdf
TIPS
w 采用1/16.
参考示意图
image
code
bug 调了很久,就是 一条半边对应面的方向其实不太稳定。
codeMain
#pragma once
#pragma once
#include "strategy.h"
#include "qwidget.h"
#include
#include
#include
#include "butterfly_surface_subdivision.h"
#include
#include
#include
/**
* @description: 构造函数
* @param {type}
* @return {type}
*/
Butterfly::Butterfly(Data* data_) : Strategy(data_) {
times = 1;
genCube();
}
/**
* @description: 析构函数
* @param {type}
* @return {type}
*/
Butterfly::~Butterfly() {}
/**
* @description: 一整套流程
* @param {type}
* @return {int} 管线运行是否成功
*/
bool Butterfly::Run() {
times = QInputDialog::getInt(this, "Surface Mesh", "Please input times",
1, 1, 1000, 1);
for (int i = 0; i <= times; i++) {
if (i == 0) {
char a[20];
sprintf(a, "output%d.off", i);
genMesh(a);
}
else {
genEdgePoint();
genVertexPoint();
connectPoints();
char a[20];
sprintf(a, "output%d.off", i);
genMesh(a);
}
// 清空变量
std::cout << "[DEBUG] 迭代了第 " << i << " 次。" << std::endl;
}
getResult();
return true;
}
/**
* @description: 生成一个立方体(四边形网格)
* @param {type}
* @return {type}
*/
void Butterfly::genCube()
{
if (getData()->triMesh.n_vertices() != 0) {
for (auto it : getData()->triMesh.vertices()) {
mesh.add_vertex(getData()->triMesh.point(it));
}
for (auto it : getData()->triMesh.faces()) {
std::vector face_vhandles;
for (auto iit : it.vertices()) {
face_vhandles.push_back(iit);
}
mesh.add_face(face_vhandles);
}
return;
}
MyMesh::VertexHandle vhandle[9];
vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1));
vhandle[1] = mesh.add_vertex(MyMesh::Point(1, -1, 1));
vhandle[2] = mesh.add_vertex(MyMesh::Point(1, 1, 1));
vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1));
vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1));
vhandle[5] = mesh.add_vertex(MyMesh::Point(1, -1, -1));
vhandle[6] = mesh.add_vertex(MyMesh::Point(1, 1, -1));
vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1));
std::vector face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[5]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[6]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[6]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[7]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[4]);
mesh.add_face(face_vhandles);
}
/**
* @description: 考虑边上和内部
* @param {type}
* @return {type}
*/
void Butterfly::genEdgePoint()
{
edgePoints.clear();
for (auto e_it = mesh.edges_begin(); e_it != mesh.edges_end(); ++e_it)
{
// 得到边所代表的半边
OpenMesh::HalfedgeHandle heh1 = mesh.halfedge_handle(*e_it, 0); // 默认一个方向的半边
OpenMesh::Vec3d edgePoint(0, 0, 0);
int edgePointsNumber = 0;
OpenMesh::DefaultTraits::Point pointV = mesh.point(mesh.from_vertex_handle(heh1)); // 这条(半)边的起点
OpenMesh::DefaultTraits::Point pointW = mesh.point(mesh.to_vertex_handle(heh1)); // 这条(半)边的终点
OpenMesh::FaceHandle fh1 = mesh.face_handle(heh1);
OpenMesh::HalfedgeHandle heh = mesh.opposite_halfedge_handle(heh1);
OpenMesh::FaceHandle fh2 = mesh.face_handle(heh);
std::vector ss1; // d3 d4
std::vector ss2; // d5 d6 d7 d8
std::vector ss_all;
// 得到这两个面的所有顶点
for (auto fv_it : mesh.fv_range(fh1)) {
if (fv_it.idx() != mesh.from_vertex_handle(heh1).idx() &&
fv_it.idx() != mesh.to_vertex_handle(heh1).idx())
ss1.push_back(fv_it);
}
for (auto fv_it : mesh.fv_range(fh2)) {
if (fv_it.idx() != mesh.from_vertex_handle(heh1).idx() &&
fv_it.idx() != mesh.to_vertex_handle(heh1).idx())
ss1.push_back(fv_it);
}
if (ss1.size() != 2) {
std::cout << "[ERROR] " << ss1.size() << std::endl;
}
ss_all.assign(ss1.begin(), ss1.end());
ss_all.push_back(mesh.from_vertex_handle(heh1));
ss_all.push_back(mesh.to_vertex_handle(heh1));
for (const auto& fe : mesh.fe_range(fh1)) {
OpenMesh::HalfedgeHandle fe_heh1 = mesh.halfedge_handle(fe, 0);
//OpenMesh::FaceHandle fe_fh1 = mesh.face_handle(fe_heh1);
OpenMesh::HalfedgeHandle fe_heh = mesh.opposite_halfedge_handle(fe_heh1);
OpenMesh::FaceHandle fe_fh2 = mesh.face_handle(fe_heh);
if (fe_fh2 == fh1 || fe_fh2 == fh2) {
OpenMesh::FaceHandle fe_fh1 = mesh.face_handle(fe_heh1);
if (fe_fh1 == fh1 || fe_fh1 == fh2) continue;
for (const auto& ffv : mesh.fv_range(fe_fh1)) {
if (std::find(ss_all.begin(), ss_all.end(), ffv) == ss_all.end()) {
ss2.push_back(ffv);
}
}
}
else {
for (const auto& ffv : mesh.fv_range(fe_fh2)) {
if (std::find(ss_all.begin(), ss_all.end(), ffv) == ss_all.end()) {
ss2.push_back(ffv);
}
}
}
}
//std::cout << "=1=\n";
//for (const auto& ffv : mesh.fv_range(fh1)) {
// std::cout << mesh.point(ffv)[0] << " " << mesh.point(ffv)[1] << " " << mesh.point(ffv)[2] << "\n";
//}
//for (const auto& ffv : mesh.fv_range(fh2)) {
// std::cout << mesh.point(ffv)[0] << " " << mesh.point(ffv)[1] << " " << mesh.point(ffv)[2] << "\n";
//}
//std::cout << mesh.point(ss_all[0])[0] << " " << mesh.point(ss_all[0])[1] << " " << mesh.point(ss_all[0])[2] << "\n";
//std::cout << mesh.point(ss_all[1])[0] << " " << mesh.point(ss_all[1])[1] << " " << mesh.point(ss_all[1])[2] << "\n";
//std::cout << mesh.point(ss_all[2])[0] << " " << mesh.point(ss_all[2])[1] << " " << mesh.point(ss_all[2])[2] << "\n";
//std::cout << mesh.point(ss_all[3])[0] << " " << mesh.point(ss_all[3])[1] << " " << mesh.point(ss_all[3])[2] << "\n";
//std::cout << "==\n";
for (const auto& fe : mesh.fe_range(fh2)) {
OpenMesh::HalfedgeHandle fe_heh1 = mesh.halfedge_handle(fe, 0);
//OpenMesh::FaceHandle fe_fh1 = mesh.face_handle(fe_heh1);
OpenMesh::HalfedgeHandle fe_heh = mesh.opposite_halfedge_handle(fe_heh1);
OpenMesh::FaceHandle fe_fh2 = mesh.face_handle(fe_heh);
if (fe_fh2 == fh1 || fe_fh2 == fh2) {
OpenMesh::FaceHandle fe_fh1 = mesh.face_handle(fe_heh1);
if (fe_fh1 == fh1 || fe_fh1 == fh2) continue;
for (const auto& ffv : mesh.fv_range(fe_fh1)) {
if (std::find(ss_all.begin(), ss_all.end(), ffv) == ss_all.end()) {
ss2.push_back(ffv);
}
}
}
else {
for (const auto& ffv : mesh.fv_range(fe_fh2)) {
if (std::find(ss_all.begin(), ss_all.end(), ffv) == ss_all.end()) {
ss2.push_back(ffv);
}
}
}
}
if (ss2.size() != 4) {
std::cout << "[ERROR] " << ss2.size() << std::endl;
}
edgePoints[heh1.idx()] = 1.0 / 2.0 * (pointV + pointW) + w * (mesh.point(ss1[0]) + mesh.point(ss1[1]))
-w/2.0 *(mesh.point(ss2[0]) + mesh.point(ss2[1]) + mesh.point(ss2[2]) + mesh.point(ss2[3]));
}
}
/**
* @description: 生成新的顶点
* @param {type}
* @return {type}
*/
void Butterfly::genVertexPoint()
{
vertexPoints.clear();
// 原始点接触的面的所有的面点的均值
for (auto v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); v_it++)
{
if (mesh.is_boundary(v_it)) { // 如果这个顶点处于边界
OpenMesh::Vec3d point(0, 0, 0);
for (auto vv_it = mesh.vv_begin(v_it); vv_it.is_valid(); vv_it++) {
if (mesh.is_boundary(vv_it)) {
point += mesh.point(vv_it);
}
}
vertexPoints[(*v_it).idx()] = 3.0 / 4.0 * mesh.point(v_it) + 1.0 / 8.0 * (point);
}
else {
// 计算度 n, 度
int n = 0;
for (auto vf_it = mesh.vv_begin(v_it); vf_it.is_valid(); ++vf_it) {
n++;
}
// 计算β
double beta = 1.0 / n * (5.0 / 8.0 - pow(3.0 / 8.0 + 1.0 / 4.0 * cos(2 * M_PI / n), 2));
// 下面的需要么??
if (n < 3)
beta = 3.0 / 16.0;
OpenMesh::Vec3d point(0, 0, 0);
for (auto vv_it = mesh.vv_begin(v_it); vv_it.is_valid(); ++vv_it) {
point += beta * mesh.point(vv_it);
}
vertexPoints[(*v_it).idx()] = (1 - n * beta) * mesh.point(v_it) + point;
}
}
}
/**
* @description: 连接面点和边点
* @param {type}
* @return {type}
*/
void Butterfly::connectPoints() {
if (!mesh.has_vertex_status()) mesh.request_vertex_status();
if (!mesh.has_face_status()) mesh.request_face_status();
if (!mesh.has_edge_status()) mesh.request_edge_status();
// 先将旧顶点移动到新顶点
std::unordered_map vertexHandle;
for (auto v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); v_it++) {
//mesh.set_point(*v_it, (OpenMesh::DefaultTraits::Point)vertexPoints[(*v_it).idx()]);
vertexHandle[(*v_it).idx()] = *v_it;
}
std::vector facePointsHandle;
std::vector faceHandle;
std::unordered_map edgesHandle;
// 再加入所有的要加入的边点
for (const auto& eh : mesh.edges()) {
edgesHandle[mesh.halfedge_handle(eh, 0).idx()] = mesh.add_vertex(MyMesh::Point(edgePoints[mesh.halfedge_handle(eh, 0).idx()]));
}
for (const auto& fh : mesh.faces()) {
faceHandle.push_back(fh);
}
std::vector> v;
for (const auto& fh : mesh.faces()) {
std::vector handlerVector(6);
int pointsNumber = 0;
for (const auto& fvh : mesh.fv_range(fh)) {
handlerVector[pointsNumber] = vertexHandle[fvh.idx()];
pointsNumber++;
}
for (const auto& feh : mesh.fe_range(fh)) {
auto fehh = mesh.halfedge_handle(feh, 0);
handlerVector[pointsNumber] = edgesHandle[fehh.idx()];
pointsNumber++;
}
v.push_back(handlerVector);
}
for (int i = 0; i < v.size(); i++) {
mesh.delete_face(faceHandle[i], true);
std::vector handlerVector;
for (int j = 0; j < v[i].size(); j++) {
handlerVector.push_back(v[i][j]);
}
std::vector face_vhandles;
face_vhandles.push_back(handlerVector[3]);
face_vhandles.push_back(handlerVector[0]);
face_vhandles.push_back(handlerVector[4]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(handlerVector[4]);
face_vhandles.push_back(handlerVector[1]);
face_vhandles.push_back(handlerVector[5]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(handlerVector[3]);
face_vhandles.push_back(handlerVector[4]);
face_vhandles.push_back(handlerVector[5]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(handlerVector[2]);
face_vhandles.push_back(handlerVector[3]);
face_vhandles.push_back(handlerVector[5]);
mesh.add_face(face_vhandles);
face_vhandles.clear();
}
mesh.garbage_collection();
if (mesh.has_vertex_status()) mesh.release_vertex_status();
if (mesh.has_face_status()) mesh.release_face_status();
if (mesh.has_edge_status()) mesh.release_edge_status();
}
/**
* @description: 输出新网格
* @param {string} name 文件名称 默认 output.obj
* @return {type}
*/
void Butterfly::genMesh(std::string name) {
if (name == "") {
name = "output.off";
}
try {
if (!OpenMesh::IO::write_mesh(mesh, name)) {
std::cerr << "Cannot write mesh to file 'output.off'" << std::endl;
return;
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return;
}
}
void Butterfly::getResult() {
//if (getData()->edges.size() == 0) {
// getData()->edges.push_back(std::vector());
//}
getData()->edges.clear();
getData()->edges.push_back(std::vector());
for (auto e_it = mesh.edges_begin(); e_it != mesh.edges_end(); ++e_it)
{
// 得到边所代表的半边
OpenMesh::HalfedgeHandle heh1 = mesh.halfedge_handle(*e_it, 0); // 默认一个方向的半边
OpenMesh::Vec3d edgePoint(0, 0, 0);
int edgePointsNumber = 0;
OpenMesh::DefaultTraits::Point pointV = mesh.point(mesh.from_vertex_handle(heh1)); // 这条(半)边的起点
OpenMesh::DefaultTraits::Point pointW = mesh.point(mesh.to_vertex_handle(heh1)); // 这条(半)边的终点
getData()->edges[0].push_back({ pointV[0], pointV[1], pointV[2] });
getData()->edges[0].push_back({ pointW[0], pointW[1], pointW[2] });
}
}