D3D的高洛德着色算法实现
- 整体分为以下几步
- 确定三角形的外接矩形
- 确定重心方程
- 绘制
确定外接矩形
p为顶点数组
float max_x = max(max(p[0].x, p[1].x), p[2].x);
float max_y = max(max(p[0].y, p[1].y), p[2].y);
float min_x = min(min(p[0].x, p[1].x), p[2].x);
float min_y = min(min(p[0].y, p[1].y), p[2].y);
这样就确定了外接矩形,接着就可以判断矩形内的每一个点是否在三角形内,然后对颜色就行平均就可以确定每个点的颜色了。
确定重心方程
由wiki的 https://zh.wikipedia.org/zh-hans/%E9%87%8D%E5%BF%83%E5%9D%90%E6%A0%87
重心坐标公式,
因为 λ123之和为1 所以三元一次方程可以简化为 二元一次方程
P.x = (1 - u - v) * P1.x + u * P2.x + v * P3.x
P.y = (1 - u - v) * P1.y + u * P2.y + v * P3.y
解二元一次方程的uv值即可得到每个点对于P点的颜色贡献值。
auto getUV = [](stD3DVertex p[3],POINT pp, double& u, double& v) {
float a = p[1].x - p[0].x;
float b = p[2].x - p[0].x;
float c = p[0].x - pp.x;
float d = p[1].y - p[0].y;
float e = p[2].y - p[0].y;
float f = p[0].y - pp.y;
u = (b*f - e * c) / (a*e - b * d);
v = (a*f - d * c) / (b*d - a * e);
};
绘制
绘制部分比较简单
遍历每个值 判断 u + v 是否大于1即可判断点的内外
不多说 直接上代码
for (float i = min_y; i < max_y; i++) {
for (float j = min_x; j < max_x; j++) {
double u, v;
getUV(p, { (int)j, (int)i }, u, v);
const auto EP = 0.000001;
if (u + v > 1)
continue;
else {
D3DCOLOR col = colorMul(1 - u - v , p[0].col) + colorMul(u , p[1].col) + colorMul(v , p[2].col);
pVertex.push_back(stD3DVertex{ j,i,0,col,0,0 });
}
}
}
颜色乘法代码
inline int D3DCOLOR_A(D3DCOLOR a) {
return a >> 24 & 0xFF;
} inline int D3DCOLOR_R(D3DCOLOR a) {
return a >> 16 & 0xFF;
} inline int D3DCOLOR_G(D3DCOLOR a) {
return a >> 8 & 0xFF;
} inline int D3DCOLOR_B(D3DCOLOR a) {
return a & 0xFF;
}
auto colorMul = []( float mul, D3DCOLOR col) -> D3DCOLOR {
return D3DCOLOR_ARGB((int)(D3DCOLOR_A(col) * mul), (int)(D3DCOLOR_R(col) * mul), (int)(D3DCOLOR_G(col) * mul), (int)(D3DCOLOR_B(col) * mul));
};
最终实现结果:
忽略掉中间的渐变色带……