[OpenGL] Shadow Map 阴影

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZJU_fish1996/article/details/83242345

                                   图:随着键盘控制点光源位置移动,阴影发生实时的变换

        之前在 https://blog.csdn.net/ZJU_fish1996/article/details/51932954 一文中已经介绍了shadow map的基本原理,至今为止,它依旧是在游戏开发中运用较(最?)广的一种阴影技术。本文是自己花了周末放假两天的时间,做的一个单点光源版的低精度硬阴影纹理,且有些地方比较偷懒,比如第一次pass仅记录了需要生成阴影物体的深度(即图中的cube),而第二次pass中绘制阴影时仅对阴影投射的物体(即图中的平面) 进行深度比较,某种程度上避开了shadow map存在的浮点精度误差的缺陷。

基本原理

        关于阴影,从理解上最直观的定义是灯光照不到的位置,以这一定义为基础,我们可以这样判断某一点是否落在阴影下:

        在以灯光为中心的观察坐标系中,该点和灯光之间进行连线,如果线段中有其它遮挡物,那么该点在阴影中;如果没有遮挡物,那么该点被光照射。这和做z-buffer运算计算遮挡关系非常类似,从这个角度来看,如果该点的深度大于深度模板中记录的深度,那么该点在阴影中;如果该点的深度等于模板中的深度,那么该点被光照射。

        最终,我们需要至少绘制两次:第一次把物体转换到灯光视图空间下,获取并写入深度到纹理。第二次将物体转换到相机视图空间下,并同时记录单个物体转换到灯光视图空间下的深度信息,用该深度信息与深度纹理进行比较,判断像素点是否在阴影中,如果在,按照正常的变换计算出颜色后,给颜色乘以一个阴影系数。

实现细节

        (1) 深度计算最终取的值是投影空间的z值,该z值需要在片元着色器中除以远裁剪面保证归一化。不同的光源对应的投影矩阵有所差异,点光源对应透视矩阵,而平行光源对应正交矩阵。远近裁剪面差值较小时纹理精度会比较大,但是这将不利于表现大场景,且数值较大的裁剪面取得的深度能够更接近线性。也就是说,远近裁剪面的选取对算法的效果有一定影响。

        (2) 在写入阴影深度纹理时,同样的,我们依然简单使用了整数帧缓冲区,对浮点深度进行编码存在rgba分量中,在使用的时候再进行解码。精度越高的纹理效果表现越好,锯齿效果越不明显,但也会耗费一定性能。

        (3) 我们在片元着色器进行深度的比较。深度的比较需要在同一个坐标系下进行,才能保证比较的正确性,在这里,我们把物体都转换到灯光视角空间下进行对比。一个要点是,在第二次绘制,对某个像素点进行深度比较时,我们需要在阴影贴图中找到它对应的像素点。经过透视变换,顶点被转换到齐次裁剪空间坐标,此时x,y分布在[-1,1]之间,而纹理uv坐标的取值范围为[0,1],我们经过x' = 0.5 * x + 0.5的运算可将前者映射到后者范围中,再根据该值作为纹理索引去取对应位置的深度即可。

        (4) 对于不在阴影中的物体,两者深度值是一样的,此时进行浮点数相等比较可能存在误差,会导致画面产生波纹,进行比较的时候需要尽可能排除这一影响,如两个深度差值到达了一个临界值才认为它们是不相等的。

代码部分

        vShader0.glsl

        记录物体在灯光视角空间下的深度。

uniform mat4 ProjectMatrix;
uniform mat4 LightMatrix;
uniform mat4 ModelMatrix;

attribute vec4 a_position;

varying float v_depth;


void main()
{
    gl_Position = ModelMatrix * a_position;
    gl_Position = LightMatrix * gl_Position;
    gl_Position = ProjectMatrix * gl_Position;
    v_depth = gl_Position.z;
}

        fShader0.glsl

        归一化深度并编码(未做线性处理),存在256位RGBA通道的颜色缓冲区中。

varying float v_depth;
uniform float zFar;

void main()
{
    float fColor = v_depth / zFar;
    float fR, fB, fG, fA;
    fColor = modf(fColor * 256, fR);
    fColor = modf(fColor * 256, fG);
    fColor = modf(fColor * 256, fB);
    fColor = modf(fColor * 256, fA);
    gl_FragColor = vec4(fR/256,fG/256,fB/256,fA/256);
}

        vShader1.glsl

        将物体变换到视点空间下,并且同时记录它在灯光视图空间下的位置信息。(该例子中,主要针对的是两个平面)

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectMatrix;
uniform mat4 LightMatrix;

