c++ - 计算三角形与四边形的 TBN 矩阵的差异?

标签 c++ opengl graphics 3d geometry

我正在尝试从网格的 segmentation 计算法线贴图,有 2 个网格,一个 UV 展开的基础网格,其中包含四边形和三角形,以及一个 segmentation 网格,仅包含四边形。

假设我有一个四边形,其中包含对象空间和 UV 空间中的所有顶点坐标(四边形不是平面的)、四边形的面法线和一个像素及其在 UV 空间中的位置。

我可以计算给定四边形的 TBN 矩阵并将颜色写入像素吗?如果可以,那么四边形是否不同?

我问这个是因为我找不到任何用于计算四边形的 TBN 矩阵的示例,只有三角形?

最佳答案

在回答您的问题之前,让我先解释一下您实际需要的切线和副切线是什么。

让我们暂时忘掉三角形、四边形或多边形。我们只有一个表面(以任何表示形式给出)和在表面上每个点定义的纹理坐标形式的参数化。然后我们可以将表面定义为:xyz = s(uv)uv 是一些 2D 纹理坐标,函数 s 将这些纹理坐标转换为 3D 世界位置 xyz。现在,切线是 u 坐标增加的方向。即,它是 3D 位置相对于 u 坐标的导数:T = d s(uv)/du。类似地,双切线是相对于 v 坐标的导数。法线是垂直于它们两者的 vector ,通常指向外。请记住,这三个 vector 通常在表面上的每个点都是不同的。

现在让我们转到离散计算机图形学,我们用多边形网格近似连续表面 s。问题是没有办法再得到精确的切线和副切线。我们只是在离散近似中丢失了很多信息。因此,无论如何我们都可以通过三种常见的方式来近似切线:

  1. 将 vector 与模型一起存储(通常不这样做)。
  2. 估计顶点处的 vector 并将它们插值到面中。
  3. 分别计算每张脸的 vector 。这会给你一个不连续的切线空间,当两个相邻面之间的二面角太大时会产生伪影。不过,这显然是大多数人正在做的事情。这显然也是您想要做的。

让我们关注第三种方法。对于三角形,这尤其简单,因为纹理坐标是在整个三角形上线性插值(重心插值)的。因此,导数都是常数(它只是一个线性函数)。这就是为什么您可以计算每个三角形的切线/副切线。

对于四边形,这不是那么简单。首先,您必须就从四边形顶点到其内部的位置和纹理坐标进行插值的方法达成一致。通常,使用双线性插值。然而,这不是线性插值,即切线和副切线不再是常量。这只会在特殊情况下发生(如果四边形是平面的并且 uv 空间中的四边形是平行四边形)。通常,这些假设不成立,您最终会得到四边形上每个点的不同切线/副切线/法线。

计算所需导数的一种方法是引入辅助坐标系。让我们定义一个坐标系 st,其中四边形的第一个角的坐标为 (0, 0),对角线的对角坐标为 (1, 1)(其他角有 (0, 1)(1, 0))。这些实际上是我们的插值坐标。因此,给定任意插值方案,计算导数 d xyz/d std uv/d st 相对简单。第一个是 3x2 矩阵,第二个是 2x2 矩阵(这些矩阵称为插值的雅可比矩阵)。然后,给定这些矩阵,您可以计算:

d xyz / d uv = (d xyz / d st) * (d st / d uv) = (d xyz / d st) * (d uv / d st)^-1

这将为您提供一个 3x2 矩阵,其中第一列是切线,第二列是副切线。

关于c++ - 计算三角形与四边形的 TBN 矩阵的差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47187600/

相关文章:

c++将仿函数和参数传递给一个方法

c++ - 从 DLL 导出常量

c++ - 程序错误说 "This file requires compiler and library support for the ISO C++ 2011 standard"

c++ - OpenGL 累积缓冲区不工作

python - 如何在 PyOpenGL 中旋转某个对象(Quad)?

c++ - Irrlicht 编译,但在执行时崩溃

java - 用 Java 绘制 pacman

c++ - 让 gcc 在 if 内对转换发出警告

c++ - gluBuild2DMipmaps 内存泄漏

java - Swing drawString : Text bounds and line wrapping