2013-04-11 41 views
1

我有一個應用程序,我在GLUT窗口上繪製了一堆點。我有一個頂點着色器和一個碎片着色器,我給了一個顏色輸入。我的頂點着色器看起來像:如何使用着色器改變點的顏色

#version 120 
attribute vec2 position; 

varying vec4 vColor; 

void main() 
{ 
    vColor = gl_Color; 
    gl_Position = vec4(position, 0.0, 1.0); 
} 

和我的frag着色器看起來像:

#version 120 

varying vec4 vColor; 
void main() 
{ 
    gl_FragColor = vColor; 
} 

我希望用戶能夠改變基於一個按鍵的點的顏色。所以,我有一些按鍵處理功能:

void handleKeyPress(unsigned char key, int x, int y) 
{ 
    if (key == 'c') 
     //todo: change the point colors to green 
} 

我該怎麼做「待辦事項」?

回答

2

有了這些着色器,你可以只是發出一個glColor()在繪製之前:

glColor3f(r, g, b); 
// draw geometry 

但是,如果你已經在使用通用的固定功能互操作預先定義的變量(在頂點着色器gl_Color)是有點無意義頂點屬性的位置。

在這種情況下,你可以使用glUniform()代替:

#include <GL/glew.h> 
#include <GL/glut.h> 
#include <iostream> 
#include <vector> 
using namespace std; 

// RAII vertex attribute wrapper 
struct Attrib 
{ 
    Attrib 
     ( 
     const char* name, const GLint size, const GLsizei stride, const GLvoid* pointer, 
     const GLenum type = GL_FLOAT, const GLboolean normalized = GL_FALSE, const GLuint prog = GetProgram() 
     ) 
    { 
     mLoc = glGetAttribLocation(prog, name); 
     if(mLoc < 0) return; 
     glVertexAttribPointer(mLoc, size, type, normalized, stride, pointer); 
     glEnableVertexAttribArray(mLoc); 
    } 

    ~Attrib() 
    { 
     if(mLoc < 0) return; 
     glDisableVertexAttribArray(mLoc); 
    } 

    GLint mLoc; 

private: 
    static GLuint GetProgram() 
    { 
     GLint program = 0; 
     glGetIntegerv(GL_CURRENT_PROGRAM, &program); 
     return program; 
    } 
}; 

// GLSL shader program loader 
struct Program 
{ 
    static GLuint Load(const char* vert, const char* geom, const char* frag) 
    { 
     GLuint prog = glCreateProgram(); 
     if(vert) AttachShader(prog, GL_VERTEX_SHADER, vert); 
     if(geom) AttachShader(prog, GL_GEOMETRY_SHADER, geom); 
     if(frag) AttachShader(prog, GL_FRAGMENT_SHADER, frag); 
     glLinkProgram(prog); 
     CheckStatus(prog); 
     return prog; 
    } 

private: 
    static void CheckStatus(GLuint obj) 
    { 
     GLint status = GL_FALSE, len = 10; 
     if(glIsShader(obj)) glGetShaderiv(obj, GL_COMPILE_STATUS, &status); 
     if(glIsProgram(obj)) glGetProgramiv(obj, GL_LINK_STATUS, &status); 
     if(status == GL_TRUE) return; 
     if(glIsShader(obj)) glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &len); 
     if(glIsProgram(obj)) glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &len); 
     std::vector<char> log(len, 'X'); 
     if(glIsShader(obj)) glGetShaderInfoLog(obj, len, NULL, &log[0]); 
     if(glIsProgram(obj)) glGetProgramInfoLog(obj, len, NULL, &log[0]); 
     std::cerr << &log[0] << std::endl; 
     exit(-1); 
    } 

    static void AttachShader(GLuint program, GLenum type, const char* src) 
    { 
     GLuint shader = glCreateShader(type); 
     glShaderSource(shader, 1, &src, NULL); 
     glCompileShader(shader); 
     CheckStatus(shader); 
     glAttachShader(program, shader); 
     glDeleteShader(shader); 
    } 
}; 

#define GLSL(version, shader) "#version " #version "\n" #shader 

const char* vert = GLSL 
(
    120, 
    attribute vec2 position; 
    void main() 
    { 
     gl_Position = vec4(position, 0.0, 1.0); 
    }  
); 

const char* frag = GLSL 
(
    120, 
    uniform vec3 uColor; 
    void main() 
    { 
     gl_FragColor = vec4(uColor, 1.0); 
    }  
); 

float r = 1, g = 0, b = 0; 
void keyboard(unsigned char key, int x, int y) 
{ 
    if(key == 'c') 
    { 
     r = 1 - r; 
     g = 1 - g; 
     b = 1 - b; 
    } 
} 

void display() 
{ 
    glClear(GL_COLOR_BUFFER_BIT); 

    // prepare to render 
    static GLuint prog = Program::Load(vert, NULL, frag); 
    glUseProgram(prog); 

    glUniform3f(glGetUniformLocation(prog, "uColor"), r, g, b); 

    float verts[] = { 
     -1/2.0, -1/2.0, 
     1/2.0, -1/2.0, 
     1/2.0, 1/2.0, 
     -1/2.0, 1/2.0, 
    }; 

    { 
     Attrib a1("position", 2, 0, verts); 
     glDrawArrays(GL_QUADS, 0, 4); 
    } 

    glutSwapBuffers(); 
} 

void timer(int extra) 
{ 
    glutTimerFunc(16, timer, 0); 
    glutPostRedisplay(); 
} 

int main(int argc, char **argv) 
{ 
    glutInit(&argc, argv); 
    glutInitWindowSize(600, 600); 
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
    glutCreateWindow("GLUT"); 
    glewInit(); 

    glutKeyboardFunc(keyboard); 
    glutDisplayFunc(display); 
    glutTimerFunc(0, timer, 0); 
    glutMainLoop(); 
    return 0; 
} 
+1

這是OpenGL的一個非常有用的屬性。對於DX而言,OpenGl dat的Niiice無法做到這一點。 :O – 2013-04-12 03:16:05

+0

謝謝!我有一個額外的懶惰的東西,放在某處去除'prog'參數(通過查詢OpenGL獲取當前程序ID)以及默認參數化一些較少使用的東西。我會盡力挖掘並編輯它。 – genpfault

+0

如果只是爲了我,不要去那麼麻煩。實際上,我現在在DirectX上工作(並且讓我的屁股被延遲渲染踢掉)。我將盡快將所有內容移植到OpenGL上,所以當發生這種情況時,我一定會完全滑向這個答案,並在我需要使用屬性時抓住這一點。 :P – 2013-04-12 03:28:20

0

有一個名爲glVertexAttrib OpenGL的功能,允許您設置一個頂點屬性爲固定值的整個繪製調用,而不是取每頂點值超出頂點緩衝區對象。與使用顏色指定統一變量相比,使用它的優點是,您可以使用相同的頂點/片段着色器對來渲染具有單個每個頂點顏色的幾何體和沒有這種屬性的幾何體。