attribute vec4 a_position;
varying vec4 lightPos;

attribute vec3 a_normal;
varying vec3 v_normal;

void main()
{
    v_normal = a_normal;
    gl_Position = ProjectMatrix * (ViewMatrix * (ModelMatrix * a_position));
    lightPos = ProjectMatrix * (LightMatrix * (ModelMatrix * a_position));
}

        fShader1.glsl

        解码纹理里深度,获取当前像素点的深度,以及对应纹理的深度,进行比较并判断是否在纹理中。对当前像素进行简单光照计算,最后乘以阴影系数。

uniform sampler2D ShadowMap;
uniform vec3 lightLocation;
varying vec4 lightPos;
varying vec3 v_normal;
uniform mat4 IT_ModelMatrix;
uniform float zFar;


float GetShadow()
{
    float fShadow = 1.0;
    float fDistance = lightPos.z / zFar;

    vec2 uv = lightPos.xy / lightPos.w * 0.5 + vec2(0.5, 0.5);

    vec4 fFactor = vec4(1,65536.0/16777216.0,256.0/16777216.0,1.0/16777216.0);
    vec4 distance = texture2D(ShadowMap, uv);
    float fDistanceMap = dot(distance, fFactor);


    if(fDistance - 0.009 > fDistanceMap)
    {
        fShadow = 0.4;
    }

    return fShadow;
}

void main()
{
    float fShadow = GetShadow();

    vec3 ambient = vec3(0.3,0.3,0.3);
    vec3 worldLightLocation = normalize(lightLocation);
    vec3 worldNormal = normalize(mat3(IT_ModelMatrix) * v_normal);
    vec3 diffuseColor = vec3(0.4,0.4,0.4);
    vec3 diffuse = diffuseColor * clamp(dot(worldNormal,worldLightLocation), 0, 1);

    vec4 color = vec4(ambient + diffuse, 1);
    gl_FragColor = color * fShadow;
}

        vShader1.glsl

         为了偷懒添加的,对图中立方体做最简单的变换,不考虑阴影和光照,仅单独贴了一个纹理。

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectMatrix;

attribute vec2 a_texcoord;
attribute vec4 a_position;
varying vec2 v_texcoord;

void main()
{
    gl_Position = ProjectMatrix * (ViewMatrix * (ModelMatrix * a_position));
    v_texcoord = a_texcoord;
}

        fShader1.glsl

        同上,仅应用于图中立方体。

uniform sampler2D texture;
varying vec2 v_texcoord;
void main()
{
    gl_FragColor = texture2D(texture, v_texcoord);
}

        mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include "geometryengine.h"

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QMatrix4x4>
#include <QVector2D>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QBasicTimer>

class GeometryEngine;

class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit MainWidget(QWidget *parent = nullptr);
    ~MainWidget() override;

protected:
    void keyPressEvent(QKeyEvent* event) override;

    void initializeGL() override;
    void resizeGL(int w, int h) override;
    void paintGL() override;
    void mousePressEvent(QMouseEvent *e) override;
    void mouseReleaseEvent(QMouseEvent *e) override;
    void timerEvent(QTimerEvent *e) override;


private:

    QQuaternion rotation;
    QBasicTimer timer;
    QVector2D mousePressPosition;
    QVector3D rotationAxis;
    qreal angularSpeed;

    GLuint shadowMap;
    GLuint fBO;

    float zFar = 100.0f;
    int screenX = 640;
    int screenY = 480;


    QMatrix4x4 lightMatrix;
    QMatrix4x4 viewMatrix;
    QMatrix4x4 projection;

    QVector3D lightPos = QVector3D(10, 20, 4);
    QVector3D eyeLocation = QVector3D(0, 0, 20);
    QVector3D lookAtLocation = QVector3D(0, 0, 0);

    GeometryEngine *geometries;

    QOpenGLTexture *texture;

    QOpenGLShaderProgram program0;
    QOpenGLShaderProgram program;
    QOpenGLShaderProgram program1;


    void CalculateViewMatrix();
    void CalculateLightMatrix();

};

