Qt OpenGL 天空盒

这里写图片描述

Author

This is the work of Emil Persson, aka Humus.
http://www.humus.name

License

This work is licensed under a Creative Commons Attribution 3.0 Unported License.
http://creativecommons.org/licenses/by/3.0/

main.cpp

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

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    GLWidget glw;
    glw.resize(600, 600);
    glw.show();

    return a.exec();
}

glwidget.cpp

#include "glwidget.h"
#include "skybox.h"
#include "torus.h"

#include <QMatrix4x4>

struct GLWidgetData
{
    QMatrix4x4 projectionMatrix;
    QMatrix4x4 viewMatrix;

    SkyBox skyBox;
    Torus torus;
};

GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    d = new GLWidgetData;

    QSurfaceFormat format;
    format.setSamples(4);
    setFormat(format);
}

GLWidget::~GLWidget()
{
    delete d;
}

void GLWidget::initializeGL()
{
    QOpenGLFunctions::initializeOpenGLFunctions();

    glClearColor(0.25, 0.35, 0.45, 1);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_POLYGON_OFFSET_LINE);
    glPolygonOffset(-0.03125f, -0.03125f);
}

void GLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);

    d->projectionMatrix.setToIdentity();
    d->projectionMatrix.perspective(60.0, float(w)/float(h), 0.1f, 20.0f);

    d->viewMatrix.setToIdentity();
}

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

    d->skyBox.render(d->viewMatrix, d->projectionMatrix);
    d->torus.render(d->viewMatrix, d->projectionMatrix);
}

skybox.cpp

#include "skybox.h"

#include <QMatrix4x4>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>

struct SkyBoxData
{
    SkyBoxData() {
        for(int i=0; i<6; i++)
            this->textures[i] = 0;
        this->vertexBuffer = 0;
        this->indexBuffer = 0;
        this->shader = 0;
    }
    ~SkyBoxData() {
        delete this->shader;
        delete this->indexBuffer;
        delete this->vertexBuffer;
        for(int i=5; i>=0; i--)
            delete this->textures[i];
    }

    QOpenGLTexture *textures[6];
    QOpenGLBuffer *vertexBuffer;
    QOpenGLBuffer *indexBuffer;
    QOpenGLShaderProgram *shader;
    QMatrix4x4 matrix;
};

SkyBox::SkyBox()
{
    d = new SkyBoxData;
}

SkyBox::~SkyBox()
{
    delete d;
}

void SkyBox::render(const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix)
{
    this->init();

    d->shader->bind();
    d->vertexBuffer->bind();
    d->indexBuffer->bind();

    d->shader->enableAttributeArray("qt_Vertex");
    d->shader->setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 3, 0);

    d->shader->enableAttributeArray("qt_MultiTexCoord0");
    const int texCoordsOffset = 24 * sizeof(QVector3D);
    d->shader->setAttributeBuffer("qt_MultiTexCoord0", GL_FLOAT, texCoordsOffset, 2, 0);

    d->matrix.rotate(-1, 0, 1, 0);

    QMatrix4x4 modelMatrix = d->matrix;
    modelMatrix.scale(10, 10, 10);

    const QMatrix4x4 mvp = projectionMatrix * viewMatrix * modelMatrix;
    d->shader->setUniformValue("qt_ModelViewProjectionMatrix", mvp);

    for(int i=0; i<6; i++)
    {
        d->textures[i]->bind(i+1);
        d->shader->setUniformValue("qt_Texture0", (i+1));

        const uint triangleOffset = i*6*sizeof(uint);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)triangleOffset);

        d->textures[i]->release(i+1);
    }

    d->indexBuffer->release();
    d->vertexBuffer->release();
    d->shader->release();
}

