struct Vertex. Color first or position first

I have a very simple example which draws a triangle.

If I write the Vertex struct like this:

struct Vertex
{
    color4 color;
    vec3 pos;
};

Then I get correct positions but incorrect colors:

002_CubeForFidarit_GLFWOpenGL31Cpp_IncorrectColors

If I write like this:

struct Vertex
{
    vec3 pos;
    color4 color;
};

Then I get incorrect positions and colors:

003_CubeForFidarit_GLFWOpenGL31Cpp_IncorrectPositionsAndColors

Color.vs

#version 140
 
uniform mat4 modelViewProjection;
 
in vec3 position;
in vec4 colour;
 
out vec4 colourV;
 
void main(void)
{
    colourV = colour;
    gl_Position = modelViewProjection * vec4(position, 1.0);
}

Color.fs

#version 140
 
in vec4 colourV;
out vec4 fragColour;
 
void main(void)
{
    fragColour = colourV;
}

main.cpp

#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// GLFW
#include "./glm/gtc/matrix_transform.hpp"

int width = 260;
int height = 260;

char* windTitle = "Minecave";

GLuint VBO;
GLuint VAO;
GLuint IBO;
GLint program;

typedef unsigned short  ushort;
typedef glm::vec3       vec3;
typedef glm::mat4       mat4;
typedef glm::vec4       color4;

struct Vertex
{
    color4 color;
    vec3 pos;
};

void CheckOnErrors()
{
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
    {
        // Process/log the error
        std::cout << err << std::endl;
    }
}

std::string ReadStringFromFile(std::string filename)
{
    std::string res;
    std::string line;
    std::ifstream in(filename);

    if (in.is_open())
    {
        while (getline(in, line))
        {
            res += line + "
";
        }
    }
    in.close();

    return res;
}

GLint CompileShader(std::string filename)
{
    GLint vs = glCreateShader(GL_VERTEX_SHADER);
    std::string cString = ReadStringFromFile("Data\\Shaders\\" + filename + ".vs");
    GLchar const* files[] = { cString.c_str() };
    GLint lengths[] = { cString.size() };
    glShaderSource(vs, 1, files, lengths);
    glCompileShader(vs);

    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vs, 512, NULL, infoLog);
        std::cout << "SHADER::VERTEX::COMPILATION_FAILED
" << std::endl;
        std::cout << infoLog << std::endl;
    }

    GLint fs = glCreateShader(GL_FRAGMENT_SHADER);
    cString = ReadStringFromFile("Data\\Shaders\\" + filename + ".fs");
    GLchar const* files1[] = { cString.c_str() };
    GLint lengths1[] = { cString.size() };
    glShaderSource(fs, 1, files1, lengths1);
    glCompileShader(fs);

    glGetShaderiv(fs, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fs, 512, NULL, infoLog);
        std::cout << "SHADER::FRAGMENT::COMPILATION_FAILED
" << std::endl;
        std::cout << infoLog << std::endl;
    }

    GLint prog = glCreateProgram();
    glAttachShader(prog, vs);
    glAttachShader(prog, fs);
    glLinkProgram(prog);
    glUseProgram(prog);

    glDetachShader(prog, vs);
    glDetachShader(prog, fs);
    glDeleteShader(vs);
    glDeleteShader(fs);
    return prog;
}

int main(int argc, char* argv[])
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(width, height, windTitle, nullptr, nullptr);
    if (window == nullptr)
    {
        std::cout << "* ERROR *: " << "Couldn't create main window" << std::endl;
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        std::cout << "* ERROR *: " << "Failed to initialize GLEW" << std::endl;
        glfwTerminate();
        return -1;
    }
    glEnable(GL_DEPTH_TEST);

    program = CompileShader("Color");
    
    //Vertex verts[3];
    std::vector<Vertex> verts(3);

    // Vertices
    verts[0].pos = vec3(-0.5f, -0.5f, 0.0f);
    verts[1].pos = vec3(0.5f, -0.5f, 0.0f);
    verts[2].pos = vec3(-0.5f, 0.5f, 0.0f);

    // Colors
    verts[0].color = color4(1.0f, 0.0f, 0.0f, 1.0f);
    verts[1].color = color4(0.0f, 1.0f, 0.0f, 1.0f);
    verts[2].color = color4(0.0f, 0.0f, 1.0f, 1.0f);

    std::vector<ushort> inds(3);
    inds[0] = 0;
    inds[1] = 1;
    inds[2] = 2;

    GLint matrixLocation = glGetUniformLocation(program, "modelViewProjection");

    mat4 matr = glm::perspective(3.14f / 180.0f * 70.0f, (float)width / height, 0.1f, 100.0f);
    matr *= glm::lookAt(vec3(0.3f, 0.4f, 1.5f), vec3(0.0f), vec3(0, 1, 0));

    glGenBuffers(1, &VBO);
    glGenBuffers(1, &IBO);
    glGenVertexArrays(1, &VAO);
    //
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(verts) * 9, verts, GL_STATIC_DRAW);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*verts.size(), &(verts[0].pos.x), GL_STATIC_DRAW);

    //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //pos
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, pos))); //pos (const GLvoid*)(offsetof(Vertex, pos))
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, color))); //rgba (const GLvoid*)(offsetof(Vertex, color))
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort) * inds.size(), &(inds[0]), GL_STATIC_DRAW);

    glBindVertexArray(0);

    //glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);
    //glScissor(0, 0, width, height);
    
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        glClearColor(0.0f, 0.75f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //CheckOnErrors();
        glBindVertexArray(VAO);

        glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, &matr[0][0]);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);

        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }

    glfwTerminate();
    return 0;
}