#endif // MAINWIDGET_H

        mainwidget.cpp

#include "mainwidget.h"
#include <QMouseEvent>
#include <math.h>

MainWidget::MainWidget(QWidget *parent) :
    QOpenGLWidget(parent),
    angularSpeed(0),
    geometries(nullptr)
{

}

MainWidget::~MainWidget()
{
    makeCurrent();
    delete geometries;
    doneCurrent();
}

void MainWidget::keyPressEvent(QKeyEvent* event)
{
    const float step = 0.3f;
    if(event->key() == Qt::Key_W)
    {
        lightPos.setZ(lightPos.z() - step);
        CalculateLightMatrix();
        update();
    }
    else if(event->key() == Qt::Key_S)
    {
        lightPos.setZ(lightPos.z() + step);
        CalculateLightMatrix();
        update();
    }
    else if(event->key() == Qt::Key_A)
    {
        lightPos.setX(lightPos.x() - step);
        CalculateLightMatrix();
        update();
    }
    else if(event->key() == Qt::Key_D)
    {
        lightPos.setX(lightPos.x() + step);
        CalculateLightMatrix();
        update();
    }
    else if(event->key() == Qt::Key_Q)
    {
        lightPos.setY(lightPos.y() + step);
        CalculateLightMatrix();
        update();
    }
    else if(event->key() == Qt::Key_E)
    {
        lightPos.setY(lightPos.y() - step);
        CalculateLightMatrix();
        update();
    }
}

void MainWidget::initializeGL()
{
    initializeOpenGLFunctions();

    CalculateViewMatrix();
    CalculateLightMatrix();
    // 清屏颜色
    glClearColor(0, 0, 0, 0);

    // 开启剔除
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    // add shader 0
    QOpenGLShader* vShader0 = new QOpenGLShader(QOpenGLShader::Vertex);
    QOpenGLShader* fShader0 = new QOpenGLShader(QOpenGLShader::Fragment);

    vShader0->compileSourceFile(":/vShader0.glsl");
    fShader0->compileSourceFile(":/fShader0.glsl");

    program0.addShader(vShader0);
    program0.addShader(fShader0);
    program0.link();

    // add shader 1
    QOpenGLShader* vShader = new QOpenGLShader(QOpenGLShader::Vertex);
    QOpenGLShader* fShader = new QOpenGLShader(QOpenGLShader::Fragment);

    vShader->compileSourceFile(":/vShader.glsl");
    fShader->compileSourceFile(":/fShader.glsl");

    program.addShader(vShader);
    program.addShader(fShader);
    program.link();

    // add shader 2
    QOpenGLShader* vShader1 = new QOpenGLShader(QOpenGLShader::Vertex);
    QOpenGLShader* fShader1 = new QOpenGLShader(QOpenGLShader::Fragment);

    vShader1->compileSourceFile(":/vShader1.glsl");
    fShader1->compileSourceFile(":/fShader1.glsl");

    program1.addShader(vShader1);
    program1.addShader(fShader1);
    program1.link();

    geometries = new GeometryEngine;

    // 加载立方体的纹理
    texture = new QOpenGLTexture(QImage(":/cube.png").mirrored());
    texture->setMinificationFilter(QOpenGLTexture::Nearest);
    texture->setMagnificationFilter(QOpenGLTexture::Linear);
    texture->setWrapMode(QOpenGLTexture::Repeat);

    // 创建一个帧缓冲对象
    glGenFramebuffers(1, &fBO);
    glBindFramebuffer(GL_FRAMEBUFFER, fBO);

    // 生成纹理图像,附加到帧缓冲
    glGenTextures(1, &shadowMap);
    glBindTexture(GL_TEXTURE_2D, shadowMap);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenX, screenY, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shadowMap, 0);

    timer.start(12, this);
}

// 计算view矩阵
void MainWidget::CalculateViewMatrix()
{
    QVector3D upDir(0, 1, 0);

    QVector3D N = eyeLocation - lookAtLocation; // 这里是和OpenGL的z轴方向保持一致
    QVector3D U = QVector3D::crossProduct(upDir, N);
    QVector3D V = QVector3D::crossProduct(N, U);

    N.normalize();
    U.normalize();
    V.normalize();

    viewMatrix.setRow(0, {U.x(), U.y(), U.z(), -QVector3D::dotProduct(U, eyeLocation)}); // x
    viewMatrix.setRow(1, {V.x(), V.y(), V.z(), -QVector3D::dotProduct(V, eyeLocation)}); // y
    viewMatrix.setRow(2, {N.x(), N.y(), N.z(), -QVector3D::dotProduct(N, eyeLocation)}); // z
    viewMatrix.setRow(3, {0, 0, 0, 1});
}

