2014-07-16 302 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將其設置爲只修改三角形的第二個頂點的顏色。