• 3D Computer Grapihcs Using OpenGL


    友情提示:继续本节之前,需要保存此前的代码,本节为了试验,会对代码做一些修改,但后续的修改需要我们把代码返回之前的进度。

    OpenGL内置支持Instancing,有专门的函数来处理这件事情。

    为了方便,我们先使用最简单的三角形来学习

    先修改sendDataToOpenGL()函数:

     1 void MyGlWindow::sendDataToOpenGL()
     2 {
     3     GLfloat tri[] = {
     4         -1.0f,+0.0f,
     5         -1.0f,+1.0f,
     6         -0.9f,+0.0f
     7     };
     8 
     9     GLuint vertexBufferID;
    10     glGenBuffers(1, &vertexBufferID);
    11     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
    12     glBufferData(GL_ARRAY_BUFFER, sizeof(tri), tri, GL_STATIC_DRAW);
    13     glEnableVertexAttribArray(0);
    14     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    15 
    16     GLushort indices[] = { 0,1,2 };
    17     GLuint indexArrayBufferID;
    18     glGenBuffers(1, &indexArrayBufferID);
    19     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexArrayBufferID);
    20     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    21     numIndices = 3;
    22 }

    相应的修改vertexshader

     1 #version 430                           
     2                                        
     3 in layout(location=0) vec2 position;   
     4                                       
     5 out vec3 passingColor;
     6                                        
     7 void main()                            
     8 {                                      
     9   
    10   gl_Position = vec4(position.xy,0,1);
    11   passingColor= vec3(1,0,0);           
    12 }

    以及paintGL()函数:

    1 void MyGlWindow::paintGL()
    2 {
    3     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    4     glViewport(0, 0, width(), height());
    5 
    6     glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
    7 }

    进行了上述修改之后,会在画布左上角绘制一个简单的红色三角形。

    假如我们现在需要达到这样的目的:复制这个三角形多次,每次都横向偏移一定的量。

    为了使用OpenGL提供的Instancing 方法,避免每次都调用glDrawElements,我们可以提供一个数组,作为偏移信息数组。

    在sendDataToOpenGL()函数中定义一个GLfloat数组,把它绑定到GL_ARRAY_BUFFER上,开启一个新的通道,把数据传输进去。

    最后在paintGL中使用glDrawElementsInstanced函数来绘制多个实例。

    具体代码如下:

     1 void MyGlWindow::sendDataToOpenGL()
     2 {
     3     GLfloat tri[] = {
     4         -1.0f,+0.0f,
     5         -1.0f,+1.0f,
     6         -0.9f,+0.0f
     7     };
     8 
     9     GLuint vertexBufferID;
    10     glGenBuffers(1, &vertexBufferID);
    11     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
    12     glBufferData(GL_ARRAY_BUFFER, sizeof(tri), tri, GL_STATIC_DRAW);
    13     glEnableVertexAttribArray(0);
    14     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    15 
    16     GLfloat offsets[] = {0.0f, 0.5f, 1.0f, 1.2f, 1.6f};
    17     GLuint offsetsBufferID;
    18     glGenBuffers(1, &offsetsBufferID);
    19     glBindBuffer(GL_ARRAY_BUFFER, offsetsBufferID);
    20     glBufferData(GL_ARRAY_BUFFER, sizeof(offsets), offsets, GL_STATIC_DRAW);
    21     glEnableVertexAttribArray(1);
    22     glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
    23     glVertexAttribDivisor(1, 1);
    24 
    25     GLushort indices[] = { 0,1,2 };
    26     GLuint indexArrayBufferID;
    27     glGenBuffers(1, &indexArrayBufferID);
    28     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexArrayBufferID);
    29     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    30     numIndices = 3;
    31 }

    16-23行是新增内容。

    16行定义了一个GLfloat数组,有5个元素。

    17-20行我们已经很熟悉,不再解释了

    21行开启了通道1

    22行设定了通道1的数据格式,第一个参数表示通道1,第二个参数表示每1个数据作为一个单元

    23行glVertexAttribDivsior是个新函数,它是配合实例化绘制的。没有它的情况下,tri数组每2个元素结合offsets数组的1个元素,也就是说offsets数组每个元素只用一次。有了这个函数之后,offsets数组的每个元素都要做一次循环,和tri数组的每组元素结合一次,形成5个批次。

    修改VertexShader:

     1 #version 430                           
     2                                        
     3 in layout(location=0) vec2 position;   
     4 in layout(location=1) float offset;  
     5                                       
     6 out vec3 passingColor;
     7                                        
     8 void main()                            
     9 {                                      
    10   
    11   gl_Position = vec4(position.x + offset, + position.y,0,1);
    12   passingColor= vec3(1,0,0);           
    13 }

    增加了第4行,对应sendDataToOpenGL的新增通道1.

    第11行中,我们把position的x坐标进行了offset的偏移。

    最后修改paintGL()函数:

    1 void MyGlWindow::paintGL()
    2 {
    3     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    4     glViewport(0, 0, width(), height());
    5     glDrawElementsInstanced(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0, 5);
    6 }

    第5行使用glDrawElementsInstanced函数代替glDrawElements函数,进行了批量绘制。

    第五个参数表示绘制五个实例。

    最后效果:

  • 相关阅读:
    nginx (待更新)
    根据 thread id 停止一个线程
    Redis 消息订阅
    faker smtp server
    DRF lazy Serializer
    python super
    django patch
    django patch 解决 ["'15428560000' value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
    自己的随笔
    CSS中文乱码解决方法
  • 原文地址:https://www.cnblogs.com/AnKen/p/8377766.html
Copyright © 2020-2023  润新知