国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

鐘表玻璃東莞網(wǎng)站建設寧波seo網(wǎng)絡推廣軟件系統(tǒng)

鐘表玻璃東莞網(wǎng)站建設,寧波seo網(wǎng)絡推廣軟件系統(tǒng),網(wǎng)站鏈接怎么做,專做mad的網(wǎng)站文章目錄QT OpenGLQOpenGLWidget:不需要GLFWQOpenGLFunction_X_X_Core:不需要GLAD你好,三角形頂點輸入頂點著色器片段著色器鏈接著色器本節(jié)代碼元素緩沖對象EBOQT交互GLSLGLSL支持的類型輸入輸出Uniform紋理紋理單元紋理環(huán)繞紋理過濾多級漸遠紋理QT OpenGL 本篇完整…

文章目錄

  • QT+ OpenGL
    • QOpenGLWidget:不需要GLFW
    • QOpenGLFunction_X_X_Core:不需要GLAD
    • 你好,三角形
      • 頂點輸入
      • 頂點著色器
      • 片段著色器
      • 鏈接著色器
      • 本節(jié)代碼
      • 元素緩沖對象EBO
    • QT交互
    • GLSL
      • GLSL支持的類型
      • 輸入輸出
      • Uniform
    • 紋理
      • 紋理單元
      • 紋理環(huán)繞
    • 紋理過濾
    • 多級漸遠紋理

QT+ OpenGL

本篇完整工程見gitee:QTOpenGL
對應點的tag,由turbolove提供技術(shù)支持,您可以關(guān)注博主或者私信博主。

什么是opengl

open graphics library 他是一個由Khronos組織制定并且維護的規(guī)范

opengl核心是一個c庫,同時也支持多種語言的派生

核心模式(core-profile):

  • 也叫可編程管線,提供了更多的靈活性,更高的效率,更重要的是可以深入的理解圖形編程。

立即渲染模式(Immediate mode)

  • 早期的OpenGL使用的模式(也就是固定渲染管線)
  • OpenGL的大多數(shù)功能都被庫隱藏起來,容易使用和理解,但是效率低下
  • 開發(fā)者很少能控制OpenGL如何進行計算
  • 因此從OpenGL3.2開始推出核心模式

狀態(tài)機(state machine)

  • OpenGL是一個聚到的狀態(tài)機 - 描述如何操作的所有變量的大集合
  • OpenGL的狀態(tài)通常被稱為上下文Context
  • 狀態(tài)設置函數(shù)(State-changing Function)
  • 狀態(tài)應用函數(shù)(State-using Function)

對象(Object)

  • 一個對象是指一些選項的集合,代表OpenGL狀態(tài)的一個子集
  • 當前狀態(tài)只有一份,如果每次顯示不同的效果,都重新配置會很麻煩
  • 我們需要使用一些小助理(對象),幫忙記錄某些狀態(tài)信息,以便復用
// 創(chuàng)建對象
GLunit objId = 0;
glGenObject(1, &objId);
// 綁定對象到上下文
glBindObject(GL_WINDOW_TARGET, objId);
// 設置GL_WINDOW_TARGET對象的一些選項
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
// 將上下文的GL_WINDOW_TARGET對象設置成默認值
glBindObject(GL_WINDOW_TARGET, 0);
// 一旦我們重新綁定這個對象到GL_WINDOW_TARGET位置,這些選項就會重新生效

QOpenGLWidget:不需要GLFW

QOpenGLWidget提供了三個便捷的虛擬函數(shù),可以沖在,用來實現(xiàn)典型的opengl任務

  • paintGL:渲染opengl場景,widget需要更新時候調(diào)用
  • resizeGL:設置opengl視口,投影等,widget調(diào)整大小(或者首次顯示)時候調(diào)用
  • initializeGL:設置opengl資源和狀態(tài),第一次調(diào)用resizeGL()或者paintGL()之前調(diào)用一次

如果需要從paintGL()意外的位置觸發(fā)重新繪制(典型示例是使用計時器設置場景動畫),則應該調(diào)用widget的update()函數(shù)來安排更新。

調(diào)用paintGL()、resizeGL()、initializeGL()時,widget的opengl呈現(xiàn)上下文變?yōu)楫斍啊H绻枰獜钠渌恢?#xff08;例如在widget的構(gòu)造函數(shù)或者自己的繪制函數(shù)中)調(diào)用openglAPI函數(shù),則必須首先調(diào)用makeCurrent()。

