这个效果比较简单,用一个立文体把我们要绘制的东西包起来即可,把摄像机的位置放到立文体内,这样就给人一个有天空,有陆地感觉。 我在这个工程中加入了以前的圆环体,其渲染器实现方法,可以查阅以前的文章。效果如下
我使用的是一个包含6个纹理图片的纹理数组,一次性把6个面都画好了,并完成了贴图。其渲染器实现如下:
#ifndef BOXSHADER_H
#define BOXSHADER_H
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QImage>
class BoxShader
{
public:
BoxShader() = default;
~BoxShader();
void initsize(int width,int height,QImage &left,QImage &bebind,QImage &right,QImage &front,QImage &top,QImage &bottom);
void render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix);
private:
QOpenGLTexture *textureArray_{nullptr};
QOpenGLShaderProgram program_;
QOpenGLBuffer vbo_;
};
#endif // BOXSHADER_H
#include "boxshader.h"
BoxShader::~BoxShader()
{
textureArray_->destroy();
delete textureArray_;
}
void BoxShader::initsize(int width, int height, QImage &left, QImage &bebind, QImage &right, QImage &front, QImage &top, QImage &bottom)
{
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
program_.link();
textureArray_ = new QOpenGLTexture(QOpenGLTexture::Target2DArray);
textureArray_->create();
textureArray_->setSize(width,height);
textureArray_->setLayers(6);
textureArray_->setFormat(QOpenGLTexture::RGB8_UNorm);
textureArray_->allocateStorage();
textureArray_->setData(0,0,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,left.convertToFormat(QImage::Format_RGB888).constBits());
textureArray_->setData(0,1,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,bebind.convertToFormat(QImage::Format_RGB888).constBits());
textureArray_->setData(0,2,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,right.convertToFormat(QImage::Format_RGB888).constBits());
textureArray_->setData(0,3,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,front.convertToFormat(QImage::Format_RGB888).constBits());
textureArray_->setData(0,4,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,top.convertToFormat(QImage::Format_RGB888).constBits());
textureArray_->setData(0,5,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,bottom.convertToFormat(QImage::Format_RGB888).constBits());
textureArray_->setMinMagFilters(QOpenGLTexture::Nearest,QOpenGLTexture::Nearest);
textureArray_->setWrapMode(QOpenGLTexture::ClampToEdge);
const GLfloat vertexs[]{
//vertex points
//left side
-1.0,+1.0,+1.0,
-1.0,-1.0,+1.0,
-1.0,-1.0,-1.0,
-1.0,+1.0,-1.0,
//behind side
-1.0,+1.0,-1.0,
-1.0,-1.0,-1.0,
+1.0,-1.0,-1.0,
+1.0,+1.0,-1.0,
//right side
+1.0,+1.0,-1.0,
+1.0,-1.0,-1.0,
+1.0,-1.0,+1.0,
+1.0,+1.0,+1.0,
//front side
-1.0,+1.0,+1.0,
+1.0,+1.0,+1.0,
+1.0,-1.0,+1.0,
-1.0,-1.0,+1.0,
//top side
-1.0,+1.0,-1.0,
+1.0,+1.0,-1.0,
+1.0,+1.0,+1.0,
-1.0,+1.0,+1.0,
//bottom side
-1.0,-1.0,-1.0,
-1.0,-1.0,+1.0,
+1.0,-1.0,+1.0,
+1.0,-1.0,-1.0,
//texture points
//left side
+0.0,+0.0,
+0.0,+1.0,
+1.0,+1.0,
+1.0,+0.0,
//behind side
+0.0,+0.0,
+0.0,+1.0,
+1.0,+1.0,
+1.0,+0.0,
//right side
+0.0,+0.0,
+0.0,+1.0,
+1.0,+1.0,
+1.0,+0.0,
//front side
+1.0,+0.0,
+0.0,+0.0,
+0.0,+1.0,
+1.0,+1.0,
//top side
+0.0,+1.0,
+1.0,+1.0,
+1.0,+0.0,
+0.0,+0.0,
//bottom side
+0.0,+0.0,
+0.0,+1.0,
+1.0,+1.0,
+1.0,+0.0,
};
vbo_.create();
vbo_.bind();
vbo_.allocate(vertexs,sizeof(vertexs));;
}
void BoxShader::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix)
{
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_CULL_FACE);
program_.bind();
vbo_.bind();
f->glActiveTexture(GL_TEXTURE0 + 0);
program_.setUniformValue("pMatrix",pMatrix);
program_.setUniformValue("vMatrix",vMatrix);
program_.setUniformValue("mMatrix",mMatrix);
program_.setUniformValue("sTexture",0);
program_.enableAttributeArray(0);
program_.enableAttributeArray(1);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));
program_.setAttributeBuffer(1,GL_FLOAT,6 * 4 * 3 * sizeof(GLfloat),2,2*sizeof(GLfloat));
textureArray_->bind();
f->glDrawArrays(GL_QUADS,0,24);
program_.disableAttributeArray(0);
program_.disableAttributeArray(1);
textureArray_->release();
vbo_.release();
program_.release();
f->glDisable(GL_DEPTH_TEST);
f->glDisable(GL_CULL_FACE);
}
其shader实现如下
#version 330
uniform mat4 pMatrix,vMatrix,mMatrix;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTextureCood;
smooth out vec2 vTextureCoord;
out float vid;
void main(void)
{
gl_Position = pMatrix * vMatrix * mMatrix * vec4(aPosition,1);
vTextureCoord = aTextureCood;
vid = gl_VertexID;//顶点序号
}
#version 330
uniform sampler2DArray sTexture;
in float vid;
in vec2 vTextureCoord;
out vec4 fragColor;
void main(void)
{
vec3 texCood = vec3(vTextureCoord.st,floor(vid/4)); //根据vid顶点序号求出纹理索引
fragColor = texture(sTexture,texCood);
}
调用如下
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include <QTimer>
#include "boxshader.h"
#include "torusrender.h"
class Widget : public QOpenGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
private:
BoxShader boxShader_;
TorusRender toruRender_;
QVector3D camera_;
QMatrix4x4 pMatrix_;
QTimer tm_;
float angleX_ = 0, angleY_ = 0, angleZ_ = 0;
private slots:
void slotTimeout();
};
#endif // WIDGET_H
#include <QWheelEvent>
#include "widget.h"
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
{
connect(&tm_,SIGNAL(timeout()),this,SLOT(slotTimeout()));
tm_.start(40);
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
camera_.setX(4.9);
camera_.setY(4.9);
camera_.setZ(4.9);
toruRender_.initsize(0.9,0.5,13,30);
boxShader_.initsize(256,256,QImage("side1.png"),QImage("side2.png"),QImage("side3.png"),QImage("side4.png"),QImage("side5.png"),QImage("side6.png"));
}
void Widget::resizeGL(int w, int h)
{
pMatrix_.setToIdentity();
pMatrix_.perspective(80,float(w)/h,0.01f,100.0f);
}
void Widget::paintGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
f->glClearColor(0.0, 0.0, 0.0, 0.0);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 vMatrix;
vMatrix.lookAt(camera_,QVector3D(-4.9,-4.9,-4.9),QVector3D(-1.0,1.0,-1.0));
QMatrix4x4 mMatrix;
mMatrix.rotate(angleX_,1,0,0);
mMatrix.rotate(angleY_,0,1,0);
mMatrix.rotate(angleZ_,0,0,1);
mMatrix.scale(20);
boxShader_.render(f,pMatrix_,vMatrix,mMatrix);
mMatrix.setToIdentity();
mMatrix.translate(-1.0,-4.9,-0.5);
mMatrix.scale(2);
mMatrix.rotate(-angleY_,0,1,0);
toruRender_.render(f,pMatrix_,vMatrix,mMatrix);
}
void Widget::slotTimeout()
{
angleY_ += 5;
update();
}
到此结束