据我所知,灰色凹凸贴图被用来扰乱表面的法线,使表面看起来有凸起。用一个规则的切线法线映射,它似乎是相对直观的,考虑到每个像素都包含“法线”本身。
据我所知,凹凸图只测量高度的变化。在像Blender这样的软件中,我可以插入一个灰度凹凸图,并得到类似于普通地图产生的凸起的结果(考虑到它们或多或少产生相同的最终结果--以扰乱法线),因此,这些结果肯定会以某种方式被转换为法线。
问题是到底该怎么做。我已经为这件事疯狂了很长时间了,经过几十次搜索,都找不到我想要的东西
据我所知,由于您只将高度信息存储在凹凸图中,从其中“提取”法线的唯一有意义的方法是沿着凹凸图的每个轴找到偏导数,然后.剩下的部分我是空白的。
据我所知,要找到每个轴上的偏导数,你可以使用中心差分法(或前向差分法),找出函数f(u,v) 返回一个像素,表示地图(u,v)上坐标处的高度值.从左到右(x轴或u方向的偏导数)和y/v轴上下变化的程度。
因此,我们发现,当我们沿着这两个轴中的任何一个移动时,函数会发生多大的变化。我们下一步该怎么做才能最终达到正常呢?我有点迷路了。我也希望得到一些帮助,帮助理解它背后的直觉,而不仅仅是简单的方程式,因为我真的想彻底理解它们。
我还要补充的是,我现在只是在钻研这个理论,我还没有做任何计算机图形编程,所以我不需要任何API特定的帮助。
发布于 2021-11-14 20:53:23
我已经重写了我的答案,使它更容易理解,我也修正了一些错误。
设S:[0,1]^2 \rightarrow \mathbb{R}^3是曲面的一些参数化(假设导数在任何地方都不是零的,即它是规则的/沉浸的)。也就是说,曲面上的点集是\mathcal{M} = \{S(\beta, \gamma) \,:\, (\beta, \gamma) \in [0,1]^2\}。让h:[0,1]^2\rightarrow \mathbb{R}做高度图。单位正规n:[0,1]^2\rightarrow \mathbb{R}^3是由偏导数:n = \frac{\partial_\beta S \times \partial_\gamma S}{\|\partial_\beta S \times \partial_\gamma S\|}的归一化交叉积给出的。然后用标高图沿法向位移曲面,构造新的曲面T(\beta, \gamma) = S(\beta, \gamma) + h(u(\beta, \gamma),v(\beta, \gamma))n(\beta, \gamma)。我们想要找到T的正常值:
上面的表达式给出了移位曲面T的法向近似(不一定是单位长度)。这是Blinn的近似,它假设h足够小,以至于h(\partial_\beta n)和h(\partial_\gamma n)可以忽略。
让我们考虑如何在实践中应用这一点。这里通常有一个三角形网格。如果我们知道如何修改每个三角形的法线,我们就知道如何对整个网格进行修改。考虑具有顶点p_0, p_1, p_2 \in \mathbb{R}^3的特定三角形。我们可以通过重心坐标\alpha, \beta, \gamma \geq 0, \alpha + \beta + \gamma = 1将三角形参数化:
我们现在可以计算S的偏导数:
结果是三角形的边缘。然后几何法线是:
我们还需要\partial_{\beta} h, \, \partial_\gamma h,以便能够评估受扰正常。设3个三角形顶点处的纹理坐标为uv_0, uv_1, uv_2 \in \mathbb{R}^2,然后通过以下方法将重心坐标重新参数化为UV坐标:
我们现在可以计算偏导数:
最后,令人不安的正常情况是:
要计算\partial_u h, \, \partial_v h,可以使用有限差分:
下面是一些代码来说明如何实现这一点:
// Assume the following is given for a triangle
vec3 p0, p1, p2; // positions of the 3 vertices
vec2 uv0, uv1, uv2; // texture coordinates at the 3 vertices
// epsilon for the finite differences
float eps;
// we want to compute the normal at bary coords (beta, gamma)
float beta, gamma; // barycentric coordinates
// compute edges
vec3 e1 = p1-p0;
vec3 e2 = p2-p0;
// compute geometric normal
vec3 n_g = cross(e1,e2);
vec3 n_g_n = normalize(n_g);
// compute n x (d_gamma S)
vec3 t_g = -cross(n_g_n, e2);
// compute (d_beta S) x n
vec3 b_g = -cross(e1, n_g_n);
// compute partial derivatives of h
vec2 uv = uv0 + beta * (uv1-uv0) + gamma * (uv2-uv0);
vec2 h_uv = 1/eps * (vec2(h(uv+vec2(eps,0)), h(uv+vec2(0,eps))) - vec2(h(uv)));
float h_beta = dot(uv1-uv0, h_uv);
float h_gamma = dot(uv2-uv0, h_uv);
// compute coefficients
float coef_n = 1.0;
float coef_t = -h_beta;
float coef_b = -h_gamma;
// compute new geometric normal
vec3 m_g = coef_n * n_g + coef_t * t_g + coef_b * b_g;请注意,这与有时定义正常映射的方式相匹配,并使用采样的普通(c_n, c_t, c_b) = (1, -\partial_\beta h, -\partial_\gamma h):
您可能会注意到,交叉乘积参数在过去的两个学期中已经切换过了。这是因为在进行正常映射时,切线空间是如何定义的。您将看到,我在代码中也做了同样的工作(t_g, b_g中涉及的最小部分)。以上不考虑阴影法线。在审议这些问题时,提出了各种办法。有关这方面的更多细节,我可以建议查看用Mikkelsen方法模拟皱纹表面。
发布于 2021-11-15 11:35:12
你的岗位是正确的..。
计算两个斜率,然后以某种方式使用这些斜率来找到一个正常值。斜率是有限差分(如中心差分)的结果。
但为什么是两个斜坡?因为我们可以用它们构造两个独立的向量,它们的交叉积将成为我们的法向量。
一个向量位于纹理的u方向,简单地说是vec3(1,0,slopeU)
另一个矢量位于纹理v方向,是vec3(0,1,slopeV)。
这些矢量从哪里来?看看一个2D笛卡尔坐标系,比如这一个。现在用我们感兴趣的原点覆盖笛卡尔坐标系上的高度地图纹理。纹理的u方向与坐标系的x方向成直线。用中心差计算高度图的u方向斜率。本文在笛卡尔坐标系上对a=(-1,0)和b=(1,0)进行了研究。这两个点在x轴上形成一条线。这也是向量需要指出的方向。请记住,向量有方向但没有位置,所以只要我们选择一个与斜率计算方向相同的向量,那么插入到向量中的值并不重要,只要它有正确的方向。与斜率相同方向的向量的自然选择是(1,0)与斜率相结合的(1,0,slopeU)。
通过计算两个方向,并创建两个向量:取交叉乘积并进行规范化,这是非常简单的。
这两个向量都与高度相切,并且相互独立。它们可以被构造为(0,1,S_v)和(1,0,S_u),因为斜坡是在这些方向上非常特殊的。如果你改变了用来计算斜率的方向,那么你必须改变向量中的方向来匹配。
还有其他一些次要的警告,比如计算总是发生在原点,而高度图,通常包含0到1之间的值,需要缩放到它的最终高度。
来源和方向选择:是的,在原点进行计算的选择完全是任意的。这只会让数学变得更方便。
(1,0)和(0,1)的选择不是任意的。之所以选择这些,是因为它们与计算的斜率方向完全相同。如果我们选择(12,243,slopeU),问题就变成了这个向量点在哪里?这个向量很大程度上指向y轴。(y值为243 )因此,我们计算沿x (slopeU)轴的斜率将用于计算接近y轴的斜率,最终结果将给出一个非常偏斜的值。因此,大多数应用程序假设高度映射点之间的网格间距为1。
理论是很好的,但是在橡胶遇到道路的地方,我们需要一些可以实现的东西,并且能够及时地运行。这些功能可以在CPU上天真地实现,也可以很容易地转换成Compute。它们也可以用于实时计算像水和地形这样的高度映射几何图形的法线。此外,这些函数直接来自于FGED2一书,这本书给出了对这里的数学的简短但很好的解释。这种中心差分的实现也可以很容易地扩展到三维,它可以用于实时计算等距面提取的法线。
X方向斜率:d_x = \frac{\Delta z}{ \Delta x} = \frac{scale}{2}[h(i+1,j)-h(i-1,j)]
Y方向斜率:d_y = \frac{\Delta z}{ \Delta y} = \frac{scale}{2}[h(i,j+1)-h(i,j-1)]
X方向矢量:u_x = (1,0,d_x)
Y方向向量:u_y = (0,1,d_y)
最终值:m = normalize(u_x \times u_y ) = \frac{(-d_x,-d_y,1)}{\sqrt{d^2_x+d^2_y+1}}
https://computergraphics.stackexchange.com/questions/12336
复制相似问题