OpenGL-ES 学习(18) ---- 实例化渲染

目录

Instancing(实例化)

OpenGL-ES 实例化Instancing)是一种只调用一次渲染函数酒能绘制出很多物体的技术,

可以实现一次将数据发送给 GPU,只使用一次绘制函数,就可以绘制出多个物体

实例化(Instancing)避免了 CPU 多次向 GPU 下达渲染命令,避免多次调用 glDrawArraysglDrawElements等绘制函数,节省了绘制多个物体时 CPUGPU 之间的通信时间,提升了渲染性能

实例化渲染方法

使用实例化渲染的接口变化:

c 复制代码
// 普通渲染
glDrawArrays(GLenum mode, GLint first, GLsizei count);
glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)

// 实例化渲染 注意多了一个 instancecount 参数
glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount)
glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount)

相对于普通绘制,实例化绘制多了一个参数 instancecount,表示需要渲染的实例数量,

调用完实例化绘制函数后,我们便将绘制数据一次性发送给 GPU,然后告诉它该如何使用一个函数来绘制这些实例

实例化(Instancing)的目标并不是实现将同一物体绘制多次,而是能基于某一物体绘制出位置、大小、形状或者颜色不同的多个物体

OpenGL-ES 着色器中有一个与实例化绘制相关的内建变量 gl_InstanceID
gl_InstanceID 表示当前正在的绘制的实例的 ID,每个实例对应一个唯一的 ID, 通过这个 ID 可以区分输入的不同的位置,大小或者颜色,实现基于一个物体绘制出位置,大小,形状或者颜色的不同的多个物体

参考代码

这里给出一个使用 instance 方法绘制出多个 立方体的参考代码, 原理是改变输入立方体的顶点的偏移

c 复制代码
// 在初始化时 vec3 translation 作为输入顶点的偏移,这里只更新了 x 和 y 参数
void testdrawColorCubeInstance::initialize() {
    // initilize instance multi translations 
    int index = 0;
    for(GLint x = 0; x < 3; x += 1) {
        for(GLint y = 0; y < 3; y += 1) {
            glm::vec3 translation;          
            translation.x = (GLfloat)x/1.0f*2;
            translation.y =  (GLfloat)y/1.0f*2;
            translation.z = 0.0f;
            userData->translations[index++] = translation;
        }
    }
    .... 
}

// 这里使用 gl_InstanceID 改变输入顶点的偏移 u_offsets,所以每个 u_offsets,都需要设置
static const char* vertexShaderSource =
    "#version 300 es                            \n"
    "precision mediump float;\n"
    "uniform mat4 u_mvpMatrix;                   \n"
    "layout(location = 0) in vec3 a_position;   \n"
    "layout(location = 1) in vec2 a_texCoord;   \n"
    "out vec2 v_texCoord;                       \n"
    "uniform vec3 u_offsets[9];               \n"
    "void main() {\n"
    "    gl_Position = u_mvpMatrix * vec4(a_position + u_offsets[gl_InstanceID], 1.0);"
    "    v_texCoord = a_texCoord;                \n"
    "}\n";


// 在这里传入所有 instance 的 u_offsets
for(GLuint i = 0; i < instance_count; i++) {
    std::string index = std::to_string(i);
    GLint location = glGetUniformLocation(userData->programObject, ("u_offsets[" + index + "]").c_str());
    glUniform3f(location, userData->translations[i].x, userData->translations[i].y, userData->translations[i].z);
}

// 最后在绘制的时候,注释使用的时 glDrawElementsInstanced 代替 glDrawElements
for(int i = 0; i < numFaces; i++) {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, userData->textureId[i]);
    glUniform1i(userData->samplerLoc, 0);

    glBindVertexArray(userData->vaoId);
    GLvoid* offset = (GLvoid*)(i*6*sizeof(GL_UNSIGNED_INT));
    //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, offset);
    glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, offset, instance_count);
    glBindVertexArray(0);
}

实际效果如下:

另一个角度的渲染效果:

相关推荐
風清掦1 分钟前
【江科大STM32学习笔记-09】USART串口协议 - 9.1 STM32 USART串口外设
笔记·stm32·单片机·嵌入式硬件·学习
奶茶精Gaaa16 分钟前
AI实战(二)生成ui自动化
功能测试·学习·自动化
red_redemption1 小时前
自由学习记录(141)
学习
xian_wwq1 小时前
【学习笔记】看参识模型
笔记·学习
星雨流星天的笔记本1 小时前
1、用于制备钙钛矿量子点的新三颈烧瓶的洗涤与使用方法
学习
FPGA小迷弟2 小时前
高频时钟设计:FPGA 多时钟域同步与时序收敛实战方案
前端·学习·fpga开发·verilog·fpga
sensen_kiss2 小时前
CPT306 Principles of Computer Games Design 电脑游戏设计原理 Pt.3 实时图形
学习·计算机视觉
東雪木2 小时前
编程算法学习——栈与队列算法
学习·算法·排序算法
ADHD多动联盟3 小时前
什么是儿童ADHD的运动干预方案?主要有怎样的应对分心走神的疗法?
学习·学习方法·玩游戏
2501_918126913 小时前
学习所有6502写游戏地图的语句
汇编·嵌入式硬件·学习·游戏·个人开发