如何更改一个顶点的颜色而不是所有顶点的颜色?

时间:2014-07-16 19:19:12

标签: opengl colors glsl vertex

我是OpenGL和GLSL的新手,我正在通过http://open.gl/学习它。

我设法绘制了一个三角形并使用以下方法更改了所有顶点的颜色:

glUniform3f(uniColor, red, 0.0, 0.0)

" red"的价值不断变化,但这会更新三角形中所有顶点的颜色值,而我只想更改一个或两个顶点。

查看代码我不知道在哪里可以实现任何逻辑来关注一个顶点而不是全部(代码几乎完全基于http://open.gl/content/code/c2_triangle_uniform.txt

在这段代码中:http://open.gl/content/code/c2_color_triangle.txt,每个顶点都有它自己的颜色,但它似乎是硬编码的,我不能随着程序的进展动态地改变颜色。

我在猜测

uniColor = glGetUniformLocation(shader.handle, "triangleColor")

给我一​​个我可以改变的变量的位置,这个变量用于更新所有顶点的颜色,也许我需要做的是创建3个变量,每个顶点一个,然后访问它们,但是我该怎么做?

如果我看一下GLSL,我有一个"统一的vec3 triangleColor;"然后用于

void main()
{
    outColor = vec4(triangleColor, 1.0);
}

但即使我创建3个这样的triangleColor变量,我怎么告诉void main()来区分哪个顶点得到什么变量?

代码:

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()

2 个答案:

答案 0 :(得分:7)

为每个顶点设置制服并不是真正可扩展的。更好的方法是创建另一个顶点缓冲区对象来存储值。这可以类似于您为位置创建的那个,除了这个将包含3个GLfloats。您可以在数据发生变化时重新缓冲数据。

我的python是垃圾,所以我用你的语法作为语法指南,但它应该是这样的:

## 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)

以后的新颜色可以重新缓冲:

## Upload new data to GPU
glBindBuffer(GL_ARRAY_BUFFER, vbocolors )
glBufferData(GL_ARRAY_BUFFER, sizeof(new_colors_gl), new_colors_gl, GL_STATIC_DRAW)

设置顶点属性指针:

colorAttrib = glGetAttribLocation(shader.handle, "color")
glEnableVertexAttribArray(colorAttrib )
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0)

然后在着色器中,您希望将此顶点颜色值从顶点着色器传递到片段着色器,片段着色器将在光栅化过程中相应地插值其值。

# 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);
}
"""

答案 1 :(得分:1)

@ Pondwater的回答中提出的方法是完全有效和合理的。因为替代品总是有价值的,所以这里的方法略有不同。

这里的想法是你有两种不同颜色的制服。要指定哪个顶点使用两种颜色中的哪一种,请引入其他顶点属性。此附加属性是单个浮点数,其中值0.0表示您要使用第一种颜色,而1.0表示您要使用第二种颜色。

对于您的三角形示例,假设您要将第1和第3个顶点的颜色设为蓝色,将第2个顶点设为红色。像这样扩展顶点数据:

vertices = [0.0, 0.5, 0.0,
            0.5, -0.5, 1.0,
           -0.5, -0.5, 0.0]

然后设置第二个顶点属性(在下面的代码中名为colorWeight),遵循与position相同的模式。您将对此新属性进行第二组glEnableVertexAttribArray()glVertexAttribPointer()等调用。

在顶点着色器中,添加新的colorWeight属性,并将其传递给片段着色器:

in vec2 position;
in float colorWeight;
out float fragColorWeight;

void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
    fragColorWeight = colorWeight;
}

然后在片段着色器中,您现在有两种统一的颜色,并根据相对颜色权重进行混合:

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);
}

现在,您可以获取secondaryColor统一变量的位置,并将其设置为独立于triangleColor,以修改三角形的第二个顶点的颜色。