Распространенные подводные камни / причины неверных данных вершин?

Итак, я работаю над этим .OBJ / .MTL-синтаксическим анализатором последние полторы недели. За это время я выслеживал / исправлял много ошибок, очищал код, документировал его и т. Д. И т. Д.

Проблема в том, что с каждой исправленной ошибкой все еще возникает эта проблема, и поскольку картинка стоит тысячи слов …

Использование GL_LINE_LOOP

(ПРИМЕЧАНИЕ: проблема заключается в том, что пирамида справа отклоняется наружу от сферы)

петля сферы

Использование GL_TRIANGLES

сферические треугольники

Еще более интересно то, что эти «плохие» данные о вершинах движутся вместе с камерой при перемещении по сцене … за исключением того, что они масштабируются и торчат за пределы меша.

Странно то, что, хотя я уверен, что проблема связана с памятью, я проверял наличие проблем, которые противоречат тому, работает ли алгоритм синтаксического анализа должным образом. После некоторых юнит-тестов он работает нормально.

Итак, я подумал, что это может быть проблема с драйвером Linux nVidia. Я обновил драйвер до следующей версии, перезапустил, и все еще не играли в кости.

После долгих размышлений я пытался найти ошибки в следующем коде.

            //! every 3 vertices should represent a triangle, therefore we'll want to
//! use the indices to grab their corresponding vertices. Since the cross product
//! of two sides of every triangle (where one side = Vn - Vm, 'n' and 'm' being on the range of 1..3),
//! we first grab the three vertices, and then compute the normal using the their differences.

const uInt32 length = mesh->vertices.size();

//! declare a pointer to the vector so we can perform simple
//! memory copies to get the indices for each triangle within the
//! iteration.

GLuint* const pIndexBuf = &mesh->indices[ 0 ];

for ( uInt32 i = 0; i < length; i += 3 )
{
GLuint thisTriIndices[ 3 ];

memcpy( thisTriIndices, pIndexBuf + i, sizeof( GLuint ) * 3 );

vec3 vertexOne   = vec3( mesh->vertices[ thisTriIndices[ 0 ] ] );
vec3 vertexTwo   = vec3( mesh->vertices[ thisTriIndices[ 1 ] ] );
vec3 vertexThree = vec3( mesh->vertices[ thisTriIndices[ 2 ] ] );

vec3 sideOne        = vertexTwo - vertexOne;
vec3 sideTwo        = vertexThree - vertexOne;

vec3 surfaceNormal  = glm::cross( sideOne, sideTwo );

mesh->normals.push_back( surfaceNormal );
}

Текущий, показанный на рисунке, даже не имеет нормальных данных, поэтому идея состоит в том, чтобы вычислить для него нормали поверхности, отсюда и приведенный выше код. Хотя я проверил несколько проверок, правильно ли загружались данные индекса в цикле, я пока не смог ничего найти.

Я думаю, что у моей памяти тоже могут быть проблемы, но я не могу понять, в чем проблема. Если я что-то пропустил, я добавлю вызовы glVertexAttribPointer:

//! Gen some buf handles

glGenBuffers( NUM_BUFFERS_PER_MESH, mesh->buffers );

//! Load the respective buffer data for the mesh

__LoadVec4Buffer( mesh->buffers[ BUFFER_VERTEX ], mesh->vertices );      //! positons
__LoadVec4Buffer( mesh->buffers[ BUFFER_COLOR ], mesh->colors );         //! material colors
__LoadVec3Buffer( mesh->buffers[ BUFFER_NORMAL ], mesh->normals );       //! normals
__LoadIndexBuffer( mesh->buffers[ BUFFER_INDEX ], mesh->indices );       //! indices

//! assign the vertex array a value

glGenVertexArrays( 1, &mesh->vertexArray );

//! Specify the memory layout for each attribute

glBindVertexArray( mesh->vertexArray );

//! Position and color are both stored in BUFFER_VERTEX.

glBindBuffer( GL_ARRAY_BUFFER, mesh->buffers[ BUFFER_VERTEX ] );