void SkyBox::init()
{
    if(d->shader)
        return;

    QOpenGLFunctions::initializeOpenGLFunctions();

    // Load all texture images
    const QImage posx = QImage(":/images/posx.jpg").mirrored();
    const QImage posy = QImage(":/images/posy.jpg").mirrored();
    const QImage posz = QImage(":/images/posz.jpg").mirrored();
    const QImage negx = QImage(":/images/negx.jpg").mirrored();
    const QImage negy = QImage(":/images/negy.jpg").mirrored();
    const QImage negz = QImage(":/images/negz.jpg").mirrored();

    // Load images as independent texture objects
    d->textures[0] = new QOpenGLTexture(posx);
    d->textures[1] = new QOpenGLTexture(posy);
    d->textures[2] = new QOpenGLTexture(posz);
    d->textures[3] = new QOpenGLTexture(negx);
    d->textures[4] = new QOpenGLTexture(negy);
    d->textures[5] = new QOpenGLTexture(negz);
    for(int i=0; i<6; i++)
    {
        d->textures[i]->setWrapMode(QOpenGLTexture::ClampToEdge);
        d->textures[i]->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
        d->textures[i]->setMagnificationFilter(QOpenGLTexture::Linear);
    }

    // Construct a template square of size 2x2
    const QVector3D p1(-1, 1, 0); // top-left
    const QVector3D p2(-1, -1, 0); // bottom-left
    const QVector3D p3(1, -1, 0); // bottom-right
    const QVector3D p4(1, 1, 0); // top-right

    // Array for storing geometry of the cube
    QVector<QVector3D> geometry;
    geometry.reserve(24);

    // Transform p1 ... p4 for posx
    QMatrix4x4 mat;
    mat.translate(1, 0, 0);
    mat.rotate(-90, 0, 1, 0);
    geometry << mat.map(p1) << mat.map(p2)
             << mat.map(p3) << mat.map(p4);

    // Transform p1 ... p4 for posy
    mat.setToIdentity();
    mat.translate(0, 1, 0);
    mat.rotate(90, 1, 0, 0);
    geometry << mat.map(p1) << mat.map(p2)
             << mat.map(p3) << mat.map(p4);

    // Transform p2 ... p4 for posz
    mat.setToIdentity();
    mat.translate(0, 0, -1);
    geometry << mat.map(p1) << mat.map(p2)
             << mat.map(p3) << mat.map(p4);

    // Transform p2 ... p4 for negx
    mat.setToIdentity();
    mat.translate(-1, 0, 0);
    mat.rotate(90, 0, 1, 0);
    geometry << mat.map(p1) << mat.map(p2)
             << mat.map(p3) << mat.map(p4);

    // Transform p2 ... p4 for negy
    mat.setToIdentity();
    mat.translate(0, -1, 0);
    mat.rotate(-90, 1, 0, 0);
    geometry << mat.map(p1) << mat.map(p2)
             << mat.map(p3) << mat.map(p4);

    // Transform p2 ... p4 for negz
    mat.setToIdentity();
    mat.translate(0, 0, 1);
    mat.rotate(180, 0, 1, 0);
    geometry << mat.map(p1) << mat.map(p2)
             << mat.map(p3) << mat.map(p4);

    // Texture coordinates
    QVector<QVector2D> texCoords;
    texCoords.reserve(24);
    for(int i=0; i<6; i++)
    {
        texCoords << QVector2D(0, 1)
                  << QVector2D(0, 0)
                  << QVector2D(1, 0)
                  << QVector2D(1, 1);
    }

    // Triangles
    QVector<uint> triangles;
    triangles.reserve(36);
    for(int i=0; i<6; i++)
    {
        const int base = i*4;
        triangles << base << base+1 << base+2;
        triangles << base << base+2 << base+3;
    }

    // Store the arrays in buffers
    d->vertexBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    d->vertexBuffer->create();
    d->vertexBuffer->bind();
    d->vertexBuffer->allocate( geometry.size()*sizeof(QVector3D) +
                               texCoords.size()*sizeof(QVector2D) );
    d->vertexBuffer->write(0, (const void *)geometry.constData(),
                           geometry.size()*sizeof(QVector3D) );
    d->vertexBuffer->write(geometry.size()*sizeof(QVector3D),
                           (const void *)texCoords.constData(),
                           texCoords.size()*sizeof(QVector2D) );
    d->vertexBuffer->release();

    d->indexBuffer = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
    d->indexBuffer->create();
    d->indexBuffer->bind();
    d->indexBuffer->allocate((const void*)triangles.constData(),
                             triangles.size()*sizeof(uint));
    d->indexBuffer->release();

    // Create shaders
    d->shader = new QOpenGLShaderProgram;
    d->shader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/skybox_vertex.glsl");
    d->shader->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/skybox_fragment.glsl");
    d->shader->link();
}


