为何我编写的三角形着色器会分裂为四个子三角形?
问题分析与修复方案
核心问题排查
1. 三角形总面积计算错误
你计算p(三角形总面积的两倍)时,传入的第一个点的y坐标写错了:
原错误代码:
int p = edgeFunction(x1,y2,x2,y2,x3,y3);
正确写法:
int p = edgeFunction(x1, y1, x2, y2, x3, y3);
这个错误导致后续颜色权重的分母完全偏离,是颜色分裂的主要诱因。
2. 内部点判断逻辑错误
原代码用(a|b|c)>=0判断点是否在三角形内,这个逻辑完全不成立。edge函数的返回值符号表示点在边的哪一侧:
- 若三角形顶点按顺时针排列,内部点的三个edge值全为负;
- 若按逆时针排列,内部点的三个edge值全为正。
正确的判断逻辑是让a、b、c与总面积p的符号一致:
if ((a * p >= 0) && (b * p >= 0) && (c * p >= 0))
这样无论顶点顺序如何,都能准确筛选出三角形内部的点。
3. 颜色权重的范围处理
原代码直接将a*255/p强制转成uint8_t,当计算结果为负数或超过255时会出现截断错误。需要先计算浮点权重,再用钳位函数确保值在0-255范围内:
float weight_a = static_cast<float>(a) / p; uint8_t r = static_cast<uint8_t>(std::clamp(weight_a * 255.0f, 0.0f, 255.0f));
修复后的完整代码
int edgeFunction(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3){ return (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1); } std::vector<fragment> RGBtri(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3){ std::vector<fragment> tri; // fragment is a struct with xyrgba int minX = std::min(x1, std::min(x2, x3)); int maxX = std::max(x1, std::max(x2, x3)); int minY = std::min(y1, std::min(y2, y3)); int maxY = std::max(y1, std::max(y2, y3)); // 修复:正确计算三角形总面积的两倍 int p = edgeFunction(x1, y1, x2, y2, x3, y3); // 避免退化三角形导致除以0 if (p == 0) return tri; for(uint16_t y = minY; y <= maxY; y++){ for(uint16_t x = minX; x <= maxX; x++){ int a = edgeFunction(x2, y2, x3, y3, x, y); int b = edgeFunction(x3, y3, x1, y1, x, y); int c = edgeFunction(x1, y1, x2, y2, x, y); // 修复:正确判断内部点 if ((a * p >= 0) && (b * p >= 0) && (c * p >= 0)){ // 计算重心权重 float weight_a = static_cast<float>(a) / p; float weight_b = static_cast<float>(b) / p; float weight_c = static_cast<float>(c) / p; // 修复:颜色值范围钳位 uint8_t r = static_cast<uint8_t>(std::clamp(weight_a * 255.0f, 0.0f, 255.0f)); uint8_t g = static_cast<uint8_t>(std::clamp(weight_b * 255.0f, 0.0f, 255.0f)); uint8_t b_color = static_cast<uint8_t>(std::clamp(weight_c * 255.0f, 0.0f, 255.0f)); tri.push_back({x, y, r, g, b_color, 255}); } } } return tri; }
补充说明
修复后,顶点(x1,y1)对应红色、(x2,y2)对应绿色、(x3,y3)对应蓝色,颜色会在三角形内平滑插值,不会出现分裂现象。新增的p == 0判断,可避免传入三点共线的退化三角形导致程序崩溃。
内容的提问来源于stack exchange,提问作者Gremlin
相关产品推荐
相关产品推荐

