2013-02-12 84 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毫秒。正如我所說,我真的不明白爲什麼這會修復任何事情,但這是一個解決方案。