glUseProgram unaffecting the rendering state - c++

I am writing a basic view manager using GL on ubuntu 13 and eeepc with a nvidia ION2 (optimus in use using bumblebee project). I've an XML file from which shaders are created when the system starts (like plugins) and added to a dictionary. Once these are compiled and linked and ready for use, a wrapper function is used to select the appropriate shader program based on the program name passed.
void ShadingProgramManager::useProgram(const std::string& program){
GLuint id = getProgramId(program);
glUseProgram(id);
if(GL_INVALID_VALUE == glGetError() || GL_INVALID_OPERATION == glGetError()){
printf("Problem Loading Shader Program");
return;
}
printf("%s is in use", program.c_str());
}
Where getProgramId simply looks inside the pre created dictionary and returns the id of the shader program.
When I render the object, I put the program to use by calling:
ShadingProgramManager::getInstance()->useProgram('vc');
'vc' is formed of the following shaders
Vertex Shader - vc.vert
#version 330
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
out vec4 vertcolor;
void main(){
vertcolor = color;
gl_Position = vec4(position, 1.0); //I've tried setting this as position * 10 also for any apparent changes on screen, but nothing changes
}
Fragment Shader - vc.frag:
#version 330
in vec4 vertcolor;
out vec4 outputcolor;
void main(){
outputcolor = vertcolor;
}
My vertex buffer is interleaved as:
VertexColor vertices[] =
{
{-1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0}, /*first 3 floats for pos, 4 for color */
{ 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0},
{ 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0},
{-1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0},
};
Index Buffer is as:
GLuint indices[] =
{
0, 1, 2,
0, 2, 3,
};
VertexColor defined as:
class VertexColor{
GLfloat x;
GLfloat y;
GLfloat z;
GLfloat r;
GLfloat g;
GLfloat b;
GLfloat a;
/** some constants as below **/
};
const int VertexColor::OFFSET_POSITION =0;
const int VertexColor::OFFSET_COLOR =12;
const int VertexColor::SIZE_POSITION =3;
const int VertexColor::SIZE_COLOR =4;
const int VertexColor::STRIDE =28;
Then I use the following code to render the quad:
ShadingProgramManager::getInstance()->useProgram('vc');
glBindBuffer(GL_ARRAY_BUFFER, &vb);
glBufferData(GL_ARRAY_BUFFER, size_of_vertices_array, vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, &ib);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_of_indices_array, indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribArrayPointer(0, VertexColor::SIZE_POSITION, GL_FLOAT, GL_FALSE, VertexColor::STRIDE, (GLvoid*)VertexColor::OFFSET_POSITION);
glVertexAttribArrayPointer(1, VertexColor::SIZE_COLOR, GL_FLOAT, GL_FALSE, VertexColor::STRIDE, (GLvoid*)VertexColor::OFFSET_COLOR);
glDrawElements(GL_TRIANGLES, size_of_indices, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
However, I only see a white quad. I suspect it's the fixed function pipeline that comes into effect.
Even if I remove the call to glUseProgram(id) or use glUseProgram(0), I'm still getting the same results. I also tried multiplying the position in the vertex shader by 10.0 but no effect on screen. I am sure that the shaders are being compiled and linked as well. When I change to use something like glUseProgram(40) or any invalid number, I get the requisite error messages but elsewise, I only see a white unit square!
Sorry for the obtrusively long post but I am stumped on this one...I just get a white unit square no matter what changes I do to the vert or frag shader. I suspect GL is defaulting to the FFP, and for some reason my shader program is not falling into effect. I am hoping it's a noobish mistake, but any pointers would be appreciated.
PS: There are no compile errors so please excuse any syntactical errors in the code. I've typed the complete code above.
UPDATE: I've added the last parameter in the call to glVertexAttribArrayPointer as suggested by Andon, Dinesh and Spektre, and I had missed earlier, but still same results.

Look at this line
glVertexAttribArrayPointer(1, VertexColor::SIZE_COLOR, GL_FLOAT, GL_FALSE, VertexColor::STRIDE);
Where is the pointer to Specifies a offset of the first component of the first generic vertex attribute in the array. In your vertex array color data starts at 4th position. You have to specify the starting position of first component of color data. Initial pointer value is 0 so program reads color data from first position to 4th position which is not color data. But it read vertex data correctly because program reads vertex data from first position to 3rd position which is correct value.That's way you see only white quad.

Problem solved.
Yes, it was a noobish mistake, but all your comments helped me run through the entire code once again. I started off with redoing everything with the FFP and moving onto the PFP. So here is the error:
I missed putting in glAttachShader(pid, sid) in the dictionary that was being created for shader programs, so while the program was in effect, the vertex shader and the frag shader were never being applied.

Related

Opengl: How to map a buffer CORRECTLY?

I'm new to stack overflow. I have the following problem: I want to have a rotating triangle in my window.
Now, I have already managed to have my code running and I had a rotating triangle. However, I wanted to rewrite the code for learning purposes, adding the two following major things:
Updating the buffer object later on with memcpy
Having an array-of-stuctures (AoS) instead of a structure-of-arrays (SoA)
I'm referring hereby to the "OpenGL Superbible" book.
I'll provide you some code snippets:
glGenVertexArrays(1, &vao);
static const vertex vertices[] = {
{ 0.25, -0.25, 0.5, 1.0 ,
1.0, 0.0, 0.0, 1.0},
{ -0.25, -0.25, 0.5, 1.0,
0.0, 1.0, 0.0, 1.0 },
{ 0.25, 0.25, 0.5, 1.0,
0.0, 0.0, 1.0, 1.0 }
};
glCreateBuffers(1, &buffer);
glNamedBufferStorage(buffer, sizeof(vertices), NULL, 0);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
void * ptr = glMapNamedBuffer(buffer, GL_WRITE_ONLY);
memcpy(ptr, vertices, sizeof(vertices));
glUnmapNamedBuffer(GL_ARRAY_BUFFER);
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));
// Positions
glVertexArrayAttribBinding(vao, 0, 0);
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, offsetof(vertex, x));
glEnableVertexArrayAttrib(vao, 0);
// Color
glVertexArrayAttribBinding(vao, 1, 0);
glVertexArrayAttribFormat(vao, 1, 4, GL_FLOAT, GL_FALSE, offsetof(vertex, r));
glEnableVertexArrayAttrib(vao, 1);
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vertex));
I set up the vertex struct as follows:
struct vertex {
// Position
float x;
float y;
float z;
float w;
// Color
float r;
float g;
float b;
float a;
};
The first time, I had the color hard-coded in my vertex shader. And I had the position data in a data-array. I set the data directly by calling 'glNamedBufferStorage' instead of (as it is now the case) inserting NULL. Back then, it worked. But as I changed the two things, it stopped working. I know by shure that both of these major steps include some errors.
Here I'll provide you with the vertex shader. the mvp matrix works, by the way, so that's not the problem.
#version 420 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
out vec4 vs_color;
uniform mat4 mvp;
void main(void)
{
gl_Position = mvp * position;
vs_color = color;
}
Any hints would be greatly appreciated.
There are several problems in the code:
glUnmapNamedBuffer takes the buffer handle as parameter, not a GLenum. Change glUnmapNamedBuffer(GL_ARRAY_BUFFER); to glUnmapNamedBuffer(buffer);. (And you should check the return value, it returns false when there is a problem).
The stride for glVertexArrayVertexBuffer is wrong. Each vertex starts 8 floats after the previous one (or sizeof(vertex)). Change
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));
to
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vertex));

