Нарисуйте пирамиду внутри куба - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь нарисовать «прозрачный» куб (только с ребрами) и поместить пирамиду в этот куб, проблема в том, что края куба рисуют над пирамидой, когда я вращаю ее.

Вот пример

enter image description here

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

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QOpenGLWindow>
#include <QSurfaceFormat>
#include <QOpenGLContext>
#include <QTimer>

#ifdef _DEBUG
#   include <QDebug>
#endif

class MainWindow: public QOpenGLWindow
{
    Q_OBJECT

public:
    MainWindow();

private:
    QOpenGLContext *m_context;
    QTimer m_timer;
    GLfloat m_angle;

private slots:
    void rotate();

protected:
    void initializeGL() override;
    void paintGL() override;

    void paintEvent(QPaintEvent *event) override;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow():
    QOpenGLWindow(),
    m_angle(0.0f)
{
    QSurfaceFormat sf;

    sf.setProfile(QSurfaceFormat::CompatibilityProfile);
    sf.setVersion(2, 1);

    setFormat(sf);
    setSurfaceType(QWindow::OpenGLSurface);
    create();

    m_context = new QOpenGLContext();
    m_context->setFormat(sf);
    m_context->create();
    m_context->makeCurrent(this);

    connect(&m_timer, SIGNAL(timeout()), this, SLOT(rotate()));

    m_timer.start(33);
}

void MainWindow::rotate()
{
    m_angle += 0.5f;

    if (m_angle >= 360.0f) {
        m_angle = 0.0f;
    }

    update();
}

void MainWindow::initializeGL()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
}

void MainWindow::paintGL()
{
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glRotatef(m_angle, 1.0f, 1.0f, 1.0f);
    glScalef(0.3f, 0.3f, 0.3f);

    glBegin(GL_TRIANGLES);
        glColor3f(1.0f, 0.0f, 0.0f);

        glVertex3f( 0.0f,  1.0f,  0.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);

        glColor3f(0.0f, 1.0f, 0.0f);

        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f( 1.0f, -1.0f, 1.0f);
        glVertex3f( 0.0f,  1.0f,  0.0f);

        glColor3f(0.0f, 0.0f, 1.0f);

        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f( 0.0f,  1.0f,  0.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);

        glColor3f(1.0f, 1.0f, 0.0f);

        glVertex3f(1.0f, -1.0f,  1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);
        glVertex3f(0.0f,  1.0f,  0.0f);

        // bottom
        glColor3f(0.0f, 1.0f, 1.0f);

        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f,  1.0f);

        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f,  1.0f);
    glEnd();

    // The cube (only edges)

    glScalef(1.5f, 1.5f, 1.5f);
    glColor3f(0.0f, 0.0f, 0.0f);

    glBegin(GL_LINE_LOOP);
        glVertex3f( 1.0f,  1.0f, -1.0f);
        glVertex3f(-1.0f,  1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
    glEnd();

    glBegin(GL_LINE_LOOP);
        glVertex3f( 1.0f,  1.0f, 1.0f);
        glVertex3f(-1.0f,  1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f( 1.0f, -1.0f, 1.0f);
    glEnd();

    glBegin(GL_LINES);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);

        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);

        glVertex3f(1.0f, 1.0f, -1.0f);
        glVertex3f(1.0f, 1.0f, 1.0f);

        glVertex3f(1.0f, -1.0f, -1.0f);
        glVertex3f(1.0f, -1.0f, 1.0f);
    glEnd();

    glFlush();
}

void MainWindow::paintEvent(QPaintEvent*)
{
    paintGL();
}

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    w.resize(480, 480);
    w.show();

    return a.exec();
}

Ответы [ 3 ]

0 голосов
/ 21 сентября 2018

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

enter image description here

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

Проблема в том, что это неправильная пирамида.Позвольте мне доказать, что:

glBegin(GL_QUADS);//(GL_LINE_LOOP);
    glVertex3f( 1.0f,  1.0f, -1.0f);
    glVertex3f(-1.0f,  1.0f, -1.0f);
    glVertex3f(-1.0f, -1.0f, -1.0f);
    glVertex3f( 1.0f, -1.0f, -1.0f);
glEnd(); 

Полученное изображение:

enter image description here

Куб вращается в предполагаемом направленииэто не наизнанку.Это означает, что пирамида есть.Одна из причин этого заключается в том, что мы на самом деле видим задние лица, а не передние.

