You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何我编写的三角形着色器会分裂为四个子三角形?

问题分析与修复方案

核心问题排查

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 20:04:51