gpt4 book ai didi

c++ - 如何从VTK IntersectWithLine获取纹理坐标?

转载 作者:搜寻专家 更新时间:2023-10-31 02:06:13 27 4
gpt4 key购买 nike

我已经通过vtkOBJReader加载了纹理映射的OBJ并将其加载到vtkModifiedBSPTree中:

auto readerOther(vtkSmartPointer<vtkOBJReader>::New());
auto rawOtherPath(modelPathOther.toLatin1());
readerOther->SetFileName(rawOtherPath.data());
readerOther->Update();

auto meshDataOther(readerOther->GetOutput());

auto bspTreeOther(vtkSmartPointer<vtkModifiedBSPTree>::New());
bspTreeOther->SetDataSet(meshDataOther);
bspTreeOther->BuildLocator();

然后,我计算线段的起点和终点,并将其输入
if (bspTreeOther->IntersectWithLine(p1, p2, tolerance, distanceAlongLine, intersectionCoords, pcoords, subId, cellId, cell))

当然还有所有相关的预定义变量。

我需要的是相交点处的纹理的UV坐标。

我对VTK非常陌生,以至于还没有了解如何将其组合在一起的逻辑。在我深入研究源代码时,抽象层仍然让我迷失。

我一直在SO和VTK用户文件中寻找这个答案,发现那些对VTK有深刻理解的人给那些自己附近的人含糊不清的暗示,因此到目前为止对我几乎没有帮助。

(附加11/9/2018)
为了明确起见,我正在使用由单个3D扫描仪镜头创建的非退化三角网格,因此我的代码永远不会看到四边形和其他更高的多边形。通用解决方案应考虑到此类问题,但可以通过首先良好地施加Handwavium对网格进行三角剖分来实现。

最佳答案



请注意,如果一个顶点属于多个多边形并且具有不同的纹理坐标,则VTK将创建该顶点的副本。
我不使用vtkCleanPolyData,因为据我所知,VTK将合并此类“重复项”,并且我们将丢失所需的信息。

我使用vtkCellLocator而不是vtkModifiedBSPTree
因为就我而言,速度更快。

主文件main.cpp
您可以在startend数组中找到幻数-这些是您的p1p2
我已经设置了这些值,例如

#include <vtkSmartPointer.h>
#include <vtkPointData.h>
#include <vtkCellLocator.h>
#include <vtkGenericCell.h>
#include <vtkOBJReader.h>
#include <vtkTriangleFilter.h>
#include <vtkMath.h>

#include <iostream>

int main(int argc, char * argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " OBJ_file_name" << std::endl;
return EXIT_FAILURE;
}
auto reader{vtkSmartPointer<vtkOBJReader>::New()};
reader->SetFileName(argv[1]);
reader->Update();
// Triangulate the mesh if needed
auto triangleFilter{vtkSmartPointer<vtkTriangleFilter>::New()};
triangleFilter->SetInputConnection(reader->GetOutputPort());
triangleFilter->Update();
auto mesh{triangleFilter->GetOutput()};
// Use `auto mesh(reader->GetOutput());` instead if no triangulation needed

// Build a locator to find intersections
auto locator{vtkSmartPointer<vtkCellLocator>::New()};
locator->SetDataSet(mesh);
locator->BuildLocator();

// Initialize variables needed for intersection calculation
double start[3]{-1, 0, 0.5};
double end[3]{ 1, 0, 0.5};
double tolerance{1E-6};
double relativeDistanceAlongLine;
double intersectionCoordinates[3];
double parametricCoordinates[3];
int subId;
vtkIdType cellId;
auto cell{vtkSmartPointer<vtkGenericCell>::New()};
// Find intersection
int intersected = locator->IntersectWithLine(
start,
end,
tolerance,
relativeDistanceAlongLine,
intersectionCoordinates,
parametricCoordinates,
subId,
cellId,
cell.Get()
);

// Get points of intersection cell
auto pointsIds{vtkSmartPointer<vtkIdList>::New()};
mesh->GetCellPoints(cellId, pointsIds);
// Store coordinates and texture coordinates of vertices of the cell
double meshTrianglePoints[3][3];
double textureTrianglePoints[3][2];
auto textureCoordinates{mesh->GetPointData()->GetTCoords()};
for (unsigned pointNumber = 0; pointNumber < cell->GetNumberOfPoints(); ++pointNumber)
{
mesh->GetPoint(pointsIds->GetId(pointNumber), meshTrianglePoints[pointNumber]);
textureCoordinates->GetTuple(pointsIds->GetId(pointNumber), textureTrianglePoints[pointNumber]);
}

// Normalize the coordinates
double movedMeshTrianglePoints[3][3];
for (unsigned i = 0; i < 3; ++i)
{
movedMeshTrianglePoints[0][i] = 0;
movedMeshTrianglePoints[1][i] =
meshTrianglePoints[1][i] -
meshTrianglePoints[0][i];
movedMeshTrianglePoints[2][i] =
meshTrianglePoints[2][i] -
meshTrianglePoints[0][i];
}
// Normalize the texture coordinates
double movedTextureTrianglePoints[3][2];
for (unsigned i = 0; i < 2; ++i)
{
movedTextureTrianglePoints[0][i] = 0;
movedTextureTrianglePoints[1][i] =
textureTrianglePoints[1][i] -
textureTrianglePoints[0][i];
movedTextureTrianglePoints[2][i] =
textureTrianglePoints[2][i] -
textureTrianglePoints[0][i];
}