QOpenGLFunction_X_X_Core:不需要GLAD

QOpenGLFunction_X_X_Core提供OpenGL x.x版本核心模式的所有功能,是對OpenGL函數(shù)的封裝

turboopenglwidget.h

#ifndef QTOPENGL_TURBOOPENGLWIDGET_H
#define QTOPENGL_TURBOOPENGLWIDGET_H#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>class TurboOpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_4_5_Core
{Q_OBJECT
public:explicit TurboOpenGLWidget(QWidget *parent = 0);protected:void initializeGL() override;void paintGL() override;void resizeGL(int w, int h) override;private:};#endif //QTOPENGL_TURBOOPENGLWIDGET_H

turboopenglwidget.cpp

#include "turboopenglwidget.h"TurboOpenGLWidget::TurboOpenGLWidget(QWidget *parent): QOpenGLWidget(parent)
{}void TurboOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();QOpenGLWidget::initializeGL();
}void TurboOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);QOpenGLWidget::paintGL();
}void TurboOpenGLWidget::resizeGL(int w, int h)
{QOpenGLWidget::resizeGL(w, h);
}

你好,三角形

float vertices[] = 
{-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f,
};

標準化設備坐標:

訂單著色器中處理過后,應該就是標準化設備坐標,x、y、z的值在-1.0到1.0的一小段空間(立方體)。落在范圍外的坐標都會被裁減。

頂點輸入

  • 他會在GPU上創(chuàng)建內(nèi)存,用于存儲我們的頂點數(shù)據(jù)
    • 通過點緩沖對象(vertex buffer object , VBO)管理
      • 頂點緩沖對象的緩沖類型是GL_ARRAY_BUFFER
  • 配置OpenGL如何解釋這些內(nèi)存
    • 通過頂點數(shù)組對象(vertex array object , VAO)管理

數(shù)組力的每一個項都對應一個屬性的解析。

OpenGL允許我們同時綁定多個緩沖,只要他們是不同的緩沖類型(每個緩沖類型類似于前面說的子集,每個VBO是一個小助理)。

VAO并不保存實際數(shù)據(jù),而是放頂點結(jié)構(gòu)定義。

// 創(chuàng)建VAO和VBO對象,并且賦予ID
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);// 綁定VAO和VBO對象
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);// 為當前綁定到target的緩沖區(qū)對象創(chuàng)建一個新的數(shù)據(jù)存儲
// 如果data不是NULL, 則使用來自此指針的數(shù)據(jù)初始化數(shù)據(jù)存儲
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 告知顯卡如何解析緩沖里面的屬性值
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);
// 開啟VAO管理的第一個屬性的值
glEnableVertexAttribArray(0);// 釋放VAO和VBO對象
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

glBufferData

是一個專門用來把用戶定義的數(shù)據(jù)復制到當前綁定緩沖的函數(shù)。

  • 第一個參數(shù)是目標緩沖的類型:頂點緩沖對象當前綁定到GL_ARRAY_BUFFER目標上。

  • 第二個參數(shù)指定傳輸數(shù)據(jù)的大小(以字節(jié)為單位);用一個簡單的sizeof計算出頂點數(shù)據(jù)大小就行。

  • 第三個參數(shù)是我們希望發(fā)送的實際數(shù)據(jù)。

  • 第四個參數(shù)指定了我們希望顯卡如何管理給定的數(shù)據(jù)。它有三種形式:

    • GL_STATIC_DRAW :數(shù)據(jù)不會或幾乎不會改變。

    • GL_DYNAMIC_DRAW:數(shù)據(jù)會被改變很多。

    • GL_STREAM_DRAW :數(shù)據(jù)每次繪制時都會改變。

