Неправильный рендеринг буфера вершин OpenGL

0

У меня немного странная проблема. Я пытаюсь отобразить некоторые данные с помощью OpenGL в моей системе Windows. Я нашел набор учебников на opengl-tutorial.org, которые были написаны для OpenGL 3.3. Поскольку мой ноутбук (где я много развиваю) поддерживает OpenGL 2.1, я начал загружать OpenGL 2.1 порт учебника. Я немного испортил его, добавив функции и рефакторинг для масштабируемости, но заметил что-то странное. Всякий раз, когда я передавал свои данные с объектами Vertex Buffer, у меня было довольно неправильное представление моих данных. Это показано ниже. http://www.majhost.com/gallery/DagonEcelstraun/Others/HelpNeeded/badrender.png Однако, когда я указываю свои данные с помощью glVertex3fv и т.д., я получаю гораздо более приятный результат, как показано ниже. http://www.majhost.com/gallery/DagonEcelstraun/Others/HelpNeeded/goodrender.png Проблема возникает как на моем ноутбуке Windows 8.1 с интегрированной графикой Intel i3, так и на моем рабочем столе Windows 7 с его nVidia GTX 660, поэтому он не проблема с оборудованием. Кто-нибудь знает, что может быть проблемой здесь?

Загрузка данных сетки:

const aiScene *scene = aiImportFile( sName.c_str(), 
aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_FlipUVs );
const aiMesh *mesh = scene->mMeshes[0];
for( int i = 0; i < mesh->mNumVertices; i++ ) {
    meshData.push_back( mesh->mVertices[i][0] );
    meshData.push_back( mesh->mVertices[i][1] );
    meshData.push_back( mesh->mVertices[i][2] );

    meshData.push_back( mesh->mNormals[i][0] );
    meshData.push_back( mesh->mNormals[i][1] );
    meshData.push_back( mesh->mNormals[i][2] );

    meshData.push_back( mesh->mTextureCoords[0][i][0] );
    meshData.push_back( mesh->mTextureCoords[0][i][1] );
    meshData.push_back( 0 );

    meshData.push_back( mesh->mTangents[i][0] );
    meshData.push_back( mesh->mTangents[i][1] );
    meshData.push_back( mesh->mTangents[i][2] );
}

for( int i = 0; i < mesh->mNumFaces; i++ ) {
    for( int j = 0; j < 3; j++ ) {
        indices.push_back( mesh->mFaces[i].mIndices[j] );
    }
}

Перенос данных на видеокарту в первый раз (называемый сразу после предыдущего кода):

glGenBuffers( 1, &glVertData );
glBindBuffer( GL_ARRAY_BUFFER, glVertData );
glBufferData( GL_ARRAY_BUFFER, meshData.size() * sizeof( GLfloat ), &meshData[0], GL_STATIC_DRAW );

// Generate a buffer for the indices as well
glGenBuffers( 1, &glIndexes );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, glIndexes );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW );

Отображение сетки:

//Tell the shader to use our data
//bindVerts, bindUvs, bindNorms, and bindTangents refer to attribute variables in my shader
//vertexPosition_modelspace, vertexUV, vertexNormal_modelspace, and vertexTangent_modelspace, respectively.
this->verts = bindVerts;
this->uvs = bindUvs;
this->norms = bindNorms;
this->tangents = bindTangents;
glEnableVertexAttribArray( verts );
glEnableVertexAttribArray( uvs );
glEnableVertexAttribArray( norms );
glEnableVertexAttribArray( tangents );

//Specify how the graphics card should decode our data
// 1rst attribute buffer : vertices
glBindBuffer( GL_ARRAY_BUFFER, glVertData );
glVertexAttribPointer( verts, 3, GL_FLOAT, GL_FALSE, 12, (void*) 0 );

// 2nd attribute buffer : normals
glVertexAttribPointer( norms, 3, GL_FLOAT, GL_FALSE, 12, (void*) 3 ); 

//3rd attribute buffer : UVs
glVertexAttribPointer( uvs, 3, GL_FLOAT, GL_FALSE, 12, (void*) 6 );

//4th attribute buffer: tangents
glVertexAttribPointer( tangents, 3, GL_FLOAT, GL_FALSE, 12, (void*) 9 );

// Index buffer
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, glIndexes );

