Неверное положение сетки OpenGL

Я пытаюсь создать простую треугольную сетку, и, выяснив, почему я только что получил пустой экран (по какой-то причине конфигурация x64 доставляла мне проблемы), я столкнулся с новой проблемой:

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

Что я получаю, так это:

введите здесь описание изображения


Я использую GLEW 1.10.0 для загрузки OpenGL, GLM 0.9.5.4 для математических операций OpenGL и SDL 2.0.3 для работы с окнами. Все работает в Windows 8.1 в Visual Studio 2013 Ultimate с последними графическими драйверами Nvidia.


Main.cpp:

#include "Display.h"
#include "Shader.h"
#include "Mesh.h"

using namespace std;

int main(int argc, char** argv)
{
    Display display(1200, 800, "Hello World");

    Vertex vertecies[] =
    {
        Vertex(vec3(-0.5, -0.5, 0)),
        Vertex(vec3(0.5, -0.5, 0)),
        Vertex(vec3(0, 0.5, 0))
    };

    Mesh mesh(vertecies, sizeof(vertecies) / sizeof(vertecies[0]));
    Shader shader(".\\res\\BasicShader");

    while (!display.IsClosed())
    {
        display.Clear(1.0f, 1.0f, 1.0f, 1.0f);

        shader.Bind();
        mesh.Draw();

        display.Update();
    }

    return 0;
}


Mesh.cpp:

#include "Mesh.h"

Mesh::Mesh(Vertex* vertecies, unsigned int numVertecies)
{
    m_drawCount = numVertecies;

    glGenVertexArrays(1, &m_vertexArrayObject);
    glBindVertexArray(m_vertexArrayObject);

    glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertecies[0]) * numVertecies, vertecies, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, m_pos));

    glBindVertexArray(0);
}

Mesh::~Mesh()
{
    glDeleteBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
    glDeleteVertexArrays(1, &m_vertexArrayObject);
}

void Mesh::Draw()
{
    glBindVertexArray(m_vertexArrayObject);

    glDrawArrays(GL_TRIANGLES, 0, m_drawCount);



    glBindVertexArray(0);
}


Display.cpp:

#include "Display.h"

Display::Display(int width, int height, string title)
{
    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    m_window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
    m_glContext = SDL_GL_CreateContext(m_window);
    m_isClosed = false;

    GLenum status = glewInit();

    if (status != GLEW_OK)
        cerr << "Could not initialize GLEW!" << endl;
}

Display::~Display()
{
    SDL_GL_DeleteContext(m_glContext);
    SDL_DestroyWindow(m_window);
    SDL_Quit();
}

void Display::Clear(float r, float g, float b, float a)
{
    glClearColor(r, g, b, a);
    glClear(GL_COLOR_BUFFER_BIT);
}

bool Display::IsClosed()
{
    return m_isClosed;
}

void Display::Update()
{
    SDL_GL_SwapWindow(m_window);

    SDL_Event e;

    while (SDL_PollEvent(&e))
    {
        if (e.type == SDL_QUIT)
            m_isClosed = true;
    }
}


Вершинный шейдер:

#version 420 core

layout(location = 0) in vec3 position;

void main()
{
    gl_Position = vec4(position, 1.0);
}


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

#version 420 core

out vec4 frag;

void main()
{
    frag = vec4(1.0, 0.0, 0.0, 1.0);
}


Вертекс.h:

#pragma once

#include <glm\glm.hpp>

using namespace glm;

struct Vertex
{

public:

    Vertex(const vec3& pos);
    virtual ~Vertex();

    vec3 m_pos;

};


Вертекс.cpp:

#include "Vertex.h"

Vertex::Vertex(const vec3& pos)
{
    m_pos = pos;
}

Vertex::~Vertex()
{
}


РЕДАКТИРОВАТЬ: Теперь все исправлено.


person mani1999    schedule 30.07.2014    source источник
comment
Как устроен ваш класс/структура Vertex? Не могли бы вы опубликовать его декларацию?   -  person kolrabi    schedule 30.07.2014
comment
@kolrabi Конечно, только что добавил Vertex.h и Vertex.cpp...   -  person mani1999    schedule 30.07.2014
comment
Вы не должны исправлять свой ответ   -  person Herrgott    schedule 31.07.2020


Ответы (1)


Вероятно, это проблема выравнивания данных, когда ваш класс Vertex дополняется. Затем OpenGL будет интерпретировать байты заполнения как допустимые данные.

Вы можете проверить это, напечатав результат sizeof(Vertex), который будет равен 8 (вы упомянули платформу 64), если он действительно дополнен.

Это сообщает OpenGL, что в памяти плотно упакованы числа с плавающей запятой без заполнения:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

Лучшим способом установки указателя вершины будет:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, m_pos));

Это также позволяет легко добавлять дополнительные атрибуты.

person kolrabi    schedule 30.07.2014
comment
Спасибо за быстрый ответ! Наконец-то это работает! Единственное, что offsetof принимает 2 параметра, тип и член типа, поэтому я просто превратил свой класс Vertex в структуру, сделал m_pos общедоступным и написал (const void*)offsetof(Vertex, m_pos) вместо (const void*)offsetof(Vertex.m_pos). - person mani1999; 30.07.2014
comment
Ах да, извините, это опечатка с моей стороны. - person kolrabi; 30.07.2014