glVertexAttribPointer

  • 第一個參數(shù)指定我們要配置的頂點屬性。還記得我們在頂點著色器中使用layout(location = 0)定義了position頂點屬性的位置值(Location)嗎?它可以把頂點屬性的位置值設置為0。因為我們希望把數(shù)據(jù)傳遞到這一個頂點屬性中,所以這里我們傳入0。
  • 第二個參數(shù)指定頂點屬性的大小。頂點屬性是一個vec3,它由3個值組成,所以大小是3。
  • 第三個參數(shù)指定數(shù)據(jù)的類型,這里是GL_FLOAT(GLSL中vec*都是由浮點數(shù)值組成的)。
  • 下個參數(shù)定義我們是否希望數(shù)據(jù)被標準化(Normalize)。如果我們設置為GL_TRUE,所有數(shù)據(jù)都會被映射到0(對于有符號型signed數(shù)據(jù)是-1)到1之間。我們把它設置為GL_FALSE。
  • 第五個參數(shù)叫做步長(Stride),它告訴我們在連續(xù)的頂點屬性組之間的間隔。由于下個組位置數(shù)據(jù)在3個float之后,我們把步長設置為3 * sizeof(float)。要注意的是由于我們知道這個數(shù)組是緊密排列的(在兩個頂點屬性之間沒有空隙)我們也可以設置為0來讓OpenGL決定具體步長是多少(只有當數(shù)值是緊密排列時才可用)。一旦我們有更多的頂點屬性,我們就必須更小心地定義每個頂點屬性之間的間隔,我們在后面會看到更多的例子(譯注: 這個參數(shù)的意思簡單說就是從這個屬性第二次出現(xiàn)的地方到整個數(shù)組0位置之間有多少字節(jié))。
  • 最后一個參數(shù)的類型是void*,所以需要我們進行這個奇怪的強制類型轉(zhuǎn)換。它表示位置數(shù)據(jù)在緩沖中起始位置的偏移量(Offset)。由于位置數(shù)據(jù)在數(shù)組的開頭,所以這里是0。我們會在后面詳細解釋這個參數(shù)。

頂點著色器

#version 330 core 
layout (location = 0) in vec3 aPos;void main()
{gl_Position = vec4(aPos, 1.0);
}
// 創(chuàng)建頂點著色器
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader ,1 ,&vertexShaderSource, NULL);
glCompileShader(vertexShader);

glShaderSource

  • 第一個參數(shù)是函數(shù)把要編譯的著色器對象。
  • 第二參數(shù)指定了傳遞的源碼字符串數(shù)量,這里只有一個。
  • 第三個參數(shù)是頂點著色器真正的源碼,
  • 第四個參數(shù)我們先設置為NULL

片段著色器

#version 330 core
out vec4 FragColor;void main()
{FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
} 
// 創(chuàng)建頂片段著色器
unsigned int fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader ,1 ,&fragShaderSource, NULL);
glCompileShader(fragShader);

鏈接著色器

unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragShader);
glLinkProgram(shaderProgram);glDeleteShader(vertexShader);
glDeleteShader(fragShader);

本節(jié)代碼

turboopenglwidget.cpp

#include "turboopenglwidget.h"float vertices[] =
{-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f,
};
const char *vertexShaderSource ="#version 330 core \n""layout (location = 0) in vec3 aPos;\n""\n""void main()\n""{\n""\tgl_Position = vec4(aPos, 1.0);\n""}";
const char *fragShaderSource ="#version 330 core\n""out vec4 FragColor;\n""\n""void main()\n""{\n""    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""} ";// 創(chuàng)建VAO和VBO對象,并且賦予ID
unsigned int VBO, VAO;
unsigned int shaderProgram;
TurboOpenGLWidget::TurboOpenGLWidget(QWidget *parent): QOpenGLWidget(parent)
{}void TurboOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// 綁定VAO和VBO對象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);// 為當前綁定到target的緩沖區(qū)對象創(chuàng)建一個新的數(shù)據(jù)存儲// 如果data不是NULL, 則使用來自此指針的數(shù)據(jù)初始化數(shù)據(jù)存儲glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 告知顯卡如何解析緩沖里面的屬性值glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(0);// 釋放VAO和VBO對象glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);// 創(chuàng)建頂點著色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader ,1 ,&vertexShaderSource, NULL);glCompileShader(vertexShader);// 創(chuàng)建頂片段著色器unsigned int fragShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragShader ,1 ,&fragShaderSource, NULL);glCompileShader(fragShader);shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragShader);glLinkProgram(shaderProgram);glDeleteShader(vertexShader);glDeleteShader(fragShader);
}void TurboOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);
}void TurboOpenGLWidget::resizeGL(int w, int h)
{}

元素緩沖對象EBO

可以繪制兩個三角形來組合成一個矩形,這會生成下面的頂點的集合:

float vertices[] = {// 第一個三角形0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, 0.5f, 0.0f,  // 左上角// 第二個三角形0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角
};

值得慶幸的是,元素緩沖區(qū)對象的工作方式正是如此。 EBO是一個緩沖區(qū),就像一個頂點緩沖區(qū)對象一樣,它存儲 OpenGL 用來決定要繪制哪些頂點的索引。這種所謂的索引繪制(Indexed Drawing)正是我們問題的解決方案。首先,我們先要定義(不重復的)頂點,和繪制出矩形所需的索引:

