2014-07-16 18 views
6

我是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变量我怎么会告诉无效的主要()来区分哪个顶点获得什么变化?

代码:

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

创建第二个包含颜色的缓冲区,它应该与您的位置相同,但不是在顶点着色器中使用它,而是在片段着色器中使用 –

回答

5

设置每个顶点的统一是不是真的可扩展性。更好的方法是创建另一个顶点缓冲区对象来存储值。这可以完成类似于你为位置创建的那个,除了这个将包含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); 
} 
""" 
+2

实际上,这样做的惯用方法是将所有顶点属性放入一个常见的VBO,通常是以隔行格式,即[[(x,y,z,r,g,b,...),...] – datenwolf

+0

我同意,但我认为对于初学者来说,建议两个独立的维也纳国际组织而不是隔行扫描,以及如何使用指针偏移量和跨度属性指针。 – kbirk

+0

在这种情况下,我认为在'glBufferData()'中指定'GL_DYNAMIC_DRAW'会更好,然后使用'glBufferSubData()'来更新颜色值。 –

1

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