Мой барицентрический растровый треугольник рисует каждый третий пиксель

Это также рисует многократные треугольники, они все смещены и в неправильном масштабе. Я пытаюсь создать собственную реализацию растрового треугольника, которая находится по адресу:

https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/rasterization-stage

Я понятия не имею, что не так с моим кодом.

#include<fstream>
#include<cmath>

class Vertice
{
public:
    float x, y;
    Vertice(float x, float y)
    {
        this->x = x;
        this->y = y;
    }
    void fitToImage(int imageWidth, int imageHeight)
    {
        x = (x * (imageWidth / 2)) + (imageWidth / 2);
        y = (-y * (imageHeight / 2)) + (imageHeight / 2);
    }
};

class Image
{
public:
    int imageWidth, imageHeight;
    unsigned char* pixels;
    Image(int imageWidth, int imageHeight)
    {
        this->imageWidth = imageWidth;
        this->imageHeight = imageHeight;
        pixels = new unsigned char[imageWidth * imageHeight * 3];
    }
    ~Image()
    {
        delete[] pixels;
    }
    void setPixel(int x, int y, int red, int green, int blue)
    {
        int help_var = ((y * imageHeight) + x) * 3;
        pixels[help_var + 0] = (char)red;
        pixels[help_var + 1] = (char)green;
        pixels[help_var + 2] = (char)blue;
    }
    void fillPixels(int red, int green, int blue)
    {
        int help_var = imageWidth * imageHeight * 3;
        for (int i = 0; i < help_var; i += 3) {
            pixels[i + 0] = (char)red;
            pixels[i + 1] = (char)green;
            pixels[i + 2] = (char)blue;
        }
    }
    //-------------------BARYCENTRIC TRIANGLE RASTERISATION------------------------
    float edgeFunction(const Vertice& A, const Vertice& B, const Vertice& P)
    {
        return ((P.x - A.x)*(B.y - A.y) + (P.y - A.y)*(B.x - A.x));
    }   

    void fillTriangleBarycentric(const Vertice& v0, const Vertice& v1, const Vertice& v2)
    {
        Vertice p(0.0f, 0.0f);
        for (int x = 0; x < imageWidth; x++) {
            for (int y = 0; y < imageHeight; y++) {
                p.x = x + 0.5f; p.y = y + 0.5f;
                float w0 = edgeFunction(v1, v2, p);
                float w1 = edgeFunction(v2, v0, p);
                float w2 = edgeFunction(v0, v1, p);
                if (w0 >= 0 && w1 >= 0 && w2 >= 0) {
                    setPixel(x, y, 0, 0, 255);
                }
            }
        }
    }
    //-----------------------------------------------------------------------------
};

int main()
{
    Image image(800, 600);
    image.fillPixels(255, 255, 255);

    Vertice a(0.2f, 0.5f);
    Vertice b(-0.5f, 0.0f);
    Vertice c(0.5f, -0.5f);

    a.fitToImage(image.imageWidth, image.imageHeight);
    b.fitToImage(image.imageWidth, image.imageHeight);
    c.fitToImage(image.imageWidth, image.imageHeight);

    image.fillTriangleBarycentric(a, b, c);

    std::ofstream imageFile;
    imageFile.open("./drawing_triangle_test_image.ppm");
    imageFile << "P6\n" << image.imageWidth << " " << image.imageHeight << "\n255\n";
    imageFile.write((char*)image.pixels, image.imageWidth * image.imageHeight * 3);
    imageFile.close();

    return 0;
}

Вот изображение, которое я получаю после запуска моей программы.

Вот изображение, которое я получаю после запуска моей программы

Спасибо за любую помощь!

Вот лучший результат (где setPixel использует imageWidth вместо imageHeight):

2 ответа

Решение

В дополнение к коррекции @ Джеффри, ваша функция ребра также не совсем верна. Так должно быть

float edgeFunction(const Vertice& A, const Vertice& B, const Vertice& P)
{
    return ((P.x - A.x)*(B.y - A.y) - (P.y - A.y)*(B.x - A.x));
}

т. е. между двумя членами должен быть отрицательный знак (поскольку он является перекрестным произведением двух векторов положения AB и AP).

y * imageHeight

Определенно тип ошибки, который есть в вашем коде (может иметь несколько экземпляров). Вам нужно умножить позицию y на ширину. В противном случае вы получите чередование треугольника в случайных положениях х.

Тот факт, что вы получаете четыре треугольника, относится к 800/600, а упрощается к 4/3. Если бы вы рендерили в 797 на 603, вы, вероятно, получили бы случайный беспорядок горизонтальных линий.

Другие вопросы по тегам