2013-02-12 85 views
-1

首先,让我澄清我的意思是“分组模型”。我不确定这是什么标准术语。为了减少渲染调用次数,我将多个模型分组到一个模型中,并使用一次调用glDrawElements(使用VBOs)来渲染整个模型。在我的代码中,我称之为ModelGroup。我将它用于各种事物,但特别适用于大量几何简单物体(如城市中的建筑物或粒子)。分组模型在iOS中缓慢渲染(OpenGL ES 2.0)

这个问题最近出现在我的ModelGroup渲染速度非常慢的地方。我已经通过在其周围放置一个计时器来隔离实际调用glDrawElements的放缓。例如,我的粒子用于在约2ms左右渲染〜10k粒子(没有实例化)。我不记得确切的数字,但让我们说,渲染绝对不是目前的瓶颈。到目前为止,一次调用glDrawElements包含10k个粒子的时间约为256ms。这种性能仅比使用单独调用glDrawElement来渲染对象稍微好一些。所以,出于某种原因,GPU显然存在巨大的负担。

我的引擎发生了什么变化: 我最近更新了XCode,并从使用EAGLView更改为使用GLKViewController。在我的代码中,我没有改变这两种完全不同的表现状态。我会说,为了迁移到GLKViewController的使用,我完全重新创建了我的项目并添加了所有的源文件。然后我重写了我的游戏循环,并由GLKViewController的更新函数进行更新。然而,这是一个非常小的变化。

为了完全清楚我的ModelGroup类的功能,我将发布将所添加的模型编译到呈现的显示模型中的函数。

-(bool) compileDisplayModelWithNormals:(bool)updateNormals withTexcoords:(bool)updateTexcoords withColor:(bool)updateColor withElements:(bool)updateElements 
{ 
    modelCompiled = YES; 
    bool initd = displayModel->positions; 

    // set properties 
    if(!initd) 
    { 
     displayModel->primType = GL_UNSIGNED_SHORT; 
     displayModel->elementType = GL_TRIANGLES; 
     displayModel->positionType = GL_FLOAT; 
     displayModel->texcoordType = GL_FLOAT; 
     displayModel->colorType = GL_FLOAT; 
     displayModel->normalType = GL_FLOAT; 
     displayModel->positionSize = 3; 
     displayModel->normalSize = 3; 
     displayModel->texcoordSize = 2; 
     displayModel->colorSize = 4; 

     // initialize to zero 
     displayModel->numVertices = 0; 
     displayModel->numElements = 0; 
     displayModel->positionArraySize = 0; 
     displayModel->texcoordArraySize = 0; 
     displayModel->normalArraySize = 0; 
     displayModel->elementArraySize = 0; 
     displayModel->colorArraySize = 0; 

     // sum the sizes 
     for(NSObject<RenderedItem> *ri in items) 
     { 
      GLModel *model = ri.modelAsset.model.displayModel; 
      displayModel->numVertices += model->numVertices; 
      displayModel->numElements += model->numElements; 
       displayModel->positionArraySize += model->positionArraySize; 
      displayModel->texcoordArraySize += model->texcoordArraySize; 
      displayModel->normalArraySize += model->normalArraySize; 
      displayModel->elementArraySize += model->elementArraySize; 
      displayModel->colorArraySize += model->colorArraySize; 
     } 
     displayModel->positions = (GLfloat *)malloc(displayModel->positionArraySize); 
     displayModel->texcoords = (GLfloat *)malloc(displayModel->texcoordArraySize); 
     displayModel->normals = (GLfloat *)malloc(displayModel->normalArraySize); 
     displayModel->elements = (GLushort *)malloc(displayModel->elementArraySize); 
     displayModel->colors = (GLfloat *)malloc(displayModel->colorArraySize); 
    } 

    // update the data 
    int vertexOffset = 0; 
    int elementOffset = 0; 
    for(int j = 0; j < [items count]; j++) 
    { 
     NSObject<RenderedItem> *ri = (GameItem *)[items objectAtIndex:j]; 
     GLModel *model = ri.modelAsset.model.displayModel; 
     if(!ri.geometryUpdate) 
     { 
      vertexOffset += model->numVertices; 
      continue; 
     } 
     // reset the update flag 
     ri.geometryUpdate = NO; 

     // get GameItem transform data 
     rpVec3 pos = [ri getPosition]; 
     rpMat3 rot = [ri orientation]; 

     int NoV = model->numVertices; 
     int NoE = model->numElements; 
     for(int i = 0; i < NoV; i++) 
     { 
      // positions 
      rpVec3 r = rpVec3(model->positions, model->positionSize * i); 

      // scale 
      rpVec3 s = ri.scale; 
      r.swizzleLocal(s); 

      // rotate 
      r = rot * r; 

      // translate 
      r.addLocal(pos); 
      int start = model->positionSize * (vertexOffset + i); 
      for(int k = 0; k < model->positionSize; k++) 
       displayModel->positions[start + k] = r[k]; 


      if(updateTexcoords) 
      { 
       // texcoords 
       start = model->texcoordSize * (vertexOffset + i); 
       if(model->texcoords) 
        for(int k = 0; k < model->texcoordSize; k++) 
         displayModel->texcoords[start + k] = model->texcoords[model->texcoordSize * i + k]; 
      } 
      if(updateNormals) 
      { 
       // normals (need to be rotated) 
       if(model->normals) 
       { 
        for(int k = 0; k < model->normalSize; k++) 
        { 
         rpVec3 vn = rpVec3(model->normals, model->normalSize * i); 
         rpVec3 vnRot = rot * vn; 
         start = model->normalSize * (vertexOffset + i); 
         displayModel->normals[start + k] = vnRot[k]; 
        } 
       } 
      } 
      if(updateColor) 
      { 
       if(model->colors) 
       { 
        start = model->colorSize * (vertexOffset + i); 
        displayModel->colors[start] = ri.color.r; 
        displayModel->colors[start + 1] = ri.color.g; 
        displayModel->colors[start + 2] = ri.color.b; 
        displayModel->colors[start + 3] = ri.color.a; 
       } 
      } 
     } 
     if(updateElements) 
     { 
      for(int i = 0; i < NoE; i++) 
      { 
       // elements 
       displayModel->elements[elementOffset + i] = model->elements[i] + vertexOffset; 
      } 
     } 
     vertexOffset += NoV; 
     elementOffset += NoE; 
    } 

    return YES; 
} 