glEnableVertexAttribArray( meshProgram->attributes[ "position" ] );
glVertexAttribPointer( meshProgram->attributes[ "position" ],               //! index
4,                                                   //! num vals
GL_FLOAT, GL_FALSE,                                  //! value type, normalized?
sizeof( vec4 ),                                      //! number of bytes until next value in the buffer
( void* ) 0 );                                       //! offset of the memory in the buffer

glBindBuffer( GL_ARRAY_BUFFER, mesh->buffers[ BUFFER_COLOR ] );

glEnableVertexAttribArray( meshProgram->attributes[ "color" ] );
glVertexAttribPointer( meshProgram->attributes[ "color" ],
4,
GL_FLOAT, GL_FALSE,
sizeof( vec4 ),
( void* ) 0 );

//! Now we specify the layout for the normals

glBindBuffer( GL_ARRAY_BUFFER, mesh->buffers[ BUFFER_NORMAL ] );

glEnableVertexAttribArray( meshProgram->attributes[ "normal" ] );
glVertexAttribPointer( meshProgram->attributes[ "normal" ],
3,
GL_FLOAT, GL_FALSE,
sizeof( vec3 ),
( void* )0 );

//! Include the index buffer within the vertex array

glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->buffers[ BUFFER_INDEX ] );

glBindVertexArray( 0 );

Любая точка в правильном направлении, по крайней мере, будет оценена: я понятия не имею, каковы общие причины этих проблем.

Изменить: опубликованный код розыгрыша по запросу

glBindVertexArray( mMeshes[ i ]->vertexArray );

UBO::LoadMatrix4( UBO::MATRIX_MODELVIEW, modelView.top() );
UBO::LoadMatrix4( UBO::MATRIX_PROJECTION, camera.projection() );

glDrawElements( GL_TRIANGLES, mMeshes[ i ]->indices.size(), GL_UNSIGNED_INT, ( void* )0 );

glBindVertexArray( 0 );

0

Решение

Я нашел окончательного виновника, в сочетании с предложениями @ radical7, они по большей части решили проблему.

            // round mesh->indices.size() down if it's not already divisible by 3.
// the rounded value is stored in numTris

std::vector< vec4 > newVertices;

uInt32 indicesLen = Math_FloorForMultiple( mesh->indices.size(), 3 );

// declare a pointer to the vector so we can perform simple
// memory copies to get the indices for each triangle within the
// iteration.

newVertices.reserve( indicesLen );

const GLuint* const pIndexBuf = &mesh->indices[ 0 ];

for ( uInt32 i = 0; i < indicesLen; i += 3 )
{
const GLuint* const thisTriIndices = pIndexBuf + i;

vec4 vertexOne   = mesh->vertices[ thisTriIndices[ 0 ] - 1 ];
vec4 vertexTwo   = mesh->vertices[ thisTriIndices[ 1 ] - 1 ];
vec4 vertexThree = mesh->vertices[ thisTriIndices[ 2 ] - 1 ];

vec4 sideOne     = vertexTwo - vertexOne;
vec4 sideTwo     = vertexThree - vertexOne;

vec3 surfaceNormal = glm::cross( vec3( sideOne ), vec3( sideTwo ) );

mesh->normals.push_back( surfaceNormal );
mesh->normals.push_back( surfaceNormal + vec3( sideOne ) );
mesh->normals.push_back( surfaceNormal + vec3( sideTwo ) );

newVertices.push_back( vertexOne );
newVertices.push_back( vertexTwo );
newVertices.push_back( vertexThree );
}mesh->vertices.clear();
mesh->vertices = newVertices;

Обратите внимание, что когда вершины захватываются в цикле, с помощью вызова mesh->vertices[ thisTriIndices[ x ] - 1 ], - 1 чрезвычайно важно: файлы сетки OBJ хранят свои индексы лица, начиная с индексов 1 … N, а не индексов 0 …. N-1.

Сами индексы также следует использовать не для рисования сетки, а скорее как средство для получения нового буфера вершин из уже временного буфера вершин: индексы используются для доступа к элементам во временных вершинах, а затем для каждая вершина, полученная из временного буфера, вы добавлять эта вершина в новый буфер. Таким образом, вы получите количество вершин, указанное в правильном порядке прорисовки. Таким образом, вы хотите нарисовать их, используя только массивы вершин.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]