Если я преобразую ваш код для эмуляции прозрачной пирамиды, но сохраню настройки отбраковки по умолчанию:

void MainWindow::initializeGL()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

/*...*/

    glFrontFace(GL_CCW);
    glBegin(GL_TRIANGLES);
        glColor4f(1.0f, 0.0f, 0.0f, 0.3f);

        glVertex3f( 0.0f,  1.0f,  0.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);

        glColor4f(0.0f, 1.0f, 0.0f, 0.3f);

        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f( 1.0f, -1.0f, 1.0f);
        glVertex3f( 0.0f,  1.0f,  0.0f);

        glColor4f(0.0f, 0.0f, 1.0f, 0.3f);

        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f( 0.0f,  1.0f,  0.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);

        glColor4f(1.0f, 1.0f, 0.0f, 0.3f);

        glVertex3f(1.0f, -1.0f,  1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);
        glVertex3f(0.0f,  1.0f,  0.0f);

        // bottom
        glColor4f(0.0f, 1.0f, 1.0f, 0.3f);

        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f,  1.0f);

        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f,  1.0f);
    glEnd();
    glFrontFace(GL_CW);
    glBegin(GL_TRIANGLES);
        glColor4f(1.0f, 0.0f, 0.0f, 0.6f);

        glVertex3f( 0.0f,  1.0f,  0.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);

        glColor4f(0.0f, 1.0f, 0.0f, 0.6f);

        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f( 1.0f, -1.0f, 1.0f);
        glVertex3f( 0.0f,  1.0f,  0.0f);

        glColor4f(0.0f, 0.0f, 1.0f, 0.6f);

        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f( 0.0f,  1.0f,  0.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);

        glColor4f(1.0f, 1.0f, 0.0f, 0.6f);

        glVertex3f(1.0f, -1.0f,  1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);
        glVertex3f(0.0f,  1.0f,  0.0f);

        // bottom
        glColor4f(0.0f, 1.0f, 1.0f, 0.6f);

        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f,  1.0f);

        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f,  1.0f);
    glEnd();

Я получаю изображение

enter image description here

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

Но теперь, если вы посмотрите на «жирные» грани пирамиды - я намеренно сделал невидимые грани без смешения жирным, придав им большее альфа-значение - вы 'Вы увидите, что они вращаются правильно, в том же направлении, что и куб.Это означает, что ваша сетка, пирамида, на самом деле перевернута "наизнанку".С невыпуклыми фигурами, которые были бы более очевидными, с выпуклыми, которые создают иллюзию противоположного вращения.

Все, что вам нужно сделать, это изменить порядок вершин или переключиться на GL_CW для пирамиды (по умолчанию GL_CCW).enter image description here

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

Примечание: трюк, который я использовал для иллюзии прозрачности, не работает так хорошо свыпуклые цифры.Зачем?Чтобы использовать смешение цветов, вы должны нарисовать грани в порядке их проверки глубины, делая это вручную.Мой грязный трюк дважды рисует все лица, но при отбраковке удаляются те, которые стоят перед камерой во время первого прохода, и удаляются те, которые обращены лицом во время второго прохода.Для невыпуклых, которые не соответствуют порядку - есть лица, которые стоят перед камерой, но находятся дальше, чем некоторые «скрытые», неправильный порядок.Требуется больше работы.Использование гибкого конвейера действительно меняет то, как OpenGL может справиться с этим.

0 голосов
/ 23 сентября 2018

Я наконец сделал это:

#include "mainwindow.h"

MainWindow::MainWindow():
    QOpenGLWindow(),
    m_angle(0.0f)
{
    QSurfaceFormat sf;

    sf.setProfile(QSurfaceFormat::CompatibilityProfile);
    sf.setDepthBufferSize(24);
    sf.setVersion(2, 1);

    setSurfaceType(QWindow::OpenGLSurface);
    setFormat(sf);
    create();

    m_context = new QOpenGLContext(this);
    m_context->setFormat(sf);
    m_context->create();
    m_context->makeCurrent(this);

    connect(&m_timer, SIGNAL(timeout()), this, SLOT(rotate()));

    m_timer.start(33);
}

void MainWindow::rotate()
{
    m_angle += 0.5f;

    if (m_angle >= 360.0f) {
        m_angle = 0.0f;
    }

    update();
}