代碼展示:

#include "turboopenglwidget.h"float vertices[] = {0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角
};unsigned int indices[] = {0, 1, 3, // 第一個三角形1, 2, 3  // 第二個三角形
};
const char *vertexShaderSource ="#version 330 core \n""layout (location = 0) in vec3 aPos;\n""\n""void main()\n""{\n""\tgl_Position = vec4(aPos, 1.0);\n""}";
const char *fragShaderSource ="#version 330 core\n""out vec4 FragColor;\n""\n""void main()\n""{\n""    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""} ";// 創(chuàng)建VAO和VBO對象,并且賦予ID
unsigned int VBO, VAO;
unsigned int EBO;
unsigned int shaderProgram;
TurboOpenGLWidget::TurboOpenGLWidget(QWidget *parent): QOpenGLWidget(parent)
{}void TurboOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 綁定VAO和VBO對象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);// 為當前綁定到target的緩沖區(qū)對象創(chuàng)建一個新的數(shù)據(jù)存儲// 如果data不是NULL, 則使用來自此指針的數(shù)據(jù)初始化數(shù)據(jù)存儲glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 告知顯卡如何解析緩沖里面的屬性值glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// 釋放VAO和VBO對象glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);// 創(chuàng)建頂點著色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader ,1 ,&vertexShaderSource, NULL);glCompileShader(vertexShader);// 創(chuàng)建頂片段著色器unsigned int fragShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragShader ,1 ,&fragShaderSource, NULL);glCompileShader(fragShader);shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragShader);glLinkProgram(shaderProgram);glDeleteShader(vertexShader);glDeleteShader(fragShader);glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}void TurboOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(shaderProgram);glBindVertexArray(VAO);
//    glDrawArrays(GL_TRIANGLES, 0, 6);
//     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}void TurboOpenGLWidget::resizeGL(int w, int h)
{}

QT交互

  • 如果需要從paintGL()以外的位置觸發(fā)重新繪制(典型示例是使用計時器設置場景動畫), 則應該調(diào)用widget的update()函數(shù)來安排更新
  • 調(diào)用paintGL()、resizeGL()和initializeGL()時,widget的OpenGL呈現(xiàn)上下文將變?yōu)楫斍?。如果需要從其他位?#xff08;例如,在widget的構(gòu)造函數(shù)或自己的繪制函數(shù)中)調(diào)用opengl API函數(shù),則必須首先調(diào)用makeCurrent()。

代碼示例:

turboopenglwidget.h

#ifndef QTOPENGL_TURBOOPENGLWIDGET_H
#define QTOPENGL_TURBOOPENGLWIDGET_H#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions_4_5_Core>class TurboOpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_4_5_Core
{Q_OBJECT
public:enum Shape{None,Rect,Circle,Triangle,};explicit TurboOpenGLWidget(QWidget *parent = 0);~TurboOpenGLWidget() override;void drawShape(Shape shape);void setWireFrame(bool mode);protected:void initializeGL() override;void paintGL() override;void resizeGL(int w, int h) override;private:Shape shape_;QOpenGLShaderProgram shader_program_;
};#endif //QTOPENGL_TURBOOPENGLWIDGET_H

turboopenglwidget.cpp

#include <iostream>
#include "turboopenglwidget.h"float vertices[] = {0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角
};unsigned int indices[] = {0, 1, 3, // 第一個三角形1, 2, 3  // 第二個三角形
};// 創(chuàng)建VAO和VBO對象,并且賦予ID
unsigned int VBO, VAO;
unsigned int EBO;
TurboOpenGLWidget::TurboOpenGLWidget(QWidget *parent): QOpenGLWidget(parent)
{}TurboOpenGLWidget::~TurboOpenGLWidget()
{makeCurrent();glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteVertexArrays(1, &VAO);doneCurrent();
}void TurboOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 綁定VAO和VBO對象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);// 為當前綁定到target的緩沖區(qū)對象創(chuàng)建一個新的數(shù)據(jù)存儲// 如果data不是NULL, 則使用來自此指針的數(shù)據(jù)初始化數(shù)據(jù)存儲glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 告知顯卡如何解析緩沖里面的屬性值glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// 釋放VAO和VBO對象glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);bool success = false;shader_program_.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/resources/shader.vert");shader_program_.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/resources/shader.frag");success = shader_program_.link();if(!success){std::cout << "shader is failed" << std::endl;}// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}void TurboOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);shader_program_.bind();glBindVertexArray(VAO);
//    glDrawArrays(GL_TRIANGLES, 0, 6);//     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);switch(shape_){case Rect:glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);break;}update();
}void TurboOpenGLWidget::resizeGL(int w, int h)
{}void TurboOpenGLWidget::drawShape(TurboOpenGLWidget::Shape shape)
{shape_ = shape;
}void TurboOpenGLWidget::setWireFrame(bool mode)
{makeCurrent();if(mode){glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);}else{glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);}
}