Trivial OpenGL Shader Storage Buffer Object (SSBO) not working

I am trying to figure out how SSBO works with a very basic example. The vertex shader:
#version 430
layout(location = 0) in vec2 Vertex;
void main() {
gl_Position = vec4(Vertex, 0.0, 1.0);
}
And the fragment shader:
#version 430
layout(std430, binding = 2) buffer ColorSSBO {
vec3 color;
};
void main() {
gl_FragColor = vec4(color, 1.0);
}
I know they work because if I replace vec4(color, 1.0) with vec4(1.0, 1.0, 1.0, 1.0) I see a white triangle in the center of the screen.
I initialize and bind the SSBO with the following code:
GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
float color[] = {1.f, 1.f, 1.f};
glBufferData(GL_SHADER_STORAGE_BUFFER, 3*sizeof(float), color, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
What is wrong here?
My guess is that you are missing the SSBO binding before rendering. In your example, you are copying the content and then you bind it immediately, which is unnecessary for the declaration. In other words, the following line in your example:
...
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo);
...
Must be placed before rendering, such as:
...
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo);
/*
Your render calls and other bindings here.
*/
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
...
Without this, your shader (theoretically) will not be able to see the content.
In addition, as Andon M. Coleman has suggested, you have to use padding for your elements when declaring arrays (e.g., use vec4 instead of vec3). If you don't, it will apparently work but produce strange results because of this fact.
The following two links have helped me out understanding the meaning of an SSBO and how to handle them in your code:
https://www.khronos.org/opengl/wiki/Shader_Storage_Buffer_Object
http://www.geeks3d.com/20140704/tutorial-introduction-to-opengl-4-3-shader-storage-buffers-objects-ssbo-demo/
I hope this helps to anyone facing similar issues!
P.S.: I know this post is old, but I wanted to contribute.
When drawing a triangle, three points are necessary, and 3 separate sets of red green blue values are required for each point. You are only putting one set into the shader buffer. For the other two points, the value of color drops to the default, which is black (0.0,0.0,0.0). If you don't have blending enabled, it is likely that the triangle is being painted completely black because two of its vertices are black.
Try putting 2 more sets of red green blue values into the storage buffer to see it will load them as color values for the other two points.

