LINUX.ORG.RU

Имитация фиксированного конвейера на современном OpenGL

 , , ,


0

3

Приветстсвую всех!

Пытаюсь воспроизвести древний пример 1996 года на opengl4

(чтобы рендерилась в точности картинка с использованием фиксированных функций - но до этого пока далеко).

Простенькая сцена. Для простоты вывожу только три плоскости: пол, левую и правую стенки.

Последовательные запуски дают разные варианты затенения:

первый вариант

второй

третий

Сталкивался ли кто-нибудь с таким эффектом? Чем он вызван?

В расчете модели освещения нет элементов случайности, так что в этом виноват не шейдер (вершинный/фрагментный).

Тут что-то с vbo?

Инициализация пола

void initFloor()
{

    // 1) Текстура
    GLfloat *textureData = make_texture(TEXDIM, TEXDIM);
    glGenTextures(1, &tex_id);

    glBindTexture(GL_TEXTURE_2D, tex_id);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, TEXDIM, TEXDIM);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEXDIM, TEXDIM, GL_RED, GL_FLOAT, textureData);
    free(textureData);
    CHECK_GL_ERROR();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);


    glActiveTexture(GL_TEXTURE0);
    CHECK_GL_ERROR();
    prog_set_uniform_int(&floorsh, "tex1", 0);

    // 2) Геометрия
    float vertexData[4*3]=
    {
         -100.f,  -100.f, -320.f,  
          100.f,  -100.f, -320.f,  
          100.f,  -100.f, -640.f,  
         -100.f,  -100.f, -640.f   
    };

    GLubyte colorData[4*3] =
    {
        200, 200, 200,
        200, 200, 200,
        200, 200, 200,
        200, 200, 200 
       
    };

    GLubyte texCoords[4*2] =
    {
        0, 0, 
        1, 0, 
        1, 1, 
        0, 1
    };

    GLuint indexList[2][3] =
    {
        {0, 1, 2},   // first triangle
        {0, 2, 3}    // second triangle
    };



    glGenBuffers(1, &vbo_floor_pos);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_pos);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(float), vertexData, GL_STATIC_DRAW);

    glGenBuffers(1, &vbo_floor_color);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_color);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(GLubyte), colorData, GL_STATIC_DRAW);

    glGenBuffers(1, &vbo_floor_tex);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_tex);
    glBufferData(GL_ARRAY_BUFFER, 4*2 * sizeof(float), texCoords, GL_STATIC_DRAW);

    glGenBuffers(1, &ebo_floor);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_floor);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2*3 * sizeof(GLuint), indexList, GL_STATIC_DRAW);

    

    glGenVertexArrays( 1, &vao_floor );
    glBindVertexArray(vao_floor);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_floor);

    

    glEnableVertexAttribArray(0);  // position
    glEnableVertexAttribArray(1);  // color
    glEnableVertexAttribArray(2);  // texture coords

    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_pos);
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_color);
    glVertexAttribPointer( 1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_tex);
    glVertexAttribPointer( 2, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, NULL );

    glBindVertexArray(0);
}

Отрисовка пола

void drawFloor()
{
    prog_use(&floorsh);

    glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex_id);
    
    glBindVertexArray(vao_floor);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_floor);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glBindVertexArray(0);
    glDisable(GL_TEXTURE_2D);
}

Инициализация левой и правой стены

/* left wall */
static float left_wall[12] = {-100.f, -100.f, -320.f,
                              -100.f, -100.f, -640.f,
                              -100.f,  100.f, -640.f,
                              -100.f,  100.f, -320.f };
static float left_normal[3] = {1.f, 0.f, 0.f};
static float left_color[3] = {165, 165, 165};
static struct PLANE left;

/* right wall */
static float right_wall[12] = {  100.f, -100.f, -320.f,
                                 100.f,  100.f, -320.f,
                                 100.f,  100.f, -640.f,
                                 100.f, -100.f, -640.f };
