Алгоритм растеризации: нахождение ST-координат точки в 2D-квадрате и обратной проекции

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

  • создание четырехугольника в 3D
  • проецирование вершин четырехугольника на экран с помощью разделения перспективы
  • преобразование полученных координат из экранного пространства в растровое пространство и вычисление ограничивающей рамки четырехугольника в растровом пространстве
  • перебирая все пиксели внутри этой ограничивающей рамки и выясняя, содержится ли текущий пиксель P в квадрате. Для этого я использую простой тест, который состоит в том, чтобы взять точку между ребром AB четырехугольника и вектором, определенным между вершиной A и точкой P. Я повторяю этот процесс для всех 4 ребер, и если знак тот же, тогда точка находится внутри четырехугольника.

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

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

PS: это НЕ домашнее задание. Я делаю это, чтобы понять алгоритм растеризации, и именно там, где я сейчас застрял, я не понимаю, что, как я полагаю, в конвейере рендеринга графического процессора включает какую-то обратную проекцию, но я просто потерялся в этот момент. Спасибо за вашу помощь.

    Vec3f verts[4]; // vertices of the quad in world space
    Vec2f vraster[4]; // vertices of the quad in raster space
    uint8_t outside = 0; // is the quad in raster space visible at all?
    Vec2i bmin(10e8), bmax(-10e8);
    for (uint32_t j = 0; j < 4; ++j) {
        // transform unit quad to world position by transforming each
        // one of its vertices by a transformation matrix (represented
        // here by 3 unit vectors and a translation value)
        verts[j].x = quads[j].x * right.x + quads[j].y * up.x + quads[j].z * forward.x + pt[i].x;
        verts[j].y = quads[j].x * right.y + quads[j].y * up.y + quads[j].z * forward.y + pt[i].y;
        verts[j].z = quads[j].x * right.z + quads[j].y * up.z + quads[j].z * forward.z + pt[i].z;

        // project the vertices on the image plane (perspective divide)
        verts[j].x /= -verts[j].z;
        verts[j].y /= -verts[j].z;

        // assume the image plane is 1 unit away from the eye
        // and fov = 90 degrees, thus bottom-left and top-right
        // coordinates of the screen are (-1,-1) and (1,1) respectively.
        if (fabs(verts[j].x) > 1 || fabs(verts[j].y) > 1) outside |= (1 << j);

        // convert image plane coordinates to raster
        vraster[j].x = (int32_t)((verts[j].x + 1) * 0.5 * width);
        vraster[j].y = (int32_t)((1 - (verts[j].y + 1) * 0.5) * width);


        // compute box of the quad in raster space
        if (vraster[j].x < bmin.x) bmin.x = (int)std::floor(vraster[j].x);
        if (vraster[j].y < bmin.y) bmin.y = (int)std::floor(vraster[j].y);
        if (vraster[j].x > bmax.x) bmax.x = (int)std::ceil(vraster[j].x);
        if (vraster[j].y > bmax.y) bmax.y = (int)std::ceil(vraster[j].y);
    }

    // cull if all vertices are outside the canvas boundaries
    if (outside == 0x0F) continue;

    // precompute edge of quad
    Vec2f edges[4];
    for (uint32_t j = 0; j < 4; ++j) {
        edges[j] = vraster[(j + 1) % 4] - vraster[j];
    }

    // loop over all pixels contained in box
    for (int32_t y = std::max(0, bmin.y); y <= std::min((int32_t)(width -1), bmax.y); ++y) {
        for (int32_t x = std::max(0, bmin.x); x <= std::min((int32_t)(width -1), bmax.x); ++x) {
            bool inside = true;
            for (uint32_t j = 0; j < 4 && inside; ++j) {
                Vec2f v = Vec2f(x + 0.5, y + 0.5) - vraster[j];
                float d = edges[j].x * v.x + edges[j].y * v.y;
                inside &= (d > 0);
            }
            // pixel is inside quad, mark in the image
            if (inside) {
                buffer[y * width + x] = 255;
            }
        }
    }

person user18490    schedule 18.01.2015    source источник
comment
Ваш первый шаг, я думаю, состоит в том, чтобы рассмотреть растеризацию треугольников. Вот как это делает современное оборудование - у квадроциклов есть неоднозначность, например, они могут быть не компланарными. Они могут быть невыпуклыми. Очевидно, что Quad можно разложить на два треугольника, которые не страдают от этих проблем (хотя треугольник может быть обратной гранью или даже вырожденным, если его точки «достаточно близки» к коллинеарности (см.: тест площади со знаком). Я предлагаю вам выбрать API, который документирует растеризацию, такую ​​​​как OpenGL. Я бы посоветовал вам понять барицентрические координаты и то, как интерполяция применяется к общим атрибутам вершин.   -  person Brett Hale    schedule 19.01.2015
comment
Спасибо за комментарии и поддержку. Я получу версию, работающую с треугольниками, но в конечном итоге я также пытаюсь заставить ее работать с четырехугольниками. Я пытаюсь сделать это как можно быстрее, и, конечно, необходимость иметь дело с двумя треугольниками, а не с одним четырехугольником, замедлит работу. Рабочий код выложу позже.   -  person user18490    schedule 19.01.2015
comment
Я понимаю, что вы сказали о треугольниках, но я хотел реализовать технику, используемую в алгоритме РЕЙЕСА: вычислить z микрополигона в точке выборки путем интерполяции, где микрополигон представляет собой четырехугольник, поэтому я надеялся сделать то же (graphics.pixar.com/library/Reyes/paper.pdf) . Я попробую вариант треугольника, так как он кажется основным, но все же интересно, как они интерполируют значение z с помощью четырехугольника.   -  person user18490    schedule 20.01.2015