只要是完整的,这里是我如何渲染粒子。里面的粒子场平局功能:

glBindVertexArray(modelGroup.displayModel->modelID); 
glBindTexture(GL_TEXTURE_2D, textureID); 

// set shader program 
if(changeShader) glUseProgram(shader.programID); 

[modelViewStack push]; 
mtxMultiply(modelViewProjectionMatrix.m, [projectionStack top].m, [modelViewStack top].m); 

glUniformMatrix4fv(shader.modelViewProjectionMatrixID, 1, GL_FALSE, modelViewProjectionMatrix.m); 
[DebugTimer check:@"particle main start"]; 
glDrawElements(GL_TRIANGLES, modelGroup.displayModel->numElements, GL_UNSIGNED_SHORT, 0); 
[DebugTimer check:@"particle main end"]; 

[modelViewStack pop]; 

夹着glDrawElements语句中的两个语句是我用来测量事件之间的时间计时器。

此外,我只是想补充一点,我已经在设备和iPad模拟器6.1上运行,结果相同。模拟器在执行多个绘图调用时速度较慢,但​​对于ModelGroup调用glDrawElements同样缓慢。就硬件加速而言,我已经检查过,以确保这种性能下降不会成为缺乏加速的一些副作用。我从一个包含1024个立方体(类似于城市的ModelGroup)的文件中读入一个模型,该模型没有任何问题(与ModelGroup中的1000个立方体没有20毫秒延迟)呈现。

回答

0

我相信我已经以一种说话的方式解决了这个谜团。毕竟,对我而言,这仍然是一个谜,为什么这能解决问题。

使用自己的自定义枚举值对于这些功能

glEnableVertexAttribArray 
glVertexAttribPointer 

,而不是使用新(为的iOS 5.0的,我认为)苹果公司指定之际,GLKViewController类的一部分值我已经:

GLKVertexAttribPosition 
GLKVertexAttribNormal 
GLKVertexAttribTexcoord0 

完成这样的更改产生调用glDrawElements当我预期的那种表现。我的模型组现在应该呈现大约0.1毫秒的数量级,而不是大约20毫秒。正如我所说,我真的不明白为什么这会修复任何事情,但这是一个解决方案。