commit
a1efe768ea
6 changed files with 359 additions and 0 deletions
@ -0,0 +1,36 @@ |
|||
# ---> C++ |
|||
# Prerequisites |
|||
*.d |
|||
|
|||
# Compiled Object files |
|||
*.slo |
|||
*.lo |
|||
*.o |
|||
*.obj |
|||
|
|||
# Precompiled Headers |
|||
*.gch |
|||
*.pch |
|||
|
|||
# Compiled Dynamic libraries |
|||
*.so |
|||
*.dylib |
|||
*.dll |
|||
|
|||
# Fortran module files |
|||
*.mod |
|||
*.smod |
|||
|
|||
# Compiled Static libraries |
|||
*.lai |
|||
*.la |
|||
*.a |
|||
*.lib |
|||
|
|||
# Executables |
|||
*.exe |
|||
*.out |
|||
*.app |
|||
|
|||
cmake-build-debug/ |
|||
.idea/ |
@ -0,0 +1,9 @@ |
|||
cmake_minimum_required(VERSION 3.21) |
|||
project(LoopDetector) |
|||
|
|||
set(CMAKE_CXX_STANDARD 14) |
|||
|
|||
add_executable(LoopDetector main.cpp src/loop_detector.cpp include/loop_detector.h) |
|||
|
|||
include_directories(E:/CLib/tinynurbs/include E:/CLib/glm) |
|||
include_directories(include) |
@ -0,0 +1,3 @@ |
|||
# GaussMap |
|||
|
|||
A Gauss mapping tool for Nurbs surfaces on CPUs. |
@ -0,0 +1,64 @@ |
|||
#ifndef LOOPDETECTOR_LOOP_DETECTOR_H |
|||
#define LOOPDETECTOR_LOOP_DETECTOR_H |
|||
|
|||
#include "tinynurbs/tinynurbs.h" |
|||
#include "glm/glm.hpp" |
|||
|
|||
using namespace std; |
|||
|
|||
class LoopDetector { |
|||
public: |
|||
// 两个曲面
|
|||
tinynurbs::RationalSurface<float> s; |
|||
tinynurbs::RationalSurface<float> f; |
|||
// 细分采样的总层数(最高与BVH的总层数相等)。从第二层开始,每一层都表示把原来的一个小sub patch分成了更小的四份
|
|||
int maxSplitLayer; |
|||
|
|||
// 采样点的求值和求切向量先设为public,因为这些因该是算好的,LoopDetector不用重复计算
|
|||
// 曲面s和f的采样点。
|
|||
vector<vector<glm::vec3>> s_evaluation; |
|||
vector<vector<glm::vec3>> f_evaluation; |
|||
// 曲面s和f的切向量。
|
|||
vector<vector<glm::vec3>> s_tangent_u; |
|||
vector<vector<glm::vec3>> s_tangent_v; |
|||
vector<vector<glm::vec3>> f_tangent_u; |
|||
vector<vector<glm::vec3>> f_tangent_v; |
|||
|
|||
// int subPatchEdgeSampleCnt; // 在一个sub patch的采样网格中,边上的采样点个数
|
|||
// void init(tinynurbs::RationalSurface<float> _s, tinynurbs::RationalSurface<float> _f, int _maxSplitLayer);
|
|||
vector<pair<int, int>> detect(pair<int, int> _s_subPatchIdxRange_u, pair<int, int> _s_subPatchIdxRange_v, |
|||
pair<int, int> _f_subPatchIdxRange_u, pair<int, int> _f_subPatchIdxRange_v); |
|||
|
|||
private: |
|||
// 需要做Loop检测的sub patch在最后一层上的下标的范围(每个范围都真包含于[0, 2^(maxSplitLayer-1)-1])
|
|||
pair<int, int> s_subPatchIdxRange_u; |
|||
pair<int, int> s_subPatchIdxRange_v; |
|||
pair<int, int> f_subPatchIdxRange_u; |
|||
pair<int, int> f_subPatchIdxRange_v; |
|||
// subPatch每条边上的采样点个数
|
|||
// 这四个值根据subPatchRange的范围得到,不可被外部修改
|
|||
int s_subPatchEdgeSampleCnt_u; |
|||
int s_subPatchEdgeSampleCnt_v; |
|||
int f_subPatchEdgeSampleCnt_u; |
|||
int f_subPatchEdgeSampleCnt_v; |
|||
// 整个曲面一条边上的采样点个数
|
|||
int edgeSampleCnt; |
|||
|
|||
// 有向距离计算结果。有向距离通过采样的方式计算,其结果与s曲面sub patch中的采样网格规模相同,即与s_evaluation大小一致
|
|||
// vector<vector<glm::vec3>> distance;
|
|||
// 确定有向距离后,对应的f曲面上的最短距离点的位置
|
|||
vector<vector<pair<int, int>>> selectedPointsIdx; |
|||
// vector fields, 即有向距离关于u、v的导数
|
|||
vector<vector<glm::vec2>> vectorFields; |
|||
|
|||
void initEvaluation(); |
|||
|
|||
void initOrientedDistance(); |
|||
|
|||
void initVectorField(); |
|||
|
|||
void getRotationNumber(); |
|||
}; |
|||
|
|||
|
|||
#endif //LOOPDETECTOR_LOOP_DETECTOR_H
|
@ -0,0 +1,77 @@ |
|||
#include <iostream> |
|||
#include "loop_detector.h" |
|||
|
|||
int main() { |
|||
LoopDetector loopDetector; |
|||
tinynurbs::RationalSurface<float> s; |
|||
tinynurbs::RationalSurface<float> f; |
|||
s.degree_u = 3; |
|||
s.degree_v = 3; |
|||
s.knots_u = {0, 0, 0, 0, 1, 1, 1, 1}; |
|||
s.knots_v = {0, 0, 0, 0, 1, 1, 1, 1}; |
|||
s.control_points = {4, 4, { |
|||
glm::vec3(0, 0.3, 0.9), glm::vec3(0, 0.6, 1), glm::vec3(0, 0.9, 1.1), glm::vec3(0, 1.2, 1), |
|||
glm::vec3(0.33, 0.3, 0.12), glm::vec3(0.33, 0.6, 0.12), glm::vec3(0.33, 0.9, 0.12), |
|||
glm::vec3(0.33, 1.2, 0.12), |
|||
glm::vec3(0.66, 0.3, 0.12), glm::vec3(0.66, 0.6, 0.12), glm::vec3(0.66, 0.9, 0.12), |
|||
glm::vec3(0.66, 1.2, 0.12), |
|||
glm::vec3(1, 0.3, 0.8), glm::vec3(1, 0.6, 1), glm::vec3(1, 0.9, 1.1), glm::vec3(1, 1.2, 1) |
|||
}}; |
|||
s.weights = {4, 4, |
|||
{ |
|||
1, 1, 1, 1, |
|||
1, 1, 1, 1, |
|||
1, 1, 1, 1, |
|||
1, 1, 1, 1, |
|||
} |
|||
}; |
|||
|
|||
f.degree_u = 3; |
|||
f.degree_v = 3; |
|||
f.knots_u = {0, 0, 0, 0, 1, 1, 1, 1}; |
|||
f.knots_v = {0, 0, 0, 0, 1, 1, 1, 1}; |
|||
f.control_points = {4, 4, { |
|||
glm::vec3(0, 0.2, 0.9), glm::vec3(0, 0.5, 1.8), glm::vec3(0, 0.8, 1.1), glm::vec3(0, 1.2, 1), |
|||
glm::vec3(0.33, 0.2, 0.12), glm::vec3(0.33, 0.5, 0.42), glm::vec3(0.33, 0.9, -0.62), |
|||
glm::vec3(0.33, 1.1, -1.756), |
|||
glm::vec3(0.66, 0.2, 0.12), glm::vec3(0.66, 0.5, 0.42), glm::vec3(0.66, 0.9, -0.62), |
|||
glm::vec3(0.66, 1.0, -1.756), |
|||
glm::vec3(1, 0.2, 0.8), glm::vec3(1, 0.5, 1), glm::vec3(1, 0.9, 1.1), glm::vec3(1, 1.2, 1) |
|||
}}; |
|||
f.weights = {4, 4, |
|||
{ |
|||
1, 1, 1, 1, |
|||
1, 1, 1, 1, |
|||
1, 1, 1, 1, |
|||
1, 1, 1, 1, |
|||
} |
|||
}; |
|||
|
|||
loopDetector.s = s; |
|||
loopDetector.f = f; |
|||
loopDetector.maxSplitLayer = 6; |
|||
// 需要做Loop检测的sub patch在最后一层上的下标的范围(每个范围都真包含于[0, 2^(maxSplitLayer-1)-1])
|
|||
// 这里范围真包含于[0, 31]
|
|||
loopDetector.detect({3, 11}, {4, 11}, {2, 7}, {6, 15}); |
|||
|
|||
glm::vec3 a(2, 3, 4); |
|||
glm::vec3 b(3, 7, 1); |
|||
auto nab = glm::normalize(a - b); |
|||
auto res = nab * (a - b); |
|||
auto ab = a * b; |
|||
cout << res.x << ", " << res.y << ", " << res.z << endl; |
|||
cout << nab.x << ", " << nab.y << ", " << nab.z << endl; |
|||
cout << ab.x << ", " << ab.y << ", " << ab.z << endl; |
|||
std::cout << "Hello, World!" << std::endl; |
|||
auto m = glm::mat2x2(1, 2, 3, 4); |
|||
cout << m[0][0] << " " << m[0][1] << endl; |
|||
auto dotRes = glm::dot(a, b); |
|||
cout << dotRes << endl; |
|||
|
|||
cout<<isnan(glm::normalize(glm::vec3(0, 0, 0)).x)<<endl; |
|||
cout<<isnan(1.)<<endl; |
|||
// auto m1 = glm::mat2(1., 2.);
|
|||
|
|||
cout<<round(3.7)<<" "<<round(3.5657567658)<<" "<<round(3.2)<<" "<<round(3.0)<<endl; |
|||
return 0; |
|||
} |
@ -0,0 +1,170 @@ |
|||
#include "loop_detector.h" |
|||
#include <utility> |
|||
|
|||
const float PI = 3.1415927; |
|||
|
|||
void LoopDetector::initEvaluation() { |
|||
// 初始化subPatch上所有采样点的值,以及它们的切向量,并存储
|
|||
// 当该工具集成到系统中后,这一部分应该是可以直接全部去掉的
|
|||
// 因为在GPU上已经做过对每个点的最细粒度的evaluation了,只需要从整个曲面把需要的subPatch找出来即可
|
|||
|
|||
// subPatch每条边上的采样点个数。边上的格子个数=range.second-range.first+1,采样点个数=格子个数+1
|
|||
s_subPatchEdgeSampleCnt_u = s_subPatchIdxRange_u.second - s_subPatchIdxRange_u.first + 2; |
|||
s_subPatchEdgeSampleCnt_v = s_subPatchIdxRange_v.second - s_subPatchIdxRange_v.first + 2; |
|||
f_subPatchEdgeSampleCnt_u = f_subPatchIdxRange_u.second - f_subPatchIdxRange_u.first + 2; |
|||
f_subPatchEdgeSampleCnt_v = f_subPatchIdxRange_v.second - f_subPatchIdxRange_v.first + 2; |
|||
|
|||
edgeSampleCnt = int(pow(2, maxSplitLayer - 1)) + 1; |
|||
|
|||
s_evaluation = vector<vector<glm::vec3>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec3>(s_subPatchEdgeSampleCnt_v)); |
|||
f_evaluation = vector<vector<glm::vec3>>(f_subPatchEdgeSampleCnt_u, vector<glm::vec3>(f_subPatchEdgeSampleCnt_v)); |
|||
// 曲面s和f的切向量。
|
|||
s_tangent_u = vector<vector<glm::vec3>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec3>(s_subPatchEdgeSampleCnt_v)); |
|||
s_tangent_v = vector<vector<glm::vec3>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec3>(s_subPatchEdgeSampleCnt_v)); |
|||
f_tangent_u = vector<vector<glm::vec3>>(f_subPatchEdgeSampleCnt_u, vector<glm::vec3>(f_subPatchEdgeSampleCnt_v)); |
|||
f_tangent_v = vector<vector<glm::vec3>>(f_subPatchEdgeSampleCnt_u, vector<glm::vec3>(f_subPatchEdgeSampleCnt_v)); |
|||
|
|||
auto s_first_u = *(s.knots_u.begin()); |
|||
auto s_first_v = *(s.knots_v.begin()); |
|||
auto s_step_u = (*(s.knots_u.end() - 1) - s_first_u) / float(edgeSampleCnt - 1); |
|||
auto s_step_v = (*(s.knots_v.end() - 1) - s_first_v) / float(edgeSampleCnt - 1); |
|||
|
|||
auto f_first_u = *(f.knots_u.begin()); |
|||
auto f_first_v = *(f.knots_v.begin()); |
|||
auto f_step_u = (*(f.knots_u.end() - 1) - f_first_u) / float(edgeSampleCnt - 1); |
|||
auto f_step_v = (*(f.knots_v.end() - 1) - f_first_v) / float(edgeSampleCnt - 1); |
|||
|
|||
for (int i = 0; i < s_subPatchEdgeSampleCnt_u; i++) { |
|||
auto u = s_first_u + s_step_u * float(s_subPatchIdxRange_u.first + i); |
|||
for (int j = 0; j < s_subPatchEdgeSampleCnt_v; j++) { |
|||
auto v = s_first_v + s_step_v * float(s_subPatchIdxRange_v.first + j); |
|||
s_evaluation[i][j] = tinynurbs::surfacePoint(s, u, v); |
|||
auto der = tinynurbs::surfaceDerivatives(s, 1, u, v); |
|||
s_tangent_u[i][j] = der(1, 0); |
|||
s_tangent_v[i][j] = der(0, 1); |
|||
} |
|||
} |
|||
for (int i = 0; i < f_subPatchEdgeSampleCnt_u; i++) { |
|||
auto u = f_first_u + f_step_u * float(f_subPatchIdxRange_u.first + i); |
|||
for (int j = 0; j < f_subPatchEdgeSampleCnt_v; j++) { |
|||
auto v = f_first_v + f_step_v * float(f_subPatchIdxRange_v.first + j); |
|||
f_evaluation[i][j] = tinynurbs::surfacePoint(f, u, v); |
|||
auto der = tinynurbs::surfaceDerivatives(f, 1, u, v); |
|||
f_tangent_u[i][j] = der(1, 0); |
|||
f_tangent_v[i][j] = der(0, 1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void LoopDetector::initOrientedDistance() { |
|||
|
|||
selectedPointsIdx = vector<vector<pair<int, int>>>(s_subPatchEdgeSampleCnt_u, |
|||
vector<pair<int, int>>(s_subPatchEdgeSampleCnt_v)); |
|||
// distance = vector<vector<glm::vec3>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec3>(s_subPatchEdgeSampleCnt_v));
|
|||
|
|||
for (int i = 0; i < s_subPatchEdgeSampleCnt_u; i++) { |
|||
for (int j = 0; j < s_subPatchEdgeSampleCnt_v; j++) { |
|||
float minDis = FLT_MAX; |
|||
int minDisFIdx_u = -1, minDisFIdx_v = -1; |
|||
for (int k = 0; k < f_subPatchEdgeSampleCnt_u; k++) { |
|||
for (int l = 0; l < f_subPatchEdgeSampleCnt_v; l++) { |
|||
auto dis = glm::distance(s_evaluation[i][j], f_evaluation[k][l]); |
|||
// 确定f上的对应点时,依据的最小欧氏距离,而不是有向距离
|
|||
if (dis < minDis) { |
|||
minDis = dis; |
|||
minDisFIdx_u = k; |
|||
minDisFIdx_v = l; |
|||
} |
|||
} |
|||
} |
|||
// auto N = glm::normalize(s_evaluation[i][j] - f_evaluation[minDisFIdx_u][minDisFIdx_v]);
|
|||
// // 直接normalize得到的单位向量总是与SF同向,但实际上N应当总是与f的一侧法向量成锐角
|
|||
// auto testAngle = N * glm::cross(f_tangent_u[minDisFIdx_u][minDisFIdx_v], f_tangent_v[minDisFIdx_u][minDisFIdx_v]);
|
|||
// N = testAngle.x + testAngle.y + testAngle.z > 0 ? N : -N;
|
|||
// distance[i][j] = N * (s_evaluation[i][j] - f_evaluation[minDisFIdx_u][minDisFIdx_v]);
|
|||
selectedPointsIdx[i][j] = {minDisFIdx_u, minDisFIdx_v}; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void LoopDetector::initVectorField() { |
|||
vectorFields = vector<vector<glm::vec2>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec2>(s_subPatchEdgeSampleCnt_v)); |
|||
for (int i = 0; i < s_subPatchEdgeSampleCnt_u; i++) { |
|||
for (int j = 0; j < s_subPatchEdgeSampleCnt_v; j++) { |
|||
auto fPointIdx = selectedPointsIdx[i][j]; |
|||
auto N = glm::normalize(s_evaluation[i][j] - f_evaluation[fPointIdx.first][fPointIdx.second]); |
|||
if (isnan(N.x) || isnan(N.y) || isnan(N.z)) { |
|||
// 绝了,曲面s和f的交线正好经过采样点,此时就无法定义向量N
|
|||
// 这里取两个曲面在交点的法向量的平均做近似
|
|||
auto tmp1 = glm::cross(s_tangent_u[i][j], s_tangent_v[i][j]); |
|||
auto tmp2 = glm::cross(f_tangent_u[fPointIdx.first][fPointIdx.second], |
|||
f_tangent_v[fPointIdx.first][fPointIdx.second]); |
|||
N = glm::normalize(glm::cross(s_tangent_u[i][j], s_tangent_v[i][j]) + |
|||
glm::cross(f_tangent_u[fPointIdx.first][fPointIdx.second], |
|||
f_tangent_v[fPointIdx.first][fPointIdx.second])); |
|||
} |
|||
// u1、u2两个向量构成和N垂直的曲面
|
|||
glm::vec3 u1(1, 1, 1); |
|||
if (N.z != 0)u1.z = (-N.x - N.y) / N.z; |
|||
else if (N.y != 0)u1.y = (-N.x - N.z) / N.y; |
|||
else u1.x = (-N.y - N.z) / N.x; |
|||
u1 = glm::normalize(u1); |
|||
auto u2 = glm::normalize(glm::cross(N, u1)); |
|||
// s,f曲面在两个方向上的偏导
|
|||
auto ps_pu = s_tangent_u[i][j], ps_pv = s_tangent_v[i][j]; |
|||
auto pf_pp = f_tangent_u[fPointIdx.first][fPointIdx.second], pf_pq = f_tangent_v[fPointIdx.first][fPointIdx.second]; |
|||
// 构造Aij矩阵,见<Detection of loops and singularities of surface intersections> APPENDIX (A7)
|
|||
auto inverseAij = glm::inverse( |
|||
glm::mat2x2(glm::dot(u1, pf_pp), glm::dot(u1, pf_pq), glm::dot(u2, pf_pp), glm::dot(u2, pf_pq)) |
|||
); |
|||
auto mBmn = glm::mat2x2(glm::dot(u1, ps_pu), glm::dot(u1, ps_pv), glm::dot(u2, ps_pu), glm::dot(u2, ps_pv)); |
|||
auto tmp = glm::vec2(glm::dot(N, pf_pp), glm::dot(N, pf_pq)); |
|||
auto vNfpNfq_inverseAij = glm::vec2(glm::dot(N, pf_pp), glm::dot(N, pf_pq)) * inverseAij; |
|||
auto pd_pu = glm::dot(N, ps_pu) - |
|||
glm::dot(vNfpNfq_inverseAij, glm::vec2(glm::dot(u1, ps_pu), glm::dot(u2, ps_pu))); |
|||
auto pd_pv = glm::dot(N, ps_pv) - |
|||
glm::dot(vNfpNfq_inverseAij, glm::vec2(glm::dot(u1, ps_pv), glm::dot(u2, ps_pv))); |
|||
vectorFields[i][j] = glm::vec2(pd_pu, pd_pv); |
|||
} |
|||
} |
|||
int a = 1; |
|||
int b = 2; |
|||
} |
|||
|
|||
void LoopDetector::getRotationNumber() { |
|||
// 以小格子为单位遍历
|
|||
for (int i = 0; i < s_subPatchEdgeSampleCnt_u - 1; i++) { |
|||
for (int j = 0; j < s_subPatchEdgeSampleCnt_v - 1; j++) { |
|||
auto rotationNumber = 0.; |
|||
|
|||
for (int biasI = 0; biasI < 2; biasI++) { |
|||
for (int biasJ = 0; biasJ < 2; biasJ++) { |
|||
auto v = vectorFields[i + biasI][j + biasJ]; |
|||
rotationNumber += atan(double(v.x / v.y)); |
|||
} |
|||
} |
|||
auto v00 = vectorFields[i][j]; |
|||
auto v01 = vectorFields[i][j + 1]; |
|||
auto v11 = vectorFields[i + 1][j + 1]; |
|||
auto v10 = vectorFields[i + 1][j]; |
|||
|
|||
rotationNumber = 2 * atan(double (v11.x/v11.y)) - 2 * atan(double(v00.x/v00.y)); |
|||
rotationNumber /= (2 * PI); |
|||
printf("rotationNumber: %lf\n", rotationNumber); |
|||
} |
|||
} |
|||
} |
|||
|
|||
vector<pair<int, int>> LoopDetector::detect(pair<int, int> _s_subPatchIdxRange_u, pair<int, int> _s_subPatchIdxRange_v, |
|||
pair<int, int> _f_subPatchIdxRange_u, |
|||
pair<int, int> _f_subPatchIdxRange_v) { |
|||
s_subPatchIdxRange_u = _s_subPatchIdxRange_u; |
|||
s_subPatchIdxRange_v = _s_subPatchIdxRange_v; |
|||
f_subPatchIdxRange_u = _f_subPatchIdxRange_u; |
|||
f_subPatchIdxRange_v = _f_subPatchIdxRange_v; |
|||
initEvaluation(); // 当evaluation已经完成,这一步就不用了,直接传入两个evaluation矩阵和四个tangent矩阵的值即可
|
|||
initOrientedDistance(); |
|||
initVectorField(); |
|||
getRotationNumber(); |
|||
return {}; |
|||
} |
Loading…
Reference in new issue