void MainWindow::initializeGL()
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClearDepth(-1.0f);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_GEQUAL);
}

void MainWindow::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // The Pyramid

    glLoadIdentity();
    glRotatef(m_angle, 1.0f, 1.0f, 1.0f);
    glScalef(0.33f, 0.33f, 0.33f);

    glEnable(GL_CULL_FACE);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glBegin(GL_TRIANGLES);
       // Front
       glColor3f(1.0f, 0.0f, 0.0f);
       glVertex3f( 0.0f,  1.0f, 0.0f);
       glVertex3f(-1.0f, -1.0f, 1.0f);
       glVertex3f( 1.0f, -1.0f, 1.0f);

       // Back
       glColor3f(0.0f, 1.0f, 0.0f);
       glVertex3f( 0.0f,  1.0f,  0.0f);
       glVertex3f( 1.0f, -1.0f, -1.0f);
       glVertex3f(-1.0f, -1.0f, -1.0f);

       // Left
       glColor3f(1.0f, 1.0f, 0.0f);
       glVertex3f( 0.0f,  1.0f,  0.0f);
       glVertex3f(-1.0f, -1.0f, -1.0f);
       glVertex3f(-1.0f, -1.0f,  1.0f);

       // Right
       glColor3f(1.0f, 0.0f, 1.0f);
       glVertex3f(0.0f,  1.0f,  0.0f);
       glVertex3f(1.0f, -1.0f,  1.0f);
       glVertex3f(1.0f, -1.0f, -1.0f);

       // Bottom
       glColor3f(0.0f, 1.0f, 1.0f);

       glVertex3f(-1.0f, -1.0f, -1.0f);
       glVertex3f( 1.0f, -1.0f, -1.0f);
       glVertex3f(-1.0f, -1.0f,  1.0f);

       glVertex3f(-1.0f, -1.0f,  1.0f);
       glVertex3f( 1.0f, -1.0f, -1.0f);
       glVertex3f( 1.0f, -1.0f,  1.0f);
    glEnd();

    // The Cube (edges)

    glLoadIdentity();
    glRotatef(m_angle, 1.0f, 1.0f, 1.0f);
    glScalef(0.5f, 0.5f, 0.5f);

    glDisable(GL_CULL_FACE);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glColor3f(0.0f, 0.0f, 0.0f);

    glBegin(GL_QUADS);
        // Front
        glVertex3f( 1.0f,  1.0f, -1.0f);
        glVertex3f(-1.0f,  1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);

        // Back
        glVertex3f( 1.0f,  1.0f, 1.0f);
        glVertex3f( 1.0f, -1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f(-1.0f,  1.0f, 1.0f);

        // Left
        glVertex3f(-1.0f,  1.0f,  1.0f);
        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f,  1.0f, -1.0f);

        // Right
        glVertex3f(1.0f,  1.0f,  1.0f);
        glVertex3f(1.0f,  1.0f, -1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);
        glVertex3f(1.0f, -1.0f,  1.0f);
    glEnd();

    glFlush();
}

void MainWindow::paintEvent(QPaintEvent*)
{
    paintGL();
}

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

демонстрационное изображение

Я хотел бы поблагодарить @Swift - Friday Pie и @Asaq за такие подробные ответы, которые помогли мне немного больше понять, как работает opengl.

Если кому-то интересно - я на Linux (Fedora 28), графическая карта Intel HD Graphics 530 (Skylake GT2).

0 голосов
/ 18 сентября 2018

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

Треугольники вашей пирамидыустанавливается по часовой стрелке, но по умолчанию многоугольники против часовой стрелки считаются фронтальными.Установите glFrontFace(GL_CW) или измените порядок glVertex3f.

Может кто-нибудь объяснить мне, почему треугольник рендерит поверх четырехугольника, пожалуйста?

Когда Проверка глубины активна, фрагменты будут отображаться в зависимости от их глубины.Значение глубины из фрагмента сравнивается со значением глубины из совпадающей выборки, в настоящее время находящейся в буфере кадров.Условный тест задается функцией glDepthFunc.Начальное значение glDepthFunc равно GL_LESS.

В вашем примере глубина фрагментов треугольника МЕНЬШЕ, чем глубина фрагментов квадрата, поэтому треугольник находится над квадратом.

enter image description here

...