static float right_normal[3] = {-1.f, 0.f, 0.f};
static float right_color[3] = {165, 165, 165};
static struct PLANE right;

void plane_init(PLANE *plane, const float *points, float *normal, float *color)
{
    
    float vertexData[4*3]=
    {
          points[0],  points[ 1], points[ 2],  
          points[3],  points[ 4], points[ 5], 
          points[6],  points[ 7], points[ 8], 
          points[9],  points[10], points[11]
    };

    GLubyte colorData[4*3] =
    {
        color[0], color[1], color[2],
        color[0], color[1], color[2],
        color[0], color[1], color[2],
        color[0], color[1], color[2]
    };

    GLubyte texCoords[4*2] =
    {
        0, 0, 
        1, 0, 
        1, 1, 
        0, 1
    };

    GLubyte normalData[4*3] =
    {
        normal[0], normal[1], normal[2],
        normal[0], normal[1], normal[2],
        normal[0], normal[1], normal[2],
        normal[0], normal[1], normal[2] 
    };

    GLuint indexList[2][3] =
    {
        {0, 1, 2},   // first triangle
        {0, 2, 3}    // second triangle
    };



    glGenBuffers(1, &plane->vbo_pos);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_pos);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(float), vertexData, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->vbo_color);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_color);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(GLubyte), colorData, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->vbo_tex);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_tex);
    glBufferData(GL_ARRAY_BUFFER, 4*2 * sizeof(float), texCoords, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->vbo_normal);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_normal);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(float), normalData, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2*3 * sizeof(GLuint), indexList, GL_STATIC_DRAW);

    

    glGenVertexArrays( 1, &plane->vao );
    glBindVertexArray(plane->vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ebo);

    

    glEnableVertexAttribArray(0);  // position
    glEnableVertexAttribArray(1);  // color
    glEnableVertexAttribArray(2);  // texture coords
    glEnableVertexAttribArray(3);  // normal

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_pos);
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_color);
    glVertexAttribPointer( 1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_tex);
    glVertexAttribPointer( 2, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_normal);
    glVertexAttribPointer( 3, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindVertexArray(0);

}

void plane_draw(PLANE *plane)
{
    glBindVertexArray(plane->vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ebo);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glBindVertexArray(0);
}

Инициализация шейдеров:

void init_scene()
{
    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
   
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f );  

    prog_create(&floorsh);
    prog_attach_shader_from_file(&floorsh, FLOOR_VERTEX_SHADER_NAME);
    prog_attach_shader_from_file(&floorsh, FLOOR_FRAGMENT_SHADER_NAME);
    prog_link(&floorsh);
    prog_use(&floorsh);
    initFloor();
    
    
    
    prog_create(&wallsh);
    prog_attach_shader_from_file(&wallsh, WALL_VERTEX_SHADER_NAME);
    prog_attach_shader_from_file(&wallsh, WALL_FRAGMENT_SHADER_NAME);
    prog_link(&wallsh);
    prog_use(&wallsh);
    initWalls();
      
 
    prog_set_uniform_3f(&wallsh, "lightSource.ambient",  1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "lightSource.diffuse",  1.0f, 1.0f, 1.0f); 
    prog_set_uniform_3f(&wallsh, "lightSource.specular", 1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "lightSource.position", 50.f, 50.f, -320.f);

    prog_set_uniform_3f(&wallsh, "lightModel.ambient",  1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "material.emission",   1.0f, 1.0f, 1.0f); 
    prog_set_uniform_3f(&wallsh, "material.ambient",    1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "material.diffuse",    1.0f, 1.0f, 1.0f); 
    prog_set_uniform_3f(&wallsh, "material.specular",   1.0f, 1.0f, 1.0f); 
    prog_set_uniform_float(&wallsh, "material.shininess",   10.0f); 

    mat4_identity(&model);
    mat4_identity(&view);
   
    MAT4 MV; 
    mat4_multiply(&MV, &view,  &model);
    prog_set_uniform_mat4(&wallsh, "modelViewMatrix", &MV);

    MAT3 NormalMatrix;
    NormalMatrix.M[0] = MV.M[0];     NormalMatrix.M[3] = MV.M[4];     NormalMatrix.M[6] = MV.M[8];
    NormalMatrix.M[1] = MV.M[1];     NormalMatrix.M[4] = MV.M[5];     NormalMatrix.M[7] = MV.M[9];
    NormalMatrix.M[2] = MV.M[2];     NormalMatrix.M[5] = MV.M[6];     NormalMatrix.M[8] = MV.M[10];
    prog_set_uniform_mat3(&wallsh,"normalMatrix", &NormalMatrix);

    
    mat4_perspective_projection(&projection, -FRUSTDIM, FRUSTDIM, -FRUSTDIM, FRUSTDIM, FRUSTNEAR, FRUSTFAR);
    prog_set_uniform_mat4(&wallsh, "projectionMatrix", &projection);
    

    glEnable(GL_DEPTH_TEST);
    //glPolygonMode(GL_FRONT, GL_FILL);

    //glCullFace(GL_BACK);

    CHECK_GL_ERROR();
}