mainwidow.h

#ifndef QTOPENGL_MAINWINDOW_H
#define QTOPENGL_MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECT
public:explicit MainWindow(QWidget *parent = nullptr);~MainWindow() override;protected slots:void drawRect();void clearPic();void lineModel(const bool &mode);private:Ui::MainWindow *ui;QToolBar *tool_bar_{nullptr};
};#endif //QTOPENGL_MAINWINDOW_H

mainwidow.cpp

#include "mainwindow.h"
#include "ui_MainWindow.h"
#include <QToolBar>
#include <QAction>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);setCentralWidget(ui->openGLWidget);tool_bar_ = new QToolBar(this);auto *action = new QAction(tr("繪制矩形"), this);auto *action2 = new QAction(tr("清空圖形"), this);auto *action3 = new QAction(tr("線框模式"), this);action3->setCheckable(true);connect(action, &QAction::triggered, this, &MainWindow::drawRect);connect(action2, &QAction::triggered, this, &MainWindow::clearPic);connect(action3, &QAction::triggered, this, &MainWindow::lineModel);tool_bar_->addAction(action);tool_bar_->addAction(action2);tool_bar_->addAction(action3);addToolBar(tool_bar_);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::drawRect()
{ui->openGLWidget->drawShape(TurboOpenGLWidget::Rect);
}void MainWindow::clearPic()
{ui->openGLWidget->drawShape(TurboOpenGLWidget::None);
}void MainWindow::lineModel(const bool &mode)
{ui->openGLWidget->setWireFrame(mode);
}

GLSL

OpenGL Shading Languaage

一個典型的shader程序結(jié)構(gòu):

#version version_number
in type in_variable_name;
in type in_variable_name;out type out_variable_name;uniform type uniform_name;int main()
{// 處理輸入并進行一些圖形操作...// 輸出處理過的結(jié)果到輸出變量out_variable_name = weird_stuff_we_processed;
}

我們能聲明的頂點數(shù)量是有限的,可以通過下面的代碼獲取:

int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

OpenGL確保至少有16個包含4分量的頂點屬性可用,但是有些硬件可能會允許更多的頂點屬性。

GLSL支持的類型

類型:

GLSL中包含C等其他語言大部分默認的基礎數(shù)據(jù)類型

int float double uint bool

GLSL也有兩種容器類型

類型含義
vecn包含n個float分量的默認向量
bvecn包含n個bool分量的向量
ivecn包含n個int分量的向量
uvecn包含n個unsigned int分量的向量
dvecn包含n個double分量的向量

向量這一數(shù)據(jù)類型也允許一些有趣而靈活的分量選擇方式,叫做重組(Swizzling)。重組允許這樣的語法:

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
vec2 vect = vec2(0.5, 0.7);
vec4 result = vec4(vect, 0.0, 0.0);
vec4 otherResult = vec4(result.xyz, 1.0);

輸入輸出

  • 在發(fā)送方著色器聲明一個輸出
  • 在接收方著色器聲明一個類似的輸入
  • 當類型和名稱都一致的時候OpenGL會把兩個變量鏈接到一起(在鏈接程序?qū)ο髸r候完成)

頂點著色器

#version 330 core
layout (location = 0) in vec3 aPos; // 位置變量的屬性位置值為0out vec4 vertexColor; // 為片段著色器指定一個顏色輸出void main()
{gl_Position = vec4(aPos, 1.0); // 注意我們?nèi)绾伟岩粋€vec3作為vec4的構(gòu)造器的參數(shù)vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把輸出變量設置為暗紅色
}

片段著色器

#version 330 core
out vec4 FragColor;in vec4 vertexColor; // 從頂點著色器傳來的輸入變量(名稱相同、類型相同)void main()
{FragColor = vertexColor;
}

頂點著色器接收的是一種特殊形式的輸入,否則就會效率低下

