基于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 <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <map>
class Butterfly :public Strategy, public QWidget
{
Q_OBJECT
private:
typedef OpenMesh::PolyMesh_ArrayKernelT<> MyMesh;
MyMesh mesh;
std::map<int, OpenMesh::Vec3d> facePoints;
std::map<int, OpenMesh::Vec3d> edgePoints;
std::map<int, OpenMesh::Vec3d> vertexPoints;
int times;
const double w = 1.0 / 16.0;
public:
Butterfly(Data* data_);
~Butterfly();
void genCube();
void genFacePoint();
void genEdgePoint();
void genVertexPoint();
void connectPoints();
void genMesh(std::string name);
bool Run();
void getResult();
};
#include "butterfly_surface_subdivision.h"
#include <iostream>
#include <unordered_map>
#include <QInputDialog>
/**
* @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<MyMesh::VertexHandle> 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<MyMesh::VertexHandle> 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<OpenMesh::VertexHandle> ss1; // d3 d4
std::vector<OpenMesh::VertexHandle> ss2; // d5 d6 d7 d8
std::vector<OpenMesh::VertexHandle> 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<int, OpenMesh::VertexHandle> 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<MyMesh::VertexHandle> facePointsHandle;
std::vector<MyMesh::FaceHandle> faceHandle;
std::unordered_map<int, MyMesh::VertexHandle> 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<std::vector<MyMesh::VertexHandle>> v;
for (const auto& fh : mesh.faces()) {
std::vector<MyMesh::VertexHandle> 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<MyMesh::VertexHandle> handlerVector;
for (int j = 0; j < v[i].size(); j++) {
handlerVector.push_back(v[i][j]);
}
std::vector<MyMesh::VertexHandle> 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<V3f>());
//}
getData()->edges.clear();
getData()->edges.push_back(std::vector<V3f>());
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] });
}
}
基于Butterfly的细分的更多相关文章
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十四章:曲面细分阶段
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十四章:曲面细分阶段 代码工程地址: https://github. ...
- 给博客使用Butterfly主题并部署到GitHub服务器
目录 前言 一.安装Butterfly主题 二.将本地博客部署到GitHub服务器 三.将个人域名与GitHub绑定 前言 安装完Hexo框架后,自带的主题在thems文件夹下可以查看,应用后界面: ...
- Butterfly美化
Butterfly美化 首先提示,本文量特别大哦!基本上有所有的美化,还在持续更新ing,谨慎入坑......... 主题配置文件修改 基础配置 最最最开始的,好不容易搭建了自己的个人博客,当然要写上 ...
- 【blade的UI设计】理解前端MVC与分层思想
前言 最近校招要来了,很多大三的同学一定按捺不住心中的焦躁,其中有期待也有彷徨,或许更多的是些许担忧,最近在开始疯狂的复习了吧 这里小钗有几点建议给各位: ① 不要看得太重,关心则乱,太紧张反而表现不 ...
- KlayGE 4.4中渲染的改进(三):高质量无限地形
转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2761 本系列的上一篇讲了DR中的一些改进.本篇开始将描述这个版本加入的新功能,高质量地形 ...
- Laxcus大数据管理系统2.0(12)- 第十章 运行
第十章 运行 本章将介绍一些Laxcus集群基本运行.使用情况,结合图片和表格表示.地点是我们的大数据实验室,使用我们的实验集群.数据来自于我们的合作伙伴,软件平台混合了Windows和Fedora ...
- .NET Core微服务之路:不断更新中的目录 (v0.43)
原文:.NET Core微服务之路:不断更新中的目录 (v0.43) 微服务架构,对于从事JAVA架构的童鞋来说,早已不是什么新鲜的事儿,他们有鼎鼎大名的Spring Cloud这样的全家桶框架支撑, ...
- Salesforce Consumer Goods Cloud 浅谈篇一之基础介绍
本篇参考: https://baike.baidu.com/item/%E6%B6%88%E8%B4%B9%E5%93%81/425802?fr=aladdin https://help.salesf ...
- .NET Core微服务之基于Ocelot+Butterfly实现分布式追踪
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.什么是Tracing? 微服务的特点决定了功能模块的部署是分布式的,以往在单应用环境下,所有的业务都在同一个服务器上,如果服务器出现错 ...
- 【Machine Learning】决策树案例:基于python的商品购买能力预测系统
决策树在商品购买能力预测案例中的算法实现 作者:白宁超 2016年12月24日22:05:42 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本 ...
随机推荐
- python,url请求失败重新请求的方法(try、except 应用)
爬虫请求链接,有时候会出现请求失败或者等待时间很长的情况,用下面的方法可以一定程度的解决这个问题 url='https://cl.xxxx.xyz/'+url try: response = requ ...
- 《Beating Floating Point at its Own Game: Posit Arithmetic》(一)
这段话描述了 Posit数制 在 动态扩展位数(追加比特) 时如何插入新的数值,并保持数值在数轴(或"数环")上的分布特性.以下是逐条解析: 1. Posit数值的动态扩展规则 P ...
- 开源项目YtyMark文本编辑器--UI界面相关功能(关于设计模式的实战运用)
开源项目地址 GitHub 开源地址(YtyMark-java) 欢迎提交 PR.Issue.Star ️! 1. 简述 YtyMark-java项目分为两大模块: UI界面(ytyedit-mark ...
- 指向const的指针和const指针的区别
1. 指向常量的指针(指向const的指针) 指向const的指针,不能改变其所指变量(对象)的值,或者说不能通过这个指向const的指针去改变所指的变量(对象)的值 // 指向const的指针,不能 ...
- 【笔记】用伽马函数证明标准正态分布EX4的值为3
2020-11-13 看了博客标准正态分布的E(X^4)积分求解的极坐标变换证明方法,已经叹服不已,然后看了底下老哥的评论,用伽马函数可以口算出来,遂去查了一下,真香!发篇博客记录一下. 现在的问题, ...
- 🧠 30 个 MCP 项目创意(附完整源码)
MCP(Model Context Protocol)是一种新兴的开放协议,旨在标准化应用程序如何向大型语言模型(LLMs)提供上下文和工具.它允许 AI 代理与实际工具和应用程序交互,从而实现复杂的 ...
- C#网络编程(四)----HttpClient
简介 HttpClient是C#中用于发送/接收HTTP请求的核心类,属于 System.Net.Http 命名空间.它是 .NET 中处理网络通信的现代 API,设计目标是替代早期的 WebClie ...
- 操作系统:linux -- 虚拟文件系统如何管理文件
本节来瞧下Linux是如何管理文件,也验证下Linux那句口号:一切皆文件 为此,我们需要首先搞清楚什么是 VFS,接着理清为了实现 VFS 所用到的数据结构,然后看看一个文件的打开.读写.关闭的过程 ...
- vue devtools安装及使用
(1)chrome商店下载 进入浏览器的设置: 或者直接进入该网址:https://chrome.google.com/webstore/search/vue devtools?hl=zh-CN (2 ...
- Tomcat启动信息乱码
异常描述:大概看到这个鬼样子-- 打开tomcat解压后文件: conf -> logging.properties 右键,选择以记事本或其他方式打开(只要能修改文件内容的软件都OK) 找到 j ...