当前位置: 首页 > news >正文

国外移动网站设计网站建设营销型

国外移动网站设计,网站建设营销型,wordpress theme 修改,推广引流吸引人的文案文章目录QT OpenGLQOpenGLWidget:不需要GLFWQOpenGLFunction_X_X_Core:不需要GLAD你好#xff0c;三角形顶点输入顶点着色器片段着色器链接着色器本节代码元素缓冲对象EBOQT交互GLSLGLSL支持的类型输入输出Uniform纹理纹理单元纹理环绕纹理过滤多级渐远纹理QT OpenGL 本篇完整… 文章目录QT OpenGLQOpenGLWidget:不需要GLFWQOpenGLFunction_X_X_Core:不需要GLAD你好三角形顶点输入顶点着色器片段着色器链接着色器本节代码元素缓冲对象EBOQT交互GLSLGLSL支持的类型输入输出Uniform纹理纹理单元纹理环绕纹理过滤多级渐远纹理QT OpenGL 本篇完整工程见gitee:QTOpenGL 对应点的tag由turbolove提供技术支持您可以关注博主或者私信博主。 什么是opengl open graphics library 他是一个由Khronos组织制定并且维护的规范 opengl核心是一个c库同时也支持多种语言的派生 核心模式core-profile 也叫可编程管线提供了更多的灵活性更高的效率更重要的是可以深入的理解图形编程。 立即渲染模式Immediate mode 早期的OpenGL使用的模式也就是固定渲染管线OpenGL的大多数功能都被库隐藏起来容易使用和理解但是效率低下开发者很少能控制OpenGL如何进行计算因此从OpenGL3.2开始推出核心模式 状态机state machine) OpenGL是一个聚到的状态机 - 描述如何操作的所有变量的大集合OpenGL的状态通常被称为上下文Context状态设置函数State-changing Function状态应用函数State-using Function 对象Object 一个对象是指一些选项的集合代表OpenGL状态的一个子集当前状态只有一份如果每次显示不同的效果都重新配置会很麻烦我们需要使用一些小助理对象,帮忙记录某些状态信息以便复用 // 创建对象 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提供了三个便捷的虚拟函数可以冲在用来实现典型的opengl任务 paintGL:渲染opengl场景widget需要更新时候调用resizeGL设置opengl视口投影等widget调整大小或者首次显示时候调用initializeGL设置opengl资源和状态第一次调用resizeGL()或者paintGL()之前调用一次 如果需要从paintGL()意外的位置触发重新绘制典型示例是使用计时器设置场景动画则应该调用widget的update()函数来安排更新。 调用paintGL()、resizeGL()、initializeGL()时widget的opengl呈现上下文变为当前。如果需要从其他位置例如在widget的构造函数或者自己的绘制函数中调用openglAPI函数则必须首先调用makeCurrent()。 QOpenGLFunction_X_X_Core:不需要GLAD QOpenGLFunction_X_X_Core提供OpenGL x.x版本核心模式的所有功能是对OpenGL函数的封装 turboopenglwidget.h #ifndef QTOPENGL_TURBOOPENGLWIDGET_H #define QTOPENGL_TURBOOPENGLWIDGET_H#include QOpenGLWidget #include QOpenGLFunctions_4_5_Coreclass 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_Hturboopenglwidget.cpp #include turboopenglwidget.hTurboOpenGLWidget::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上创建内存用于存储我们的顶点数据 通过点缓冲对象vertex buffer object , VBO管理 顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER 配置OpenGL如何解释这些内存 通过顶点数组对象vertex array object , VAO管理 数组力的每一个项都对应一个属性的解析。 OpenGL允许我们同时绑定多个缓冲只要他们是不同的缓冲类型每个缓冲类型类似于前面说的子集每个VBO是一个小助理。 VAO并不保存实际数据而是放顶点结构定义。 // 创建VAO和VBO对象并且赋予ID unsigned int VBO, VAO; glGenVertexArrays(1, VAO); glGenBuffers(1, VBO);// 绑定VAO和VBO对象 glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO);// 为当前绑定到target的缓冲区对象创建一个新的数据存储 // 如果data不是NULL, 则使用来自此指针的数据初始化数据存储 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 是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数。 第一个参数是目标缓冲的类型顶点缓冲对象当前绑定到GL_ARRAY_BUFFER目标上。 第二个参数指定传输数据的大小(以字节为单位)用一个简单的sizeof计算出顶点数据大小就行。 第三个参数是我们希望发送的实际数据。 第四个参数指定了我们希望显卡如何管理给定的数据。它有三种形式 GL_STATIC_DRAW 数据不会或几乎不会改变。 GL_DYNAMIC_DRAW数据会被改变很多。 GL_STREAM_DRAW 数据每次绘制时都会改变。 glVertexAttribPointer 第一个参数指定我们要配置的顶点属性。还记得我们在顶点着色器中使用layout(location 0)定义了position顶点属性的位置值(Location)吗它可以把顶点属性的位置值设置为0。因为我们希望把数据传递到这一个顶点属性中所以这里我们传入0。第二个参数指定顶点属性的大小。顶点属性是一个vec3它由3个值组成所以大小是3。第三个参数指定数据的类型这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。下个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE所有数据都会被映射到0对于有符号型signed数据是-1到1之间。我们把它设置为GL_FALSE。第五个参数叫做步长(Stride)它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在3个float之后我们把步长设置为3 * sizeof(float)。要注意的是由于我们知道这个数组是紧密排列的在两个顶点属性之间没有空隙我们也可以设置为0来让OpenGL决定具体步长是多少只有当数值是紧密排列时才可用。一旦我们有更多的顶点属性我们就必须更小心地定义每个顶点属性之间的间隔我们在后面会看到更多的例子译注: 这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组0位置之间有多少字节。最后一个参数的类型是void*所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头所以这里是0。我们会在后面详细解释这个参数。 顶点着色器 #version 330 core layout (location 0) in vec3 aPos;void main() {gl_Position vec4(aPos, 1.0); }// 创建顶点着色器 unsigned int vertexShader glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader ,1 ,vertexShaderSource, NULL); glCompileShader(vertexShader);glShaderSource 第一个参数是函数把要编译的着色器对象。第二参数指定了传递的源码字符串数量这里只有一个。第三个参数是顶点着色器真正的源码第四个参数我们先设置为NULL。 片段着色器 #version 330 core out vec4 FragColor;void main() {FragColor vec4(1.0f, 0.5f, 0.2f, 1.0f); } // 创建顶片段着色器 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);本节代码 turboopenglwidget.cpp #include turboopenglwidget.hfloat 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 \nlayout (location 0) in vec3 aPos;\n\nvoid main()\n{\n\tgl_Position vec4(aPos, 1.0);\n}; const char *fragShaderSource #version 330 core\nout vec4 FragColor;\n\nvoid main()\n{\n FragColor vec4(1.0f, 0.5f, 0.2f, 1.0f);\n} ;// 创建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的缓冲区对象创建一个新的数据存储// 如果data不是NULL, 则使用来自此指针的数据初始化数据存储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);// 创建顶点着色器unsigned int vertexShader glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader ,1 ,vertexShaderSource, NULL);glCompileShader(vertexShader);// 创建顶片段着色器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 // 左上角 };值得庆幸的是元素缓冲区对象的工作方式正是如此。 EBO是一个缓冲区就像一个顶点缓冲区对象一样它存储 OpenGL 用来决定要绘制哪些顶点的索引。这种所谓的索引绘制(Indexed Drawing)正是我们问题的解决方案。首先我们先要定义不重复的顶点和绘制出矩形所需的索引 代码展示 #include turboopenglwidget.hfloat 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 \nlayout (location 0) in vec3 aPos;\n\nvoid main()\n{\n\tgl_Position vec4(aPos, 1.0);\n}; const char *fragShaderSource #version 330 core\nout vec4 FragColor;\n\nvoid main()\n{\n FragColor vec4(1.0f, 0.5f, 0.2f, 1.0f);\n} ;// 创建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的缓冲区对象创建一个新的数据存储// 如果data不是NULL, 则使用来自此指针的数据初始化数据存储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);// 创建顶点着色器unsigned int vertexShader glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader ,1 ,vertexShaderSource, NULL);glCompileShader(vertexShader);// 创建顶片段着色器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()以外的位置触发重新绘制典型示例是使用计时器设置场景动画 则应该调用widget的update()函数来安排更新调用paintGL()、resizeGL()和initializeGL()时widget的OpenGL呈现上下文将变为当前。如果需要从其他位置例如在widget的构造函数或自己的绘制函数中调用opengl API函数则必须首先调用makeCurrent()。 代码示例 turboopenglwidget.h #ifndef QTOPENGL_TURBOOPENGLWIDGET_H #define QTOPENGL_TURBOOPENGLWIDGET_H#include QOpenGLWidget #include QOpenGLShaderProgram #include QOpenGLFunctions_4_5_Coreclass 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.hfloat 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 // 第二个三角形 };// 创建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的缓冲区对象创建一个新的数据存储// 如果data不是NULL, 则使用来自此指针的数据初始化数据存储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 QMainWindowQT_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 QActionMainWindow::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程序结构 #version version_number in type in_variable_name; in type in_variable_name;out type out_variable_name;uniform type uniform_name;int main() {// 处理输入并进行一些图形操作...// 输出处理过的结果到输出变量out_variable_name weird_stuff_we_processed; }我们能声明的顶点数量是有限的可以通过下面的代码获取 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等其他语言大部分默认的基础数据类型 int float double uint boolGLSL也有两种容器类型 类型含义vecn包含n个float分量的默认向量bvecn包含n个bool分量的向量ivecn包含n个int分量的向量uvecn包含n个unsigned int分量的向量dvecn包含n个double分量的向量 向量这一数据类型也允许一些有趣而灵活的分量选择方式叫做重组(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);输入输出 在发送方着色器声明一个输出在接收方着色器声明一个类似的输入当类型和名称都一致的时候OpenGL会把两个变量链接到一起在链接程序对象时候完成 顶点着色器 #version 330 core layout (location 0) in vec3 aPos; // 位置变量的属性位置值为0out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl_Position vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数vertexColor vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色 }片段着色器 #version 330 core out vec4 FragColor;in vec4 vertexColor; // 从顶点着色器传来的输入变量名称相同、类型相同void main() {FragColor vertexColor; }顶点着色器接收的是一种特殊形式的输入否则就会效率低下 从顶点数据中直接接收输入。为了定义顶点数据该如何管理我们使用location这一元数据metadata指定输入变量这样我们才可以在CPU上配置顶点属性。例如 layout(location 0)。 layout这个标识使得我们能把它链接到顶点数据。 可以忽略layout( location 0) 标识符通过在OPenGL代码中使用glGetAttrribLocation查询属性位置Location或者是glBindAttribLocation属性位置值Location但是推荐在着色器中设置他们这样会更容易理解而且节省你和OpenGL的工作量 #include iostream #include turboopenglwidget.hfloat 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 // 第二个三角形 };// 创建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的缓冲区对象创建一个新的数据存储// 如果data不是NULL, 则使用来自此指针的数据初始化数据存储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中的着色器发送数据的方式 uniform是全局的可以被任意的着色器程序在任一阶段访问 #version 330 core out vec4 FragColor;uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量void main() {FragColor ourColor; }如果声明了一个uniform却没有用过编译器会默认移除这个变导致最后编译出的版本中并不会包含它这可能导致几个非常麻烦的错误切记 这次我们不去给像素单独传递一个颜色而是让他随着时间改变颜色。 OpenGL在其核心是一个C库所以他不支持类型重载在函数参数类型不同时候就要为其定义新的函数glUniform是一个典型的例子。这个函数有特定的后缀用来标识设定的uniform的类型。可能的后缀有 后缀含义f函数需要一个float作为它的值i函数需要一个int作为它的值ui函数需要一个unsigned int作为它的值3f函数需要3个float作为它的值fv函数需要一个float向量/数组作为它的值 QT 为我们封装了这个函数因此我们可以不用太过关注该函数的详细内容但是你要是用原生的OpenGL的话需要关注该函数。 纹理 当我们需要给图形赋予真实的颜色的时候不大可能使用前面的方法为每一个顶点指定第一个颜色通常我们会采用纹理贴图。 每个顶点关联一个纹理坐标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设置为我们从顶点数据那里得到的输入颜色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.hfloat 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 // 第二个三角形 };// 创建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的缓冲区对象创建一个新的数据存储// 如果data不是NULL, 则使用来自此指针的数据初始化数据存储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_TEXTURE08可以获得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);纹理环绕 环绕方式描述GL_REPEAT对纹理的默认行为。重复纹理图像。GL_MIRRORED_REPEAT和GL_REPEAT一样但每次重复图片是镜像放置的。GL_CLAMP_TO_EDGE纹理坐标会被约束在0到1之间超出的部分会重复纹理坐标的边缘产生一种边缘被拉伸的效果。GL_CLAMP_TO_BORDER超出的坐标为用户指定的边缘颜色。 相关代码请到gitee查看这里不复制 纹理过滤 纹理坐标不依赖于分辨率OpenGL需要知道怎么将纹理像素映射到纹理坐标 可以想象你打开一张图片不断放大会发现它是由无数像素点组成的这个点就是纹理像素 纹理坐标的精度是无限的可以是任意浮点值纹理像素是有限的图片分辨率一个像素需要一个颜色所谓采样就是通过纹理坐标问图片要纹理像素的颜色值 大图片贴小面片时纹理的精度高相邻纹理像素往往色差不打无需融合直接就近选取即可。 主要函数 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);相关代码请到gitee查看这里不复制 多级渐远纹理 简单来说就是一系列的纹理图像根据观察者与物体的距离参考临界值选择最适合物体的距离的那个纹理 OpenGL有一个glGenerateMipmaps函数可以生产多级渐远纹理 过滤方式描述GL_NEAREST_MIPMAP_NEAREST使用最邻近的多级渐远纹理来匹配像素大小并使用邻近插值进行纹理采样GL_LINEAR_MIPMAP_NEAREST使用最邻近的多级渐远纹理级别并使用线性插值进行采样GL_NEAREST_MIPMAP_LINEAR在两个最匹配像素大小的多级渐远纹理之间进行线性插值使用邻近插值进行采样GL_LINEAR_MIPMAP_LINEAR在两个邻近的多级渐远纹理之间使用线性插值并使用线性插值进行采样 主要函数: 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);相关代码请到gitee查看这里不复制
http://www.w-s-a.com/news/906092/