從頂點數(shù)據(jù)中直接接收輸入。為了定義頂點數(shù)據(jù)該如何管理,我們使用location這一元數(shù)據(jù)(metadata)指定輸入變量,這樣我們才可以在CPU上配置頂點屬性。例如: layout(location = 0)。 layout這個標識,使得我們能把它鏈接到頂點數(shù)據(jù)。

可以忽略layout( location = 0) 標識符,通過在OPenGL代碼中使用glGetAttrribLocation查詢屬性位置(Location),或者是glBindAttribLocation屬性位置值(Location),但是推薦在著色器中設置他們,這樣會更容易理解而且節(jié)省你和(OpenGL)的工作量

#include <iostream>
#include "turboopenglwidget.h"float vertices[] = {0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角
};unsigned int indices[] = {0, 1, 3, // 第一個三角形1, 2, 3  // 第二個三角形
};// 創(chuàng)建VAO和VBO對象,并且賦予ID
unsigned int VBO, VAO;
unsigned int EBO;
TurboOpenGLWidget::TurboOpenGLWidget(QWidget *parent): QOpenGLWidget(parent)
{}TurboOpenGLWidget::~TurboOpenGLWidget()
{makeCurrent();glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteVertexArrays(1, &VAO);doneCurrent();
}void TurboOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 綁定VAO和VBO對象glBindVertexArray(VAO);shader_program_.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/resources/shader.vert");shader_program_.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/resources/shader.frag");bool success = false;success = shader_program_.link();if(!success){std::cout << "shader is failed" << std::endl;}glBindBuffer(GL_ARRAY_BUFFER, VBO);// 為當前綁定到target的緩沖區(qū)對象創(chuàng)建一個新的數(shù)據(jù)存儲// 如果data不是NULL, 則使用來自此指針的數(shù)據(jù)初始化數(shù)據(jù)存儲glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 告知顯卡如何解析緩沖里面的屬性值int location = shader_program_.attributeLocation("aPos");glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(location);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// 釋放VAO和VBO對象glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);
}void TurboOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);shader_program_.bind();glBindVertexArray(VAO);
//    glDrawArrays(GL_TRIANGLES, 0, 6);//     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);switch(shape_){case Rect:glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);break;}update();
}void TurboOpenGLWidget::resizeGL(int w, int h)
{}void TurboOpenGLWidget::drawShape(TurboOpenGLWidget::Shape shape)
{shape_ = shape;
}void TurboOpenGLWidget::setWireFrame(bool mode)
{makeCurrent();if(mode){glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);}else{glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);}
}

Uniform

另一種從CPU的應用,向GPU中的著色器發(fā)送數(shù)據(jù)的方式

uniform是全局的,可以被任意的著色器程序在任一階段訪問

#version 330 core
out vec4 FragColor;uniform vec4 ourColor; // 在OpenGL程序代碼中設定這個變量void main()
{FragColor = ourColor;
}

如果聲明了一個uniform卻沒有用過,編譯器會默認移除這個變,導致最后編譯出的版本中并不會包含它,這可能導致幾個非常麻煩的錯誤,切記

這次我們不去給像素單獨傳遞一個顏色,而是讓他隨著時間改變顏色。

OpenGL在其核心是一個C庫,所以他不支持類型重載,在函數(shù)參數(shù)類型不同時候就要為其定義新的函數(shù),glUniform是一個典型的例子。這個函數(shù)有特定的后綴,用來標識設定的uniform的類型。可能的后綴有:

后綴含義
f函數(shù)需要一個float作為它的值
i函數(shù)需要一個int作為它的值
ui函數(shù)需要一個unsigned int作為它的值
3f函數(shù)需要3個float作為它的值
fv函數(shù)需要一個float向量/數(shù)組作為它的值

QT 為我們封裝了這個函數(shù),因此我們可以不用太過關(guān)注該函數(shù)的詳細內(nèi)容,但是你要是用原生的OpenGL的話,需要關(guān)注該函數(shù)。

紋理

當我們需要給圖形賦予真實的顏色的時候,不大可能使用前面的方法為每一個頂點指定第一個顏色,通常我們會采用紋理貼圖。

每個頂點關(guān)聯(lián)一個紋理坐標(Texture Coordinate),之后在圖形的其他片段上進行片段插值

我們只需要告訴OpenGL如何對紋理采樣即可

