How to creating a skybox using samplerCube and the QOpenGLTexture class?



  • Hi, I'm trying to create a skybox using the samplerCube mapping in the shader program. As I understand it, it should be possible to use the coordinates of the skybox vertices for mapping the texture to the skybox. I would like to do this using the QOpenGLTexture class.

    Does any one know how to setup the QOpenGLTexture to use samplerCube mapping? I would like to use a texture that looks like this one: http://www.keithlantz.net/wp-content/uploads/2011/10/skybox_texture.jpg (from http://www.keithlantz.net/2011/10/rendering-a-skybox-using-a-cube-map-with-opengl-and-glsl/) Guess I should use QOpenGLTexture::BindingTargetCubeMap somehow(?).

    Here is a short example program where I try to implement a skybox:

    main.cpp
    @
    int main(int argc, char **argv)
    {
    QGuiApplication app(argc, argv);
    // Setup OpenGL window
    OpenGLWindow window;
    return app.exec();
    }
    @

    OpenGLWindow.hpp
    @
    #include "Skybox.hpp"

    class OpenGLWindow : public QWindow, protected QOpenGLFunctions
    {
    Q_OBJECT

    Skybox* m_skybox;
    bool m_update_pending;
    bool m_animating;

    QOpenGLContext *m_context;
    QOpenGLShaderProgram m_program;

    QMatrix4x4 m_projectionMatrix;

    QOpenGLVertexArrayObject m_vao;

    public:
    explicit OpenGLWindow(QWindow *parent = 0)
    : QWindow(parent)
    , m_update_pending(false)
    , m_animating(true)
    , m_context(0)
    {
    setSurfaceType(OpenGLSurface);
    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    format.setMajorVersion(3);
    format.setMinorVersion(3);
    format.setProfile(QSurfaceFormat::CoreProfile);
    setFormat(format);
    resize(640, 480);
    show();
    create();

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

    initializeOpenGLFunctions();

    m_vao.create();
    m_vao.bind();

    m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, "simple.vert");
    m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "simple.frag");
    m_program.link()

    m_skybox = new Skybox(m_program);

    m_projectionMatrix.setToIdentity();
    m_projectionMatrix.perspective(90.0f, 640.0f/480.0f, 0.1f, 30.0f);

    glViewport(0, 0, width(), height());
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    }

    void render()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_CULL_FACE);

    m_program.bind();

    glDisable(GL_DEPTH_TEST);
    // Set camera position
    QMatrix4x4 viewMatrix;
    viewMatrix.setToIdentity();
    QVector3D eye(0.0f, 0.0f, 0.0f);
    QVector3D center(1.0f, 1.0f, 1.0f);
    QVector3D up(0.0f, 1.0f, 0.0f);
    viewMatrix.lookAt(eye, center, up);

    // Render skybox
    m_skybox->draw(viewMatrix, m_projectionMatrix);

    glEnable(GL_DEPTH_TEST);

    // Render other stuff .....
    }

    void setAnimating(bool animating)
    {
    m_animating = animating;

    if (animating)
    renderLater();
    }

    public slots:
    void renderLater()
    {
    if (!m_update_pending)
    {
    m_update_pending = true;
    QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
    }
    }

    void renderNow()
    {
    if (!isExposed())
    return;

    m_context->makeCurrent(this);

    render();

    m_context->swapBuffers(this);

    if (m_animating)
    renderLater();
    }

    protected:
    bool event(QEvent *event)
    {
    switch (event->type()) {
    case QEvent::UpdateRequest:
    m_update_pending = false;
    renderNow();
    return true;
    default:
    return QWindow::event(event);
    }
    }
    void exposeEvent(QExposeEvent *event)
    {
    Q_UNUSED(event);

    if (isExposed())
    renderNow();
    }
    };
    @

    Skybox.hpp
    @
    #define NUMB_VER 36

    class Skybox
    {
    private:
    static QOpenGLBuffer m_vertexPositionBuffer;
    static const GLfloat m_vertices[NUMB_VER*3];
    QOpenGLShaderProgram& m_program;
    QOpenGLTexture m_texture;

    public:
    ~Skybox(){};

    explicit Skybox(QOpenGLShaderProgram& program)
    : m_program(program)
    , m_texture(QImage(QString("skybox_texture.jpg")).mirrored())
    {
    m_vertexPositionBuffer.create();
    m_vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
    m_vertexPositionBuffer.bind();
    m_vertexPositionBuffer.allocate(m_vertices, NUMB_VER3sizeof(GLfloat));

    m_texture.setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    m_texture.setMagnificationFilter(QOpenGLTexture::Linear);
    }

    inline void draw(const QMatrix4x4& viewMatrix, const QMatrix4x4& projectionMatrix)
    {
    // Remove translates but keep rotations of the camera
    QMatrix4x4 modelViewMatrix = viewMatrix;
    modelViewMatrix.setColumn(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));

    const QMatrix3x3 normalMatrix = modelViewMatrix.normalMatrix();
    const QMatrix4x4 mvp = projectionMatrix * modelViewMatrix;

    m_program.bind();
    m_program.setUniformValue("modelViewMatrix", modelViewMatrix);
    m_program.setUniformValue("normalMatrix", normalMatrix);
    m_program.setUniformValue("projectionMatrix", projectionMatrix);
    m_program.setUniformValue("mvp", mvp);

    m_vertexPositionBuffer.bind();
    m_program.enableAttributeArray("vertexPosition");
    m_program.setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3);

    m_texture.bind();

    glDrawArrays(GL_TRIANGLES, 0, NUMB_VER);
    }
    };
    @

    Skybox.cpp
    @
    #include "Skybox.hpp"

    QOpenGLBuffer Skybox::m_vertexPositionBuffer;

    const GLfloat Skybox::m_vertices[NUMB_VER*3] =
    {
    -1.0f, 1.0f, -1.0f,
    -1.0f, -1.0f, -1.0f,
    1.0f, -1.0f, -1.0f,
    1.0f, -1.0f, -1.0f,
    1.0f, 1.0f, -1.0f,
    -1.0f, 1.0f, -1.0f,

    -1.0f, -1.0f, 1.0f,
    -1.0f, -1.0f, -1.0f,
    -1.0f, 1.0f, -1.0f,
    -1.0f, 1.0f, -1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f, -1.0f, 1.0f,

    1.0f, -1.0f, -1.0f,
    1.0f, -1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, -1.0f,
    1.0f, -1.0f, -1.0f,

    -1.0f, -1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, -1.0f, 1.0f,
    -1.0f, -1.0f, 1.0f,

    -1.0f, 1.0f, -1.0f,
    1.0f, 1.0f, -1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, -1.0f,

    -1.0f, -1.0f, -1.0f,
    -1.0f, -1.0f, 1.0f,
    1.0f, -1.0f, -1.0f,
    1.0f, -1.0f, -1.0f,
    -1.0f, -1.0f, 1.0f,
    1.0f, -1.0f, 1.0f
    };
    @

    Thanks in advance!



  • ... and here are the shader programs

    simple.vert
    @
    #version 330

    in vec3 vertexPosition;

    uniform mat4 modelViewMatrix;
    uniform mat4 normalMatrix;
    uniform mat4 projectionMatrix;
    uniform mat4 mvp;

    //uniform sampler2D texUnit1;
    uniform samplerCube texUnit1;

    out vec3 position;

    void main()
    {
    position = vertexPosition;

    gl_Position = mvp*vec4(vertexPosition, 1.0);
    }
    @

    simple.frag
    @
    #version 330

    in vec3 position;

    //uniform sampler2D texUnit1;
    uniform samplerCube texUnit1;

    out vec4 gl_Color;

    void main()
    {
    gl_Color = texture(texUnit1, position);
    }
    @



  • You need to use manual upload of each cube face using:

    http://qt-project.org/doc/qt-5/qopengltexture.html#setData



  • Hi,

    Do you find a way to use it ? I tried it, but impossible I have a read access violation ... Could you please send an example ?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.