网站生成手机端,个人怎么做跨境电商,自己怎样免费建网站,免费引流软件下载实例化
对于在同一场景中使用相同顶点数据的对象#xff08;如草地中的草#xff09;#xff0c;可以使用实例化#xff08;Instancing#xff09;技术#xff0c;用一个绘制函数让OpenGL绘制多个物体#xff0c;而非循环#xff08;Drawcall: N-1#xff09;。 …实例化
对于在同一场景中使用相同顶点数据的对象如草地中的草可以使用实例化Instancing技术用一个绘制函数让OpenGL绘制多个物体而非循环Drawcall: N-1。 实例化技术本质上是减少了数据从CPU到GPU的传输次数。 实例化这项技术能够让我们使用一个渲染调用来绘制多个物体来节省每次绘制物体时CPU - GPU的通信它只需要一次即可。
使用 glDrawArraysInstanced 和 glDrawElementsInstanced 就可以。这些渲染函数的实例化版本需要一个额外的参数叫做实例数量(Instance Count)它能够设置我们需要渲染的实例个数。
顶点着色器内建变量 gl_InstanceID 保存了当前渲染图元所在是实例索引。借助该变量我们可以改变其位置渲染方式等。从0开始当渲染第43个实例时该变量为42
索引一个包含100个偏移向量的uniform数组将偏移值加到每个实例化的四边形上。最终的结果是一个排列整齐的四边形网格 //vs
#version 330 core
out vec4 FragColor;in vec3 fColor;void main()
{FragColor vec4(fColor, 1.0);
}//fs
#version 330 core
layout (location 0) in vec2 aPos;
layout (location 1) in vec3 aColor;out vec3 fColor;uniform vec2 offsets[100];void main()
{vec2 offset offsets[gl_InstanceID];gl_Position vec4(aPos offset, 0.0, 1.0);fColor aColor;
}//.cpp//定义数组
glm::vec2 translations[100];
int index 0;
float offset 0.1f;
for(int y -10; y 10; y 2)
{for(int x -10; x 10; x 2){glm::vec2 translation;translation.x (float)x / 10.0f offset;translation.y (float)y / 10.0f offset;translations[index] translation;}
}//将数组转移到顶点着色器的uniform中
shader.use();
for(unsigned int i 0; i 100; i)
{stringstream ss;string index;ss i; index ss.str(); shader.setVec2((offsets[ index ]).c_str(), translations[i]);
}//绘制
glBindVertexArray(quadVAO);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100); 实例化数组
实例化数组(Instanced Array)它被定义为一个顶点属性能够让我们储存更多的数据仅在顶点着色器渲染一个新的实例时才会更新。
使用顶点属性时顶点着色器的每次运行都会让GLSL获取新一组适用于当前顶点的属性。而当我们将顶点属性定义为一个实例化数组时顶点着色器就只需要对每个实例而不是每个顶点更新顶点属性的内容了。这允许我们对逐顶点的数据使用普通的顶点属性而对逐实例的数据使用实例化数组。
#version 330 core
layout (location 0) in vec2 aPos;
layout (location 1) in vec3 aColor;
layout (location 2) in vec2 aOffset;//实例化数组out vec3 fColor;void main()
{gl_Position vec4(aPos aOffset, 0.0, 1.0);fColor aColor;
}
unsigned int instanceVBO;
glGenBuffers(1, instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100, translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(2, 1);
可以看到唯一的区别在于 glVertexAttribDivisor(AttribIdx,Count) 函数。这个函数定义了什么时候更新顶点属性的内容到新一组数据。Count参数为0时每次顶点着色器运行都更新即默认的方式参数为1时运行到每个实例时更新参数为2时每两个实例更新以此类推。
小行星带
随机代码
unsigned int amount 1000;
glm::mat4 *modelMatrices;
modelMatrices new glm::mat4[amount];
srand(glfwGetTime()); // 初始化随机种子
float radius 50.0;
float offset 2.5f;
for(unsigned int i 0; i amount; i)
{glm::mat4 model;// 1. 位移分布在半径为 radius 的圆形上偏移的范围是 [-offset, offset]float angle (float)i / (float)amount * 360.0f;float displacement (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float x sin(angle) * radius displacement;displacement (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float y displacement * 0.4f; // 让行星带的高度比x和z的宽度要小displacement (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float z cos(angle) * radius displacement;model glm::translate(model, glm::vec3(x, y, z));// 2. 缩放在 0.05 和 0.25f 之间缩放float scale (rand() % 20) / 100.0f 0.05;model glm::scale(model, glm::vec3(scale));// 3. 旋转绕着一个半随机选择的旋转轴向量进行随机的旋转float rotAngle (rand() % 360);model glm::rotate(model, rotAngle, glm::vec3(0.4f, 0.6f, 0.8f));// 4. 添加到矩阵的数组中modelMatrices[i] model;
}
绘制代码
// 绘制行星
shader.use();
glm::mat4 model;
model glm::translate(model, glm::vec3(0.0f, -3.0f, 0.0f));
model glm::scale(model, glm::vec3(4.0f, 4.0f, 4.0f));
shader.setMat4(model, model);
planet.Draw(shader);// 绘制小行星
for(unsigned int i 0; i amount; i)
{shader.setMat4(model, modelMatrices[i]);rock.Draw(shader);
} 不使用实例化绘制了1000个小行星帧率为 60 参考实例化 - LearnOpenGL CN
LearnOpenGL学习笔记十 - 高级GLSL、几何着色器、实例化与抗锯齿 - Yois Home