将 OpenGL 应用移植到 Metal API
Porting OpenGL app to Metal API
在 OpenGL 中我得到了这个(缩短的代码)
void Mesh::CreateBuffer() {
glBindBuffer( GL_ARRAY_BUFFER, m_Buffers[POS_VB] );
glBufferData( GL_ARRAY_BUFFER, sizeof(Positions[0] /*vec3*/) * iVerticeNum, &Positions[0], GL_STATIC_DRAW );
glEnableVertexAttribArray( POSITION_LOCATION );
glVertexAttribPointer( POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0 );
// Fill index buffer.
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_Buffers[INDEX_BUFFER] );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices[0] /*unsigned int*/) * iIndiceNum, &Indices[0], GL_STATIC_DRAW );
}
void Mesh::Render() {
// bind vertex arrays here!
.....
glDrawElements( GL_TRIANGLES, this->NumIndices, GL_UNSIGNED_INT, 0);
....
}
上面的代码在我的引擎中运行完美。但是当我决定将它移植到 Metal API 时,我遇到了一些问题,- 它只使用 index data 渲染了一半的模型,有 NO 组在它的网格中,它只是简单的网格。但是当我尝试使用顶点数据 ( drawPrimitives ) 渲染它时,它渲染得很好。
这是我用来初始化和渲染我的网格的 Metal 代码:
INIT
....
// Initialize mesh.
MetalMesh mesh;
mesh.vertexBuffer = [MetalDataBase->device newBufferWithBytes:Positions/* Vertice data */
length:sizeof(vec3) * iNumVertices
options:MTLResourceOptionCPUCacheModeDefault];
mesh.indexBuffer = [MetalDataBase->device newBufferWithBytes:Indices
length:sizeof(unsigned int) * iNumIndices
options:MTLResourceOptionCPUCacheModeDefault];
DRAW
// Drawing..
[MetalDataBase->commandEncoder setVertexBuffer:metalResource->metalMeshes[index].vertexBuffer offset:0 atIndex:0];
// DrawPrimitives renders mesh **fine**, as it should.
//[MetalDataBase->commandEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:iVerticeNum];
// But it doesn't, it just renders half of model,
// while **iIndiceNum** is right number with its data.
[MetalDataBase->commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:iIndiceNum indexType:MTLIndexTypeUInt32 indexBuffer:metalResource->metalMeshes[index].indexBuffer indexBufferOffset:0];
好的,我已经解决了问题。
可以在这里找到类似的线程:
http://www.gamedev.net/topic/544669-d3d9-only-1st-submesh-renders-w-indexed-vertexbuffer-solved/
首先,我使用了几个子网格,在 OpenGL 中我有这样的东西:
// Count the number of vertices and indices
for( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) {
m_Entries[i].MaterialIndex = pScene->mMeshes[i]->mMaterialIndex;
m_Entries[i].NumIndices = (pScene->mMeshes[i]->mNumFaces * VerticesPerPrim);
m_Entries[i].NumVertices = pScene->mMeshes[i]->mNumVertices;
m_Entries[i].BaseVertex = NumVertices;
m_Entries[i].BaseIndex = NumIndices;
Con::Printf( LOG_INFO, "\t\tMesh #%i: %i vertices and %i indices\r\n", i, NumVertices, NumIndices );
NumVertices += pScene->mMeshes[i]->mNumVertices;
NumIndices += m_Entries[i].NumIndices;
}
.... load bones, textures etc..
// Load INDEXIES(haha) data now
if(something) { ..
for( unsigned int i = 0; i < paiMesh->mNumFaces; ++i ) {
const aiFace & Face = paiMesh->mFaces[i];
//if( Face.mNumIndices == 3 ) {
Indices[iIndiceNum] = Face.mIndices[0]; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[1]; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[2]; ++iIndiceNum;
//}
}
}
但经过一番折腾和拉扯,我发现了一个 link 我之前 post 编辑的,它帮助了我(查看最后一个 post )。所以在 Metal 中我现在有这样的东西:(注意 'for' 循环第二行的 '+NumVertices' )
const unsigned int VerticesPerPrim = m_withAdjacencies ? 6 : 3;
// Count the number of vertices and indices
for( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) {
m_Entries[i].MaterialIndex = pScene->mMeshes[i]->mMaterialIndex;
m_Entries[i].NumIndices = (pScene->mMeshes[i]->mNumFaces * VerticesPerPrim) + NumVertices ;
m_Entries[i].NumVertices = pScene->mMeshes[i]->mNumVertices;
m_Entries[i].BaseVertex = NumVertices;
m_Entries[i].BaseIndex = NumIndices;
g_Console->Print( LOG_INFO, "\t\tMesh #%i: %i vertices and %i indices\r\n", i, NumVertices, NumIndices );
NumVertices += pScene->mMeshes[i]->mNumVertices;
NumIndices += m_Entries[i].NumIndices;
}
.. load bones, textures, etc now....
// Load INDEXIEES data
if( something ) {
int offset = 0;
if( MeshIndex > 0 )
for ( int k = 0; k < MeshIndex; k++ )
offset += wtf->mMeshes[k]->mNumVertices;
for( unsigned int i = 0; i < paiMesh->mNumFaces; ++i ) {
const aiFace & Face = paiMesh->mFaces[i];
//if( Face.mNumIndices == 3 ) {
Indices[iIndiceNum] = Face.mIndices[0] + offset; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[1] + offset; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[2] + offset; ++iIndiceNum;
//}
}
}
哈哈,谢谢'indexes','vertexes'语法提示。
这是我使用 Metal 渲染它的方式:
// index = mesh index in Metal API(kinda array)
for( int i = 0; i < mesh[j]->mNumMeshes; ++i )
[MetalDataBase->commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:m_Entries[i].numIndices indexType:MTLIndexTypeUInt32 indexBuffer:metalResource->metalMeshes[index].indexBuffer indexBufferOffset:0];
Soo,现在我得到了完全加载的网格(及其子网格):
在 OpenGL 中我得到了这个(缩短的代码)
void Mesh::CreateBuffer() {
glBindBuffer( GL_ARRAY_BUFFER, m_Buffers[POS_VB] );
glBufferData( GL_ARRAY_BUFFER, sizeof(Positions[0] /*vec3*/) * iVerticeNum, &Positions[0], GL_STATIC_DRAW );
glEnableVertexAttribArray( POSITION_LOCATION );
glVertexAttribPointer( POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0 );
// Fill index buffer.
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_Buffers[INDEX_BUFFER] );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices[0] /*unsigned int*/) * iIndiceNum, &Indices[0], GL_STATIC_DRAW );
}
void Mesh::Render() {
// bind vertex arrays here!
.....
glDrawElements( GL_TRIANGLES, this->NumIndices, GL_UNSIGNED_INT, 0);
....
}
上面的代码在我的引擎中运行完美。但是当我决定将它移植到 Metal API 时,我遇到了一些问题,- 它只使用 index data 渲染了一半的模型,有 NO 组在它的网格中,它只是简单的网格。但是当我尝试使用顶点数据 ( drawPrimitives ) 渲染它时,它渲染得很好。
这是我用来初始化和渲染我的网格的 Metal 代码:
INIT
....
// Initialize mesh.
MetalMesh mesh;
mesh.vertexBuffer = [MetalDataBase->device newBufferWithBytes:Positions/* Vertice data */
length:sizeof(vec3) * iNumVertices
options:MTLResourceOptionCPUCacheModeDefault];
mesh.indexBuffer = [MetalDataBase->device newBufferWithBytes:Indices
length:sizeof(unsigned int) * iNumIndices
options:MTLResourceOptionCPUCacheModeDefault];
DRAW
// Drawing..
[MetalDataBase->commandEncoder setVertexBuffer:metalResource->metalMeshes[index].vertexBuffer offset:0 atIndex:0];
// DrawPrimitives renders mesh **fine**, as it should.
//[MetalDataBase->commandEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:iVerticeNum];
// But it doesn't, it just renders half of model,
// while **iIndiceNum** is right number with its data.
[MetalDataBase->commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:iIndiceNum indexType:MTLIndexTypeUInt32 indexBuffer:metalResource->metalMeshes[index].indexBuffer indexBufferOffset:0];
好的,我已经解决了问题。 可以在这里找到类似的线程: http://www.gamedev.net/topic/544669-d3d9-only-1st-submesh-renders-w-indexed-vertexbuffer-solved/
首先,我使用了几个子网格,在 OpenGL 中我有这样的东西:
// Count the number of vertices and indices
for( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) {
m_Entries[i].MaterialIndex = pScene->mMeshes[i]->mMaterialIndex;
m_Entries[i].NumIndices = (pScene->mMeshes[i]->mNumFaces * VerticesPerPrim);
m_Entries[i].NumVertices = pScene->mMeshes[i]->mNumVertices;
m_Entries[i].BaseVertex = NumVertices;
m_Entries[i].BaseIndex = NumIndices;
Con::Printf( LOG_INFO, "\t\tMesh #%i: %i vertices and %i indices\r\n", i, NumVertices, NumIndices );
NumVertices += pScene->mMeshes[i]->mNumVertices;
NumIndices += m_Entries[i].NumIndices;
}
.... load bones, textures etc..
// Load INDEXIES(haha) data now
if(something) { ..
for( unsigned int i = 0; i < paiMesh->mNumFaces; ++i ) {
const aiFace & Face = paiMesh->mFaces[i];
//if( Face.mNumIndices == 3 ) {
Indices[iIndiceNum] = Face.mIndices[0]; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[1]; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[2]; ++iIndiceNum;
//}
}
}
但经过一番折腾和拉扯,我发现了一个 link 我之前 post 编辑的,它帮助了我(查看最后一个 post )。所以在 Metal 中我现在有这样的东西:(注意 'for' 循环第二行的 '+NumVertices' )
const unsigned int VerticesPerPrim = m_withAdjacencies ? 6 : 3;
// Count the number of vertices and indices
for( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) {
m_Entries[i].MaterialIndex = pScene->mMeshes[i]->mMaterialIndex;
m_Entries[i].NumIndices = (pScene->mMeshes[i]->mNumFaces * VerticesPerPrim) + NumVertices ;
m_Entries[i].NumVertices = pScene->mMeshes[i]->mNumVertices;
m_Entries[i].BaseVertex = NumVertices;
m_Entries[i].BaseIndex = NumIndices;
g_Console->Print( LOG_INFO, "\t\tMesh #%i: %i vertices and %i indices\r\n", i, NumVertices, NumIndices );
NumVertices += pScene->mMeshes[i]->mNumVertices;
NumIndices += m_Entries[i].NumIndices;
}
.. load bones, textures, etc now....
// Load INDEXIEES data
if( something ) {
int offset = 0;
if( MeshIndex > 0 )
for ( int k = 0; k < MeshIndex; k++ )
offset += wtf->mMeshes[k]->mNumVertices;
for( unsigned int i = 0; i < paiMesh->mNumFaces; ++i ) {
const aiFace & Face = paiMesh->mFaces[i];
//if( Face.mNumIndices == 3 ) {
Indices[iIndiceNum] = Face.mIndices[0] + offset; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[1] + offset; ++iIndiceNum;
Indices[iIndiceNum] = Face.mIndices[2] + offset; ++iIndiceNum;
//}
}
}
哈哈,谢谢'indexes','vertexes'语法提示。
这是我使用 Metal 渲染它的方式:
// index = mesh index in Metal API(kinda array)
for( int i = 0; i < mesh[j]->mNumMeshes; ++i )
[MetalDataBase->commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:m_Entries[i].numIndices indexType:MTLIndexTypeUInt32 indexBuffer:metalResource->metalMeshes[index].indexBuffer indexBufferOffset:0];
Soo,现在我得到了完全加载的网格(及其子网格):