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

01A*_*key 8 opengl colors glsl vertex

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

我已设法绘制一个三角形并使用以下方法更改所有顶点的颜色:

glUniform3f(uniColor, red, 0.0, 0.0)
Run Code Online (Sandbox Code Playgroud)

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

查看代码我没看到我可以在哪里实现任何逻辑来关注一个顶点而不是全部(代码几乎完全基于http://open.gl/content/code/c2_triangle_uniform.txt)

但是在这段代码中:http://open.gl/content/code/c2_color_triangle.txt,每个顶点都有它自己的颜色,但它似乎是硬编码的,我不能随着程序的进展动态地改变颜色.

我正在猜测

uniColor = glGetUniformLocation(shader.handle, "triangleColor")
Run Code Online (Sandbox Code Playgroud)

给我一个变量的位置,我可以改变,这个变量用于更新所有顶点的颜色,也许我需要做的是创建3个变量,每个顶点一个,然后访问那些,但我怎么做去做?

如果我看一下GLSL我有一个"统一的vec3 triangleColor"; 然后用于

void main()
{
    outColor = vec4(triangleColor, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

但即使我创建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()
Run Code Online (Sandbox Code Playgroud)

kbi*_*irk 7

为每个顶点设置一个统一体并不是真正可扩展的.更好的方法是创建另一个顶点缓冲区对象来存储值.这可以类似于您为位置创建的那个,除了这个将包含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)
Run Code Online (Sandbox Code Playgroud)

以后可以重新缓冲新颜色:

## Upload new data to GPU
glBindBuffer(GL_ARRAY_BUFFER, vbocolors )
glBufferData(GL_ARRAY_BUFFER, sizeof(new_colors_gl), new_colors_gl, GL_STATIC_DRAW)
Run Code Online (Sandbox Code Playgroud)

设置顶点属性指针:

colorAttrib = glGetAttribLocation(shader.handle, "color")
glEnableVertexAttribArray(colorAttrib )
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0)
Run Code Online (Sandbox Code Playgroud)

然后在着色器中,您希望将此顶点颜色值从顶点着色器传递到片段着色器,片段着色器将在光栅化过程中相应地插值其值.

# 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);
}
"""
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这样做的惯用方法是将所有顶点属性放入一个通用的VBO中,通常采用隔行格式,即`[(x,y,z,r,g,b,...),...]` (2认同)
  • @BartekBanachewicz:当然,你提到的角落*可能*有利于使用多个VBO.然而,缓存一致性对整体性能的影响更大; 还有一些实现,比如AMD(编辑:对不起,我把它们与NVidia混合在一起)忽略了对`glBufferData`的`usage`提示,并从运行时行为推断它.此外,如果您有一些顶点属性changine,而其他则不是,而不是隔行扫描它是非常常见的连接属性数组,当然是步长和元素对齐到一些catch-all边界(8字节). (2认同)
  • @BartekBanachewicz:还有一个小细节; 目前为目前存在的所有OpenGL实现O(glVertexAttribPointer)<O(glBindBuffer)<< O(glBindVertexArray) - 是的,*<<*不是拼写错误,glBindVertexArray在当前的OpenGL实现中速度过慢; Valve在他们的事后关于将源引擎移植到OpenGL和Linux时明确提到了这一事实. (2认同)