Consider your change in light of the above line of code.

Also, you apparently aren’t using explicit attribute locations in your shader. So where are your vertex attribute bindings? See this wiki link for more details:

[ul]
[li]Vertex Shader#Inputs [/li][/ul]

Excellent! I spend a whole day to find in the Internet how to use an array of structures for positions and colors.

I see that I can use CODE=“C++”

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*verts.size(), &(verts[0].pos.x), GL_STATIC_DRAW);

I see that my struct must start with “pos” because I copy my array of struct to graphics card memory from the position “.pos.x”. This is error too. If I will change the order of “pos” and “color” in the Vertex structure I will have a logic error.

But I do not see there this way:

    GLint positionLoc = glGetAttribLocation(program, "position");
    if (positionLoc < 0) std::cout << "Failed to get a "position" variable" << std::endl;
    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, pos)));
    glEnableVertexAttribArray(positionLoc);

    GLint colorLoc = glGetAttribLocation(program, "color");
    if (colorLoc < 0) std::cout << "Failed to get a "color" variable" << std::endl;
    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, color)));
    glEnableVertexAttribArray(colorLoc);

I found it here: Generic Vertex Attribute - examples

Solution

  1. The “pos” variable must be first:
struct Vertex
{
    vec3 pos;
    color4 color;
};

Because I copy the “verts” array from “verts[0].pos.x”:

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*verts.size(), &(verts[0].pos.x), GL_STATIC_DRAW);
  1. I must use vertex attribute bindings. I chose glGetLocation way:
    GLint positionLoc = glGetAttribLocation(program, "position");
    if (positionLoc < 0) std::cout << "Failed to get a "position" variable" << std::endl;
    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, pos))); //pos
    glEnableVertexAttribArray(positionLoc);
 
    GLint colorLoc = glGetAttribLocation(program, "color");
    if (colorLoc < 0) std::cout << "Failed to get a "color" variable" << std::endl;
    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, color))); //rgba
    glEnableVertexAttribArray(colorLoc);

Result:

004_CubeForFidarit_GLFWOpenGL31Cpp_ColoredTriangle

Color.vs

#version 140
 
uniform mat4 modelViewProjection;
 
in vec3 position;
in vec4 color;
 
out vec4 colorV;
 
void main(void)
{
    colorV = color;
    gl_Position = modelViewProjection * vec4(position, 1.0);
}

Color.fs

#version 140
 
in vec4 colorV;
out vec4 fragColor;
 
void main(void)
{
    fragColor = colorV;
}

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// GLFW
#include "./glm/gtc/matrix_transform.hpp"

int width = 260;
int height = 260;

char* windTitle = "Minecave";

GLuint VBO;
GLuint VAO;
GLuint IBO;
GLint program;

typedef unsigned short  ushort;
typedef glm::vec3       vec3;
typedef glm::mat4       mat4;
typedef glm::vec4       color4;

struct Vertex
{
    vec3 pos;
    color4 color;
};

void CheckOnErrors()
{
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
    {
        // Process/log the error
        std::cout << err << std::endl;
    }
}

std::string ReadStringFromFile(std::string filename)
{
    std::string res;
    std::string line;
    std::ifstream in(filename);

    if (in.is_open())
    {
        while (getline(in, line))
        {
            res += line + "
";
        }
    }
    in.close();

    return res;
}

GLint CompileShader(std::string filename)
{
    GLint vs = glCreateShader(GL_VERTEX_SHADER);
    std::string cString = ReadStringFromFile("Data\\Shaders" + filename + ".vs");
    GLchar const* files[] = { cString.c_str() };
    GLint lengths[] = { cString.size() };
    glShaderSource(vs, 1, files, lengths);
    glCompileShader(vs);

    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vs, 512, NULL, infoLog);
        std::cout << "SHADER::VERTEX::COMPILATION_FAILED
" << std::endl;
        std::cout << infoLog << std::endl;
    }

    GLint fs = glCreateShader(GL_FRAGMENT_SHADER);
    cString = ReadStringFromFile("Data\\Shaders" + filename + ".fs");
    GLchar const* files1[] = { cString.c_str() };
    GLint lengths1[] = { cString.size() };
    glShaderSource(fs, 1, files1, lengths1);
    glCompileShader(fs);

    glGetShaderiv(fs, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fs, 512, NULL, infoLog);
        std::cout << "SHADER::FRAGMENT::COMPILATION_FAILED
