QT中学习Opengl---(纹理环绕方式与过滤)

前言:

本文的代码是 LearnOpenGL 中对应代码,这里提供学习,大家喜欢的可去官方网站去看看:

LearnOpenGL-CNhttps://learnopengl-cn.readthedocs.io/zh/latest/本章简单使用不同的环绕方式,来显示不同的纹理方案。

Texture Wrapping

      纹理坐标通常的范围是从(0, 0)到(1, 1), 如果我们把纹理坐标设置为范围以外会发生什么?
OpenGL默认的行为是重复这个纹理图像(我们简单地忽略浮点纹理坐标的整数部分), 但
OpenGL提供了更多的选择:

环绕方式描述
GL_REPEAT纹理的默认行为, 重复纹理图像
GL_MIRRORED_REPEAT和 GL_REPEAT 一样, 除了重复的图片是镜像放置的
GL_CLAMP_TO_EDGE纹理坐标会在0到1之间, 超出的部分会重复纹理坐标的
边缘, 就是边缘被拉伸
GL_CLAMP_TO_BORDER超出的部分是用户指定的边缘的颜色

对应的图标状况:

      前面提到的选项都可以使用 glTexParameter 函数单独设置每个坐标轴 s 、 t (如果是使用3D
纹理那么还有一个 r )它们和 x 、 y ( z )是相等的。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

       如果我们选择 GL_CLAMP_TO_BORDER 选项, 我们还要指定一个边缘的颜色。 这次使
用 glTexParameter 函数的 fv 后缀形式, 加上 GL_TEXTURE_BORDER_COLOR 作为选项, 这个函数需要我们传递一个边缘颜色的float数组作为颜色值:

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

 例子:

顶点坐标:

float vertices[] = {
        // positions          // colors           // texture coords
         0.8f,  0.8f, 0.0f,   1.0f, 0.0f, 0.0f,   2.0f, 2.0f, // top right
         0.8f, -0.8f, 0.0f,   0.0f, 1.0f, 0.0f,   2.0f, 0.0f, // bottom right
        -0.8f, -0.8f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.8f,  0.8f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 2.0f  // top left
    };


unsigned int indices[] = {  // note that we start from 0!
    0, 1, 3,  // first Triangle
    1, 2, 3   // second Triangle
};

这里纹理我们不在是1 1, 写出纹理超出部分。 

 顶点着色器写法: 

#version 330 core
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 = vec2(aTexCoord.x, aTexCoord.y);
}

 片段着色器

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
        // linearly interpolate between both textures (80% container, 20% awesomeface)
        //FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
        FragColor =texture(texture2,TexCoord);
}

 这里我们使用了纹理2

GL_CLAMP_TO_BORDER:

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);

效果:

 我们可以看到,超出部分都用黄色代替了。

GL_CLAMP_TO_EDGE

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

 

 GL_MIRRORED_REPEAT:

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT);

效果:

GL_REPEAT:

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);

 

 所有代码:

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
class BKQOpenglW : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    enum Shape{None,Rect,circle,Triangle};
    explicit BKQOpenglW(QWidget *parent = nullptr);
    ~BKQOpenglW();
    void drawShapes(Shape shape);
    void setWireFrame(bool b);
protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();

signals:

public slots:

private:
unsigned int VBO, VAO,EBO;
Shape m_Shape;
QOpenGLShaderProgram shaderProgram;
unsigned int texture;
QOpenGLTexture *pTexture;
QOpenGLTexture *pTexture2;
};

#endif // BKQOPENGLW_H

对应cpp:

#include "bkqopenglw.h"
#include<iostream>
#include <QDebug>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

float vertices[] = {
        // positions          // colors           // texture coords
         0.8f,  0.8f, 0.0f,   1.0f, 0.0f, 0.0f,   2.0f, 2.0f, // top right
         0.8f, -0.8f, 0.0f,   0.0f, 1.0f, 0.0f,   2.0f, 0.0f, // bottom right
        -0.8f, -0.8f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.8f,  0.8f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 2.0f  // top left
    };


unsigned int indices[] = {  // note that we start from 0!
    0, 1, 3,  // first Triangle
    1, 2, 3   // second Triangle
};

BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{

}

BKQOpenglW::~BKQOpenglW()
{
    makeCurrent();
    glDeleteVertexArrays(1,&VAO);
    glDeleteBuffers(1,&VBO);
    doneCurrent();
}

void BKQOpenglW::drawShapes(BKQOpenglW::Shape shape)
{
    m_Shape = shape;
    update();
}

void BKQOpenglW::setWireFrame(bool b)
{
    makeCurrent();
    if(b)
    {
       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else {
       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }
    update();
    doneCurrent();
}

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

    //    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
    //    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/shader.vs");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/shader.fs");
    shaderProgram.link();
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //绑定ebo
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    //绑定纹理
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    pTexture = new QOpenGLTexture(QImage(":/images/images/brickwall.jpg").mirrored());
    pTexture2 = new QOpenGLTexture(QImage(":/images/images/awesomeface.png").mirrored());
    shaderProgram.bind();
    shaderProgram.setUniformValue("texture1",0);
    shaderProgram.setUniformValue("texture2",1);
    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);

}

void BKQOpenglW::resizeGL(int w, int h)
{
       glViewport(0,0,w,h);
}

void BKQOpenglW::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
    shaderProgram.bind();
    glBindVertexArray(VAO);
    switch (m_Shape) {
    case Triangle:
        glDrawArrays(GL_TRIANGLES,0,3);
        break;
    case Rect:
        pTexture->bind(0);
        pTexture2->bind(1);
        //默认为GL_REPEAT 重复 GL_MIRRORED_REPEAT镜像  GL_CLAMP_TO_EDGE 边缘拉伸 GL_CLAMP_TO_BORDER 超出部分使用用户定义
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);
//        glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
        glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);
        break;
    default:
        break;
    }

}

纹理过滤(Texture Filtering)

   GL_NEAREST(Nearest Neighbor Filtering, 邻近过滤) 是一种OpenGL默认的纹理过滤方式。 当设置为 GL_NEAREST 的时候, OpenGL选择最接近纹理坐标中心点的那个像素。 下图你
会看到四个像素, 加号代表纹理坐标。 左上角的纹理像素是距离纹理坐标最近的那个, 这样它就会选择这个作为采样颜色:

 


 GL_LINEAR((Bi)linear Filtering, 线性过滤) 它会从纹理坐标的临近纹理像素进行计算, 返
回一个多个纹理像素的近似值。 一个纹理像素距离纹理坐标越近, 那么这个纹理像素对最终
的采样颜色的影响越大。 下面你会看到临近像素返回的混合颜色:

 

 基本区别:

使用方式: 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

最后的话:

 每天写代码时间不多,上班时间还是比较长,写博客不易,喜欢的朋友,可以关注偶。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值