Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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()
like image 767
01AutoMonkey Avatar asked Jul 16 '14 19:07

01AutoMonkey


People also ask

How do you change the vertex color?

In the properties window, open the Active Tool browser and choose a color in the color picker. Hit shift-k or Paint — Set Vertex Colors to paint all the selected faces that color.


1 Answers

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);
}
"""
like image 190
kbirk Avatar answered Oct 03 '22 08:10

kbirk