Искажение перспективы OpenGL

У меня эта странная проблема, и я надеюсь, что кто-то сможет прояснить это для меня, чтобы я мог понять, что не так, и действовать соответствующим образом. В OpenGL (фиксированная функция) я визуализирую трубу с внутренними гранями в ортогональной проекции.

На изображении ниже показан результат. Он состоит из 4 колец вершин, которые образуют треугольники с использованием индексного шаблона, показанного слева. Для вашего удобства я пронумеровал вершины трубки. Справа - используемая текстура:

введите описание изображения здесь

Как видите, текстура сильно искажена. Поскольку я изначально создавал трубку только с двумя кольцами вершин, я думал, что увеличение количества колец исправит искажение, но без радости. Также glHint, похоже, не влияет на эту конкретную проблему.

Координаты текстуры в порядке. Кроме того, кажется, что шаблон в клетку отображается правильно, но я предполагаю, что искажение просто не видно в этом очень конкретном шаблоне.

Не обращайте внимания на пересекающиеся линии, так как одна из них - несуществующее ребро; Я визуализировал каркас через GL_LINE_LOOP.


person Will Kru    schedule 25.01.2012    source источник
comment
может это быть из-за того, что вы используете ортогональную проекцию?   -  person geofftnz    schedule 26.01.2012


Ответы (3)


Этот конкретный эффект вызван тем, как координаты текстуры интерполируются в треугольник. Что происходит, так это то, что одно направление становится основным компонентом, тогда как другое искажается. Ваш экземпляр очень склонен к этому. Это также может быть проблемой с перспективными проекциями и текстурами на полу или стенах. Вам понадобится так называемое "перспективное правильное текстурирование" ПКТ. Для этого есть glHint, но я думаю, вы уже пробовали это.

Честно говоря, единственный способ избежать этого - разделить и, применив также коррекцию перспективы. Но, к счастью, это достаточно просто для геометрии на основе четырехугольника (например, вашей). При подразделении краев интерполируйте координаты текстуры в центрах подразделения по всем 4 краям и используйте среднее значение 4 из них. Интерполяция координаты текстуры только по одному краю - это именно то, чего вы хотите избежать.

Если вы хотите, чтобы ваши геометрические данные оставались нетронутыми, вы можете реализовать PCT во фрагментном шейдере.

person datenwolf    schedule 25.01.2012
comment
Пока я пытался добавить больше колец, я не пробовал добавлять больше вершин на кольцо, что решило проблему. Так что, действительно, деление было правильным решением. Спасибо! - person Will Kru; 26.01.2012

Попробуйте какое-нибудь подразделение:

template< typename Vec >
void glVec2d( const Vec& vec )
{
    glVertex2f( static_cast<float>( vec.x() ) , static_cast<float>( vec.y() ) );
}

template< typename Vec >
void glTex2d( const Vec& vec )
{
    glTexCoord2f( static_cast<float>( vec.x() ) , static_cast<float>( vec.y() ) );
}

template< typename Vec > 
void glQuad
    (
    const Vec& A,
    const Vec& B,
    const Vec& C,
    const Vec& D,
    unsigned int divs = 2,
    const Vec& At = Vec(0,0),
    const Vec& Bt = Vec(1,0),
    const Vec& Ct = Vec(1,1),
    const Vec& Dt = Vec(0,1)
    )
{
    // base case
    if( divs == 0 )
    {
        glTex2d( At );
        glVec2d( A );

        glTex2d( Bt );
        glVec2d( B );

        glTex2d( Ct );
        glVec2d( C );

        glTex2d( Dt );
        glVec2d( D );

        return;
    }

    Vec AB = (A+B) * 0.5;
    Vec BC = (B+C) * 0.5;
    Vec CD = (C+D) * 0.5;
    Vec AD = (A+D) * 0.5;
    Vec ABCD = (AB+CD) * 0.5;

    Vec ABt = (At+Bt) * 0.5;
    Vec BCt = (Bt+Ct) * 0.5;
    Vec CDt = (Ct+Dt) * 0.5;
    Vec ADt = (At+Dt) * 0.5;
    Vec ABCDt = (ABt+CDt) * 0.5;

    // subdivided point layout
    // D   CD   C
    // 
    // AD ABCD BC 
    //
    // A   AB   B

    // subdivide
    glQuad2d( A, AB, ABCD, AD, divs - 1, At, ABt, ABCDt, ADt );
    glQuad2d( AB, B, BC, ABCD, divs - 1, ABt, Bt, BCt, ABCDt );
    glQuad2d( ABCD, BC, C, CD, divs - 1, ABCDt, BCt, Ct, CDt );
    glQuad2d( AD, ABCD, CD, D, divs - 1, ADt, ABCDt, CDt, Dt );
}

Обычно я использую Eigen::Vector2f для Vec.

person genpfault    schedule 25.01.2012

Почему вы используете для этого ортогональную проекцию? Если бы вы использовали перспективную проекцию, OpenGL исправил бы наложение текстуры за вас.

person geofftnz    schedule 25.01.2012