图:随着键盘控制点光源位置移动,阴影发生实时的变换
之前在 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通道的颜色缓冲区中。
补充:此处是2019年1月20日补充的发现的一处不规范的地方,这是我做的第一版demo,所以会有很多不完善的地方。这里深度取的是透视转换之后的z分量,再除以远裁剪面。正确的归一化操作实际上应该为:float fColor = position.z / position.w,也就是分母是透视空间齐次坐标的w分量,它的几何含义也就是到投影面的距离(此处取值范围为-1到1,所以还需要转到0,1);但是,如果灯光视锥体没有完全包裹住相机视锥体,此处的归一化计算会导致未被包裹的位置进行比较的时候,无法从shadowmap中读取到对应的结果。
在本次初版demo中,虽然计算是不准确的,但是结果不会受到影响,因为这里相当于把深度编码到(0,1)之间,再到比较的时候解码到原始大小的步骤,也就是一个编码解码的过程。取远裁剪面会导致精度受损,但是由于编解码规则是统一的,最终重建的结果也是可行的。
但是,这是不规范的,对于实际使用而言,应该求出合适灯光视锥体,使其恰好包含场景包围盒和相机视锥体相交构成的凸包,然后使用pos.z/pos.w来计算。此外,此处由于灯光视角使用的是透视投影,最好能把深度做线性处理(因为透视投影后z是非线性的)。正确的线性处理是视图空间z值除以远裁剪面。具体内容会在shadow map改进中给出。
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;
varying vec3 worldPos;
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
#include
#include
#include
#include
#include
#include
#include
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
#include
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
#include
#include
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
#include
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
#include
#include
#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();
}