arap deformation 网格变形可视化

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。
arap deformation 网格变形可视化_第1张图片

rarp变形全称是 As-Rigid-As-Possible Suface Deformation.
意思是变形时尽量使每条边保持一个钢性变换。基本思路是基于能量优化来做。

能量定义

E = ∑ i = 1 N v w i ∑ j ∈ Ω ( i ) w i j ∣ ∣ ( p i ′ − p j ′ ) − R i ( p i − p j ) ∣ ∣ 2 E=\displaystyle \sum ^{N_v}_{i=1}w_i \displaystyle \sum_{j\in \Omega(i)}w_{ij}||(p'_i-p'_j)-R_i(p_i-p_j)||^2 E=i=1NvwijΩ(i)wij(pipj)Ri(pipj)2

w i 可 取 邻 域 面 积 , w i j 可 以 取 c o t 权 , 实 际 实 现 是 取 1 w_i可取邻域面积,w_{ij}可以取cot权,实际实现是取1 wiwijcot1
其 中 变 量 是 p i ′ 和 R i 其中变量是p'_i和R_i piRi

上述式子意思是尽量让每边的变化尽量是一个旋转变化。

求解过程

基本思路是通过local/global 交替迭代法来做。

Local部分

给 定 p i ′ , 计 算 R i 给定p'_i, 计算R_i pi,Ri

每一个点的能量可以单独计算,对于第i个点计算如下。

E i = ∑ j ∈ Ω ( i ) w i j ∣ ∣ ( p i ′ − p j ′ ) − R i ( p i − p j ) ∣ ∣ 2 E_i=\displaystyle \sum_{j\in \Omega(i)}w_{ij}||(p'_i-p'_j)-R_i(p_i-p_j)||^2 Ei=jΩ(i)wij(pipj)Ri(pipj)2

令 e i j ′ = p i ′ − p j ′ , e i j = p i − p j 令e'_{ij}=p'_i-p'_j, e_{ij}=p_i-p_j eij=pipj,eij=pipj

