纹理,简单说就是将图片展示在物体表面。可以将其类比为墙纸。纹理分为1D,2D, 3D 三类。这里只讨论2D纹理。先要记录一下比较基本的概念。
一、纹理坐标
纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。和数学二维坐标一样。
二、纹理创建
Qt提供方便的纹理类——QOpenGLTexture。它使纹理操作变得非常简单。这样就创建了一个纹理对象了。和创建QImage对象类似。不过要注意坐标系(纹理坐标与绘制设备坐标)的不同原因。所以需进行镜像操作。
m_texture = new QOpenGLTexture(QImage(":/images/side6.png").mirrored());
三、纹理映射与采样
就像贴墙纸一样,壁纸上的点要和墙面上点要对应起来。那就需要指定物体的每个顶点各自对应纹理的哪个部分。我们看到的壁纸上边有各种图案,图案实际是由每个颜色点组成。使用纹理坐标获取纹理颜色就是采样。
四、纹理过滤方式
这是s.t 两个坐标方向上的属性。暂时先记住结论性的一句话:“纹理被缩小的时候使用邻近过滤,被放大时使用线性过滤。”以后对它有深刻认识在深入讨论。
m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
m_texture->setMagnificationFilter(QOpenGLTexture::Linear);
五、纹理的其他属性
纹理环绕方式,类似qss的border-img。通常设置为GL_REPEAT:
m_texture->setWrapMode(QOpenGLTexture::Repeat);
六、编码
CPU端:
//
#pragma once
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
class OpenGLWidget : public QOpenGLWidget,
private QOpenGLFunctions_3_3_Core /*QOpenGLFunctions*/
{
Q_OBJECT
public:
OpenGLWidget(QWidget *parent = nullptr);
~OpenGLWidget();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
private:
bool createSharderProgram();
void makeObject();
private:
QOpenGLShaderProgram *m_program;
QOpenGLTexture *m_texture;
QOpenGLBuffer m_vbo;
int m_matrixUniform;
QMatrix4x4 m_projectMat;
};
#include "opengl_widget.h"
#include <QVariant>
OpenGLWidget::OpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent),
m_program(nullptr),
m_texture(nullptr),
m_vbo(QOpenGLBuffer::VertexBuffer),
m_matrixUniform(0),
m_projectMat()
{
}
OpenGLWidget::~OpenGLWidget()
{
makeCurrent();
m_vbo.destroy();
}
void OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
createSharderProgram();
m_vbo.create();
makeObject();
}
void OpenGLWidget::resizeGL(int w, int h)
{
float aspect = float(w)/float(h?h:1);
float fov = 45.0f, zNear = 0.1f, zFar = 100.f;
m_projectMat.setToIdentity();
m_projectMat.perspective(fov, aspect, zNear, zFar);
}
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
m_program->bind();
QMatrix4x4 mvMat;
mvMat.translate(0.0f, 0.0f, -3.0f);
m_program->setUniformValue(m_matrixUniform, m_projectMat*mvMat);
m_texture->bind();
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
m_texture->release();
m_program->release();
}
bool OpenGLWidget::createSharderProgram()
{
bool suc(false);
m_program = new QOpenGLShaderProgram(this);
suc = m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vsharder.glsl");
suc = m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/first_texture.glsl");
suc = m_program->link();
suc = m_program->bind();
if(!suc) {
close();
return suc;
}
m_matrixUniform = m_program->uniformLocation("mvpMat");
return suc;
}
void OpenGLWidget::makeObject()
{
m_texture = new QOpenGLTexture(QImage(":/images/side6.png").mirrored());
m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
m_texture->setMagnificationFilter(QOpenGLTexture::Linear);
m_texture->setWrapMode(QOpenGLTexture::Repeat);
float arrVertex[] {
// position texture
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
m_vbo.bind();
m_vbo.allocate(arrVertex, sizeof(arrVertex));
int attr = -1;
attr = m_program->attributeLocation("attrPos");
m_program->setAttributeBuffer(attr, GL_FLOAT, 0,
3, sizeof(float) * 5);
m_program->enableAttributeArray(attr);
attr = m_program->attributeLocation("attrTexCoord");
m_program->setAttributeBuffer(attr, GL_FLOAT, 3 * sizeof(float),
2, sizeof(float) * 5);
m_program->enableAttributeArray(attr);
m_vbo.release();
}
GPU端
v s
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
uniform mat4 mvpMat;
attribute vec4 attrPos;
attribute vec2 attrTexCoord;
varying vec2 texture_coord;
void main()
{
gl_Position = mvpMat * attrPos;
texture_coord = attrTexCoord;
}
f s
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
varying vec2 texture_coord;
uniform sampler2D samp;
void main()
{
gl_FragColor = texture2D(samp, texture_coord);
}