2014-07-16 13 views
6

Jestem nowy w OpenGL i GLSL i uczę się go przez http://open.gl/.Jak zmienić kolor jednego wierzchołka zamiast ich wszystkich?

udało mi się narysować trójkąt i zmienić kolor wszystkich wierzchołków za pomocą:

glUniform3f(uniColor, red, 0.0, 0.0) 

Jeżeli wartość „czerwony” ciągle się zmienia, ale to aktualizuje wartość koloru wszystkich wierzchołków w trójkącie, a ja chcę tylko zmienić jeden lub dwa wierzchołki.

Patrząc na kodzie nie widzę gdzie mogę realizować żadnej logiki, aby skupić się na jednym wierzchołku zamiast nich wszystkich (kod jest prawie całkowicie w oparciu o http://open.gl/content/code/c2_triangle_uniform.txt)

W tym kodzie Jednakże: http://open.gl/content/code/c2_color_triangle.txt każda vertex dostaje swój własny kolor, ale wydaje się być mocno zakodowany, nie mogę dynamicznie zmieniać kolorów w miarę postępu programu.

Zgaduję

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

daje mi lokalizację zmiennej mogę zmienić i zmienna ta służy do aktualizacji kolor wszystkich wierzchołkach, i że być może to, co trzeba zrobić, to stworzyć 3 zmienne, po jednym dla każdego wierzchołka, a następnie dostęp do nich, ale jak mam to zrobić?

Jeśli spojrzę na GLSL, mam "uniform vec3 triangleColor;" które są następnie wykorzystywane w

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

ale nawet jeśli tworzę 3 takich zmiennych triangleColor jak chciałbym powiedzieć void main(), aby odróżnić, który wierzchołek co dostaje zmienną?

Kod:

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

utworzyć drugi bufor zawierający kolory, powinien być taki sam jak twoje pozycje, ale zamiast używać go w vertex shader, używasz ich w module cieniującym –

Odpowiedz

5

Ustawianie uniform dla każdego wierzchołka naprawdę nie jest skalowalne. Lepszym sposobem byłoby utworzenie kolejnego obiektu bufora wierzchołków w celu przechowywania wartości. Można to zrobić podobnie jak w przypadku pozycji, z wyjątkiem tego, że będzie zawierał 3 GLfloats. Możesz ponownie buforować dane w miarę ich zmiany.

Mój pyton jest fatalna, więc ja używałem je jako przewodnik składni, ale powinno to być coś na wzór:

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

Późniejsze nowe kolory mogą być ponownie buforowane:

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

zachodzącego wierzchołków wskaźniki atrybut:

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

Następnie w cieniującego, chcesz przekazać ten kolor wierzchołków wartość z modułu cieniującego wierzchołka do modułu cieniującego fragment, który odpowiednio interpoluje jego wartość podczas rasteryzacji.

# 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

W rzeczywistości idiomatycznym sposobem na to jest umieszczenie wszystkich atrybutów wierzchołków w wspólny VBO, często w formacie z przeplotem, czyli '[(x, y, z, r, g, b, ...), ...]' – datenwolf

+0

Zgadzam się, ale myślę, że dla początkującego było prostsze zaproponować dwa oddzielne VBOs zamiast przeplatać się i używać przesunięć wskaźnika i kroku dla wskaźników atrybutów. – kbirk

+0

W tym przypadku, myślę, że byłoby lepiej, aby określić 'GL_DYNAMIC_DRAW' w' glBufferData() ', a następnie użyj' glBufferSubData() 'aby zaktualizować wartość koloru. –

1

Podejście zaproponowane w odpowiedzi @ Pondwater jest całkowicie poprawne i uzasadnione. Ponieważ alternatywy są zawsze cenne, oto nieco inne podejście.

Pomysł polega na tym, że masz dwa mundury w dwóch różnych kolorach. Aby określić, który wierzchołek używa jednego z dwóch kolorów, wprowadzasz dodatkowy atrybut wierzchołków.Ten dodatkowy atrybut jest pojedynczym zmiennoprzecinkowym, gdzie wartość 0.0 oznacza, że ​​chcesz użyć pierwszego koloru, a 1.0, w którym chcesz użyć drugiego koloru.

Dla przykładu trójkąta, powiedz, że chcesz pokolorować pierwszy i trzeci niebieski wierzchołek, a drugi czerwony wierzchołek. Rozszerz dane wierzchołków tak:

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

Następnie utwórz drugi wierzchołek (atrybut o nazwie colorWeight w poniższym kodzie), według tego samego wzoru, który wykorzystano do position. Będziesz mieć drugi zestaw glEnableVertexAttribArray(), glVertexAttribPointer() itp. Wywołań dla tego nowego atrybutu.

W swojej vertex shader, należy dodać nowy atrybut colorWeight i przekazać go za pośrednictwem modułu cieniującego fragmentu:

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

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

Następnie w shadera fragmentów, masz teraz dwie jednolite kolory i wymieszać je w oparciu o relatywna waga kolor:

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

teraz można dostać lokalizację zmiennej jednolity z secondaryColor i ustaw go niezależnie od triangleColor zmodyfikować kolor tylko drugiego wierzchołka trójkąta.

Powiązane problemy