CPU 与使用具有许多独特图元的实例化绘图时的内存权衡
CPU vs Memory trade-offs when using instanced drawing w/ many unique primitives
我在 iOS 上使用 OpenGL ES 2 来渲染一个(相对)巨大的二维网格,其中正方形 ("pixels") 是不连续的——间隔开,而不是棋盘图案—— - 并勾勒出轮廓,并且我正在最糟糕的时间试图找出一种有效的方法来绘制它,以便可以为每个正方形和该正方形的轮廓分配不同的颜色,因为这是用于绘图应用程序的。网格必须能够表示最大 1024x1024 "pixels".
最初,我尝试将我所有的顶点数据放在一个巨大的缓冲区中,并在每帧调用一次 glDrawArrays
来渲染它,但是,正如您所预料的那样,内存使用是不合理的并且那只是轮廓(用 GL_LINES 制作)——没有填充。进一步的研究教会了我有关实例化绘图的知识,我现在正在通过 glDrawArraysInstancedEXT
进行此操作,但是,当然,1024*1024 实例化绘图调用正在扼杀 CPU/FPS。我猜这个问题的解决方案介于这两种方法之间——绘制一个更大的 "grouped" GL_TRIANGLE_STRIPs 原语,使用退化顶点来分隔生成的正方形……但我不认为我可以给每个方块赋予它自己的颜色。不用说,我还在学习;人们通常如何绘制大量简单、相同但颜色独特的多边形??
相关代码...
static const int numColumns = 1024;
static const int numRows = 1024;
static const GLfloat outlineVertices[] = {
0.1f, -0.1f,
0.9f, -0.1f,
0.1f, -0.9f,
0.9f, -0.9f
};
static const GLfloat innerVertices[] = {
0.2f, -0.2f,
0.8f, -0.2f,
0.2f, -0.8f,
0.8f, -0.8f
};
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
[self loadShaders];
glDisable(GL_DEPTH_TEST);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(outlineVertices), outlineVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniform1i(uniforms[NUM_COLUMNS], numColumns);
glUniform1i(uniforms[NUM_ROWS], numRows);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(outlineVertices), outlineVertices, GL_STATIC_DRAW);
glUniform1i(uniforms[DRAWING_INNER], 0);
glDrawArraysInstancedEXT(GL_TRIANGLE_STRIP, 0, 4, numColumns * numRows);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(innerVertices), innerVertices, GL_STATIC_DRAW);
glUniform1i(uniforms[DRAWING_INNER], 1);
glDrawArraysInstancedEXT(GL_TRIANGLE_STRIP, 0, 4, numColumns * numRows);
}
vshader:
#extension GL_EXT_draw_instanced : enable
attribute vec4 vertices;
varying lowp vec4 colorVarying;
uniform int numColumns;
uniform int numRows;
uniform mat4 modelViewProjectionMatrix;
uniform int drawingInner;
void main()
{
if (drawingInner == 0) {
colorVarying = vec4(1.0, 0.0, 1.0, 1.0);
} else {
colorVarying = vec4(0.0, 0.0, 1.0, 1.0);
}
float column = mod(float(gl_InstanceIDEXT), float(numColumns));
float row = -(float(gl_InstanceIDEXT / numColumns));
gl_Position = vec4(vertices.x + column, vertices.y + row, vertices.zw) * modelViewProjectionMatrix;
}
感谢您提供任何帮助,包括有关最佳做法的提示。有没有一种方法可以有效地绘制这个巨大的网格,而无需根据用户当前看到的内容更改数据……某种手动剔除?谢谢!
最好只在片段着色器中执行此操作。这样,您就可以只使用普通的普通纹理,而不必渲染除单个四边形之外的任何东西。这是一个绘制网格的着色器,每个像素具有不同的前景/背景颜色。它在 ShaderToy 中写入 运行,因此您必须根据您的程序对其进行调整。
我放了一个live demo on ShaderToy(和下面的代码有点不同,所以可以运行在ShaderToy上)
片段着色器
precision mediump float;
// Texture coordinates, from 0 to 1
varying vec2 TexCoord;
uniform sampler2D FGTex;
uniform sampler2D BGTex;
// Texture size, in pixels.
uniform vec2 TexSize;
// Width of grid lines, from 0 to 1
uniform float GridWidth;
void main() {
// Get the foreground and background colors
vec4 fgColor = texture2D(FGTex, TexCoord);
vec4 bgColor = texture2D(BGTex, TexCoord);
// Calculate the grid
vec2 gridPos = fract(TexCoord * TexSize + GridWidth * 0.5);
vec2 gridFrac = step(GridWidth, gridPos);
gl_FragColor = mix(bgColor, fgColor, gridFrac.x * gridFrac.y);
}
结果
请注意,网格线是不一致的,除非您完全正确地进行数学运算以使它们对齐,但无论如何您都必须这样做。
我在 iOS 上使用 OpenGL ES 2 来渲染一个(相对)巨大的二维网格,其中正方形 ("pixels") 是不连续的——间隔开,而不是棋盘图案—— - 并勾勒出轮廓,并且我正在最糟糕的时间试图找出一种有效的方法来绘制它,以便可以为每个正方形和该正方形的轮廓分配不同的颜色,因为这是用于绘图应用程序的。网格必须能够表示最大 1024x1024 "pixels".
最初,我尝试将我所有的顶点数据放在一个巨大的缓冲区中,并在每帧调用一次 glDrawArrays
来渲染它,但是,正如您所预料的那样,内存使用是不合理的并且那只是轮廓(用 GL_LINES 制作)——没有填充。进一步的研究教会了我有关实例化绘图的知识,我现在正在通过 glDrawArraysInstancedEXT
进行此操作,但是,当然,1024*1024 实例化绘图调用正在扼杀 CPU/FPS。我猜这个问题的解决方案介于这两种方法之间——绘制一个更大的 "grouped" GL_TRIANGLE_STRIPs 原语,使用退化顶点来分隔生成的正方形……但我不认为我可以给每个方块赋予它自己的颜色。不用说,我还在学习;人们通常如何绘制大量简单、相同但颜色独特的多边形??
相关代码...
static const int numColumns = 1024;
static const int numRows = 1024;
static const GLfloat outlineVertices[] = {
0.1f, -0.1f,
0.9f, -0.1f,
0.1f, -0.9f,
0.9f, -0.9f
};
static const GLfloat innerVertices[] = {
0.2f, -0.2f,
0.8f, -0.2f,
0.2f, -0.8f,
0.8f, -0.8f
};
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
[self loadShaders];
glDisable(GL_DEPTH_TEST);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(outlineVertices), outlineVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniform1i(uniforms[NUM_COLUMNS], numColumns);
glUniform1i(uniforms[NUM_ROWS], numRows);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(outlineVertices), outlineVertices, GL_STATIC_DRAW);
glUniform1i(uniforms[DRAWING_INNER], 0);
glDrawArraysInstancedEXT(GL_TRIANGLE_STRIP, 0, 4, numColumns * numRows);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(innerVertices), innerVertices, GL_STATIC_DRAW);
glUniform1i(uniforms[DRAWING_INNER], 1);
glDrawArraysInstancedEXT(GL_TRIANGLE_STRIP, 0, 4, numColumns * numRows);
}
vshader:
#extension GL_EXT_draw_instanced : enable
attribute vec4 vertices;
varying lowp vec4 colorVarying;
uniform int numColumns;
uniform int numRows;
uniform mat4 modelViewProjectionMatrix;
uniform int drawingInner;
void main()
{
if (drawingInner == 0) {
colorVarying = vec4(1.0, 0.0, 1.0, 1.0);
} else {
colorVarying = vec4(0.0, 0.0, 1.0, 1.0);
}
float column = mod(float(gl_InstanceIDEXT), float(numColumns));
float row = -(float(gl_InstanceIDEXT / numColumns));
gl_Position = vec4(vertices.x + column, vertices.y + row, vertices.zw) * modelViewProjectionMatrix;
}
感谢您提供任何帮助,包括有关最佳做法的提示。有没有一种方法可以有效地绘制这个巨大的网格,而无需根据用户当前看到的内容更改数据……某种手动剔除?谢谢!
最好只在片段着色器中执行此操作。这样,您就可以只使用普通的普通纹理,而不必渲染除单个四边形之外的任何东西。这是一个绘制网格的着色器,每个像素具有不同的前景/背景颜色。它在 ShaderToy 中写入 运行,因此您必须根据您的程序对其进行调整。
我放了一个live demo on ShaderToy(和下面的代码有点不同,所以可以运行在ShaderToy上)
片段着色器
precision mediump float;
// Texture coordinates, from 0 to 1
varying vec2 TexCoord;
uniform sampler2D FGTex;
uniform sampler2D BGTex;
// Texture size, in pixels.
uniform vec2 TexSize;
// Width of grid lines, from 0 to 1
uniform float GridWidth;
void main() {
// Get the foreground and background colors
vec4 fgColor = texture2D(FGTex, TexCoord);
vec4 bgColor = texture2D(BGTex, TexCoord);
// Calculate the grid
vec2 gridPos = fract(TexCoord * TexSize + GridWidth * 0.5);
vec2 gridFrac = step(GridWidth, gridPos);
gl_FragColor = mix(bgColor, fgColor, gridFrac.x * gridFrac.y);
}
结果
请注意,网格线是不一致的,除非您完全正确地进行数学运算以使它们对齐,但无论如何您都必须这样做。