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);
}
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)
Related
I have the following minimal shader example (running in Python 2.7). I expect to see the entire screen taken up by a shaded quad (that is red). Instead I just see black. This example used to work perfectly on my previous Mac machine but now it seizes to function -- am I missing some OpenGL call that is needed?
from OpenGL.GLU import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLUT.freeglut import glutLeaveMainLoop
from OpenGL.arrays import vbo
from OpenGL.GL import shaders
from OpenGL.GL.ARB.color_buffer_float import *
from OpenGL.raw.GL.ARB.color_buffer_float import *
import numpy as np
QUAD_VERTEX_SHADER = """
attribute vec2 points;
varying vec2 coord;
varying vec2 index;
void main() {
index = (points + 1.0) / 2.0;
coord = (points * vec2(1, -1) + 1.0) / 2.0;
gl_Position = vec4(points, 0.0, 1.0);
}
"""
FRAG_SHADER = """
varying vec2 index;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
"""
def display():
glViewport(0, 0, int(width), int(height))
shaders.glUseProgram(shader)
vbo.bind()
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointerf(vbo)
glDrawArrays(GL_TRIANGLES, 0, 6)
vbo.unbind()
glDisableClientState(GL_VERTEX_ARRAY)
glutSwapBuffers()
def idle():
glutPostRedisplay()
width = 640
height = 480
vertices = [
[ -1, 1, 0 ],
[ -1,-1, 0 ],
[ 1,-1, 0 ],
[ -1, 1, 0 ],
[ 1,-1, 0 ],
[ 1, 1, 0 ]
]
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ACCUM | GLUT_DEPTH)
glutInitWindowSize(width, height)
window_id = glutCreateWindow('Visualization')
glClearColor(0.,0.,0.,0.)
glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
glEnable( GL_PROGRAM_POINT_SIZE )
glMatrixMode(GL_MODELVIEW)
glutIdleFunc(idle)
glutDisplayFunc(display)
vp = shaders.compileShader(QUAD_VERTEX_SHADER, GL_VERTEX_SHADER)
fp = shaders.compileShader(FRAG_SHADER, GL_FRAGMENT_SHADER)
shader = shaders.compileProgram(vp, fp)
vbo = vbo.VBO(np.array(vertices,'float32'))
glutMainLoop()
You have to specify the array of vertex attributes with glVertexAttribPointer and you have to enable it with glEnableVertexAttribArray:
shader = shaders.compileProgram(vp, fp)
points_loc = glGetAttribLocation(shader, 'points');
glUseProgram(shader)
vbo.bind()
glEnableVertexAttribArray(points_loc);
glVertexAttribPointer(points_loc, 3, GL_FLOAT, GL_FALSE, 0, None)
glDrawArrays(GL_TRIANGLES, 0, 6)
The app is based on PyOpenGL (core profile) and using orthographic projection. I have to draw several different 2d shapes on a quad(2 triangles).
I have found a really great article on rendering 2d/3d shapes using SDF. The first shape I'm trying is a rounded rectangle with border. This Shadertoy example perfectly fits to my requirement. Here are my two shaders:
VERTEX SHADER
#version 330 core
// VERTEX SHADER
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 tex_coord;
uniform mat4 mvp;
void main()
{
gl_Position = mvp * vec4(aPos, 1.0);
tex_coord = aTexCoord;
}
FRAGMENT SHADER
#version 330 core
// FRAGMENT SHADER
uniform vec4 in_color;
in vec2 tex_coord;
vec2 resolution = vec2(800, 600);
float aspect = resolution.x / resolution.y;
const float borderThickness = 0.01;
const vec4 borderColor = vec4(1.0, 1.0, 0.0, 1.0);
const vec4 fillColor = vec4(1.0, 0.0, 0.0, 1.0);
const float radius = 0.05;
float RectSDF(vec2 p, vec2 b, float r)
{
vec2 d = abs(p) - b + vec2(r);
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;
}
void main() {
// https://www.shadertoy.com/view/ltS3zW
vec2 centerPos = tex_coord - vec2(0.5, 0.5); // <-0.5,0.5>
//vec2 centerPos = (tex_coord/resolution - vec2(0.5)) * 2.0;
//centerPos *= aspect; // fix aspect ratio
//centerPos = (centerPos - resolution.xy) * 2.0;
float fDist = RectSDF(centerPos, vec2(0.5, 0.5), radius);
vec4 v4FromColor = borderColor; // Always the border color. If no border, this still should be set
vec4 v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); // Outside color
if (borderThickness > 0.0)
{
if (fDist < 0.0)
{
v4ToColor = fillColor;
}
fDist = abs(fDist) - borderThickness;
}
float fBlendAmount = smoothstep(-0.01, 0.01, fDist);
// final color
gl_FragColor = mix(v4FromColor, v4ToColor, fBlendAmount);
}
And the difference between two outputs:
Problem 1
In Shadertoy example, border is neat and there is no blurring, mine is blurred.
Problem 2
I am using ndc coordinates to specify borderThickness and radius, because of this I'm not getting a consistent border. If you see in the image, horizontal border is slightly wider then vertical one. I would prefer to use borderThickness and radius in pixel size. The idea is to get a consistent border around the rectangle irrespective of screen dimension.
Problem 3
Make outside blue color transparent.
Problem 4
As I've mentioned that I've recently started to learn GLSL, Some where I've read that too many "if" conditions would greatly affect the shader performance and chances are you might be using them unnecessary. There are already two "if" conditions exists in this code and I'm not sure if they can be omitted.
Use a Uniform (rectSize) to to specify the size of the rectangle in pixel. The texture coordinates (tex_coord) need to be in range [0.0, 1.0]. Compute the pixel position in the rectangle (rectSize * tex_coord). Now you can specify the radius and the edge thickness in pixels:
in vec2 tex_coord;
uniform vec2 rectSize;
const float borderThickness = 10.0;
const float radius = 30.0;
// [...]
void main()
{
vec2 pos = rectSize * tex_coord;
float fDist = RectSDF(pos-rectSize/2.0, rectSize/2.0 - borderThickness/2.0-1.0, radius);
float fBlendAmount = smoothstep(-1.0, 1.0, abs(fDist) - borderThickness / 2.0);
vec4 v4FromColor = borderColor;
vec4 v4ToColor = (fDist < 0.0) ? fillColor : vec4(0.0);
gl_FragColor = mix(v4FromColor, v4ToColor, fBlendAmount);
}
rect_loc = glGetUniformLocation(program, "rectSize")
glUniform2f(rect_loc, width, height)
Use Blending to make the outside transparent. For this, the alpha channel of the outer color must be 0. (e.g. vec4(0.0))
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
Minimal example:
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import OpenGL.GL.shaders
from ctypes import c_void_p
import glm
sh_vert = """
#version 330 core
// VERTEX SHADER
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 tex_coord;
uniform mat4 mvp;
void main()
{
gl_Position = mvp * vec4(aPos, 1.0);
tex_coord = aTexCoord;
}
"""
sh_frag = """
#version 330 core
// FRAGMENT SHADER
in vec2 tex_coord;
uniform vec2 rectSize;
const vec4 borderColor = vec4(1.0, 1.0, 0.0, 1.0);
const vec4 fillColor = vec4(1.0, 0.0, 0.0, 1.0);
const float borderThickness = 10.0;
const float radius = 30.0;
float RectSDF(vec2 p, vec2 b, float r)
{
vec2 d = abs(p) - b + vec2(r);
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;
}
void main()
{
vec2 pos = rectSize * tex_coord;
float fDist = RectSDF(pos-rectSize/2.0, rectSize/2.0 - borderThickness/2.0-1.0, radius);
float fBlendAmount = smoothstep(-1.0, 1.0, abs(fDist) - borderThickness / 2.0);
vec4 v4FromColor = borderColor;
vec4 v4ToColor = (fDist < 0.0) ? fillColor : vec4(0.0);
gl_FragColor = mix(v4FromColor, v4ToColor, fBlendAmount);
}
"""
def display():
glClear(GL_COLOR_BUFFER_BIT)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
glutSwapBuffers()
glutPostRedisplay()
def reshape(width, height):
glViewport(0, 0, width, height)
resolution = (640, 480)
rect = (50, 50, 350, 250)
attributes = (GLfloat * 20)(*[rect[0],rect[1],0,0,1, rect[2],rect[1],0,1,1, rect[2],rect[3],0,1,0, rect[0],rect[3],0,0,0])
indices = (GLuint * 6)(*[0,1,2, 0,2,3])
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
glutInitWindowSize(*resolution)
glutCreateWindow(b"OpenGL Window")
glutDisplayFunc(display)
glutReshapeFunc(reshape)
vao = glGenVertexArrays(1)
vbo = glGenBuffers(1)
ebo = glGenBuffers(1)
glBindVertexArray(vao)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, attributes, GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 5 * 4, None)
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 2, GL_FLOAT, False, 5 * 4, c_void_p(3 * 4))
glEnableVertexAttribArray(1)
program = OpenGL.GL.shaders.compileProgram(
OpenGL.GL.shaders.compileShader(sh_vert, GL_VERTEX_SHADER),
OpenGL.GL.shaders.compileShader(sh_frag, GL_FRAGMENT_SHADER)
)
glUseProgram(program)
mvp_loc = glGetUniformLocation(program, "mvp")
mvp = glm.ortho(0, *resolution, 0, -1, 1)
glUniformMatrix4fv(mvp_loc, 1, GL_FALSE, glm.value_ptr(mvp))
rect_loc = glGetUniformLocation(program, "rectSize")
glUniform2f(rect_loc, rect[2]-rect[0], rect[3]-rect[1])
glClearColor(0.5, 0.5, 0.5, 0.0)
glutMainLoop()
I've been facing an issue for the past couple of days, and I still haven't been able to figure it out.. I'm trying to port a previous C++ Opengl project to PyOpengl, but I'm not able to get the object to render as it should. I'm simply trying to render a 3D grid model, which works in the original C++ code, but not in Python PyOpenGL.
What it should look like: (C++ OpenGL)
What it looks like (Python PyOpenGL)
This is the code I end up with in PyOpenGL :
import glfw
import glm
import numpy as np
from OpenGL.GL import *
import Shader
# Settings
SCR_WIDTH = 800
SCR_HEIGHT = 600
def framebuffer_size_callback(window, width, height):
if width != 0 and height != 0:
width = width
height = height
glViewport(0, 0, width, height)
def create_v_array():
vertexArray = []
indexArray = []
for x in range(-100, 102, 2):
# To draw lines across x axis from z = -1 to z = 1
vertexArray.append(glm.vec3(x / 100.0, 0.0, -1.0)) # Vertex position 1
vertexArray.append(glm.vec3(1.0, 1.0, 1.0)) # color for v1
vertexArray.append(glm.vec3(x / 100.0, 0.0, 1.0)) # Vertex position 2
vertexArray.append(glm.vec3(1.0, 1.0, 1.0)) # color for v2
for z in range(-100, 102, 2):
# To draw lines across z axis from x = -1 to x = 1
vertexArray.append(glm.vec3(-1.0, 0.0, z / 100.0)) # Vertex position 1
vertexArray.append(glm.vec3(1.0, 1.0, 1.0)) # color for v1
vertexArray.append(glm.vec3(1.0, 0.0, z / 100.0)) # Vertex position 2
vertexArray.append(glm.vec3(1.0, 1.0, 1.0)) # color for v2
for i in range(10000):
indexArray.append(i)
vao = GLuint()
vbo = GLuint()
ebo = GLuint()
vertexArray = np.array(vertexArray, dtype=np.float32)
indexArray = np.array(indexArray, dtype=np.float32)
# Bind vao
glGenVertexArrays(1, vao)
glBindVertexArray(vao)
# Upload Vertex Buffer (VBO) to the GPU, keep a reference to it (vertexBufferObject)
glGenBuffers(1, vbo)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, vertexArray.nbytes, vertexArray, GL_STATIC_DRAW)
# Upload Index Buffer (EBO) to the GPU, keep a reference to it (elementBufferObject)
glGenBuffers(1, ebo)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexArray.nbytes, indexArray, GL_STATIC_DRAW)
# Position
glVertexAttribPointer(0,
3,
GL_FLOAT,
GL_FALSE,
24,
None
)
glEnableVertexAttribArray(0)
# Color
glVertexAttribPointer(1,
3,
GL_FLOAT,
GL_FALSE,
24,
ctypes.c_void_p(12)
)
glEnableVertexAttribArray(1)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
return vao
def main():
# Initialize the library
#glfw.glewExperimental = GL_TRUE
if not glfw.init():
return
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 2)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE)
# Create a windowed mode window and its OpenGL context
window = glfw.create_window(SCR_WIDTH, SCR_HEIGHT, "OpenGL", None, None)
if not window:
glfw.terminate()
return
# Make the window's context current
glfw.make_context_current(window)
glfw.set_framebuffer_size_callback(window, framebuffer_size_callback)
#glEnable(GL_DEPTH_TEST)
#glDepthFunc(GL_LESS)
shader = Shader.Shader("VertexShader.vsh", "FragmentShader.fsh")
vao = create_v_array()
glUseProgram(shader.ID)
# Loop until the user closes the window
while not glfw.window_should_close(window):
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(shader.ID)
glBindVertexArray(vao)
model = glm.mat4(1)
view = glm.mat4(1)
model = glm.rotate(model, glm.radians(15.0), glm.vec3(1.0, 0.0, 0.0))
view = glm.translate(view, glm.vec3(0.0, 0.0, -1.0))
projection = glm.perspective(glm.radians(45.0), (SCR_WIDTH/SCR_HEIGHT), 0.1, 100.0)
shader.set_mat4("model", model)
shader.set_mat4("view", view)
shader.set_mat4("projection", projection)
glBindVertexArray(vao)
glDrawElements(GL_LINES, 20000, GL_UNSIGNED_INT, None)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
if __name__ == "__main__":
main()
Custom Shader class:
class Shader:
def __init__(self, vertex_path, fragment_path):
vertex_code = get_file_content(vertex_path)
fragment_code = get_file_content(fragment_path)
vertex = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertex, vertex_code)
glCompileShader(vertex)
result = glGetShaderiv(vertex, GL_COMPILE_STATUS)
if not (result):
print("Vertex shader ERROR!")
raise RuntimeError(glGetShaderInfoLog(vertex))
fragment = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragment, fragment_code)
glCompileShader(fragment)
result2 = glGetShaderiv(fragment, GL_COMPILE_STATUS)
if not (result2):
print("Fragment shader ERROR!")
raise RuntimeError(glGetShaderInfoLog(vertex))
self.ID = glCreateProgram()
glAttachShader(self.ID, vertex)
glAttachShader(self.ID, fragment)
glLinkProgram(self.ID)
success = glGetProgramiv(self.ID, GL_LINK_STATUS)
if not success:
print("gad darn")
infolog = glGetProgramInfoLog(self.ID)
print("ERROR::SHADER::PROGRAM::LINKING_FAILED\n", infolog)
glDeleteShader(vertex)
glDeleteShader(fragment)
def set_mat4(self, name, matrix):
glUniformMatrix4fv(glGetUniformLocation(self.ID, name), 1, GL_FALSE, glm.value_ptr(matrix))
def use(self):
glUseProgram(self.ID)
# Helper Function
def get_file_content(file):
with open(file) as f:
content = f.read()
return content
glsl files:
Vertex Shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 vertexColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
vertexColor = aColor;
}
Fragment Shader:
#version 330 core
in vec3 vertexColor;
out vec4 FragColor;
void main()
{
FragColor = vec4(vertexColor.r, vertexColor.g, vertexColor.b, 1.0f);
}
The type of the indices must be integral instead of the floating point:
indexArray = np.array(indexArray, dtype=np.float32)
indexArray = np.array(indexArray, dtype=np.uint32)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Important edit: I am using the PyOpenGL binding of OpenGL
I am trying not to use the glRotate and glTranslate functions, but I have not found any alternative to this two functions. This functions are deprecated. What can I use?
The modern way is to write a Shader program, to use Vertex Array Objects and to use Uniform variable(s) of type mat4.
There is more code to write, in compare to the deprecated fixed function pipeline but the benefit is high flexibility and a far better performance, in compare to drawing by glBegin/glEnd sequences.
For the matrix calculations can be used the PyGLM library, which is the python version of the c++ OpenGL Mathematics (glm) library.
e.g. A scale, rotation matrix around the z-axis by an angle and translation can set by:
model = glm.mat4(1)
model = glm.translate(model, glm.vec3(0.2, 0.2, 0))
model = glm.rotate(model, angle, glm.vec3(0, 0, 1))
model = glm.scale(model, glm.vec3(0.5, 0.5, 1))
In compare to the the Legacy OpenGL operation glRoatate, the angle has to be set in radians.
Note, instead of using PyGLM it is also possible to use the popular NumPy library and numpy.matrix, but PyGLM is closer to that what you know from Legacy OpenGL and the functions glScale, glTranslate and glRotate.
Of course it would be possible to set the the 4x4 matrices with out any library and to implement the matrix operations by yourself, too.
See the small example program, which uses PyOpenGL and PyGLM (beside the modules math and ctypes):
import math
import ctypes
import glm
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GL.shaders import *
class MyWindow:
__caption = 'OpenGL Window'
__vp_size = [800, 600]
__vp_valid = False
__glut_wnd = None
__glsl_vert = """
#version 450 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec4 a_col;
out vec4 v_color;
layout (location = 0) uniform mat4 u_proj;
layout (location = 1) uniform mat4 u_view;
layout (location = 2) uniform mat4 u_model;
void main()
{
v_color = a_col;
gl_Position = u_proj * u_view * u_model * vec4(a_pos.xyz, 1.0);
}
"""
__glsl_frag = """
#version 450 core
out vec4 frag_color;
in vec4 v_color;
void main()
{
frag_color = v_color;
}
"""
__program = None
__vao = None
__vbo = None
def __init__(self, w, h):
self.__vp_size = [w, h]
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(self.__vp_size[0], self.__vp_size[1])
__glut_wnd = glutCreateWindow(self.__caption)
self.__program = compileProgram(
compileShader( self.__glsl_vert, GL_VERTEX_SHADER ),
compileShader( self.__glsl_frag, GL_FRAGMENT_SHADER ),
)
attribures = [
# x y z R G B A
-0.866, -0.5, 0, 1, 0, 0, 1,
0.866, -0.5, 0, 1, 1, 0, 1,
0, 1.0, 0, 0, 0, 1, 1
]
vertex_attributes = (GLfloat * len(attribures))(*attribures)
itemsize = ctypes.sizeof(ctypes.c_float)
self.__vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.__vbo)
glBufferData(GL_ARRAY_BUFFER, vertex_attributes, GL_STATIC_DRAW)
self.__vao = glGenVertexArrays(1)
glBindVertexArray(self.__vao)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 7*itemsize, None)
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 4, GL_FLOAT, False, 7*itemsize, ctypes.c_void_p(3*itemsize))
glEnableVertexAttribArray(1)
glUseProgram(self.__program)
glutReshapeFunc(self.__reshape)
glutDisplayFunc(self.__mainloop)
def run(self):
self.__starttime = 0
self.__starttime = self.elapsed_ms()
glutMainLoop()
def elapsed_ms(self):
return glutGet(GLUT_ELAPSED_TIME) - self.__starttime
def __reshape(self, w, h):
self.__vp_valid = False
def __mainloop(self):
if not self.__vp_valid:
self.__vp_size = [glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)]
self.__vp_valid = True
glViewport(0, 0, self.__vp_size[0], self.__vp_size[1])
proj = glm.mat4(1)
view = glm.mat4(1)
model = glm.mat4(1)
aspect = self.__vp_size[0]/self.__vp_size[1]
aspect_x = aspect if self.__vp_size[0] > self.__vp_size[1] else 1.0
aspect_y = 1/aspect if self.__vp_size[0] < self.__vp_size[1] else 1.0
proj = glm.ortho(-aspect_x, aspect_x, -aspect_y, aspect_y, -1.0, 1.0)
angle = self.elapsed_ms() * math.pi * 2 / 3000.0
model = glm.translate(model, glm.vec3(0.2, 0.2, 0))
model = glm.rotate(model, angle, glm.vec3(0, 0, 1))
model = glm.scale(model, glm.vec3(0.5, 0.5, 1))
glUniformMatrix4fv(0, 1, GL_FALSE, glm.value_ptr(proj) )
glUniformMatrix4fv(1, 1, GL_FALSE, glm.value_ptr(view) )
glUniformMatrix4fv(2, 1, GL_FALSE, glm.value_ptr(model) )
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glDrawArrays(GL_TRIANGLES, 0, 3)
glutSwapBuffers()
glutPostRedisplay()
window = MyWindow(800, 600)
window.run()
I am trying to dynamically set the point size of my vertexes and I am only able to do so if I use a static non-changing value:
#version 450 core
layout(location = 0) in vec4 vPosition;
layout(location = 4) uniform float Size = 50;
void main()
{
gl_Position = vPosition;
gl_PointSize = Size;
}
Result:
However when I try to update them dynamically I see that only one of the vertices sizes change and the others disappear entirely:
#version 450 core
layout(location = 0) in vec4 vPosition;
layout(location = 4) in float Size;
void main()
{
gl_Position = vPosition;
gl_PointSize = Size;
}
Which I then set it's value:
def drawWithoutVBOs(vertices, indices):
...
glEnableVertexAttribArray(4)
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, 0, 50)
glDrawElementsus(GL_POINTS, indices)
Result:
Could someone please help me spot what I am doing wrong?
Sourcecode for this project
#!/usr/bin/env python2
import time
from OpenGL.GL import *
from OpenGL.GL.shaders import *
import pygame
from pygame.locals import *
import numpy
width = 640
height = 480
vertices = numpy.array([0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0], numpy.float32)
indices = numpy.array([0, 1, 2], numpy.ushort)
def init():
vertexShader = compileShader("""
#version 450 core
layout(location = 0) in vec4 vPosition;
layout(location = 4) in float Size;
//layout(location = 4) uniform float Size = 50;
void main()
{
gl_Position = vPosition;
gl_PointSize = Size;
}""", GL_VERTEX_SHADER)
fragmentShader = compileShader("""
#version 450 core
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}""", GL_FRAGMENT_SHADER)
program = glCreateProgram()
glAttachShader(program, vertexShader)
glAttachShader(program, fragmentShader)
glBindAttribLocation(program, 0, "vPosition")
glBindAttribLocation(program, 4, "Size")
glLinkProgram(program)
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) #allow the program to specify the point size
glClearColor(0.0, 0.0, 0.0, 1.0)
return program
def drawWithoutVBOs(vertices, indices):
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices)
glEnableVertexAttribArray(4)
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, 0, 50)
glDrawElementsub(GL_POINTS, indices)
#glDrawElements(GL_POINTS, indices.size, GL_UNSIGNED_INT, indices)
def main():
pygame.init()
pygame.display.set_mode((width, height), HWSURFACE|OPENGL|DOUBLEBUF)
program = init()
glViewport(0, 0, width, height)
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(program)
drawWithoutVBOs(vertices, indices)
pygame.display.flip()
time.sleep(3)
if __name__ == '__main__':
main()