confused trying to draw coloured elements for drawing using using glDrawElements using vertex and fragment shaders

I'm creating a set of classes to read in 3d objects from COLLADA files. I started with some basic code to read in the positions and normals and plot them with opengl. I added code to scale the vertices successfully and added all the code I need to read in the color or texture connected with each graphics element in the COLLAD file. But now I need to add the code to draw the vertices with color. I have created the buffer object array to house the color array for each of the vertices array and buffer objects.
This is the code I have to build the arrays from data I obtain from the COLLADA file:
Keep in mind I am still creating this it's not perfect.
// Set vertex coordinate data
glBindBuffer(GL_ARRAY_BUFFER, vbosPosition[i]);
glBufferData(GL_ARRAY_BUFFER, col->vectorGeometry[i].map["POSITION"].size,
scaledData, GL_STATIC_DRAW);
free(scaledData);
loc = glGetAttribLocation(program, "in_coords");//get a GLuint for the attribute and put it into GLuint loc.
glVertexAttribPointer(loc, col->vectorGeometry[i].map["POSITION"].stride, col->vectorGeometry[i].map["POSITION"].type, GL_FALSE, 0, 0);//glVertexAttribPointer — loc specifies the index of the generic vertex attribute to be modified.
glEnableVertexAttribArray(0);
#ifdef Testing_Mesh3D
PrintGLVertex(vbosPosition[i], col->vectorGeometry[i].map["POSITION"].size / 4);
#endif // Set normal vector data
glBindBuffer(GL_ARRAY_BUFFER, vbosNormal[i]);
glBufferData(GL_ARRAY_BUFFER, col->vectorGeometry[i].map["NORMAL"].size, col->vectorGeometry[i].map["NORMAL"].data, GL_STATIC_DRAW);
loc = glGetAttribLocation(program, "in_normals");
glVertexAttribPointer(loc, col->vectorGeometry[i].map["NORMAL"].stride, col->vectorGeometry[i].map["NORMAL"].type, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vbosColor[i]);
Material* material = col->mapGeometryUrlToMaterial2Effect[col->vectorGeometry[i].id];
if (material->effect1.size() > 0)
{
Effect effect1 = material->effect1[0];
if (effect1.type == enumEffectTypes::color)
{
Color color = effect1.color;
glBufferData(GL_ARRAY_BUFFER, color.length, color.values, GL_STATIC_DRAW);
loc = glGetAttribLocation(program, "in_colors");
glVertexAttribPointer(loc, color.length, color.type, GL_FALSE, 0, 0);
}
else
{
}
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
// Initialize uniform data
void Mesh3D::InitializeUniforms(GLuint program) {
GLuint program_index, ubo_index;
struct LightParameters params;
// Specify the rotation matrix
glm::vec4 diff_color = glm::vec4(0.3f, 0.3f, 1.0f, 1.0f);
GLint location = glGetUniformLocation(program, "diffuse_color");
glUniform4fv(location, 1, &(diff_color[0]));
// Initialize UBO data
params.diffuse_intensity = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
params.ambient_intensity = glm::vec4(0.3f, 0.3f, 0.3f, 1.0f);
params.light_direction = glm::vec4(-1.0f, -1.0f, 0.25f, 1.0f);
// Set the uniform buffer object
glUseProgram(program);
glGenBuffers(1, &ubo);
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
glBufferData(GL_UNIFORM_BUFFER, 3 * sizeof(glm::vec4), &params, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glUseProgram(program);
// Match the UBO to the uniform block
glUseProgram(program);
ubo_index = 0;
program_index = glGetUniformBlockIndex(program, "LightParameters");
glUniformBlockBinding(program, program_index, ubo_index);
glBindBufferRange(GL_UNIFORM_BUFFER, ubo_index, ubo, 0, 3 * sizeof(glm::vec4));
glUseProgram(program);
This is a hearder file containing the two string literals I housing the strings used to build the vertex and fragment shader. Again I am new to this and not sure how I need to modify the shader to include colored vertices, I have started by adding an input vec4 for the four float colour ( includes alpha). Any help?
#pragma once
#ifndef Included_shaders
#define Included_shaders
#include<stdio.h>
#include<iostream>
static std::string shaderVert = "#version 330\n"
"in vec3 in_coords;\n"
"in vec3 in_normals;\n"
"in vec4 in_colors; \n"//added by me
"out vec3 vertex_normal;\n"
"void main(void) {\n"
"vertex_normal = in_normals;\n"
"gl_Position = vec4(in_coords, 1.0);\n"
"}\n";
static std::string shaderFrag = "#version 330\n"
"in vec3 vertex_normal;\n"
"out vec4 output_color;\n"
"layout(std140) uniform LightParameters{\n"
"vec4 diffuse_intensity;\n"
"vec4 ambient_intensity;\n"
"vec4 light_direction;\n"
"};\n"
"uniform vec4 diffuse_color;\n"
"void main() {\n"
"/* Compute cosine of angle of incidence */\n"
"float cos_incidence = dot(vertex_normal, light_direction.xyz);\n"
"cos_incidence = clamp(cos_incidence, 0, 1);\n"
"/* Compute Blinn term */\n"
"vec3 view_direction = vec3(0, 0, 1);\n"
"vec3 half_angle = normalize(light_direction.xyz + view_direction);\n"
"float blinn_term = dot(vertex_normal, half_angle);\n"
"blinn_term = clamp(blinn_term, 0, 1);\n"
"blinn_term = pow(blinn_term, 1.0);\n"
"/* Set specular color and compute final color */\n"
"vec4 specular_color = vec4(0.25, 0.25, 0.25, 1.0);\n"
"output_color = ambient_intensity * diffuse_color +\n"
"diffuse_intensity * diffuse_color * cos_incidence +\n"
"diffuse_intensity * specular_color * blinn_term;\n"
"}\n";
#endif
Finally this is the funciton I am modifying to draw the colored elements
void Mesh3D::DrawToParent()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw elements of each mesh in the vector
for (int i = 0; i<nVectorGeometry; i++)
{
glBindVertexArray(vaos[i]);
glDrawElements(col->vectorGeometry[i].primitive/*This is 4 for GL_Triangles*/, col->vectorGeometry[i].index_count,
GL_UNSIGNED_SHORT, col->vectorGeometry[i].indices);
}
glBindVertexArray(0);
glutSwapBuffers();
}
am getting a little confused about the glVertexAttribPointer and glGetAttribLocation though I think I get the basic idea. Am I using this right.
Am I setting up the buffer object for colors correctly. Am I correct I have a color for each vertex in this buffer, right now I have only placed the single color that applies to all associated buffers in this array and probably need to change that?
How exactly do I go about drawing the colored vertices when I call glDrawElements?
Don't just refer me to the resources for opengl a lot of the wordy explanations make little sense to me.
Make your vertex shader output color and make the fragment shader take it as input. The color will be interpolated between vertices.
Yes, it seems you have understood glAttribPointer correctly.
DrawElements takes the indices of the vertices you want to draw. The last argument should not contain the indices. Instead, it should probably be null. The indices should be specified with glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...).
If the color buffer is correctly bound you don't need to do anything special id drawElements for the colors. The shaders will get all the enabled attribarrays.
I can help you better if you run the code and you tell me what problems you get. It would also help if the code was easier to read. If you split it into functions under ten lines in length you may spot some errors yourself and possibly remove some duplication.

How do I change the color of one vertex instead of all of them?

I'm new to OpenGL and GLSL, and am learning it through http://open.gl/ .
I've managed to draw a triangle and change the color of all the vertexes using:
glUniform3f(uniColor, red, 0.0, 0.0)
Where the value of "red" is constantly changing, but this updates the color value of all the vertexes in the triangle, while I only want to change one or two of the vertexes.
Looking over the code I don't see where I can implement any logic to focus on one vertex instead of them all (the code is almost completely based on http://open.gl/content/code/c2_triangle_uniform.txt)
In this code however: http://open.gl/content/code/c2_color_triangle.txt , each vertex gets it's own color, but it seems to be hard coded, I can't dynamically change the colors as the program progresses.
I'm guessing
uniColor = glGetUniformLocation(shader.handle, "triangleColor")
gives me the location of a variable I can change and this variable is used to update the color of all the vertexes, and that perhaps what I need to do is create 3 variables, one for each vertex and then access those, but how do I do that?
If I look at the GLSL I have a "uniform vec3 triangleColor;" which is then used in
void main()
{
outColor = vec4(triangleColor, 1.0);
}
but even if I create 3 such triangleColor variables how would I tell void main() to distinguish which vertex gets what variable?
The code:
import pyglet
from pyglet.gl import *
from shader import Shader
from ctypes import pointer, sizeof
import math
import time
window = pyglet.window.Window(800, 600, "OpenGL")
window.set_location(100, 100)
# Vertex Input
## Vertex Array Objects
vao = GLuint()
glGenVertexArrays(1, pointer(vao))
glBindVertexArray(vao)
## Vertex Buffer Object
vbo = GLuint()
glGenBuffers(1, pointer(vbo)) # Generate 1 buffer
vertices = [0.0, 0.5,
0.5, -0.5,
-0.5, -0.5]
## Convert the verteces array to a GLfloat array, usable by glBufferData
vertices_gl = (GLfloat * len(vertices))(*vertices)
## Upload data to GPU
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_gl), vertices_gl, GL_STATIC_DRAW)
# Shaders (Vertex and Fragment shaders)
vertex = """
#version 150
in vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
"""
fragment = """
#version 150
uniform vec3 triangleColor;
out vec4 outColor;
void main()
{
outColor = vec4(triangleColor, 1.0);
}
"""
## Compiling shaders and combining them into a program
shader = Shader(vertex, fragment)
shader.bind() #glUseProgram
# Making the link between vertex data and attributes
## shader.handle holds the value of glCreateProgram()
posAttrib = glGetAttribLocation(shader.handle, "position")
glEnableVertexAttribArray(posAttrib)
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0)
uniColor = glGetUniformLocation(shader.handle, "triangleColor")
# Set clear color
glClearColor(0.0, 0.0, 0.0, 1.0)
#window.event
def on_draw():
# Set the color of the triangle
red = (math.sin(time.clock() * 4.0) + 1.0) / 2.0
glUniform3f(uniColor, red, 0.0, 0.0)
# Clear the screen to black
glClear(GL_COLOR_BUFFER_BIT)
# Draw a triangle from the 3 vertices
glDrawArrays(GL_TRIANGLES, 0, 3)
#window.event
def on_key_press(symbol, modifiers):
pass
#window.event
def on_key_release(symbol, modifiers):
pass
def update(dt):
pass
pyglet.clock.schedule(update)
pyglet.app.run()
Setting a uniform for each vertex isn't really scalable. A better way would be to create another Vertex Buffer Object to store the values. This can be done similar to the one you create for positions, except this one will contain 3 GLfloats. You can re-buffer the data as it changes.
My python is rubbish, so i've used yours as a syntax guide, but it should be something along the lines of:
## Vertex Buffer Object
vbocolors = GLuint()
glGenBuffers(1, pointer(vbocolors ))
colors = [1.0, 0.0, 0.0, # red vertex
0.0, 1.0, 0.0, # green vertex
0.0, 0.0, 1.0] # blue vertex
## Convert the verteces array to a GLfloat array, usable by glBufferData
colors_gl = (GLfloat * len(colors))(*colors)
## Upload data to GPU
glBindBuffer(GL_ARRAY_BUFFER, vbocolors )
glBufferData(GL_ARRAY_BUFFER, sizeof(colors_gl), colors_gl, GL_STATIC_DRAW)
Later new colors can be re-buffered:
## Upload new data to GPU
glBindBuffer(GL_ARRAY_BUFFER, vbocolors )
glBufferData(GL_ARRAY_BUFFER, sizeof(new_colors_gl), new_colors_gl, GL_STATIC_DRAW)
Setting the vertex attribute pointers:
colorAttrib = glGetAttribLocation(shader.handle, "color")
glEnableVertexAttribArray(colorAttrib )
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0)
Then in your shader, you want to pass this vertex color value from the vertex shader to the fragment shader, which will interpolate its value accordingly during the rasterization process.
# Shaders (Vertex and Fragment shaders)
vertex = """
#version 150
in vec2 position;
in vec3 color;
out vec3 interpColor;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
interpColor= color;
}
"""
fragment = """
#version 150
in vec3 interpColor;
out vec4 outColor;
void main()
{
outColor = vec4(interpColor, 1.0);
}
"""
The approach proposed in #Pondwater's answer is perfectly valid and reasonable. Because alternatives are always valuable, here's a slightly different approach.
The idea here is that you have two uniforms with two different colors. To specify which vertex uses which of the two colors, you introduce an additional vertex attribute. This additional attribute is a single float, where value 0.0 means that you want to use the first color, and 1.0 that you want to use the second color.
For your triangle example, say you want to color the 1st and 3rd vertex blue, and the 2nd vertex red. Extend the vertex data like this:
vertices = [0.0, 0.5, 0.0,
0.5, -0.5, 1.0,
-0.5, -0.5, 0.0]
Then you set up a second vertex attribute (named colorWeight in the code below), following the same pattern you used for position. You'll have a second set of glEnableVertexAttribArray(), glVertexAttribPointer(), etc. calls for this new attribute.
In your vertex shader, you add the new colorWeight attribute, and pass it through to the fragment shader:
in vec2 position;
in float colorWeight;
out float fragColorWeight;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
fragColorWeight = colorWeight;
}
Then in the fragment shader, you now have two uniform colors, and mix them based on the relative color weight:
uniform vec3 triangleColor;
uniform vec3 secondaryColor;
in float fragColorWeight;
out vec4 outColor;
void main()
{
vec3 mixedColor = mix(triangleColor, secondaryColor, fragColorWeight);
outColor = vec4(mixedColor, 1.0);
}
Now you can get the location of the secondaryColor uniform variable, and set it independently of triangleColor to modify the color of just the second vertex of the triangle.

