用顶点颜色着色三角形的算法

时间:2014-10-22 17:41:59

标签: 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|与{的比率{1}}。所以|L|的重量在整个对面都是0。
  5. 最后一个似乎最有可能,但我在实施它时遇到了麻烦,所以我不确定它是否正确。

2 个答案:

答案 0 :(得分:4)

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;

然后,要插入像颜色,color1,color2和color3这样的顶点颜色,你可以这样做:

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分别是V1V2V3的原始顶点的第四个组成部分。
第一次计算中的V1V2V3因为交叉积而必须是3维,但在第二个中(最有效),它可以是2维以及3维度,结果将是相同的(我想你猜测2D在第二次计算中速度更快),但在这两种情况下,如果你没有忘记将它们除以原始矢量的第四个分量。在这种情况下进行透视变换并使用第二个公式进行插值。 (如果您不理解,那些计算中的所有向量都不应该包含第四个组件!)

最后一件事;我强烈建议您使用OpenGL只需在屏幕上渲染一个大四边形并将所有代码放在着色器中(尽管您需要非常强大的OpenGL知识才能获得高级用途),因为您将从并行性中受益(即使是作为#!+视频卡),除非您在30年前的计算机上写过,或者您只是这样做以了解它是如何工作的。

答案 1 :(得分:0)

IIRC,为此你不需要在GLSL中做任何事情 - 如果你只是传递顶点着色器中的顶点颜色,插值颜色将已经是片段着色器的输入颜色。

编辑:是的,这不回答这个问题 - 正确答案在上面的第一条评论中:使用重心坐标(这就是GL的作用)。