torus.cpp

#include "torus.h"

#include <QColor>
#include <QMatrix4x4>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>

struct TorusData
{
    TorusData() :
        tubeRadius(0.3), torusRadius(1.0),
        tubeResolution(20), torusResolution(40),
        vertexBuffer(0), indexBuffer(0), shader(0),
        angle(0) { }
    ~TorusData() {
        delete vertexBuffer;
        delete indexBuffer;
        delete shader;
    }

    const float tubeRadius;
    const float torusRadius;
    const int tubeResolution;
    const int torusResolution;

    QOpenGLTexture *environment;
    QOpenGLBuffer *vertexBuffer;
    QOpenGLBuffer *indexBuffer;
    QOpenGLShaderProgram *shader;

    float angle;
};

Torus::Torus()
{
    d = new TorusData;
}

Torus::~Torus()
{
    delete d;
}

void Torus::render(const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix)
{
    this->init();

    d->shader->bind();
    d->vertexBuffer->bind();
    d->indexBuffer->bind();

    d->shader->enableAttributeArray("qt_Vertex");
    d->shader->setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 3, 2*sizeof(QVector3D));

    d->shader->enableAttributeArray("qt_Normal");
    d->shader->setAttributeBuffer("qt_Normal", GL_FLOAT, sizeof(QVector3D), 3, 2*sizeof(QVector3D));

    QMatrix4x4 modelMatrix;
    modelMatrix.translate(0, 0, -3.0);
    modelMatrix.rotate(d->angle, 0, 1, 0);
    d->angle += 5;

    const QMatrix4x4 mvMat = viewMatrix * modelMatrix;
    const QMatrix4x4 normalMat = mvMat.inverted().transposed();
    d->shader->setUniformValue("qt_ModelViewMatrix", mvMat);
    d->shader->setUniformValue("qt_ProjectionMatrix", projectionMatrix);
    d->shader->setUniformValue("qt_NormalMatrix", normalMat);

    d->shader->setUniformValue("qt_EyePosition", QVector3D(0,0,-1));

    d->shader->setUniformValue("qt_Light.direction", QVector3D(1,1,1));
    d->shader->setUniformValue("qt_Light.ambientColor", QColor(Qt::gray));
    d->shader->setUniformValue("qt_Light.diffuseColor", QColor(Qt::white));
    d->shader->setUniformValue("qt_Light.specularColor", QColor(Qt::white));

    d->shader->setUniformValue("qt_Material.ambientColor", QColor(Qt::gray).darker());
    d->shader->setUniformValue("qt_Material.diffuseColor", QColor(Qt::gray).lighter());
    d->shader->setUniformValue("qt_Material.specularColor", QColor(Qt::white));
    d->shader->setUniformValue("qt_Material.specularPower", 0.9f);
    d->shader->setUniformValue("qt_Material.opacity", 1.0f);
    d->shader->setUniformValue("qt_Material.brightness", 2.0f);

    d->environment->bind(0);
    d->shader->setUniformValue("qt_Environment", 0);

    glEnable(GL_CULL_FACE);
    glCullFace(GL_CCW);

    const int nrIndicies = d->torusResolution * d->tubeResolution * 6;
    glDrawElements(GL_TRIANGLES, nrIndicies, GL_UNSIGNED_INT, (void*)0);

    glDisable(GL_CULL_FACE);

    d->indexBuffer->release();
    d->vertexBuffer->release();
    d->environment->release(0);
    d->shader->release();
}

