opengl - 按顶点颜色为三角形着色的算法

标签 opengl raytracing

我正在使用基于顶点的三角形开发玩具光线追踪器,类似于 OpenGL。每个顶点都有自己的颜色,三角形每个点的着色应基于顶点颜色的加权平均值,并根据点与每个顶点的距离进行加权。

我不知道如何计算三角形上给定点处每种颜色的权重以模仿 OpenGL 完成的颜色着色,如许多示例所示 here 。我有几种想法,但不确定哪一种是正确的(V 是一个顶点,UW 是另外两个顶点,P是颜色点,C是三角形的质心,|PQ|是距点P的距离 指向Q):

  1. 权重等于 `1-(|VP|/|VC|),但这会在质心处留下黑色(所有颜色的权重均为 0),这是不正确的。
  2. 权重等于1-(|VP|/max(|VU|,|VW|)),因此 V 在两个顶点较近的位置具有非零权重,我认为不正确。
  3. 权重等于1-(|VP|/min(|VU|,|VW|)),因此 V 在两个顶点较近的位置处的权重为零,负权重 (两者中较远的一个会饱和到 0)。我不确定这是否正确。
  4. 线段LV经过P延伸到三角形的对边(UW):权重是|VP||L|的比率。因此,V 沿相反一侧的权重均为 0。

最后一个似乎是最有可能的,但我在实现它时遇到了困难,所以我不确定它是否正确。

最佳答案

OpenGL 使用重心坐标(精确的线性插值,尽管您可以使用插值函数或最新版本中的 centroidnoperspective 等限定符来更改它)。

如果您不知道,重心坐标的工作原理如下:
对于由顶点V1、V2、V3组成的三角形中的位置P,其各自的系数为C1、C2、C3,例如C1+C2+C3=1(这些系数指的是每个顶点对P的颜色的影响)OpenGL必须计算那些结果等价于

C1 = (AreaOfTriangle PV2V3) / (AreaOfTriangle V1V2V3)
C2 = (AreaOfTriangle PV3V1) / (AreaOfTriangle V1V2V3)
C3 = (AreaOfTriangle PV1V2) / (AreaOfTriangle V1V2V3)

三角形的面积可以用定义它的两个向量的叉积的一半长度来计算(直接意义),例如 AreaOfTriangle V1V2V3 = length(cross(V2-V1, V3-V1) )/2 然后我们得到类似的东西:

float areaOfTriangle = length(cross(V2-V1, V3-V1));    //Two times the area of the triangle
float C1 = length(cross(V2-P, V3-P)) / areaOfTriangle; //Because A1*2/A*2 = A1/A
float C2 = length(cross(V3-P, V1-P)) / areaOfTriangle; //Because A2*2/A*2 = A2/A
float C3 = 1.0f - C1 - C2;                             //Because C1 + C2 + C3 = 1

但是经过一些数学计算(以及一点点网络研究:D),我发现最有效的方法是:

YOURVECTYPE sideVec1 = V2 - V1, sideVec2 = V3 - V1, sideVec3 = P - V1;
float dot11 = dot(sideVec1, sideVec1);
float dot12 = dot(sideVec1, sideVec2);
float dot22 = dot(sideVec2, sideVec2);
float dot31 = dot(sideVec3, sideVec1);
float dot32 = dot(sideVec3, sideVec2);
float denom = dot11 * dot22 - dot12 * dot12;
float C1 = (dot22 * dot31 - dot12 * dot32) / denom;
float C2 = (dot11 * dot32 - dot12 * dot31) / denom;
float C3 = 1.0f - C1 - C2;

然后,要插入诸如颜色、颜色 1、颜色 2 和颜色 3 作为顶点颜色的内容,您需要执行以下操作:

float color = C1*color1 + C2*color2 + C3*color3;

但请注意,如果您使用透视变换(或任何暗示 w 组件的顶点变换),这将无法正常工作,因此在这种情况下,您必须使用:

float color = (C1*color1/w1 + C2*color2/w2 + C3*color3/w3)/(C1/w1 + C2/w2 + C3/w3);

w1w2w3 分别是构成 V1 的原始顶点的第四个分量, V2V3
由于叉积,第一个计算中的 V1V2V3 必须是 3 维的,但在第二个计算中(最有效),它可以是二维的,也可以是三维的,结果是相同的(我想你猜到第二次计算中二维更快),但在这两种情况下,不要忘记将它们除以原始值的第四个分量如果您正在进行透视变换,请使用向量,并在这种情况下使用第二个公式进行插值。 (如果您不明白,这些计算中的所有向量不应包含第四个分量!)

最后一件事;我强烈建议您使用 OpenGL,只需在屏幕上渲染一个大四边形并将所有代码放入着色器中(尽管您需要有关 OpenGL 的高级知识非常丰富的知识),因为您将受益于并行性(甚至可以从并行性中受益) #!+ 视频卡)除非您在一台 30 年前的计算机上编写该代码,或者您只是为了看看它是如何工作的。

关于opengl - 按顶点颜色为三角形着色的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26513712/

相关文章:

java - Java:光线追踪:光面反射着色

opengl - 当面片大小 > 4 时,曲面分割如何知道面中哪些顶点属于一起?

python-3.x - 如何在 PyOpenGL 中获取当前相机位置?

c++ - 在 OpenGL 中重新组织图像/图片数组以适应 2 次方纹理大小

c++ - RayTracing,失真如何处理?

c# - 在内存中固定指针数组

java - 2D 相机翻译

c++ - OGRE 异常(7:InternalErrorException):在 FreeImageCodec::decode 中解码图像时出错

math - 检测并找到相交射线与立方贝塞尔三角形

math - 检查点积是否接近 0 时,epsilon 应该有多大?