2014-07-16 9 views
6

Ich bin neu zu OpenGL und GLSL, und ich lerne es durch http://open.gl/. mitWie ändere ich die Farbe eines Scheitelpunkts statt aller?

Ich habe es geschafft, ein Dreieck zu zeichnen und die Farbe aller Scheiteln ändern:

glUniform3f(uniColor, red, 0.0, 0.0) 

Wenn der Wert von „Rot“ ändert sich ständig, aber diese aktualisiert den Farbwert aller Scheiteln im Dreieck, während ich nur ein oder zwei der Eckpunkte ändern möchte.

den Code Mit Blick auf Ich sehe nicht, wo ich jede Logik implementieren kann auf eine Ecke zu konzentrieren, anstatt von allen (der Code fast vollständig auf http://open.gl/content/code/c2_triangle_uniform.txt basiert)

In diesem Code aber: http://open.gl/content/code/c2_color_triangle.txt, die jeweils Vertex bekommt seine eigene Farbe, aber es scheint hart codiert zu sein, ich kann die Farben nicht dynamisch ändern, während das Programm fortschreitet.

Ich vermute, ich

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

gibt mir die Lage einer Variablen I und diese Variable verwendet wird, ändern die Farbe aller Scheiteln zu aktualisieren, und dass vielleicht das, was ich tun muss, ist 3 erstellen Variablen, eine für jeden Eckpunkt und dann Zugriff auf diese, aber wie mache ich das?

Wenn ich mir die GLSL ansehe habe ich eine "uniform vec3 triangleColor;" die dann in

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

verwendet, aber auch wenn ich 3 so triangleColor Variablen zu erstellen, wie würde ich sagen void main() zu unterscheiden, welche Vertex erhält, welche Variable?

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

machen Sie einen zweiten Puffer, der Farben enthält, er sollte Ihren Stellungen entsprechen, aber anstatt sie im Vertex-Shader zu verwenden, verwenden Sie sie im Fragment-Shader –

Antwort

5

eine Uniform für jeden Vertex Einstellung ist nicht wirklich skalierbar. Ein besserer Weg wäre, ein weiteres Vertex-Buffer-Objekt zum Speichern der Werte zu erstellen. Dies kann ähnlich wie für Stellungen geschehen, außer dass dieser 3 GLfloats enthält. Sie können die Daten neu puffern, wenn sie sich ändern.

Mein Python ist Müll, also habe ich Ihnen als Syntax Leitfaden verwendet, aber es sollte etwas entlang der Linien der folgenden sein:

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

Später neue Farben können umgepuffert werden:

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

Einstellung der Vertexattribut Zeiger:

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

Dann in Ihrem Shader, möchten Sie diese Vertex Farbe passieren Wert vom Vertex-Shader zum Fragment-Shader, der seinen Wert während des Rasterungsprozesses entsprechend interpoliert.

# 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

Das idiomatische Verfahren besteht darin, alle Eckpunktattribute zu platzieren ein gemeinsamer VBO, oft in einem verschachtelten Format, dh '[(x, y, z, r, g, b, ...), ...]' – datenwolf

+0

Ich stimme zu, aber ich denke, für einen Anfänger war es einfacher, zwei getrennte VBOs vorzuschlagen anstatt Interlacing und wie Zeigeroffsets und Schritt für die Attributzeiger zu verwenden. – kbirk

+0

In diesem Fall wäre es besser, 'GL_DYNAMIC_DRAW' in' glBufferData() 'anzugeben und dann' glBufferSubData() 'zu verwenden, um den Farbwert zu aktualisieren. –

1

Der vorgeschlagene Ansatz in @ Antwort ist das Teichwasser vollkommen gültig und zumutbar ist. Weil Alternativen immer wertvoll sind, hier ein etwas anderer Ansatz.

Die Idee hier ist, dass Sie zwei Uniformen mit zwei verschiedenen Farben haben. Um festzulegen, welcher Stützpunkt welche der beiden Farben verwendet, führen Sie ein zusätzliches Stützpunktattribut ein.Dieses zusätzliche Attribut ist ein einzelner Gleitkommawert, wobei Wert 0.0 bedeutet, dass Sie die erste Farbe verwenden möchten, und 1.0, die Sie die zweite Farbe verwenden möchten.

Für Ihr Dreieckbeispiel sagen Sie, dass Sie den 1. und 3. Scheitel blau und den 2. Scheitel rot färben möchten. Erweitern Sie die Vertex-Daten wie folgt aus:

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

Dann ein zweiter Eckpunkt Attribut einrichten (colorWeight in dem folgenden Code genannt), nach dem gleichen Muster, das Sie für position verwendet. Sie werden einen zweiten Satz von glEnableVertexAttribArray(), glVertexAttribPointer(), usw. Anrufe für dieses neue Attribut haben.

In Ihren Vertex-Shader, fügen Sie das neue colorWeight Attribut, und übergeben es an den Fragment-Shader durch:

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

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

Dann in den Fragment-Shader, haben Sie jetzt zwei einheitliche Farben und mischen sie basierend auf das relative Farbgewicht:

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

Jetzt können Sie den Speicherort der secondaryColor einheitlichen Variable erhalten und es unabhängig von triangleColor setzen die Farbe nur den zweiten Eckpunkt des Dreiecks zu ändern.