OpenGL Vertex Shader Runtime Issues (not using VBOs or textures)

I have the following vertex shader:
uniform mat4 uMVP;
attribute vec4 aPosition;
attribute vec4 aNormal;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
varying vec4 vPrimaryColor;
void main() {
gl_Position = uMVP * aPosition;
vPrimaryColor = vec4(1.0, 1.0, 1.0, 1.0);
vTexCoord = aTexCoord;
}
And the following fragment shader:
uniform sampler2D sTex;
varying vec2 vTexCoord;
varying vec4 vPrimaryColor;
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
Note that while I have a vTexCoord and vPrimaryColor, neither of which are used in the fragment shader. (The reason why they are there is because they eventually will be).
Now, I also set uMVP to be the identity matrix for now, and draw using the following code:
// Load the matrix
glUniformMatrix4fv(gvMVPHandle, 1, false, &mvPMatrix.matrix[0][0]);
// Draw the square to be textured
glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gFullScreenQuad);
glEnableVertexAttribArray(gvPositionHandle);
glVertexAttribPointer(gvTexCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, gFullScreenQuad);
glDrawArrays(GL_QUADS, 0, 4);
where the square is:
const GLfloat PlotWidget::gFullScreenQuad[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
So, when I run this program, I get a black screen. Which does not seem like you would expect. However, when I change the line in the shade:
vTexCoord = aTexCoord;
To
vTexCoord = vec2(1.0, 1.0);
It works perfectly. So I would assume the problem with the code is with that line of code, but I can't think of anything in opengl that would cause this. Also, I'm using Qt for this project, which means this class is using the QGLWidget. I've never had this issue with OpenGL ES 2.0.
Any suggestions?
I'm sorry for the vague title, but I don't even know what class of problem this would be.
Are you checking glGetShaderInfoLog and glGetProgramInfoLog during your shader compilation? If not then I would recommend that as the first port of call.
Next thing to check would be your the binding for the texture coordinates. Are the attributes are being set up correctly? Is the data valid?
Finally, start stepping through your code with liberal spraying of glGetError calls. It wil almost certainly fail on glDrawArrays which won't help you much, but that's usually when the desparation sets in for me!
OR
You could try gDEBugger. I use it mainly to look for bottlenecks and to make sure I'm releasing OpenGL resources properly so can't vouch for the debugger, but it's worth a shot.
Apparently you need to actually use the whole use glEnableVertexAttribArray if it's getting passed into the fragment shader. I have no idea why though. But changing the drawing code to this:
glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gFullScreenQuad);
glEnableVertexAttribArray(gvPositionHandle);
glVertexAttribPointer(gvTexCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, gFullScreenQuad);
glEnableVertexAttribArray(gvTexCoordHandle);
glDrawArrays(GL_QUADS, 0, 4);
made it work.
Same problem, different cause.
For some devices the automatic variable linking in glLinkProgram does not work as specified.
Make sure things are done in the following order:
glCreateProgram
glCreateShader && glCompileShader for both shaders
glBindAttribLocation for all attributes
glLinkProgram
Step 3 can be repeated later at any time to rebind variables to different buffer slots - however changes only become effective after another call to glLinkgProgram.
or short: whenever you call glBindAttribLocation make sure a glLinkProgram calls comes after.