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



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

我已经成功地画了一个三角形,并使用

改变所有顶点的颜色:
glUniform3f(uniColor, red, 0.0, 0.0)

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

查看代码,我不知道在哪里我可以实现任何逻辑集中在一个顶点,而不是他们所有(代码几乎完全基于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,我有一个"uniform 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()

为每个顶点设置统一是不可伸缩的。更好的方法是创建另一个顶点缓冲对象来存储这些值。这可以类似于你为位置创建的那个,除了这个将包含3个glfloat。当数据发生变化时,可以重新缓冲。

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

@Pondwater回答中提出的方法是完全有效和合理的。因为替代方案总是有价值的,这里有一个稍微不同的方法。

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

对于三角形的例子,假设你想把第一个和第三个顶点涂成蓝色,第二个顶点涂成红色。像这样扩展顶点数据:

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设置以修改三角形第二个顶点的颜色。

最新更新