void Torus::init()
{
    if(d->shader)
        return;

    QOpenGLFunctions::initializeOpenGLFunctions();

    d->vertexBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    d->vertexBuffer->create();
    d->vertexBuffer->bind();
    d->vertexBuffer->allocate(d->tubeResolution * d->torusResolution * sizeof(QVector3D) * 2);

    d->indexBuffer = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
    d->indexBuffer->create();
    d->indexBuffer->bind();
    d->indexBuffer->allocate( d->torusResolution * d->tubeResolution * 6 * sizeof(uint) );

    QMatrix4x4 matrix;
    const float tubeAngleStep = 360.0f / float(d->tubeResolution-1);
    const float torusAngleStep = 360.0f / float(d->torusResolution-1);

    int vertexBufferOffset = 0;
    for(int i=0; i<d->torusResolution; i++)
    {
        QMatrix4x4 tmp = matrix;
        tmp.translate(d->torusRadius, 0, 0);

        const QVector3D centerPt = tmp.map(QVector3D(0,0,0));
        for(int j=0; j<d->tubeResolution; j++)
        {
            const QVector3D pt = tmp.map( QVector3D(d->tubeRadius, 0, 0) );
            d->vertexBuffer->write(vertexBufferOffset, &pt, sizeof(pt));
            vertexBufferOffset += sizeof(pt);

            const QVector3D normal = (pt - centerPt).normalized();
            d->vertexBuffer->write(vertexBufferOffset, &normal, sizeof(normal));
            vertexBufferOffset += sizeof(normal);
            tmp.rotate(tubeAngleStep, QVector3D(0,1,0));
        }

        matrix.rotate(torusAngleStep, QVector3D(0,0,1));
    }

    int indexBufferOffset = 0;
    int base = 0;
    const int nrPoints = (d->torusResolution * d->tubeResolution);
#define P(x) (x)%nrPoints
    for(int i=0; i<d->torusResolution; i++)
    {
        for(int j=0; j<d->tubeResolution; j++)
        {
            const uint tgls[] = {
                                    P(base),
                                    P(base+1),
                                    P(base+1+d->tubeResolution),
                                    P(base),
                                    P(base+1+d->tubeResolution),
                                    P(base+d->tubeResolution)
                                };
            d->indexBuffer->write(indexBufferOffset, (const void*)tgls, sizeof(uint)*6);
            indexBufferOffset += sizeof(uint)*6;
            ++base;
        }
#undef P
    }

    d->indexBuffer->release();
    d->vertexBuffer->release();

    // Load all environment texture images
    const QImage posx = QImage(":/images/posx.jpg").mirrored().convertToFormat(QImage::Format_RGBA8888);
    const QImage posy = QImage(":/images/posy.jpg").mirrored().convertToFormat(QImage::Format_RGBA8888);
    const QImage posz = QImage(":/images/posz.jpg").mirrored().convertToFormat(QImage::Format_RGBA8888);
    const QImage negx = QImage(":/images/negx.jpg").mirrored().convertToFormat(QImage::Format_RGBA8888);
    const QImage negy = QImage(":/images/negy.jpg").mirrored().convertToFormat(QImage::Format_RGBA8888);
    const QImage negz = QImage(":/images/negz.jpg").mirrored().convertToFormat(QImage::Format_RGBA8888);

    // Construct the environment texture
    d->environment = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
    d->environment->create();
    d->environment->setSize(posx.width(), posx.height(), posx.depth());
    d->environment->setFormat(QOpenGLTexture::RGBA8_UNorm);
    d->environment->allocateStorage();
    d->environment->setData(0, 0, QOpenGLTexture::CubeMapPositiveX,
                            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
                            (const void*)posx.constBits(), 0);
    d->environment->setData(0, 0, QOpenGLTexture::CubeMapPositiveY,
                            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
                            (const void*)posy.constBits(), 0);
    d->environment->setData(0, 0, QOpenGLTexture::CubeMapPositiveZ,
                            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
                            (const void*)posz.constBits(), 0);
    d->environment->setData(0, 0, QOpenGLTexture::CubeMapNegativeX,
                            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
                            (const void*)negx.constBits(), 0);
    d->environment->setData(0, 0, QOpenGLTexture::CubeMapNegativeY,
                            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
                            (const void*)negy.constBits(), 0);
    d->environment->setData(0, 0, QOpenGLTexture::CubeMapNegativeZ,
                            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
                            (const void*)negz.constBits(), 0);
    d->environment->generateMipMaps();
    d->environment->setWrapMode(QOpenGLTexture::ClampToEdge);
    d->environment->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    d->environment->setMagnificationFilter(QOpenGLTexture::LinearMipMapLinear);

    // Load and link shader programs
    d->shader = new QOpenGLShaderProgram;
    d->shader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/torus_vertex.glsl");
    d->shader->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/torus_fragment.glsl");
    d->shader->link();

    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}

