在iOS上的OpenGL-ES中绘制线条的简单方法

时间:2015-09-06 21:39:10

标签: ios objective-c opengl-es

我一直试图在iOS上用OpenGL创建一个绘图库。我需要绘制具有良好性能的实时数据。我之前使用过OpenGL,但OpenGL-ES似乎非常困难。

这是我根据我所知道的OpenGL和我在网上找到的内容拼凑而成的代码。

GLfloat* curve = [_dataSource curveForOGLGraphObject:self];
GLuint curveLength = [_dataSource lengthOfCurveForOGLGraphObject:self];

GLfloat lineVertices[curveLength*2];

int i;
for (i = 0; i < curveLength; i++)
{
    lineVertices[i * 2] = i;
    lineVertices[i * 2 + 1] = curve[i];
}

// Have OpenGL generate a buffer name and store it in the buffer object array
glGenBuffers(1, &viewRenderBuffer);

// Bind the buffer object array to the GL_ARRAY_BUFFER target buffer
glBindBuffer(GL_ARRAY_BUFFER, viewRenderBuffer);

// Send the line data over to the target buffer in GPU RAM
glBufferData(
             GL_ARRAY_BUFFER,   // the target buffer
             sizeof(lineVertices),      // the number of bytes to put into the buffer
             lineVertices,              // a pointer to the data being copied
             GL_STATIC_DRAW);   // the usage pattern of the data

// Enable vertex data to be fed down the graphics pipeline to be drawn
glEnableVertexAttribArray(GLKVertexAttribPosition);

// Specify how the GPU looks up the data
glVertexAttribPointer(
                      GLKVertexAttribPosition, // the currently bound buffer holds the data
                      2,                       // number of coordinates per vertex
                      GL_FLOAT,                // the data type of each component
                      GL_FALSE,                // can the data be scaled
                      2*sizeof(float),                     // how many bytes per vertex (2 floats per vertex)
                      NULL);                   // offset to the first coordinate, in this case 0
glLineWidth(3.0f);
glDrawArrays(GL_LINE_STRIP, 0, curveLength); // render

我以前习惯使用glBegin()和glEnd(),但我可以理解它们被移除的原因。但是,这似乎是绘制线条的一种痛苦方式。特别是因为使用glColor4f似乎没有任何效果,但如果我只想要一条纯色线,那么为每个顶点指定一个颜色似乎很疯狂。

2 个答案:

答案 0 :(得分:0)

桌面上的旧OpenGL与GLES 2.0之间的最大区别在于前者是可配置,而后者是可编程

因此,在较旧的OpenGL中,您可以使用glColor4f为顶点设置全局颜色,现在您可以灵活地在着色器中根据您想要的任何数据源计算该颜色,无论是是一个缓冲区,每个顶点都有一个颜色,一个是统一的,硬编码的,或者其他一些东西。

这意味着更多的工作,但这也意味着你可以实现以前不可能的效果。

以下是如何仅使用4个GLFloats来实现目标的示例:

//In your Objc code (On the CPU)
GLFloat color[4]; //declared elsewhere
glVertexAttrib4f(MyShadersColorAttributeHandle, color[0], color[1], color[2], color[3]);
//MyShaderColorAttribHandle is acquired when you are setting up your shaders.

//On the GPU: vertex shader

attribute vec3 position;
attribute vec4 color; //corresponds to MyShadersColorAttributeHandle

void main() {
  gl_Position = position;
}

// fragment shader
vary lowp vec4 color;
void main {    
    gl_FragColor = color;
}

其他一些观察结果:

  • Core Plot是一个应该满足您需求的现有框架。
  • 我非常怀疑你确实需要OpenGL ES来实现你的目标。核心图形很可能足够好,而且会更简单。
  • 目前还不清楚你要做什么,但是每次画画时你可能都不需要制作新的渲染缓冲区。您可以(并且应该)重复使用此对象,或者从视图层获取该对象。
  • 如果您的数据是实时更新的,您可能不想要GL_STATIC_DRAW,因为这意味着重复使用相同的数据。

答案 1 :(得分:0)

您发布的代码非常少,并且描述的问题非常糟糕。对于你正在做的事情你也可以使用具有固定管道的ES1,你不需要任何着色器,代码将与你似乎习惯的代码非常相似。即使glColor4f也可以。

在任何情况下,你都应该尝试尽可能多地绘制一个三角形或一条线,以便我可以设置颜色和位置。之后,您将轻松整合您的线条。

但是你必须注意很多事情。如前所述,您将被限制为某些FPS,对于所有重要设备应为60。这就是为什么您的绘图引擎应该收集数据而不是从系统中提供数据并迫使openGL绘制的原因。这意味着您应该使用计时器重绘场景并收集当前准备好的数据。例如,创建一个将保存顶点数据(点和计数)的类。获取新数据时,创建此类,填充数据并将其存储在某个属性中。现在,当绘图是自由的时,您可以从属性中收集相同的对象并使用它来绘制。如果openGL变慢并且效果非常传统,则可以跳过某些数据缓冲区。

至于你正在使用的缓冲区,我认为它们在你的情况下毫无用处。您通常会在GPU上生成缓冲区(glGenBuffers),因此您可以重复使用它们并减少GPU的流量。既然你不断创建缓冲区并将数据推送到它们,我会说你只是产生了开销。对于持续流式传输,最好只删除缓冲区并将指针本身作为最后一个参数提供给glVertexAttribPointer(... , lineVertices)。另一种方法是生成足够大的缓冲区并始终将数据流式传输到同一缓冲区,同时将标志更改为GL_DYNAMIC_DRAW甚至GL_STREAM_DRAW。如果需要,您可能希望自己测试这3个程序以获得性能。一旦使用完毕,请不要忘记删除缓冲区。

关于绘制线条本身有很多报道最好将矩形绘制为三角形条带以获得性能。这是您可能想要检查的另一件事。

关于ES2 +和已经提到的颜色,只需将其硬编码到着色器中或使用制服,如果你想将它作为常量。否则你可以在着色器中做很多事情,例如你可以使用像素位置来制作颜色,这样最底部的点是蓝色,最顶部的红色创建一个漂亮的渐变。