Заранее благодарю за осмысленные ответы и помощь!



Последнее исправление: Gyros (всего исправлений: 4)

А не так?

-    int indexList[2][3] =
-    {
-        {0, 1, 2},   // first triangle
-        {0, 2, 3}    // second triangle
-    };

+    int indexList[6] =
+    {
+        0, 1, 2,   // first triangle
+        0, 2, 3    // second triangle
+    };
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexList), indexList, GL_STATIC_DRAW);

Я не помню, всё забыл, но ведь тут glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2*3 * sizeof(GLuint), indexList, GL_STATIC_DRAW); ты передаёшь indexList как массив, но если его читать текущий с линейной индексацией то будет мусор. Хотя может я туплю, так, по диагонали глянул.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)

А ошибки то какие-то ты отлавливаешь ? Вижу в конце CHECK_GL_ERROR();, а во всех остальных случаях ? Рекомендую начать именно с этого и в частности проверить компиляцию шейдера. Также обращу внимание на glEnableVertexAttribArray uses currently bound vertex array object for the operation, в данном случае у тебя они вызываются до привязки.

AKonia ★★
()
Последнее исправление: AKonia (всего исправлений: 1)
Ответ на: комментарий от AKonia

Спасибо за ответ!

Ошибок после CHECK_GL_ERROR() нет.

Компилируется шейдеры тоже без ошибок, ресурсы освобождаются, см лог:

~/Works/lighting$ ./lighting
[INFO]: Start!
glut_version = 30400
GLEW init success!
OpenGL version: 4.6.0 NVIDIA 390.157!
Shader language is support!
Shading language version: 4.60 NVIDIA!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Debug message (0): Start OpenGL debugging
Source:   Application
Type:     Marker
Severity: NOTIFY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Init scene
[INFO]: Create shader program: id=1
[INFO]: Loading shader type: VERTEX from  'shaders/floor.vert'
[INFO]: Shader id=2 from 'shaders/floor.vert' compiled and attached.
[INFO]: Loading shader type: FRAGMENT from  'shaders/floor.frag'
[INFO]: Shader id=3 from 'shaders/floor.frag' compiled and attached.
[INFO]: Linking glsl program.. 
[INFO]: OK
[INFO]: Validation.. 
[INFO]: OK
[INFO]: Create shader program: id=4
[INFO]: Loading shader type: VERTEX from  'shaders/wall.vert'
[INFO]: Shader id=5 from 'shaders/wall.vert' compiled and attached.
[INFO]: Loading shader type: FRAGMENT from  'shaders/wall.frag'
[INFO]: Shader id=6 from 'shaders/wall.frag' compiled and attached.
[INFO]: Linking glsl program.. 
[INFO]: OK
[INFO]: Validation.. 
[INFO]: OK
Reshape
[INFO]: Delete id=2 shader.
[INFO]: Delete id=3 shader.
[INFO]: Delete program id=1.
[INFO]: Free dictionary.
[INFO]: Delete id=5 shader.
[INFO]: Delete id=6 shader.
[INFO]: Delete program id=4.
[INFO]: Free dictionary.
Delete floor vbo
Delete plane vbo
Delete plane vbo
Delete plane vbo
Delete plane vbo
[INFO]: Done.
Bye bye!

