How do I change the color of one vertex instead of all of them?
colors, glsl, opengl, vertex
Solution
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);
}
"""
Problem
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() ```