tenjohn
tenjohn

Reputation: 207

PyOpenGL passing variable to the vertex shader

After a few suggestion I decided the learn a little bit OpenGL with the hard way. I tried to pass a (float - named myAttrib) variable to the vertex shader and it seemed to work (line 33), but obviously doesn't. Later I would like to divide the code into further parts.

Code:

from OpenGL.GL import *
from OpenGL.GL.shaders import *

import pygame
from pygame.locals import *
import numpy, time

def getFileContent(file):
    content = open(file, 'r').read()
    return content

def initDraw():
    pygame.init()
    pygame.display.set_mode((640, 480), HWSURFACE | OPENGL | DOUBLEBUF)

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

    vertices = numpy.array(vertices, dtype = numpy.float32)

    myAttrib = 0.3

    vertexShader = compileShader(getFileContent("helloTriangle.vert"), GL_VERTEX_SHADER)
    fragmentShader = compileShader(getFileContent("helloTriangle.frag"), GL_FRAGMENT_SHADER)

    shaderProgram = glCreateProgram()
    glAttachShader(shaderProgram, vertexShader)
    glAttachShader(shaderProgram, fragmentShader)
    glBindAttribLocation(shaderProgram, 1, "myAttrib")
    glLinkProgram(shaderProgram)

    print(glGetAttribLocation(shaderProgram, "myAttrib"))

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices)
    glEnableVertexAttribArray(0)

    glClearColor(0, 0, 0, 1)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    glUseProgram(shaderProgram)
    glDrawArrays(GL_TRIANGLES, 0, 3)

    pygame.display.flip()
    time.sleep(2)

initDraw()

Vertex shader:

#version 130

attribute vec2 vPosition;
attribute float myAttrib;

void main()
{
    gl_Position = vec4(vPosition.x, vPosition.y + myAttrib, 0.0, 1.0);
}

Fragment shader:

#version 130

void main()
{
    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);            
}

Upvotes: 1

Views: 2294

Answers (1)

Rabbid76
Rabbid76

Reputation: 210889

If you use an attribute, the you have to define an array of generic vertex attributes, with one attribute value per vertex coordinate (3 in your case). See Vertex Specification.
If you would use a uniform, then you can set one value for the program stored in an uniform variable in the default uniform block (you can imagine this somehow like a global variable). See Uniform (GLSL):

Case 1 - Attribute myAttrib:

Vertex shader

#version 130

attribute vec2 vPosition;
attribute float myAttrib;

void main()
{
    gl_Position = vec4(vPosition.x, vPosition.y + myAttrib, 0.0, 1.0);
}

You have to define an array of generic vertex attributes as you do it for the vertex coordinates:

attrib = [-0.2, 0.2, 0.0]
myAttrib  = numpy.array(attrib, dtype = numpy.float32)

# .....

glLinkProgram(shaderProgram)
myAttrib_location = glGetAttribLocation(shaderProgram, "myAttrib")

# .....

glVertexAttribPointer(myAttrib_location, 1, GL_FLOAT, GL_FALSE, 0, myAttrib)
glEnableVertexAttribArray(myAttrib_location)

or

glBindAttribLocation(shaderProgram, 1, "myAttrib")
glLinkProgram(shaderProgram)

# .....

glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, myAttrib)
glEnableVertexAttribArray(1)

Case 2 - Uniform myUniform

Vertex shader

#version 130

attribute vec2 vPosition;
uniform float myUniform;

void main()
{
    gl_Position = vec4(vPosition.x, vPosition.y + myUniform, 0.0, 1.0);
}

Get the location of the uniform ("myUniform") by glGetUniformLocation and set the value to the uniform by glUniform:

myUniform = 0.3

# .....

glLinkProgram(shaderProgram)
myUniform_location = glGetUniformLocation(shaderProgram, "myUniform")

# .....

glUseProgram(shaderProgram)
glUniform1f(myUniform_location, myUniform)

glDrawArrays(GL_TRIANGLES, 0, 3)

Upvotes: 3

Related Questions