" << std::endl;
        std::cout << infoLog << std::endl;
    }

    GLint prog = glCreateProgram();
    glAttachShader(prog, vs);
    glAttachShader(prog, fs);
    glLinkProgram(prog);
    glUseProgram(prog);

    glDetachShader(prog, vs);
    glDetachShader(prog, fs);
    glDeleteShader(vs);
    glDeleteShader(fs);
    return prog;
}

int main(int argc, char* argv[])
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(width, height, windTitle, nullptr, nullptr);
    if (window == nullptr)
    {
        std::cout << "* ERROR *: " << "Couldn't create main window" << std::endl;
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        std::cout << "* ERROR *: " << "Failed to initialize GLEW" << std::endl;
        glfwTerminate();
        return -1;
    }
    glEnable(GL_DEPTH_TEST);

    program = CompileShader("Color");

    //Vertex verts[3];
    std::vector<Vertex> verts(3);

    // Vertices
    verts[0].pos = vec3(-0.5f, -0.5f, 0.0f);
    verts[1].pos = vec3(0.5f, -0.5f, 0.0f);
    verts[2].pos = vec3(-0.5f, 0.5f, 0.0f);

    //// Colors
    verts[0].color = color4(1.0f, 0.0f, 0.0f, 1.0f);
    verts[1].color = color4(0.0f, 1.0f, 0.0f, 1.0f);
    verts[2].color = color4(0.0f, 0.0f, 1.0f, 1.0f);

    //// Zero vertex; color = "red"
    //verts[0].color.r = 1.0f;
    //verts[0].color.g = 0.0f;
    //verts[0].color.b = 0.0f;
    //verts[0].color.a = 1.0f;
    //// First vertex; color = "green"
    //verts[1].color.r = 0.0f;
    //verts[1].color.g = 1.0f;
    //verts[1].color.b = 0.0f;
    //verts[1].color.a = 1.0f;
    //// Second vertex; color = "blue"
    //verts[2].color.r = 0.0f;
    //verts[2].color.g = 0.0f;
    //verts[2].color.b = 1.0f;
    //verts[2].color.a = 1.0f;

    //VertexColor verts[8];
    //verts[0].pos = vec3(-1, -1, -1);
    //verts[1].pos = vec3(-1, -1, 1);
    //verts[2].pos = vec3(-1, 1, -1);
    //verts[3].pos = vec3(-1, 1, 1);
    //verts[4].pos = vec3(1, -1, -1);
    //verts[5].pos = vec3(1, -1, 1);
    //verts[6].pos = vec3(1, 1, -1);
    //verts[7].pos = vec3(1, 1, 1);

    //ushort inds[3] = { 0, 1, 2 };
    std::vector<ushort> inds(3);
    inds[0] = 0;
    inds[1] = 1;
    inds[2] = 2;

    //uint16 inds[36] = {
    //    0, 1, 2, 2, 1, 3,
    //    4, 5, 6, 6, 5, 7,

    //    0, 2, 4, 4, 2, 6,
    //    1, 3, 5, 5, 3, 7,

    //    0, 1, 4, 4, 1, 5,
    //    2, 3, 6, 6, 3, 7,
    //};

    GLint matrixLocation = glGetUniformLocation(program, "modelViewProjection");

    mat4 matr = glm::perspective(3.14f / 180.0f * 70.0f, (float)width / height, 0.1f, 100.0f);
    matr *= glm::lookAt(vec3(0.3f, 0.4f, 1.5f), vec3(0.0f), vec3(0, 1, 0));

    glGenBuffers(1, &VBO);
    glGenBuffers(1, &IBO);
    glGenVertexArrays(1, &VAO);
    //
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(verts) * 9, verts, GL_STATIC_DRAW);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * verts.size(), &(verts[0].pos.x), GL_STATIC_DRAW);

    //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //pos

    GLint positionLoc = glGetAttribLocation(program, "position");
    if (positionLoc < 0) std::cout << "Failed to get a "position" variable" << std::endl;
    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, pos))); //pos
    glEnableVertexAttribArray(positionLoc);

    GLint colorLoc = glGetAttribLocation(program, "color");
    if (colorLoc < 0) std::cout << "Failed to get a "color" variable" << std::endl;
    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(offsetof(Vertex, color))); //rgba
    glEnableVertexAttribArray(colorLoc);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort) * inds.size(), &(inds[0]), GL_STATIC_DRAW);

    glBindVertexArray(0);

    //glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);
    //glScissor(0, 0, width, height);

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        glClearColor(0.0f, 0.75f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //CheckOnErrors();
        glBindVertexArray(VAO);

        glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, &matr[0][0]);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);

        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }

    glfwTerminate();
    return 0;
}