//rendering the mesh with VBOs:
glDrawElements( GL_LINES, indices.size(), GL_UNSIGNED_SHORT, (void*) 0 );

//specifying the vertex data individually:
glBegin( GL_TRIANGLES );
int ind;
for( int i = 0; i < indices.size(); i++ ) {
    ind = indices[i] * 12;
    glNormal3fv( &meshData[ind + 3] );
    glTexCoord2fv( &meshData[ind + 6] );
    glVertex3fv( &meshData[ind] );
}
glEnd();

//clean up after the render
glDisableVertexAttribArray( verts );
glDisableVertexAttribArray( uvs );
glDisableVertexAttribArray( norms );
glDisableVertexAttribArray( tangents );

Мой вершинный шейдер:

#version 130

// Input vertex data, different for all executions of this shader.
//it doesn't work, so we'll just get rid of it
attribute vec3 vertexPosition_modelspace;
attribute vec3 vertexUV;
attribute vec3 vertexNormal_modelspace;
attribute vec3 vertexTangent_modelspace;

// Output data ; will be interpolated for each fragment.
out vec2 UV;
out vec3 Position_worldspace;
out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;
out vec3 LightDirection_cameraspace;
out vec4 ShadowCoord;

// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform vec3 LightInvDirection_worldspace;
uniform mat4 DepthBiasMVP;
uniform sampler2D normalMap;

attribute vec3 vTangent;

void main() {
    // Output position of the vertex, in clip space : MVP * position
    gl_Position =  MVP * vec4( vertexPosition_modelspace, 1 );

    ShadowCoord = DepthBiasMVP *  vec4( vertexPosition_modelspace, 0 );

    // Position of the vertex, in worldspace : M * position
    Position_worldspace = ( M * vec4( vertexPosition_modelspace, 0 ) ).xyz;

    // Vector that goes from the vertex to the camera, in camera space.
    // In camera space, the camera is at the origin (0,0,0).
    EyeDirection_cameraspace = vec3( 0, 0, 0 ) - ( V * M *  vec4(         vertexPosition_modelspace, 0 ) ).xyz;

    // Vector that goes from the vertex to the light, in camera space
    LightDirection_cameraspace = ( V * vec4( LightInvDirection_worldspace, 0 ) ).xyz;

    // UV of the vertex. No special space for this one.
    UV = vertexUV.st;

    // Normal of the the vertex, in camera space
    // Only correct if ModelMatrix does not scale the model ! Use its inverse transpose if not.
    Normal_cameraspace = ( V * M * vec4( vertexNormal_modelspace.xyz, 0 ) ).xyz; 
}

Фрагментный шейдер:

#version 130

// Interpolated values from the vertex shaders
in vec2 UV;
in vec3 Position_worldspace;
in vec3 Normal_cameraspace;
in vec3 EyeDirection_cameraspace;
in vec3 LightDirection_cameraspace;
in vec4 ShadowCoord;

out vec4 fragColor;

// Values that stay constant for the whole mesh.
uniform sampler2D diffuse;
uniform mat4 MV;
uniform vec3 LightPosition_worldspace;
uniform sampler2D shadowMap;
//uniform int shadowLevel;  //0 is no shadow, 1 is hard shadows, 2 is soft shadows, 3 is PCSS

// Returns a random number based on a vec3 and an int.
float random( vec3 seed, int i ) {
    vec4 seed4 = vec4( seed, i );           
    float dot_product = dot( seed4, vec4( 12.9898, 78.233, 45.164, 94.673 ) );
    return fract( sin( dot_product ) * 43758.5453 );
}

int mod( int a, int b ) {
    return a - (a / b);
}