skybox_fragment.glsl

uniform sampler2D qt_Texture0;
varying vec4 qt_TexCoord0;

void main(void)
{
    gl_FragColor = texture2D(qt_Texture0, qt_TexCoord0.st);
}

skybox_vertex.glsl

attribute vec4 qt_Vertex;
attribute vec4 qt_MultiTexCoord0;
uniform mat4 qt_ModelViewProjectionMatrix;
varying vec4 qt_TexCoord0;

void main(void)
{
    gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;
    qt_TexCoord0 = qt_MultiTexCoord0;
}

torus_vertex.glsl

attribute vec3 qt_Vertex;
attribute vec3 qt_Normal;

uniform mat4 qt_NormalMatrix;
uniform mat4 qt_ModelViewMatrix;
uniform mat4 qt_ProjectionMatrix;

varying vec3 v_Position;
varying vec3 v_Normal;
varying vec3 v_TexCoord;

const float c_zero = 0.0;
const float c_one = 1.0;

void main(void)
{
    vec4 normal = normalize( qt_NormalMatrix * vec4(qt_Normal, c_zero) );
    v_Normal = normal.xyz;

    vec4 position = qt_ModelViewMatrix * vec4(qt_Vertex, c_one);
    v_Position = position.xyz;

    v_TexCoord = v_Normal;

    mat4 mat = qt_ProjectionMatrix * qt_ModelViewMatrix;
    gl_Position = mat * vec4(qt_Vertex, c_one);
}

torus_fragment.glsl

struct directional_light
{
    vec3 direction;
    vec4 ambientColor;
    vec4 diffuseColor;
    vec4 specularColor;
};

struct material_properties
{
    vec4 ambientColor;
    vec4 diffuseColor;
    vec4 specularColor;
    float specularPower;
    float opacity;
    float brightness;
};

uniform directional_light qt_Light;
uniform material_properties qt_Material;
uniform vec3 qt_EyePosition;
uniform samplerCube qt_Environment;

varying vec3 v_Position;
varying vec3 v_Normal;
varying vec3 v_TexCoord;

const float c_zero = 0.0;
const float c_one = 1.0;

vec4 evaluateColor(in vec3 normal, in vec3 texCoord)
{
    // Start with black color
    vec3 finalColor = vec3(c_zero, c_zero, c_zero);

    // Upgrade black color to the base ambient color
    finalColor += qt_Light.ambientColor.rgb * qt_Material.ambientColor.rgb;

    // Add diffuse component to it
    vec3 lightDir = normalize(qt_Light.direction);
    float diffuseFactor = max( c_zero, dot(lightDir, normal) );
    if(diffuseFactor > c_zero)
    {
        finalColor += qt_Light.diffuseColor.rgb *
                qt_Material.diffuseColor.rgb *
                diffuseFactor * qt_Material.brightness;
    }

    // Add specular component to it
    vec3 viewDir = normalize(qt_EyePosition - v_Position);
    vec3 reflectionVec = reflect(viewDir, normal);
    const vec3 blackColor = vec3(c_zero, c_zero, c_zero);
    if( !(qt_Material.specularColor.rgb == blackColor ||
          qt_Light.specularColor.rgb == blackColor ||
          qt_Material.specularPower == c_zero) )
    {
        float specularFactor = max( c_zero, dot(reflectionVec, -viewDir) );
        if(specularFactor > c_zero)
        {
            specularFactor = pow( specularFactor, qt_Material.specularPower );
            finalColor += qt_Light.specularColor.rgb *
                    qt_Material.specularColor.rgb *
                    specularFactor;
        }
    }

    // Texture mapping
    finalColor *= textureCube(qt_Environment, reflectionVec).rgb;

    // All done!
    return vec4( finalColor, c_one );
}

void main(void)
{
    gl_FragColor = evaluateColor(v_Normal, v_TexCoord);
}

源码: http://download.csdn.net/detail/yulinxx/9873347

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值