void MainWidget::mousePressEvent(QMouseEvent *e)
{
    // Save mouse press position
    mousePressPosition = QVector2D(e->localPos());
}

void MainWidget::mouseReleaseEvent(QMouseEvent *e)
{
    // Mouse release position - mouse press position
    QVector2D diff = QVector2D(e->localPos()) - mousePressPosition;

    // Rotation axis is perpendicular to the mouse position difference
    // vector
    QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();

    // Accelerate angular speed relative to the length of the mouse sweep
    qreal acc = diff.length() / 100.0;

    // Calculate new rotation axis as weighted sum
    rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();

    // Increase angular speed
    angularSpeed += acc;
}

void MainWidget::timerEvent(QTimerEvent *)
{
    // Decrease angular speed (friction)
    angularSpeed *= 0.99;

    // Stop rotation when speed goes below threshold
    if (angularSpeed < 0.01) {
        angularSpeed = 0.0;
    } else {
        // Update rotation
        rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;

        // Request an update
        update();
    }
}

void MainWidget::CalculateLightMatrix()
{
    QVector3D lookAtLocation = QVector3D(0, 0, 0);
    QVector3D upDir(0, 1, 0);

    QVector3D N = lightPos - lookAtLocation;
    QVector3D U = QVector3D::crossProduct(upDir, N);
    QVector3D V = QVector3D::crossProduct(N, U);

    N.normalize();
    U.normalize();
    V.normalize();

    lightMatrix.setRow(0, {U.x(), U.y(), U.z(), -QVector3D::dotProduct(U, lightPos)}); // x
    lightMatrix.setRow(1, {V.x(), V.y(), V.z(), -QVector3D::dotProduct(V, lightPos)}); // y
    lightMatrix.setRow(2, {N.x(), N.y(), N.z(), -QVector3D::dotProduct(N, lightPos)}); // z
    lightMatrix.setRow(3, {0, 0, 0, 1});

}

void MainWidget::resizeGL(int w, int h)
{
    screenX = w;
    screenY = h;

    float aspect = float(w) / float(h ? h : 1);
    const qreal zNear = 2.0, fov = 60.0;
    projection.setToIdentity();
    projection.perspective(fov, aspect, zNear, zFar);
}