// Calculate SVD of a matrix consisting of normalized vertices
double U[3][3];
double w[3];
double VT[3][3];
vtkMath::SingularValueDecomposition3x3(movedMeshTrianglePoints, U, w, VT);
// Calculate pseudo inverse of a matrix consisting of normalized vertices
double pseudoInverse[3][3]{0};
for (unsigned i = 0; i < 3; ++i)
{
for (unsigned j = 0; j < 3; ++j)
{
for (unsigned k = 0; k < 3; ++k)
{
if (w[k] != 0)
{
pseudoInverse[i][j] += VT[k][i] * U[j][k] / w[k];
}
}
}
}

// Calculate interpolation matrix
double interpolationMatrix[3][2]{0};
for (unsigned i = 0; i < 3; ++i)
{
for (unsigned j = 0; j < 2; ++j)
{
for (unsigned k = 0; k < 3; ++k)
{
interpolationMatrix[i][j] += pseudoInverse[i][k] * movedTextureTrianglePoints[k][j];
}
}
}

// Calculate interpolated texture coordinates of the intersection point
double interpolatedTexturePoint[2]{textureTrianglePoints[0][0], textureTrianglePoints[0][1]};
for (unsigned i = 0; i < 2; ++i)
{
for (unsigned j = 0; j < 3; ++j)
{
interpolatedTexturePoint[i] += (intersectionCoordinates[j] - meshTrianglePoints[0][j]) * interpolationMatrix[j][i];
}
}

// Print the result
std::cout << "Interpolated texture coordinates";
for (unsigned i = 0; i < 2; ++i)
{
std::cout << " " << interpolatedTexturePoint[i];
}
std::cout << std::endl;

return EXIT_SUCCESS;
}

CMake项目文件 CMakeLists.txt
cmake_minimum_required(VERSION 3.1)

PROJECT(IntersectInterpolate)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(VTK REQUIRED)
include(${VTK_USE_FILE})

add_executable(IntersectInterpolate MACOSX_BUNDLE main.cpp)

if(VTK_LIBRARIES)
target_link_libraries(IntersectInterpolate ${VTK_LIBRARIES})
else()
target_link_libraries(IntersectInterpolate vtkHybrid vtkWidgets)
endif()

数学

我们需要的

假设您有一个由三角形组成的网格,并且您的顶点具有纹理坐标。

给定三角形 ABC的顶点,相应的纹理坐标 A'B'C',您想要找到一个从三角形的另一个内部和边界点到纹理的映射(以进行插值)。
让我们做出一些合理的假设:
  • ABC应该对应于它们的纹理坐标A'B'C'
  • 边界上的每个点X(即AB)应通过以下方式与A'B'线的点相对应:|AX| / |AB| = |A'X'| / |A'B'|-原始三角形的一半应位于纹理贴图的一半;
  • 三角形(A + B + C) / 3的质心应对应于纹理三角形(A' + B' + C') / 3的质心。

  • 方程解

    看起来我们想要进行仿射映射:原始三角形的顶点坐标应乘以一些系数,并添加到某些常数中。
    让我们构建方程组
    Ax * Mxx + Ay * Myx + Az * Mzx + M0x = A'x
    Ax * Mxy + Ay * Myy + Az * Mzy + M0y = A'y
    Ax * Mxz + Ay * Myz + Az * Mzz + M0z = 0

    BC相同。
    您可以看到我们有 9方程和 12未知数。
    不过,包含 Miz的方程式(对于 i中的 {x, y, z})具有解 0,并且在进一步的计算中不起作用,因此我们可以将它们设置为等于 0
    因此,我们的系统具有 6方程和 8未知数
    Ax * Mxx + Ay * Myx + Az * Mzx + M0x = A'x
    Ax * Mxy + Ay * Myy + Az * Mzy + M0y = A'y

    让我们在矩阵 View 中编写整个系统
    --          --   --       --   --       --
    | 1 Ax Ay Az | | M0x M0y | | A'x A'y |
    | 1 Bx By Bz | x | Mxx Mxy | = | B'x B'y |
    | 1 Cx Cy Cz | | Myx Myy | | C'x C'y |
    -- -- | Mzx Mzy | -- --
    -- --

    我从 AB中减去 C顶点的坐标
    和纹理坐标 A'B'中的 C'
    现在我们有了第一个顶点的三角形
    在坐标系的开始以及相应的纹理坐标。
    这意味着现在三角形不相对于另一个进行平移(移动)
    而且我们不需要插值矩阵的 M0部分
    --        --   --       --   --       --
    | Bx By Bz | | Mxx Mxy | | B'x B'y |
    | Cx Cy Cz | x | Myx Myy | = | C'x C'y |
    -- -- | Mzx Mzy | -- --
    -- --



    我们将第一个矩阵称为 P,第二个 M和最后一个 T
    P M = T

    矩阵 P不是正方形。
    如果我们向其添加零行,矩阵将变为奇异。
    因此,我们必须计算它的伪逆来求解方程。
    在VTK中没有用于计算伪逆矩阵的功能。
    我们转到Wikipedia上的 Moore–Penrose inverse文章,看到可以使用SVD进行计算。
    VTKMath::SingularValueDecomposition3x3函数允许我们执行此操作。
    该函数为我们提供了 USVT矩阵。
    我将矩阵 P的伪逆写为 P"
    U换位为 UT和将 VT换位为 V
    对角矩阵 S的伪逆是具有 1 / Sii元素的矩阵
    其中 Sii不为零,而 0为零元素
    P = U S VT
    P" = V S" UT
    M = P" T

    用法

    要应用插值矩阵,
    我们不必忘记我们需要转换输入和输出 vector 。 A'是三角形中第一个顶点的纹理坐标的2D vector , A是顶点坐标的3D vector , M是找到的插值矩阵, p是我们想要获取纹理坐标的3D交点, t'是带有插值纹理坐标的2D vector
    t' = A' + (p - A) M

    关于c++ - 如何从VTK IntersectWithLine获取纹理坐标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50595530/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com