∴ E i = ∑ j ∈ Ω ( i ) w i j ∣ ∣ e i j ′ − R i e i j ∣ ∣ 2 \therefore E_i=\displaystyle \sum_{j\in \Omega(i)}w_{ij}||e'_{ij}-R_ie_{ij}||^2 Ei=jΩ(i)wijeijRieij2
= ∑ j ∈ Ω ( i ) w i j ( e i j ′ − R i e i j ) T ( e i j ′ − R i e i j ) =\displaystyle \sum_{j\in \Omega(i)}w_{ij}(e'_{ij}-R_ie_{ij})^T(e'_{ij}-R_ie_{ij}) =jΩ(i)wij(eijRieij)T(eijRieij)
= ∑ j ∈ Ω ( i ) w i j ( e i j ′ T e i j ′ − 2 e i j ′ T R i e i j + e i j T R i T R i e i j ) =\displaystyle \sum_{j\in \Omega(i)}w_{ij}(e'^T_{ij}e'_{ij}-2e'^T_{ij}R_ie_{ij}+e^T_{ij}R^T_iR_ie_{ij}) =jΩ(i)wij(eijTeij2eijTRieij+eijTRiTRieij)

∵ R i T R i 是 单 位 矩 阵 \because R^T_iR_i 是单位矩阵 RiTRi

∴ = ∑ j ∈ Ω ( i ) w i j ( e i j ′ T e i j ′ − 2 e i j ′ T R i e i j + e i j T e i j ) \therefore =\displaystyle \sum_{j\in \Omega(i)}w_{ij}(e'^T_{ij}e'_{ij}-2e'^T_{ij}R_ie_{ij}+e^T_{ij}e_{ij}) =jΩ(i)wij(eijTeij2eijTRieij+eijTeij)

由于Ri是变量,前后两项是常量。只要优化中间项即可

a r g    m i n R i ∑ j ∈ Ω ( i ) − w i j 2 e i j ′ T R i e i j arg\;\underset{R_i}{min} \displaystyle \sum_{j \in \Omega(i)}-w_{ij}2e'^T_{ij}R_ie_{ij} argRiminjΩ(i)wij2eijTRieij
负的最小,就是正的最大。去负号
= a r g    m a x R i ∑ j ∈ Ω ( i ) w i j 2 e i j ′ T R i e i j =arg\;\underset{R_i}{max} \displaystyle \sum_{j \in \Omega(i)}w_{ij}2e'^T_{ij}R_ie_{ij} =argRimaxjΩ(i)wij2eijTRieij
= a r g    m a x R i    T r ( ∑ j ∈ Ω ( i ) w i j R i e i j e i j ′ T ) =arg\;\underset{R_i}{max} \;Tr \left ( \displaystyle \sum_{j \in \Omega(i)}w_{ij}R_ie_{ij}e'^T_{ij} \right ) =argRimaxTrjΩ(i)wijRieijeijT

= a r g    m a x R i    T r ( R i ∑ j ∈ Ω ( i ) w i j e i j e i j ′ T ) ( ∗ ) =arg\;\underset{R_i}{max} \;Tr \left ( R_i \displaystyle \sum_{j \in \Omega(i)}w_{ij}e_{ij}e'^T_{ij} \right )(*) =argRimaxTrRijΩ(i)wijeijeijT

令 S i = ∑ j ∈ Ω ( i ) w i j e i j e i j ′ T ( 都 是 常 量 ) , S i = U i ∑ i V i T ( S V D 分 解 ) 令S_i = \displaystyle \sum_{j \in \Omega(i)}w_{ij}e_{ij}e'^T_{ij}(都是常量), S_i = U_i \sum_iV^T_i (SVD分解) Si=jΩ(i)wijeijeijT,Si=UiiViTSVD

根据定理:如果 M是一个对称正定矩阵,那么对于任意正交矩阵R
Tr(M)>Tr(RM)。

只 有 当 R i 是 对 称 正 定 矩 阵 时 ( ∗ ) 取 最 优 值 , 故 R i = V i U i T 只有当R_i是对称正定矩阵时(*)取最优值,故R_i = V_iU^T_i RiRi=ViUiT

当Ri的行列式值小于0时,需要对第三列取相反数。

Global部分

给 定 R i , 计 算 p i ′ 给定R_i, 计算p'_i Ri,pi

文 章 中 说 对 E 进 行 p i ′ 求 偏 导 可 以 得 到 文章中说对E进行p'_i求偏导可以得到 Epi

∂ E ∂ p i ′ = ∑ j ∈ Ω ( i ) ( ( p i ′ − p j ′ ) − 1 2 ( R i + R j ) ( p i − p j ) ) \frac {\partial E}{\partial p'_i}=\displaystyle \sum_{j\in \Omega(i)} \left((p'_i-p'_j) -\frac{1}{2}(R_i+R_j)(p_i - p_j) \right) piE=jΩ(i)((pipj)21(Ri+Rj)(pipj))

文章中没有解释为什么。我这边自己推导一下。

当 我 们 对 p i ′ 求 导 时 , 跟 p i ′ 无 关 的 式 子 结 果 就 是 0 , 那 有 关 的 是 哪 些 呢 。 当我们对p'_i求导时,跟p'_i无关的式子结果就是0,那有关的是哪些呢。 pipi0

有 关 的 是 E i = ∑ j ∈ Ω ( i ) w i j ∣ ∣ ( p i ′ − p j ′ ) − R i ( p i − p j ) ∣ ∣ 2 , 以 及 E j 中 和 i 相 关 的 。 有关的是 E_i=\displaystyle \sum_{j\in \Omega(i)}w_{ij}||(p'_i-p'_j)-R_i(p_i-p_j)||^2,以及E_j中和i相关的。 Ei=jΩ(i)wij(pipj)Ri(pipj)2Eji

不 难 发 现 每 一 个 w i j ∣ ∣ ( p i ′ − p j ′ ) − R i ( p i − p j ) ∣ ∣ 2 肯 定 有 一 个 对 应 的 反 向 式 子 。 不难发现每一个w_{ij}||(p'_i-p'_j)-R_i(p_i-p_j)||^2肯定有一个对应的反向式子。 wij(pipj)Ri(pipj)2
w j i ∣ ∣ ( p j ′ − p i ′ ) − R j ( p j − p i ) ∣ ∣ 2 w_{ji}||(p'_j-p'_i)-R_j(p_j-p_i)||^2 wji(pjpi)Rj(pjpi)2

记 ∂ i = ∑ j ∈ Ω ( i ) ( w i j ∣ ∣ ( p i ′ − p j ′ ) − R i ( p i − p j ) ∣ ∣ 2 + w j i ∣ ∣ ( p j ′ − p i ′ ) − R j ( p j − p i ) ∣ ∣ 2 ) 记\partial i = \displaystyle \sum_{j\in \Omega(i)}(w_{ij}||(p'_i-p'_j)-R_i(p_i-p_j)||^2+w_{ji}||(p'_j-p'_i)-R_j(p_j-p_i)||^2) i=jΩ(i)(wij(pipj)Ri(pipj)2+wji(pjpi)Rj(pjpi)2)

∴ ∂ E ∂ p i ′ = ∂ i ∂ p i ′ = ∑ j ∈ Ω ( i ) ( 2 w i j [ ( p i ′ − p j ′ ) − R i ( p i − p j ) ] + 2 w j i [ ( p j ′ − p i ′ ) − R j ( p j − p i ) ] ) \therefore \frac {\partial E}{\partial p'_i}=\frac {\partial i}{\partial p'_i}=\displaystyle \sum_{j\in \Omega(i)}(2w_{ij}\left[(p'_i-p'_j)-R_i(p_i-p_j)\right]+2w_{ji}[(p'_j-p'_i)-R_j(p_j-p_i)]) piE=pii=jΩ(i)(2wij[(pipj)Ri(pipj)]+2wji[(pjpi)Rj(pjpi)])

∵ w i j = w j i , i , j 也 可 以 互 换 \because w_{ij}=w_{ji}, i,j也可以互换 wij=wji,i,j

∴ ∂ E ∂ p i ′ = ∑ j ∈ Ω ( i ) ( 2 w i j [ ( p i ′ − p j ′ ) − R i ( p i − p j ) ] + 2 w i j [ ( p i ′ − p j ′ ) − R j ( p i − p j ) ] ) \therefore \frac {\partial E}{\partial p'_i}=\displaystyle \sum_{j\in \Omega(i)}(2w_{ij}\left[(p'_i-p'_j)-R_i(p_i-p_j)\right]+2w_{ij}[(p'_i-p'_j)-R_j(p_i-p_j)]) piE=jΩ(i)(2wij[(pipj)Ri(pipj)]+2wij[(pipj)Rj(pipj)])

= ∑ j ∈ Ω ( i ) w i j [ 4 ( p i ′ − p j ′ ) − 2 ( R i + R i ) ( p i − p j ) ] =\displaystyle \sum_{j\in \Omega(i)}w_{ij}[4(p'_i-p'_j)-2(R_i+R_i)(p_i-p_j)] =jΩ(i)wij[4(pipj)2(Ri+Ri)(pipj)]

= ∑ j ∈ Ω ( i ) 4 w i j [ ( p i ′ − p j ′ ) − 1 2 ( R i + R i ) ( p i − p j ) ] =\displaystyle \sum_{j\in \Omega(i)}4w_{ij}\left[(p'_i-p'_j)-\frac 1 2(R_i+R_i)(p_i-p_j)\right] =jΩ(i)4wij[(pipj)21(Ri+Ri)(pipj)]

令上式等于0,整理一下将常数项移到右边,得到第i行等式如下

∑ j ∈ Ω ( i ) w i j ( p i ′ − p j ′ ) = ∑ j ∈ Ω ( i ) w i j 2 ( R i + R i ) ( p i − p j ) \displaystyle \sum_{j\in \Omega(i)}w_{ij}(p'_i-p'_j) =\displaystyle \sum_{j\in \Omega(i)} \frac {w_{ij}} 2(R_i+R_i)(p_i-p_j) jΩ(i)wij(pipj)=jΩ(i)2wij(Ri+Ri)(pipj)

= > ( ∑ j ∈ Ω ( i ) w i j ) p i ′ − ∑ j ∈ Ω ( i ) w i j p j ′ = ∑ j ∈ Ω ( i ) w i j 2 ( R i + R i ) ( p i − p j ) =>\left(\displaystyle \sum_{j\in \Omega(i)}w_{ij}\right)p'_i-\displaystyle \sum_{j\in \Omega(i)}w_{ij}p'_j =\displaystyle \sum_{j\in \Omega(i)} \frac {w_{ij}} 2(R_i+R_i)(p_i-p_j) =>jΩ(i)wijpijΩ(i)wijpj=jΩ(i)2wij(Ri+Ri)(pipj)

代码实现

代码库:https://github.com/LightningBilly/ACMAlgorithms/tree/master/图形学算法/三角网格算法/ARAP Deformation/

#include "glew/2.2.0_1/include/GL/glew.h"
#include "glfw/3.3.4/include/GLFW/glfw3.h"
#include 
#include 
#include "IOManager.h"
#include 
#include 
#include 
#include 
#include
#include
#include

using namespace std;

#define  ColoredVertex(c,v) do{ glColor3fv(c); glVertex3fv(v); }while(0)

 char *path = "/Users/bytedance/CLionProjects/glTriangle/cow.obj";
// char *path = "/Users/bytedance/CLionProjects/glTriangle/input_1.obj";
void arap_deformation();
PolyMesh * mesh;

int motion_mode = 0;

//set fix handle
//set handles_f = {12,505,381,712,296};
set<int> handles_f;

//set move handle
//vector handles_m = {652};
//vector handles_m_pos = { MVector3(0.05,0.2,0.05) };
vector<int> handles_m;
vector<MVector3> handles_m_pos;

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    //如果按下ESC,把windowShouldClose设置为True,外面的循环会关闭应用
    if(key==GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
        std::cout << "ESC" << mode;
    }

    if (action != GLFW_PRESS)return;
    switch (key)
    {
        case GLFW_KEY_ESCAPE:
            glfwSetWindowShouldClose(window, GL_TRUE);
            break;
        case  GLFW_KEY_1:
        {
            cout<<GLFW_KEY_1<<endl;
        }
            break;
        default:
            break;
    }
    cout<<"isd: "<<isdigit(key)<<endl;
    if(isdigit(key)) motion_mode=key;

}

int moving = 0;
double sx=0, sy=0, angy=0, angx=0;
MPoint3 st;

void mouse_click(GLFWwindow* window, int button, int action, int mods) {
    cout<<"m : "<<motion_mode<<endl;

    cout<<button<<","<<action<<","<<mods<<endl;
    double xpos, ypos;
    glfwGetCursorPos(window, &xpos, &ypos);

    // cout<
    switch (motion_mode) {
        case GLFW_KEY_1:
        sx = xpos;
        sy = ypos;
        moving = action;
            break;
        case GLFW_KEY_2: // 选择固定点
            if(action==0){
                auto si=mesh->getNearPoint(MPoint3(xpos/300-1, 1-ypos/300, 0));
                if(si>=0) {
                    handles_f.insert(si);
                }
            }
        break;
        case GLFW_KEY_3: // 选择移动点
            if(action==0){
                auto si=mesh->getNearPoint(MPoint3(xpos/300-1, 1-ypos/300, 0));
                if(si>=0) {
                    handles_m.push_back(si);
                }
            }
            break;

        case GLFW_KEY_4: // 选择移动点
            if(action==1){
                st = MPoint3(xpos/300-1, 1-ypos/300, 0);
            } else {
                MVector3 v = MPoint3(xpos/300-1, 1-ypos/300, 0) - st;
                handles_m_pos.assign(handles_m.size(), MPoint3());
                for(int i=0;i<handles_m.size();i++) {
                    handles_m_pos[i] = mesh->vert(handles_m[i])->position()+v;
                }

                arap_deformation();
            }
            break;
    }

}

MVector3 cal_circum_enter(const MVector3& a, const MVector3& b, const MVector3& c)
{
    MVector3 ac = c - a, ab = b - a;
    MVector3 abXac = cross(ab, ac), abXacXab = cross(abXac, ab), acXabXac = cross(ac, abXac);
    return a + (abXacXab * ac.normSq() + acXabXac * ab.normSq()) / (2.0 * abXac.normSq());
}

void cal_local_ave_region(std::vector<double> &vertexLAR)
{
    vertexLAR.assign(mesh->numVertices(), 0);

    for(auto v:mesh->vertices()) {
        auto ps = mesh->vertAdjacentPolygon(v);
        if(ps.size()==0)continue;

        auto n =  ps[0]->normal();
        for(int i=1;i<ps.size();i++) n+=ps[i]->normal();
        n/=ps.size();
        //v->setNormal(n);
    }

    for (MPolyFace* fh : mesh->polyfaces())
    {
        // judge if it's obtuse
        bool isObtuseAngle = false;
        MVert *obtuseVertexHandle;
        MHalfedge *he = fh->halfEdge();
        MHalfedge *he_next = he->next(), *he_prev = he->prev();
        MVert *v_from_he = he->fromVertex(), *v_from_he_next = he_next->fromVertex(), *v_from_he_prev = he_prev->fromVertex();
        MVector3 vec_he_nor = he->tangent(), vec_he_next_nor = he_next->tangent(), vec_he_prev_nor = he_prev->tangent();
        if (vectorAngle(vec_he_nor, -vec_he_prev_nor) > M_PI / 2.0)
        {
            isObtuseAngle = true;
            obtuseVertexHandle = v_from_he;
        }
        else if (vectorAngle(vec_he_next_nor, -vec_he_nor) > M_PI / 2.0)
        {
            isObtuseAngle = true;
            obtuseVertexHandle = v_from_he_next;
        }
        else if (vectorAngle(vec_he_prev_nor, -vec_he_next_nor) > M_PI / 2.0)
        {
            isObtuseAngle = true;
            obtuseVertexHandle = v_from_he_prev;
        }

        // calculate area
        if (isObtuseAngle)
        {
            double faceArea = 0.5*norm(cross(v_from_he_next->position() - v_from_he->position(), v_from_he_prev->position() - v_from_he->position()));
            for (MVert* fv : mesh->polygonVertices(fh))
            {
                if (fv == obtuseVertexHandle)
                    vertexLAR[fv->index()] += faceArea / 2.0;
                else
                    vertexLAR[fv->index()] += faceArea / 4.0;
            }
        }
        else
        {
            MVector3 cc = cal_circum_enter(v_from_he->position(), v_from_he_next->position(), v_from_he_prev->position());
            for (MHalfedge* fhh : mesh->polygonHalfedges(fh))
            {
                MVector3 edgeMidpoint = 0.5*(fhh->fromVertex()->position() + fhh->toVertex()->position());
                double edgeLength = fhh->edge()->length();
                double partArea = 0.5 * edgeLength * (edgeMidpoint - cc).norm();
                vertexLAR[fhh->fromVertex()->index()] += 0.5*partArea;
                vertexLAR[fhh->toVertex()->index()] += 0.5*partArea;
            }
        }
    }
}


void cal_gaussian_curvature(const std::vector<double> &vertexLAR,std::vector<double> &gaussianCur)
{
    gaussianCur.assign(mesh->numVertices(), 0);
    for (MVert* vh : mesh->vertices())
    {
        double angle_temp = 2 * M_PI;
        MVector3  p_vh = vh->position();
        for (auto voh_it = mesh->voh_iter(vh); voh_it.isValid(); ++voh_it)
        {
            if (!(*voh_it)->isBoundary())
            {
                MHalfedge* next_voh = (*voh_it)->next();
                MVert* to_voh = (*voh_it)->toVertex(), *to_next_voh = next_voh->toVertex();
                MVector3 p_to_voh = to_voh->position(), p_to_next_voh = to_next_voh->position();
                double angle = vectorAngle(p_to_voh - p_vh, p_to_next_voh - p_vh);
                angle_temp -= angle;
            }
        }
        angle_temp /= vertexLAR[vh->index()];
        gaussianCur[vh->index()] = angle_temp;
    }
    std::cout << "Calculate Gaussian Curvature Done" << std::endl;
}


void calc_cot_weight(vector<double>& cots)
{
    cots.clear();
    cots.resize(mesh->numHalfEdges(), 0.);
    for (auto ithe = mesh->halfedge_begin(); ithe != mesh->halfedge_end(); ithe++)
    {
        if (mesh->isBoundary(*ithe))
            continue;
        auto v0=(*ithe)->fromVertex()->position();
        auto v1 = (*ithe)->toVertex()->position();
        auto v2 = (*ithe)->next()->toVertex()->position();
        auto e0 = v0 - v2;
        auto e1 = v1 - v2;
        double cotangle = dot(e0,e1) / cross(e0,e1).norm();
//		cots[ithe->idx()] = cotangle;
        cots[(*ithe)->index()] = 1.;
    }
}

void arap_deformation()
{
    int nf = mesh->numPolygons();
    int nv = mesh->numVertices();

    //position backup
    vector<MVector3> pos_mesh_ref;
    pos_mesh_ref.resize(nv);
    for (auto itv : mesh->vertices())
    {
        pos_mesh_ref[itv->index()] = itv->position();
    }

    vector<double> cots;
    calc_cot_weight(cots);


    set<int> handles = handles_f;
    handles.insert(handles_m.begin(), handles_m.end());

    //calc cot-weight laplacian matrix
    vector<Eigen::Triplet<double>> trivec;
    // 根据求导公式将左边填充
    for (int i = 0; i < nv; i++)
    {
        // 固定点直接将该点参数填1
        if (handles.count(i) > 0)
        {
            trivec.emplace_back(i, i, 1.);
            continue;
        }
        auto v_h = mesh->vert(i);
        double weight_sum = 0.;
        for (auto itvoh = mesh->voh_iter(v_h); itvoh.isValid(); ++itvoh)
        {
            auto v_to_h = (*itvoh)->toVertex();
            double weight_ = cots[(*itvoh)->index()] + cots[(*itvoh)->pair()->index()];

            weight_sum += weight_;
            trivec.emplace_back(i, v_to_h->index(), -weight_);
        }
        trivec.emplace_back(i, i, weight_sum);
    }
    Eigen::SparseMatrix<double> smat;
    smat.resize(nv, nv);
    smat.setFromTriplets(trivec.begin(),trivec.end());

    Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
    solver.compute(smat);

    Eigen::MatrixX3d uv;
    uv.resize(nv, 3);

    vector<Eigen::Matrix3d> Lts;
    Lts.resize(nv);
    Eigen::MatrixX3d b;
    b.resize(nv, 3);

    //local-global iteration
    for (int iter = 0; iter < 10; iter++)
    {
        //local calc Lt
#pragma omp parallel for
        for (int i = 0; i < nv; i++)
        {
            auto v_h = mesh->vert(i);
            Eigen::Matrix3d J = Eigen::Matrix3d::Zero();
            for (auto itvoh = mesh->voh_iter(v_h); itvoh.isValid(); ++itvoh)
            {
                auto v_to_h = (*itvoh)->toVertex();
                auto e_ = pos_mesh_ref[i] - pos_mesh_ref[v_to_h->index()];
                auto ep_ = v_h->position() - v_to_h->position();
                double weight_ = cots[(*itvoh)->index()] + cots[(*itvoh)->pair()->index()];
                Eigen::Vector3d ep(ep_[0], ep_[1], ep_[2]);
                Eigen::Vector3d e(e_[0], e_[1], e_[2]);
                J += weight_ * (e*ep.transpose());
            }

            Eigen::JacobiSVD<Eigen::Matrix3d> svd(J, Eigen::ComputeFullU| Eigen::ComputeFullV);
            Eigen::Matrix3d U = svd.matrixU();
            Eigen::Matrix3d V = svd.matrixV();

            Eigen::Matrix3d R = V * U.transpose();

            if (R.determinant() < 0)
            {
                U(0, 2) *= -1;
                U(1, 2) *= -1;
                U(2, 2) *= -1;
                R = V * U.transpose();
            }
            Lts[i] = R;
        }

        //global calc b
#pragma omp parallel for
        for (int i = 0; i < nv; i++)
        {
            auto v_h = mesh->vert(i);
            Eigen::Vector3d b_tmp(0., 0., 0.);
            for (auto itvoh = mesh->voh_iter(v_h); itvoh.isValid(); ++itvoh)
            {
                auto v_to_h = (*itvoh)->toVertex();
                auto ep_ = pos_mesh_ref[i] - pos_mesh_ref[v_to_h->index()];
                Eigen::Vector3d ep(ep_[0], ep_[1], ep_[2]);

                Eigen::Matrix3d JR = Lts[i] + Lts[v_to_h->index()];
                double weight_ = (cots[(*itvoh)->index()] + cots[(*itvoh)->pair()->index()]) / 2.0;
                b_tmp += weight_ * (JR*ep);

            }
            b(i, 0) = b_tmp[0];
            b(i, 1) = b_tmp[1];
            b(i, 2) = b_tmp[2];
        }

        //set handles
        for (int i:handles_f)
        {
            auto b_tmp = pos_mesh_ref[i];
            b(i, 0) = b_tmp[0];
            b(i, 1) = b_tmp[1];
            b(i, 2) = b_tmp[2];
        }

        for (int i = 0; i < handles_m.size(); i++)
        {
            auto b_tmp = handles_m_pos[i];
            b(handles_m[i], 0) = b_tmp[0];
            b(handles_m[i], 1) = b_tmp[1];
            b(handles_m[i], 2) = b_tmp[2];
        }

        //global solve
        uv.col(0) = solver.solve(b.col(0));
        uv.col(1) = solver.solve(b.col(1));
        uv.col(2) = solver.solve(b.col(2));

#pragma omp parallel for
        for (int i = 0; i < nv; i++)
        {
            auto v_h = mesh->vert(i);
            v_h->setPosition(uv(i, 0), uv(i, 1), uv(i, 2));
        }
    }

}

int lastse = -1;

int main(void) {
    auto r = new OBJReader();
    string writePath = "/Users/bytedance/CLionProjects/glTriangle/d1.txt";
    mesh = new PolyMesh();
    r->read(path, mesh);
    std::vector<double> gaussianCur;
    std::vector<double> vertexLAR;
    cal_local_ave_region(vertexLAR);
    cal_gaussian_curvature(vertexLAR, gaussianCur);
    // mesh->scale(0.5);
    mesh->scale(1);
    double m = *max_element(gaussianCur.begin(), gaussianCur.end());
    /*
    for(int i=0;i

/*
    auto w = new OBJWriter();
    w->write(writePath, mesh);
  */
    //初始化GLFW库
    if (!glfwInit())
        return -1;
    //创建窗口以及上下文
    GLFWwindow *window = glfwCreateWindow(600, 600, "hello world", NULL, NULL);
    if (!window) {
        //创建失败会返回NULL
        glfwTerminate();
    }

    //建立当前窗口的上下文
    glfwMakeContextCurrent(window);

    glfwSetKeyCallback(window, key_callback); //注册回调函数
    glfwSetMouseButtonCallback(window, mouse_click);
    //glViewport(0, 0, 400, 400);
    //gluOrtho2D(-200, 200.0, -200, 200.0);
    //循环,直到用户关闭窗口


    while (!glfwWindowShouldClose(window)) {
        /*******轮询事件*******/
        glfwPollEvents();
        // cout<<456<
        //选择清空的颜色RGBA
        double xpos, ypos;
        glfwGetCursorPos(window, &xpos, &ypos);
        if ( ypos>0 && xpos>0&&(fabs(ypos -sy)>1 || (fabs(xpos -sx)>1)))  {
            if(moving) {
                cout << "cur p" << xpos << "," << ypos << endl;
                angy += (sy - ypos) / 300 * 360 + 360;
                while (angy >= 360) angy -= 360;
                cout << "angley:" << angy << endl;


                angx += (sx - xpos) / 300 * 360 + 360;
                while (angx >= 360) angx -= 360;
                cout << "anglex:" << angx << endl;

            }
            sx = xpos;
            sy = ypos;
            // cout<<"select"<
            auto si=mesh->getNearPoint(MPoint3(xpos/300-1, 1-ypos/300, 0));
            if(si!=lastse && lastse>=0) mesh->vert(lastse)->setSelected(false);
            if(si>=0) {
                lastse=si;
                // cout<<"666 "<
                mesh->vert(si)->setSelected(true);
            }

        }

        for(auto i: handles_f) {
            mesh->vert(i)->setSelected(true);
        }

        for(auto i: handles_m) {
            mesh->vert(i)->setSelected(true);
        }
        /*
        sx = xpos/300-1;
        sy = -(ypos/300-1);
         */
        glClearColor(0, 0, 0, 1);
        // glColor3f(0,0, 0);
        glMatrixMode(GL_PROJECTION);
        glEnable(GL_DEPTH_TEST);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        mesh->Draw(angy, angx, gaussianCur);
        angy = 0, angx=0;
        for (int i=0, n=1000; i<n;i++) {
            auto rgb=getRGB(i);
            glColor3f(rgb[0], rgb[1],rgb[2]);
            glRectf(0.7, 1.0*i/n-0.2,0.8, 1.0*(i+1)/n-0.2);
        }
        glFlush();
        // RevolveTriangle();
//        glColor3f(1,0,0);
//        glPointSize(10);
//        glBegin(GL_POINTS);
//        glVertex3d(xpos/300-1, -ypos/300+1, -1 );
//        glEnd();
        // glGetFloatv()
        /******交换缓冲区,更新window上的内容******/
        glfwSwapBuffers(window);
    }
    glfwTerminate();
    return 0;
}

效果展示

arap deformation 网格变形可视化_第2张图片

arap deformation 网格变形可视化_第3张图片

你可能感兴趣的:(图形学,线性代数,三角网格,网格变形,图形学)