頂點著色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 1) in vec2 aTexCord;
out vec3 ourColor; // 向片段著色器輸出一個顏色
out vec2 texCord; // 向片段著色器輸出一個顏色
void main()
{gl_Position = vec4(aPos, 1.0);ourColor = aColor; // 將ourColor設置為我們從頂點數(shù)據(jù)那里得到的輸入顏色texCord = aTexCord;
}

片段著色器

#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 texCord;
uniform sampler2D texture0;
void main()
{FragColor = texture(texture0, texCord);
}

對應的顯示代碼:

#include <iostream>
#include "turboopenglwidget.h"float vertices[] = {0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上角0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下角-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f // 左上角
};unsigned int indices[] = {0, 1, 3, // 第一個三角形1, 2, 3  // 第二個三角形
};// 創(chuàng)建VAO和VBO對象,并且賦予ID
unsigned int VBO, VAO;
unsigned int EBO;
TurboOpenGLWidget::TurboOpenGLWidget(QWidget *parent): QOpenGLWidget(parent)
{connect(&timer, &QTimer::timeout, this, &TurboOpenGLWidget::timeout);// timer.start(100);
}TurboOpenGLWidget::~TurboOpenGLWidget()
{if(!isValid()) return;makeCurrent();glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteVertexArrays(1, &VAO);doneCurrent();
}void TurboOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 綁定VAO和VBO對象glBindVertexArray(VAO);shader_program_.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/resources/shader.vert");shader_program_.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/resources/shader.frag");bool success = false;success = shader_program_.link();if(!success){std::cout << "shader is failed" << std::endl;}glBindBuffer(GL_ARRAY_BUFFER, VBO);// 為當前綁定到target的緩沖區(qū)對象創(chuàng)建一個新的數(shù)據(jù)存儲// 如果data不是NULL, 則使用來自此指針的數(shù)據(jù)初始化數(shù)據(jù)存儲glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 告知顯卡如何解析緩沖里面的屬性值int location = shader_program_.attributeLocation("aPos");glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0);// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(location);int location2 = shader_program_.attributeLocation("aColor");glVertexAttribPointer(location2, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float)));// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(location2);int location3 = shader_program_.attributeLocation("aTexCord");glVertexAttribPointer(location3, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float)));// 開啟VAO管理的第一個屬性的值glEnableVertexAttribArray(location3);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);texture_wall_ = new QOpenGLTexture(QImage(":/resources/wall.jpg"));// 釋放VAO和VBO對象glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);}void TurboOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);shader_program_.bind();glBindVertexArray(VAO);
//    glDrawArrays(GL_TRIANGLES, 0, 6);//     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);switch(shape_){case Rect:texture_wall_->bind();glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);break;}update();
}void TurboOpenGLWidget::resizeGL(int w, int h)
{}void TurboOpenGLWidget::drawShape(TurboOpenGLWidget::Shape shape)
{shape_ = shape;
}void TurboOpenGLWidget::setWireFrame(bool mode)
{makeCurrent();if(mode){glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);}else{glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);}
}
#include <QTime>
void TurboOpenGLWidget::timeout()
{if(shape_){return;}makeCurrent();int time = QTime::currentTime().second();float green = (sin(time) / 2.0f) + 0.5f;shader_program_.setUniformValue("ourColor", 0.0f, green, 0.0f, 1.0f);
}

紋理單元

OpenGL保證至少16個紋理單元,也就是說你可以激活從GL_TEXTURE0到GL_TEXTURE15。他們都是按照順序定義的, GL_TEXTURE0+8可以獲得GL_TEXTURE8

以下是QT主要代碼,在gitee項目中查看完整代碼。

texture_wall_ = new QOpenGLTexture(QImage(":/resources/wall.jpg").mirrored());
texture_le_ = new QOpenGLTexture(QImage(":/resources/awesomeface.png").mirrored());shader_program_.bind();
shader_program_.setUniformValue("textureWall", 0);
shader_program_.setUniformValue("textureSmile", 1);

紋理環(huán)繞

環(huán)繞方式描述
GL_REPEAT對紋理的默認行為。重復紋理圖像。
GL_MIRRORED_REPEAT和GL_REPEAT一樣,但每次重復圖片是鏡像放置的。
GL_CLAMP_TO_EDGE紋理坐標會被約束在0到1之間,超出的部分會重復紋理坐標的邊緣,產(chǎn)生一種邊緣被拉伸的效果。
GL_CLAMP_TO_BORDER超出的坐標為用戶指定的邊緣顏色。

相關(guān)代碼請到gitee查看,這里不復制

紋理過濾

