PDA

View Full Version : Passing additional data to shader separated from vertices



Sunny_Lime
04-17-2017, 01:56 PM
So I have a scene where I'm drawing a bunch of different spheres, and each sphere is just a single solid color. I'm doing this by interleaving the color and vertex data into a single array, like { x1,y1,z1,r1,g1,b1,x2,y2... }. I'm approximating the spheres from an icosahedron, similar to this (http://stackoverflow.com/questions/7687148/drawing-sphere-in-opengl-without-using-glusphere). Unfortunately, to get decent approximations, each sphere is over 1000 vertices, which means over 1000 copies of exactly the same color. I also need to loop through each vertex in order to combine the color/vertex data into a single array, which takes way too long.

Ideally, I could just pass a single color vec3 into the shader. I can't use a uniform, because the colors will be different for each sphere. I saw this post (http://stackoverflow.com/questions/7223623/storing-different-vertex-attributes-in-different-vbos), which I'm guessing is the right direction for me. But I cannot get that solution to work at all. For one thing, glEnableVertexAttrib does not seem to be valid in my version of opengl. Any help would be much appreciated.

Here's the relevant code:


void Visual::drawVertices() {
std::vector<SimulationObject> objects = simulation.getCurrentObjects();
std::vector<float> offsets = simulation.GetFocusOffsets(objects);
for (int i = 0; i < objects.size(); i++) {

std::vector<GLfloat> vertices(2 * sphere.vertices.size());
//sphere is just a collection of vertices/indices.
//need to translate each vertex for the current object, and combine them with colors.
//This loop is KILLING the fps. Could get rid of it if I could pass a single color and vertex offset into the shader
for (int j = 0, k = 0; j < sphere.vertices.size(); j+=3, k+=6) {
vertices[k] = objects[i].position.GetBaseValue(0) - offsets[0] + sphere.vertices[j];
vertices[k + 1] = objects[i].position.GetBaseValue(1) - offsets[1] + sphere.vertices[j + 1];
vertices[k + 2] = objects[i].position.GetBaseValue(2) - offsets[2] + sphere.vertices[j + 2];

vertices[k + 3] = simulation.objectSettings[i].color[0];
vertices[k + 4] = simulation.objectSettings[i].color[1];
vertices[k + 5] = simulation.objectSettings[i].color[2];
}
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), &vertices[0], GL_STREAM_DRAW);

// Position Attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);

// Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphere.indices.size() * sizeof(GLfloat), &sphere.indices[0], GL_STREAM_DRAW);

glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, sphere.indices.size(), GL_UNSIGNED_INT, 0);

glBindVertexArray(0);

glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
}

and vertex shader:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 inputColor;

out vec3 vertexColor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
vertexColor = inputColor;
}

Silence
04-17-2017, 11:35 PM
What you're looking for is instancing (https://learnopengl.com/#!Advanced-OpenGL/Instancing).

glVertexAttribDivisor (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribDivisor.xhtml) will allow you to specify how often your color will change.

Sunny_Lime
04-18-2017, 06:46 PM
Awesome, thank you! That was exactly what I needed.