相关文章:

  • PHP网站开发与管理设计心得网站流量图怎么做
  • 苏州做网站企业wordpress点击文字弹出层
  • 做网站必要性中山古镇做网站
  • 增城住房和城乡建设局网站2021网站你懂我意思正能量
  • seo优秀网站深圳企业医疗网站建设
  • 单页 网站 模板重庆微信网站制作专家
  • 石家庄网站定制制作企业所得税优惠政策最新2022文件
  • 免费推广网站途径有哪些郑州企业型网站建设
  • wap网站建设设计wordpress首页名称
  • wordpress网站换空间南宁网站设计可以找我
  • 期货贵金属网站建设招远网站建设哪家专业
  • 上海网站排名个人网站可以做百度推广
  • 网站主题及样式优化个人网站 可以做论坛吗
  • 中企动力 网站推广一级域名免费申请
  • 山东专业的网站建设博罗做网站哪家强
  • 手机网站支持微信支付吗宝塔如何添加ip域名做网站
  • 什么专业学网站建设企业合同管理系统
  • 我要啦免费统计怎么做网站销售订单管理系统软件
  • 门户网站建设教程更改wordpress端口
  • 普兰店网站建设公司云计算培训
  • 网站建设的网络技术app下载平台哪个好
  • 中国建筑人才网是什么网站导购网站制作
  • 网站建设开票东莞龙岗网站建设
  • 17网站一起做网批最近湘潭的新闻
  • 专业网站设计专业服务网站news怎么做
  • 杭州租房网站建设设计网站架构
  • 安徽做网站公司哪家好建设网站需要什么内容
  • 哪些网络公司可以做机票预订网站网站新闻后台怎么做
  • 微网站 域名企业网站怎么做推广
  • 兴安盟住房和城乡建设部网站在国外做网站