Расстановка glEnableVertexAttribArray после привязки (к соотв. буферу):

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_pos);
    glEnableVertexAttribArray(0);  // position
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_color);
    glEnableVertexAttribArray(1);  // color
    glVertexAttribPointer( 1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_tex);
    glEnableVertexAttribArray(2);  // texture coords
    glVertexAttribPointer( 2, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_normal);
    glEnableVertexAttribArray(3);  // normal
    glVertexAttribPointer( 3, 3, GL_FLOAT, GL_FALSE, 0, NULL );

не меняет поведения программы.

Кстати, я отловил новый вариант затенения

четвертый вариант

А должно получиться: к чему стремлюсь

Процедура отрисовки:

void display_cb ()
{
  glClear ( GL_COLOR_BUFFER_BIT  | GL_DEPTH_BUFFER_BIT) ;
      
  if (line_mode)
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  else
      glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);

  prog_use(&floorsh); 
  drawFloor();

  prog_use(&wallsh);
  drawWalls();
  
  glFlush();
  glutSwapBuffers();
}

Вершинный шейдер стен (здесь (стандартная) реализация модели освещения фиксированного конвейера):

#version 440

 layout (location=0) in vec3 vertexPosition; 
 layout (location=1) in vec3 vertexColor;
 layout (location=2) in vec2 vertexTexCoords; 
 layout (location=3) in vec3 vertexNormals; 

 
 
 uniform mat4 modelViewMatrix;
 uniform mat3 normalMatrix;
 uniform mat4 projectionMatrix;
                 
 
struct LightSource
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    vec3 position;
};

uniform LightSource lightSource;

struct LightModel
{
    vec3 ambient;
};


uniform LightModel lightModel;

struct Material
{
    vec3  emission;
    vec3  ambient;
    vec3  diffuse;
    vec3  specular;
    float shininess;
};

uniform Material material;

out vec3 v_color;

void main()
{
    vec3 normal     = normalize(normalMatrix * vertexNormals);                      // normal vector
    vec3 position   = vec3(modelViewMatrix * vec4(vertexPosition, 1));              // vertex pos in eye coords
    vec3 halfVector = normalize(lightSource.position + vec3(0,0,1));                // light half vector
    float nDotVP    = dot(normal, normalize(lightSource.position));                 // normal . light direction
    float nDotHV    = max(0.f, dot(normal,  halfVector));                           // normal . light half vector
    float pf        = mix(0.f, pow(nDotHV, material.shininess), step(0.f, nDotVP)); // power factor

    vec3 ambient    = lightSource.ambient;
    vec3 diffuse    = lightSource.diffuse * nDotVP;
    vec3 specular   = lightSource.specular * pf;
    vec3 sceneColor = material.emission + material.ambient * lightModel.ambient;

    v_color = clamp(sceneColor + 
                    ambient  * material.ambient + 
                    diffuse  * material.diffuse +
                    specular * material.specular, 0.f, 1.f );

    gl_Position = projectionMatrix * modelViewMatrix * vec4(vertexPosition, 1);
}

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

#version 440

 in vec3 v_color;
                                             
 layout (location=0) out vec4 FragColor;
                                          
                                               
 void main()                                  
 {                                            
     FragColor = vec4(v_color, 1);
 }
Gyros
() автор топика