博客
关于我
4.QOpenGLWidget-对三角形进行纹理贴图、纹理叠加
阅读量:440 次
发布时间:2019-03-06

本文共 4269 字,大约阅读时间需要 14 分钟。

在上一章中,我们为每个顶点添加颜色来增加图形的细节,从而创建出有趣的图像。但是,如果想让图形看起来更真实,我们就必须有足够多的顶点,从而指定足够多的颜色。这将会产生很多额外开销。

所以,我们使用纹理(Texture)。纹理是一个2D图片(甚至也有1D和3D的纹理),你可以想象纹理是一张绘有砖块的纸,无缝折叠贴合到你的3D房子上,这样你的房子看起来就像有砖墙外表了。

下面你会看到之前教程的那个三角形贴上了一张砖墙图片。

除了图像以外,纹理也可以被用来储存大量的数据,这些数据可以发送到着色器上,比如传输大量RGB数据显示一幅画面。

为了能够把纹理映射到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(译注:采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。

纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。

纹理坐标看起来就像这样:

float texCoords[] = { 0.0f, 0.0f, // 左下角 1.0f, 0.0f, // 右下角 0.5f, 1.0f // 上中 };

对纹理采样的解释非常宽松,它可以采用几种不同的插值方式。所以我们需要自己告诉OpenGL该怎样对纹理采样。QOpenGLTexture纹理对象介绍

在QT中,通过QOpenGLTexture类封装了一个OpenGL纹理对象,QOpenGLTexture可以很容易地使用OpenGL纹理和它们提供的无数特性和目标,这取决于你的OpenGL实现的能力。

QOpenGLTexture纹理的范围是从(0, 0)到(1, 1),如果超过范围后,OpenGL默认是重复纹理图像。当然也可以通过setWrapMode函数来重新设置。

QOpenGLTexture放大缩小的过滤方式是通过setMinMagFilters函数实现,比如:

m_texture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,QOpenGLTexture::Nearest);

参数1:设置缩小方式,参数2:设置放大方式。设置缩小和放大的方式,缩小图片采用LinearMipMapNearest线性过滤,并使用多级渐远纹理邻近过滤,放大图片采用:Nearest邻近过滤。

具体可以设置的参数有:

  • Nearest:邻近过滤,速度快,可能有锯齿,等同于OpenGL中的GL_NEAREST
  • Linear:线性过滤,速度慢,画面好,等同于OpenGL中的GL_LINEAR
  • NearestMipMapNearest:使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样,等同于GL_NEAREST_MIPMAP_NEAREST
  • NearestMipMapLinear:在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样,等同于GL_NEAREST_MIPMAP_LINEAR
  • LinearMipMapNearest:使用最邻近的多级渐远纹理级别,并使用线性插值进行采样,等同于GL_LINEAR_MIPMAP_NEAREST
  • LinearMipMapLinear:在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样,等同于GL_LINEAR_MIPMAP_LINEAR

缩小之多级渐远纹理

当纹理大于渲染屏幕时,使用纹理缩小算法(minifying)来渲染屏幕,就可以设置NearestMipMapNearest等4个参数。比如在一个场景中,由于远处的物体只占有很少的片段(近大远小,非常远的物体看起来就像一个点),OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题。

它简单来说就是将一个图像生成一系列的纹理图像,后一个纹理图像是前一个的二分之一,直到生成只有1个像素大小的图片为止。

然后绘制物体时,把摄像机到物体的距离与阙值作比较,在不同的距离空间内选用不同的纹理图像。由于距离远,解析度不高也不会被用户注意到。

所以多级渐远纹理只应用于纹理被缩小的情况下。

源码实现

具体代码如下所示:

#include "myglwidget.h" #include

#include

GL_VERSION "#version 330 core\n" #define GLCHA(x) #@x #define GLSTR(x) #x #define GET_GLSTR(x) GL_VERSION#x

const char *vsrc = GET_GLSTR( layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; layout (location = 2) in vec2 aTexCoord; out vec3 ourColor; out vec2 TexCoord; void main() { gl_Position = vec4(aPos, 1.0); ourColor = aColor; TexCoord = aTexCoord; } );

const char *fsrc = GET_GLSTR( out vec4 FragColor; in vec3 ourColor; in vec2 TexCoord; uniform sampler2D ourTexture; void main() { FragColor = texture(ourTexture, TexCoord); } );

myGlWidget::myGlWidget(QWidget *parent):QOpenGLWidget(parent){}

void myGlWidget::paintGL() { // 绘制 int w = width(); int h = height(); int side = qMin(w, h); glViewport((w - side) / 2, (h - side) / 2, side, side); glClear(GL_COLOR_BUFFER_BIT);

// 渲染Shader
vao.bind();
m_texture->bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
m_texture->release();
vao.release();

}

void myGlWidget::initializeGL() { initializeOpenGLFunctions(); glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

// 初始化纹理对象
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->setData(QImage(":wall1"));
m_texture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Nearest);
m_texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
m_texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
// 创建着色器程序
program = new QOpenGLShaderProgram;
program->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
program->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);
program->link();
program->bind();
// 初始化VBO
float vertices[] = {
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 2.0f // 顶部
};
vbo.create();
vbo.bind();
vbo.allocate(vertices, sizeof(vertices));
vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
// 初始化VAO
vao.create();
vao.bind();
program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 8 * sizeof(float));
program->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(float), 3, 8 * sizeof(float));
program->setAttributeBuffer(2, GL_FLOAT, 6 * sizeof(float), 2, 8 * sizeof(float));
program->enableAttributeArray(0);
program->enableAttributeArray(1);
program->enableAttributeArray(2);
vao.release();
vbo.release();

}

void myGlWidget::resizeEvent(QResizeEvent *e) {}

转载地址:http://uaiyz.baihongyu.com/

你可能感兴趣的文章
Objective-C实现数组的循环右移(附完整源码)
查看>>
Objective-C实现数组的循环左移(附完整源码)
查看>>
Objective-C实现数组逆置 (附完整源码)
查看>>
Objective-C实现数除以二divideByTwo算法(附完整源码)
查看>>
Objective-C实现整个字符串转换为小写字母算法(附完整源码)
查看>>
Objective-C实现整数N以内的质数算法(附完整源码)
查看>>
Objective-C实现文件传输(附完整源码)
查看>>
Objective-C实现文件分割(附完整源码)
查看>>
Objective-C实现文件拷贝(附完整源码)
查看>>
Objective-C实现文件断点传输(附完整源码)
查看>>
Objective-C实现文件的删除、复制与重命名操作实例(附完整源码)
查看>>
Objective-C实现无序表查找算法(附完整源码)
查看>>
Objective-C实现无锁链表(附完整源码)
查看>>
Objective-C实现无锁链表(附完整源码)
查看>>
Objective-C实现时间戳转为年月日时分秒(附完整源码)
查看>>
Objective-C实现是否为 Pythagoreantriplet 毕氏三元数组算法(附完整源码)
查看>>
Objective-C实现显示响应算法(附完整源码)
查看>>
Objective-C实现晚捆绑测试实例(附完整源码)
查看>>
Objective-C实现普通矩阵A和B的乘积(附完整源码)
查看>>
Objective-C实现更新数字指定偏移量上的值updateBit算法(附完整源码)
查看>>