void main() {
    int shadowLevel = 1;    //let just do hard shadows
    // Light emission properties
    vec3 LightColor = vec3( 1, 1, 1 );
    float LightPower = 1.0f;

    // Material properties
    vec3 MaterialDiffuseColor = texture( diffuse, UV ).rgb;
    vec3 MaterialAmbientColor = vec3( 0.1, 0.1, 0.1 ) * MaterialDiffuseColor;
    vec3 MaterialSpecularColor = vec3( 0.3, 0.3, 0.3 );

    vec3 n = normalize( Normal_cameraspace );
    vec3 l = normalize( LightDirection_cameraspace );
    float cosTheta = clamp( dot( n, l ), 0.2, 1 );

    // Eye vector (towards the camera)
    vec3 E = normalize( EyeDirection_cameraspace );
    // Direction in which the triangle reflects the light
    vec3 R = reflect( -l, n );
    // Cosine of the angle between the Eye vector and the Reflect vector,
    // clamped to 0
    //  - Looking into the reflection -> 1
    //  - Looking elsewhere -> < 1
    float cosAlpha = clamp( dot( E, R ), 0, 1 );

    float visibility = 1.0;

    //variable bias
    float bias = 0.005 * tan( acos( cosTheta ) );
    bias = clamp( bias, 0, 0.01 );

    // dFragment to the light
    float dFragment = ( ShadowCoord.z-bias ) / ShadowCoord.w;
    float dBlocker = 0;
    float penumbra = 1;
    float wLight = 5.0;

    if( shadowLevel == 3 ) {
        // Sample the shadow map 8 times
        float count = 0;
        float temp;
        float centerBlocker = texture( shadowMap, ShadowCoord.xy).r;
        float scale = (wLight * (dFragment - centerBlocker)) / dFragment;
        for( int i = 0; i < 16; i++ ) {    
            temp = texture( shadowMap, ShadowCoord.xy + (scale * poissonDisk( i ) / 50.0) ).r;
            if( temp < dFragment ) {
                dBlocker += temp;
                count += 1;    
            }
        }

        if( count > 0 ) {
            dBlocker /= count;
            penumbra = wLight * (dFragment - dBlocker) / dFragment;
        }
    }

    if( shadowLevel == 1 ) {
        if( texture( shadowMap,  ShadowCoord.xy).r < dFragment ) {
            visibility -= 0.8;
        }
    } else if( shadowLevel > 1 ) {
        float iterations = 32;
        float sub = 0.8f / iterations;
        for( int i = 0; i < iterations; i++ ) {
            int index = mod( int( 32.0 * random( gl_FragCoord.xyy, i ) ), 32 );
            if( texture( shadowMap,  ShadowCoord.xy + (penumbra * poissonDisk( index ) / 250.0) ).r < dFragment ) {
                visibility -= sub;
            }
        }
    }
    visibility = min( visibility, cosTheta );
    //MaterialDiffuseColor = vec3( 0.8, 0.8, 0.8 );
    fragColor.rgb = MaterialAmbientColor +
        visibility * MaterialDiffuseColor * LightColor * LightPower +
        visibility * MaterialSpecularColor * LightColor * LightPower * pow( cosAlpha, 5             );
}

Обратите внимание, что poissonDisk (int ind) возвращает vec2 с величиной не более 1, которая находится в распределении пуассоновского диска. Хотя я использую шейдерную версию 130, я использовал функцию, а не массив, потому что массив работает довольно медленно на моем ноутбуке.

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

Кто-нибудь знает, что вызывает этот неправильный рендер?

Теги:
opengl
vbo
rendering

1 ответ

1
Лучший ответ

Ну, прежде всего, прекратите рисовать VBO, используя GL_LINES. Используйте тот же примитивный режим для немедленного режима и чертежа VBO.

Кроме того, поскольку, когда 3 * 4 = 3? Адрес (смещение) в ваших указателях вершин VBO должен быть числом элементов, умноженным на размер типа данных при использовании чередующейся структуры данных. GL_FLOAT - 4 байта, если у вас есть трехкомпонентная позиция вершин, это означает, что смещение к следующему полю вашего VBO равно 3 * 4 = (void *)12, а не (void *)3. Этот процесс должен продолжаться для каждого дополнительного указателя массива вершин, все они используют неправильные смещения.

Аналогично, шаг вашего VBO должен быть 12 * sizeof (GLfloat) = 48, а не 12.

  • 0
    Я сделал это и получил ряд ошибок от nvoglv32.dll, которые были обнаружены при быстром поиске в качестве драйвера OpenGL моей карты nVidia. В частности, он сказал мне, что у него были проблемы с чтением из местоположения 0x00000000. Небольшая быстрая отладка показала, что проблема в Mesh :: draw (), когда я вызываю glDrawElements. Я также обнаружил, что я пытался отправить позиции вершин, нормали, касательные и UV в местоположение 0. Как только я это исправил, это работало замечательно. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню