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

C++自制3D引擎三角形光栅化器Z Buffer异常问题求助

3D引擎Z Buffer特定视角失效问题求助

我是C++及编程领域的新手,代码写法可能存在怪异之处还请见谅。近期我正在开发自制3D引擎,却遇到了Z Buffer相关问题:通常情况下所有像素显示正常,但在特定视角下Z Buffer似乎无法正常工作。我怀疑这与浮点舍入有关,但缺乏相关经验无法确定。以下附上相关代码及问题说明,若能得到帮助将万分感谢!

相关代码

void Triangle::draw(Screen screen, Camera& camera, float* zbuffer) {

    //drawTriangle(screen, camera, sP1, sP2, sP3, color, mP1, mP2, mP3, zbuffer);
    draw3(screen, camera, zbuffer);
}

void Triangle::draw3(Screen screen, Camera& camera, float* zbuffer) {

    //check if the triangle is visible on screen
    if (sP1.x < 0 && sP2.x < 0 && sP3.x < 0 ||
        sP1.y < 0 && sP2.y < 0 && sP3.y < 0 ||
        sP1.x > Screen::SCREEN_WIDTH && sP2.x > Screen::SCREEN_WIDTH && sP3.x > Screen::SCREEN_WIDTH ||
        sP1.y > Screen::SCREEN_HEIGHT && sP2.y > Screen::SCREEN_HEIGHT && sP3.y > Screen::SCREEN_HEIGHT) {
        return;
    }

    //sort points based on height
    Point2D temp2d; Point3D temp3d;
    if (sP1.y > sP2.y) { temp2d = sP1; sP1 = sP2; sP2 = temp2d; temp3d = mP1; mP1 = mP2; mP2 = temp3d; }
    if (sP1.y > sP3.y) { temp2d = sP1; sP1 = sP3; sP3 = temp2d; temp3d = mP1; mP1 = mP3; mP3 = temp3d; }
    if (sP2.y > sP3.y) { temp2d = sP2; sP2 = sP3; sP3 = temp2d; temp3d = mP2; mP2 = mP3; mP3 = temp3d; }

    //dont draw triangle with no area
    if (sP1.y == sP3.y) { return; }

    float longSlope = (sP1.x - sP3.x) / (sP3.y - sP1.y);
    //if the triangle has a flat top, dont calculate the short sloap
    float shortSlope = 0;
    float bottomSloap = 0;
    if (sP1.y != sP2.y) { shortSlope = (sP1.x - sP2.x) / (sP2.y - sP1.y); }
    if (sP2.y != sP3.y) { bottomSloap = (sP2.x - sP3.x) / (sP3.y - sP2.y); }

    //start at the peak of the triangle and work down
    float leftX = sP1.x;
    float rightX = sP1.x;
    float bisectX;
    float leftSlope = longSlope;
    float rightSlope = shortSlope;
    float end = sP2.y;
    bool swap = false;
    int y = sP1.y;
    if (sP1.y > 0) { y = sP1.y + 1; }
    double totalArea = areaOfTriangle(sP1, sP2, sP3), areaP1P2P4, areaP1P3P4, areaP2P3P4;
    float ratioP1, ratioP2, ratioP3;
    float mP4Dist;

    //make sure leftSlope corrosponds to the left most sloap
    bisectX = sP1.x - (sP1.x - sP3.x) / (sP3.y - sP1.y) * (sP2.y - sP1.y);
    if (sP2.x < bisectX) {
        leftSlope = shortSlope;
        rightSlope = longSlope;
        swap = true;
    }
    if (sP1.y == sP2.y) { y += 1; }
    if (sP1.y != sP2.y) {
        for (y; y < sP2.y; ++y) {
            for (int x = leftX; x < rightX - 1; x++) {

                sP4.x = x;
                sP4.y = y;
                //find bary coords
                areaP1P2P4 = areaOfTriangle(sP1, sP2, sP4);
                areaP1P3P4 = areaOfTriangle(sP1, sP3, sP4);
                areaP2P3P4 = areaOfTriangle(sP2, sP3, sP4);

                ratioP1 = areaP2P3P4 / totalArea;
                ratioP2 = areaP1P3P4 / totalArea;
                ratioP3 = areaP1P2P4 / totalArea;

                mP4.x = mP1.x * ratioP1 + mP2.x * ratioP2 + mP3.x * ratioP3;
                mP4.y = mP1.y * ratioP1 + mP2.y * ratioP2 + mP3.y * ratioP3;
                mP4.z = mP1.z * ratioP1 + mP2.z * ratioP2 + mP3.z * ratioP3;

                mP4Dist = getLineDist3d(mP4, camera.map);
                    if (x > 0 && x < Screen::SCREEN_WIDTH && y > 0 && y < Screen::SCREEN_HEIGHT) {
                        if (mP4Dist < screen.m_zbuffer[x + y * Screen::SCREEN_WIDTH]) {
                            screen.setPixel(x, y, color);
                            screen.setZBuffer(x, y, mP4Dist);
                        }
                    }
            }
            leftX -= leftSlope;
            rightX -= rightSlope;
        }
    }

    if (swap) { leftSlope = bottomSloap; leftX = sP2.x; }
    else { rightSlope = bottomSloap; rightX = sP2.x; }


    if (sP2.y != sP3.y) {
        for (y; y < sP3.y; y++) {

            for (int x = leftX; x < rightX - 1; x++) {

                sP4.x = x;
                sP4.y = y;
                //find bary coords
                areaP1P2P4 = areaOfTriangle(sP1, sP2, sP4);
                areaP1P3P4 = areaOfTriangle(sP1, sP3, sP4);
                areaP2P3P4 = areaOfTriangle(sP2, sP3, sP4);

                ratioP1 = areaP2P3P4 / totalArea;
                ratioP2 = areaP1P3P4 / totalArea;
                ratioP3 = areaP1P2P4 / totalArea;

                mP4.x = mP1.x * ratioP1 + mP2.x * ratioP2 + mP3.x * ratioP3;
                mP4.y = mP1.y * ratioP1 + mP2.y * ratioP2 + mP3.y * ratioP3;
                mP4.z = mP1.z * ratioP1 + mP2.z * ratioP2 + mP3.z * ratioP3;

                mP4Dist = getLineDist3d(mP4, camera.map);

                if (x > 0 && x < Screen::SCREEN_WIDTH && y > 0 && y < Screen::SCREEN_HEIGHT) {
                    if (mP4Dist < screen.m_zbuffer[x + y * Screen::SCREEN_WIDTH]) {
                        screen.setPixel(x, y, color);
                        screen.setZBuffer(x, y, mP4Dist);

                    }
                }
            }
            leftX -= leftSlope;
            rightX -= rightSlope;
        }
    }
}

float areaOfTriangle(Point2D p1, Point2D p2, Point2D p3) {

    //black box Heron's Formula finds area of triangle based on 3 points
    float area = 0.5 * abs((p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)));
    return area;
}

问题现象

特定视角下,红色三角形错误地嵌入到棕色三角形内部,说明Z Buffer未正确判断像素的深度优先级。


内容的提问来源于stack exchange,提问作者Sol

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 01:01:06