0

我有一个三角形,我通过一个顶点和片段着色器。我想为每个纹素绘制一个校正向量u(在通道中编码) rb它指向顶点坐标空间(不是纹理坐标)中最近的边缘(甚至更远一个像素):u纹素之间的距离(中心? ) 和边缘。

此纹理稍后用作粒子的查找表以计算反应。我将u用于位置校正和确定反射矢量。这已经适用于硬编码值。取决于纹素u是最后一块。着色器必须是 OpenGL ES 友好的。

对于v我传递给顶点着色器的每个顶点,我(如果有帮助的话)也可以传递每个连接边的法线和三角形的中心。

知道如何做到这一点吗?

在此处输入图像描述

4

1 回答 1

2

从点 P 到线段 (A,B) 的有符号距离由下式给出:

d = area(A, B, P) / length(B - A)

在哪里

area(A, B, C) = (B.x - A.x)*(C.y - A.y) - (B.y - A.y)*(C.x - A.x)

因此,您正在寻找的距离由下式给出:

dist0 = area(P, B, C) / length(C - B)
dist1 = area(A, P, C) / length(A - C)
dist2 = area(A, B, P) / length(B - A)
minimum distance = min(dist0, dist1, dist2)

剩下的问题是如何将其映射到 GPU 管道中。

一种方法是计算vec3 dist三角形的每个顶点,然后让 OpenGL 对其进行插值:

dist at A = vec3( area(A, B, C)/length(C - B), 0, 0 )
dist at B = vec3( 0, area(A, B, C)/length(A - C), 0 )
dist at C = vec3( 0, 0, area(A, B, C)/length(B - A) )

然后在片段着色器中,您只需要计算插值 dist 分量的最小值:

in vec3 dist; // interpolated from the above
minimum distance = min(dist.x, min(dist.y, dist.z))

或者,如果您已经有了可用的重心坐标(例如,通过NV_fragment_shader_barycentric扩展),您可以搭载它。请注意,重心坐标公式与上述相同,直到比例因子:

bary0 = area(P, B, C) / area(A, B, C)
bary1 = area(A, P, C) / area(A, B, C)
bary2 = area(A, B, P) / area(A, B, C)

因此,如果bary已经可用,我们只需要通过以下方式对其进行扩展:

dist0 = bary0 * area(A, B, C) / length(C - B)
dist1 = bary1 * area(A, B, C) / length(A - C)
dist2 = bary2 * area(A, B, C) / length(B - A)

由于三角形的比例因子是恒定的,因此可以减少一些 FLOP。


编辑:我错过了您要求的实际矢量而不仅仅是距离。不过这个概念保持不变:您需要将法线或顶点传递到着色器中,并根据计算出的距离(使用上述任一方法),选择最近边缘的法线,缩放并返回它. 假设n0, n1,n2是与顶点A, B,C相对应的法线;那么您将在片段着色器中执行以下操作:

in vec3 dist; // interpolated from the above
in vec2 n0, n1, n2; // normals
...

vec2 result;
if(dist.x < min(dist.y, dist.z))
    result = dist.x*n0;
else if(dist.y < dist.z)
    result = dist.y*n1;
else
    result = dist.z*n2;
于 2022-02-10T19:03:58.347 回答