Проблемы с растеризацией треугольников

Я пытаюсь написать пару функций для рисования (заполненных) треугольников с плоской вершиной и плоским дном. По большей части они работают, однако между соседними треугольниками, имеющими общую сторону, все еще иногда видны трещины. Я использую метод интерполяции, при котором я растрарую треугольник построчно, вычисляя новые левые и правые пределы на каждом шаге. Многое из этого объяснено в коде, но вот общая идея (для плоского дна):

1) Найдите dy (высоту)

2) Найдите dy/dx (наклон) от верхней точки до каждой нижней точки.

3) Перейдите к начальной строке ( пол (верхняя точка) ) и найдите начальные координаты x-start и x-end.

4) Перейти к следующей строке, рассчитать новые начальные и конечные пределы...

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

typedef unsigned int uint32;

void Line(uint32 y, uint32 x_left, uint32 x_right);  //Draws a horizontal line

struct vector2
{
    float x,y;
};

//--------------------------------------------------------------------------------
//        Draws a flat bottom triangle from top to bottom
//--------------------------------------------------------------------------------
void Draw_Bottom_Tri_SOLID(Vector2 p0, Vector2 p1, Vector2 p2)
{
    //Point order:
    //Bottom left:    p0
    //Bottom right:   p1
    //Top point:      p2

    //calculate dy
    float dy = p2.y - p0.y;

    //dx/dy for the left and right edges
    float dxdy_left = (p0.x - p2.x)/dy;
    float dxdy_right = (p1.x - p2.x)/dy;

    //Since we start the raster process at floor(p2.y)
    //we need to shift the initial x start and x end 
    //postions along by this factor:
    float y_bump = p2.y - floor(p2.y);

    //Initial start and end x values
    float xs = p2.x + dxdy_left*y_bump;   //x left (start)
    float xe = p2.x + dxdy_right*y_bump;  //x right (end)

    uint32 yb = uint32(p0.y) + 1;         //y bottom, +1 for top left fill convention
    uint32 yt = uint32(p2.y);             //y top, use casting instead of std::floor

    //Draw lines
    for (uint32 i = yt; i >= yb; i--)
    {
        //Set left and right limits, use casting instead of std::floor
        uint32 left = uint32(xs) + 1;     //+1 for top left fill convention
        uint32 right = uint32(xe);

        //Draw line, can also be std::fill or simply a for loop.
        Line(i, left, right);

        //Increment limits
        xs += dxdy_left;
        xe += dxdy_right;
    }

}    //End: Draw_Bottom_Tri_SOLID()


//--------------------------------------------------------------------------------
//        Draws a flat top triangle from bottom to top
//--------------------------------------------------------------------------------
void Draw_Top_Tri_SOLID(Vector2 p0, Vector2 p1, Vector2 p2)
{
    //Point order:
    //Top left:        p0
    //Top right:       p1
    //Bottom point:    p2

    //calculate dy (height)
    float dy = p0.y - p2.y;

    //dx/dy for the left and right edges
    float dxdy_left = (p0.x - p2.x)/dy;
    float dxdy_right = (p1.x - p2.x)/dy;

    //Find shifting factor
    float y_bump = ceil(p2.y) - p2.y;

    //Initial start and end x values
    float xs = p2.x + dxdy_left*y_bump;    //x left  (start)
    float xe = p2.x + dxdy_right*y_bump;   //x right (end)

    uint32 yb = uint32(p2.y) + 1;          //y bottom, +1 for top left fill convention
    uint32 yt = uint32(p0.y) ;             //y top

    //Draw lines
    for (uint32 i = yb; i <= yt; i++)
    {
        //Set left and right limits
        uint32 left = uint32(xs) + 1;      //+1 for top left fill convention
        uint32 right = uint32(xe);

        //Draw line, can be std::fill or simply a for loop.
        Line(i, left, right);

        //Increment limits
        xs += dxdy_left;
        xe += dxdy_right;
    }


}    //End: Draw_Top_Tri_SOLID()

person Frank    schedule 17.12.2012    source источник


Ответы (1)


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

  • Вместо этого используйте фиксированную точку. Это также, вероятно, будет быстрее.
  • Если перерисовка не является проблемой, вы можете просто добавить достаточно большой эпсилон к своим значениям с плавающей запятой.
person rasmus    schedule 30.01.2013