紋理坐標不依賴于分辨率,OpenGL需要知道怎么將紋理像素映射到紋理坐標;

可以想象你打開一張圖片,不斷放大,會發(fā)現(xiàn)它是由無數(shù)像素點組成的,這個點就是紋理像素

  • 紋理坐標的精度是無限的,可以是任意浮點值
  • 紋理像素是有限的(圖片分辨率)
  • 一個像素需要一個顏色
  • 所謂采樣就是通過紋理坐標,問圖片要紋理像素的顏色值

大圖片貼小面片時:紋理的精度高,相鄰紋理像素往往色差不打,無需融合,直接就近選取即可。

主要函數(shù):

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

相關(guān)代碼請到gitee查看,這里不復制

多級漸遠紋理

簡單來說就是一系列的紋理圖像,根據(jù)觀察者與物體的距離,參考臨界值,選擇最適合物體的距離的那個紋理

OpenGL有一個glGenerateMipmaps函數(shù),可以生產(chǎn)多級漸遠紋理

過濾方式描述
GL_NEAREST_MIPMAP_NEAREST使用最鄰近的多級漸遠紋理來匹配像素大小,并使用鄰近插值進行紋理采樣
GL_LINEAR_MIPMAP_NEAREST使用最鄰近的多級漸遠紋理級別,并使用線性插值進行采樣
GL_NEAREST_MIPMAP_LINEAR在兩個最匹配像素大小的多級漸遠紋理之間進行線性插值,使用鄰近插值進行采樣
GL_LINEAR_MIPMAP_LINEAR在兩個鄰近的多級漸遠紋理之間使用線性插值,并使用線性插值進行采樣

主要函數(shù):

texture_small_->generateMipMaps();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

相關(guān)代碼請到gitee查看,這里不復制

http://aloenet.com.cn/news/47149.html

相關(guān)文章:

  • h5 網(wǎng)站建設網(wǎng)絡營銷活動方案
  • 深圳網(wǎng)站建設定制網(wǎng)站seo推廣多少錢
  • 做網(wǎng)站那個公司網(wǎng)站建設公司官網(wǎng)
  • 網(wǎng)站建設進展推進表旺道seo軟件技術(shù)
  • 網(wǎng)站建設崗位廉政風險防控互聯(lián)網(wǎng)銷售平臺有哪些
  • 西安建設過政府網(wǎng)站的公司國外網(wǎng)站搭建
  • 公司文化墻圖片大全關(guān)鍵詞優(yōu)化排名軟件案例
  • wordpress建購物網(wǎng)站成都網(wǎng)絡營銷公司哪家好
  • wordpress網(wǎng)站突然打不開阿里云域名注冊官網(wǎng)
  • 做網(wǎng)站騙子成都seo論壇
  • 用jsp怎么做網(wǎng)站關(guān)鍵詞排名推廣軟件
  • 中國做網(wǎng)站瀏覽器打開網(wǎng)站
  • 診斷網(wǎng)站seo現(xiàn)狀的方法廣州市網(wǎng)絡seo外包
  • 怎么查看網(wǎng)站是否備案網(wǎng)站top排行榜
  • 衢州做網(wǎng)站的公司bt種子搜索
  • 信息網(wǎng)站怎么做網(wǎng)絡零售的優(yōu)勢有哪些
  • 深圳商城網(wǎng)站建設google學術(shù)搜索
  • 介紹自己做的電影網(wǎng)站google推廣專員招聘
  • 南寧網(wǎng)站建設清單怎么注冊網(wǎng)址
  • 網(wǎng)站提交收錄入口鏈接福州短視頻seo
  • 新網(wǎng)站如何做seo推廣網(wǎng)站的友情鏈接是什么意思
  • 百度seo sem南京seo優(yōu)化培訓
  • 教育類電商網(wǎng)站seo優(yōu)化網(wǎng)站
  • 萊蕪翰林名苑萊蕪論壇杭州seo價格
  • 公司網(wǎng)站建設南寧百度客服電話24小時人工服務熱線
  • 什么網(wǎng)站好看用h5做外貿(mào)網(wǎng)站谷歌seo
  • 怎樣網(wǎng)絡營銷推廣東莞優(yōu)化疫情防控措施
  • 做 專而精 的網(wǎng)站網(wǎng)站宣傳文案范例
  • 網(wǎng)站移動頁面怎么做google關(guān)鍵詞規(guī)劃師
  • 高校網(wǎng)站建設管理辦法怎樣做一個自己的網(wǎng)站