void MainWidget::paintGL()
{
    QMatrix4x4 plane1ModelMatrix;
    plane1ModelMatrix.translate(0, -5, 5);
    plane1ModelMatrix.scale(8.0f, 1.0f, 5.0f);

    QMatrix4x4 plane2ModelMatrix;
    plane2ModelMatrix.rotate(90, QVector3D(1,0,0));
    plane2ModelMatrix.scale(8.0f, 1.0f, 5.0f);

    QMatrix4x4 cubeModelMatrix;
    cubeModelMatrix.translate(0,-3,4);
    cubeModelMatrix.rotate(rotation);
    cubeModelMatrix.scale(2,2,2);

    glBindFramebuffer(GL_FRAMEBUFFER, fBO);
    glClearColor(1,1,1,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    program0.bind();

    program0.setUniformValue("LightMatrix",   lightMatrix);
    program0.setUniformValue("ProjectMatrix", projection);
    program0.setUniformValue("zFar", zFar);

    program0.setUniformValue("ModelMatrix",   cubeModelMatrix);
    geometries->drawCubeGeometry(&program0);



    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    program.bind();

    glBindTexture(GL_TEXTURE_2D, shadowMap);
    program.setUniformValue("ShadowMap",0);

    program.setUniformValue("LightMatrix",   lightMatrix);
    program.setUniformValue("ProjectMatrix", projection);
    program.setUniformValue("ViewMatrix",   viewMatrix);
    program.setUniformValue("lightLocation",lightPos);
    program.setUniformValue("zFar", zFar);

    QMatrix4x4 IT_Matrix;
    IT_Matrix = plane1ModelMatrix.inverted();
    IT_Matrix = IT_Matrix.transposed();
    program.setUniformValue("IT_ModelMatrix",   IT_Matrix);

    program.setUniformValue("ModelMatrix",   plane1ModelMatrix);
    geometries->drawPlane(&program);

    QMatrix4x4 IT_Matrix2;
    IT_Matrix2 = plane2ModelMatrix.inverted();
    IT_Matrix2 = IT_Matrix2.transposed();
    program.setUniformValue("IT_ModelMatrix",   IT_Matrix2);

    program.setUniformValue("ModelMatrix",   plane2ModelMatrix);
    geometries->drawPlane(&program);

    program1.bind();
    texture->bind();
    program1.setUniformValue("ProjectMatrix", projection);
    program1.setUniformValue("ViewMatrix",   viewMatrix);
    program1.setUniformValue("ModelMatrix",   cubeModelMatrix);
    program1.setUniformValue("texture",0);
    geometries->drawCubeGeometry(&program1);
}

        geometryengine.h

#ifndef GEOMETRYENGINE_H
#define GEOMETRYENGINE_H

#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>

class GeometryEngine : protected QOpenGLFunctions
{
public:
    GeometryEngine();
    virtual ~GeometryEngine();

    void drawCubeGeometry(QOpenGLShaderProgram *program);
    void drawPlane(QOpenGLShaderProgram *program);

private:
    void initCubeGeometry();

    QOpenGLBuffer screenArrayBuf;
    QOpenGLBuffer screenIndexBuf;

    QOpenGLBuffer arrayBuf;
    QOpenGLBuffer indexBuf;
};

#endif // GEOMETRYENGINE_H

        geometryengine.cpp


#include "geometryengine.h"

#include <QVector2D>
#include <QVector3D>

struct VertexData
{
    QVector3D position;
    QVector2D texture;
};

struct VertexData1
{
    QVector3D position;
    QVector3D normal;
};

GeometryEngine::GeometryEngine()
    : screenIndexBuf(QOpenGLBuffer::IndexBuffer),indexBuf(QOpenGLBuffer::IndexBuffer)
{
    initializeOpenGLFunctions();

    arrayBuf.create();
    indexBuf.create();

    screenArrayBuf.create();
    screenIndexBuf.create();

    initCubeGeometry();
}

GeometryEngine::~GeometryEngine()
{
    arrayBuf.destroy();
    indexBuf.destroy();

    screenArrayBuf.destroy();
    screenIndexBuf.destroy();
}

void GeometryEngine::initCubeGeometry()
{

    VertexData vertices[] = {
        // Vertex data for face 0
        {QVector3D(-1.0f, -1.0f,  1.0f), QVector2D(0.0f, 0.0f)}, // v0
        {QVector3D( 1.0f, -1.0f,  1.0f), QVector2D(0.33f, 0.0f)}, // v1
        {QVector3D(-1.0f,  1.0f,  1.0f), QVector2D(0.0f, 0.5f)}, // v2
        {QVector3D( 1.0f,  1.0f,  1.0f), QVector2D(0.33f, 0.5f)}, // v3

        // Vertex data for face 1
        {QVector3D( 1.0f, -1.0f,  1.0f), QVector2D( 0.0f, 0.5f)}, // v4
        {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.5f)}, // v5
        {QVector3D( 1.0f,  1.0f,  1.0f), QVector2D(0.0f, 1.0f)}, // v6
        {QVector3D( 1.0f,  1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v7

        // Vertex data for face 2
        {QVector3D( 1.0f, -1.0f, -1.0f),  QVector2D(0.66f, 0.5f)}, // v8
        {QVector3D(-1.0f, -1.0f, -1.0f),  QVector2D(1.0f, 0.5f)}, // v9
        {QVector3D( 1.0f,  1.0f, -1.0f),  QVector2D(0.66f, 1.0f)}, // v10
        {QVector3D(-1.0f,  1.0f, -1.0f),  QVector2D(1.0f, 1.0f)}, // v11

        // Vertex data for face 3
        {QVector3D(-1.0f, -1.0f, -1.0f),  QVector2D(0.66f, 0.0f)}, // v12
        {QVector3D(-1.0f, -1.0f,  1.0f),  QVector2D(1.0f, 0.0f)}, // v13
        {QVector3D(-1.0f,  1.0f, -1.0f),  QVector2D(0.66f, 0.5f)}, // v14
        {QVector3D(-1.0f,  1.0f,  1.0f),  QVector2D(1.0f, 0.5f)}, // v15

        // Vertex data for face 4
        {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.0f)}, // v16
        {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v17
        {QVector3D(-1.0f, -1.0f,  1.0f), QVector2D(0.33f, 0.5f)}, // v18
        {QVector3D( 1.0f, -1.0f,  1.0f), QVector2D(0.66f, 0.5f)}, // v19

        // Vertex data for face 5
        {QVector3D(-1.0f,  1.0f,  1.0f), QVector2D(0.33f, 0.5f)}, // v20
        {QVector3D( 1.0f,  1.0f,  1.0f), QVector2D(0.66f, 0.5f)}, // v21
        {QVector3D(-1.0f,  1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v22
        {QVector3D( 1.0f,  1.0f, -1.0f), QVector2D(0.66f, 1.0f)}, // v23
    };

    GLushort indices[] = {
         0,  1,  2,  3,  3,     // Face 0 - triangle strip ( v0,  v1,  v2,  v3)
         4,  4,  5,  6,  7,  7, // Face 1 - triangle strip ( v4,  v5,  v6,  v7)
         8,  8,  9, 10, 11, 11, // Face 2 - triangle strip ( v8,  v9, v10, v11)
        12, 12, 13, 14, 15, 15, // Face 3 - triangle strip (v12, v13, v14, v15)
        16, 16, 17, 18, 19, 19, // Face 4 - triangle strip (v16, v17, v18, v19)
        20, 20, 21, 22, 23      // Face 5 - triangle strip (v20, v21, v22, v23)
    };

    // Transfer vertex data to VBO 0
    arrayBuf.bind();
    arrayBuf.allocate(vertices, 24 * sizeof(VertexData));

    // Transfer index data to VBO 1
    indexBuf.bind();
    indexBuf.allocate(indices, 34 * sizeof(GLushort));

    VertexData1 screenVertices[] =
    {
        {QVector3D(-1.0f, 0.0f, -1.0f), QVector3D(0,1,0) },
        {QVector3D(-1.0f, 0.0f, 1.0f), QVector3D(0,1,0)  },
        {QVector3D(1.0f, 0.0f, 1.0f), QVector3D(0,1,0)  },
        {QVector3D(1.0f, 0.0f, -1.0f),  QVector3D(0,1,0)},
    };

    GLushort screenIndices[] = {
         0, 1, 2, 2, 3, 0
    };

    screenArrayBuf.bind();
    screenArrayBuf.allocate(screenVertices, 4 * sizeof(VertexData1));

    screenIndexBuf.bind();
    screenIndexBuf.allocate(screenIndices, 6 * sizeof(GLushort));
}


void GeometryEngine::drawCubeGeometry(QOpenGLShaderProgram *program)
{

    arrayBuf.bind();
    indexBuf.bind();

    int offset = 0;

    int vertexLocation = program->attributeLocation("a_position");
    program->enableAttributeArray(vertexLocation);
    program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));

    offset += sizeof(QVector3D);

    int texcoordLocation = program->attributeLocation("a_texcoord");
    program->enableAttributeArray(texcoordLocation);
    program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));

    glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, nullptr);
}


void GeometryEngine::drawPlane(QOpenGLShaderProgram *program)
{
    screenArrayBuf.bind();
    screenIndexBuf.bind();

    int offset = 0;
    int vertexLocation = program->attributeLocation("a_position");
    program->enableAttributeArray(vertexLocation);
    program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData1));

    offset += sizeof(QVector3D);

    int normalLocation = program->attributeLocation("a_normal");
    program->enableAttributeArray(normalLocation);
    program->setAttributeBuffer(normalLocation, GL_FLOAT, offset, 3, sizeof(VertexData1));


    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
}

        main.cpp

#include <QApplication>
#include <QLabel>
#include <QSurfaceFormat>

#ifndef QT_NO_OPENGL
#include "mainwidget.h"
#endif

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    QSurfaceFormat::setDefaultFormat(format);

    app.setApplicationName("cube");
    app.setApplicationVersion("0.1");
#ifndef QT_NO_OPENGL
    MainWidget widget;
    widget.show();
#else
    QLabel note("OpenGL Support required");
    note.show();
#endif
    return app.exec();
}

猜你喜欢

转载自blog.csdn.net/ZJU_fish1996/article/details/83242345
今日推荐