Transparent textures being rendered as black in OpenGL - python

I have a texture with transparent parts, instead of being rendered transparent they're black.
To test if the RGBA values get passed on correctly to the shader, I made everything render in greyscale. And as I thought they alpha values aren't getting passed on corrctly.
So anyways here is how the textures get loaded:
#classmethod
def load_texture(cls, file_name: str):
try:
img = Image.open(f"{sys.path[0]}/res/{file_name}.png").convert('RGBA')
img = img.transpose(Image.FLIP_TOP_BOTTOM) # flip image upside down
except Exception as e:
print(e)
img = Image.open(f"{sys.path[0]}/res/missing_texture.png").convert('RGBA')
img = img.transpose(Image.FLIP_TOP_BOTTOM) # flip image upside down
ix, iy, image = img.size[0], img.size[1], img.tobytes("raw", "RGBA", 0, -1)
texture_id = glGenTextures(1) # generate a texture ID
cls.__textures.append(texture_id)
glBindTexture(GL_TEXTURE_2D, texture_id) # make it current
# copy the texture into the current texture texture_id
glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
return texture_id
And this is my fragment shader (the commented out part obviously not working):
#version 400 core
in vec2 pass_texture_coords;
in vec3 surface_normal;
in vec3 to_light_vector;
in vec3 to_camera_vector;
out vec4 out_color;
uniform sampler2D model_texture;
uniform vec3 light_color;
uniform float shine_damper;
uniform float reflectivity;
void main(void){
vec4 texture_color = texture(model_texture, pass_texture_coords);
texture_color = vec4(vec3(texture_color.a), 1.0);
//if(texture_color.a < 0.5){
// discard;
//}
vec3 unit_normal = normalize(surface_normal);
vec3 unit_light_vector = normalize(to_light_vector);
float n_dot1 = dot(unit_normal, unit_light_vector);
float brightness = max(n_dot1, 0.1);
vec3 diffuse = brightness * light_color;
vec3 unit_vector_to_camera = normalize(to_camera_vector);
vec3 light_direction = -unit_light_vector;
vec3 reflected_light_direction = reflect(light_direction, unit_normal);
float specular_factor = dot(reflected_light_direction, unit_vector_to_camera);
specular_factor = max(specular_factor, 0.0);
float damped_factor = pow(specular_factor, shine_damper);
vec3 final_specular = damped_factor * reflectivity * light_color;
out_color = vec4(diffuse, 1.0) * texture_color + vec4(final_specular, 1.0);
}
Also before rendering anything this method gets called:
#staticmethod
def update_display():
InputController().apply_input() # apply inputs every frame
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # so that transparent bits of the texture won't get rendered
glEnable(GL_ALPHA_TEST)
glEnable(GL_DEPTH_TEST)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Remove everything from screen (i.e. displays all white)
glClearColor(0, 0.3, 0, 1) # set backdrop color
glLoadIdentity() # Reset all graphic/shape's position

https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml:
glTexImage2D(
GL_TEXTURE_2D, //target
0, //level
3, //internalformat -> 3 -> GL_RGB -> no alpha
//framebuffer does not necessarily need an alpha channel
//but if you want transparent textures you have to specify one,
//e.g. GL_RGBA (or any other format from Table 2 with alpha)
ix, //width
iy, //height
0, //border, must be 0
GL_RGBA, //format of data
GL_UNSIGNED_BYTE, //type of data
image //data, which gets converted from format to internalformat
//in your case, the alpha components will be discarded
);
Hint: always use symbols, e.g. GL_XXXX, legacy OpenGL accepts a numeric value for internalformat but the spec in the link above explicitly mandates one of the symbols from the tables.

Related

GLSL, SDF based Rounding Rectangle

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

Different results between glfw offscreen and window rendering with large images

I am having different results using glfw window and offscreen rendering. I want to apply texture mapping using this texture_image on a mesh. The image dimension is 3500 x 1752.
My code for rendering and displaying the rendered image on a pop-up glfw window is as follows:
t_obj = "mesh.obj"
tex_file_path = "texture.png"
tex_im = cv2.imread(tex_file_path)
h, w = tex_im.shape[:2]
vertices, tex_coords, indices = load_obj_file(t_obj, dimension=3)
colors = np.ones((len(vertices), 3), dtype=np.float)
vertices = np.hstack((vertices, colors, tex_coords))
vertices = np.array(vertices, dtype=np.float32)
# a vertex shader consists of x, y, z and w.
vertex_src = """
# version 330
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_color;
layout(location = 2) in vec2 a_texture;
uniform mat4 rotation;
out vec3 v_color;
out vec2 v_texture;
void main()
{
gl_Position = rotation * vec4(a_position, 1.0);
v_color = a_color;
v_texture = a_texture;
//v_texture = 1 - a_texture; // Flips the texture vertically and horizontally
//v_texture = vec2(a_texture.s, 1 - a_texture.t); // Flips the texture vertically
}
"""
# fragment shader consists of R, G, B and A.
fragment_src = """
# version 330
in vec3 v_color;
in vec2 v_texture;
out vec4 out_color;
uniform sampler2D s_texture;
void main()
{
out_color = texture(s_texture, v_texture) * vec4(v_color, 1.0f);
}
"""
# glfw callback functions
def window_resize(window, width, height):
glViewport(0, 0, width, height)
# initializing glfw library
if not glfw.init():
raise Exception("glfw can not be initialized!")
# creating the window
# glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window = glfw.create_window(w, h, "My OpenGL window", None, None)
# check if window was created
if not window:
glfw.terminate()
raise Exception("glfw window can not be created!")
# set window's position
glfw.set_window_pos(window, w, h)
# set the callback function for window resize
glfw.set_window_size_callback(window, window_resize)
# make the context current
glfw.make_context_current(window)
shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER),
compileShader(fragment_src, GL_FRAGMENT_SHADER))
# Step2: Create and bind VBO objects to transfer data
VBO = glGenBuffers(1) # request a buffer slot from GPU.
glBindBuffer(GL_ARRAY_BUFFER, VBO) # make this buffer the default one.
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW) # upload CPU data to GPU buffer.
# Step3: Create and bind EBO object to transfer data
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
# Step4: Specify the resolution method and enable vertex attributes
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(0))
# Vertex color attributes
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(12))
# Vertex texture attributes
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(24))
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
# Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
# load image
image = Image.open(tex_file_path)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
img_data = image.convert("RGBA").tobytes()
# Attach a texture image to the texture buffer.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
glUseProgram(shader)
glClearColor(1, 1, 1, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
model = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.0, 0.0, 0]))
rotation_loc = glGetUniformLocation(shader, "rotation")
# the main application loop
while not glfw.window_should_close(window):
glfw.poll_events()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
glfw.swap_buffers(window)
# save_image
data = glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE)
pil_image = Image.frombytes("RGBA", (w, h), data)
pil_image = ImageOps.flip(pil_image)
pil_image.save('output.png')
glfw.terminate()
The result is with_popup_window_result.
However, the output image saved to disk is resized to a smaller image and then padded so that the final width and height are the same as those of the texture image. Here is the saved_output.
However, if I modify the code so that it does off-screen rendering and does not display the glfw window, the output image is cropped. Here is the modified code:
t_obj = "obj_time_0.5.obj"
tex_file_path = "s.png"
tex_im = cv2.imread(tex_file_path)
h, w = tex_im.shape[:2]
vertices, tex_coords, indices = load_obj_file(t_obj, dimension=3)
colors = np.ones((len(vertices), 3), dtype=np.float)
vertices = np.hstack((vertices, colors, tex_coords))
vertices = np.array(vertices, dtype=np.float32)
# a vertex shader consists of x, y, z and w.
vertex_src = """
# version 330
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_color;
layout(location = 2) in vec2 a_texture;
uniform mat4 rotation;
out vec3 v_color;
out vec2 v_texture;
void main()
{
gl_Position = rotation * vec4(a_position, 1.0);
v_color = a_color;
v_texture = a_texture;
//v_texture = 1 - a_texture; // Flips the texture vertically and horizontally
//v_texture = vec2(a_texture.s, 1 - a_texture.t); // Flips the texture vertically
}
"""
# fragment shader consists of R, G, B and A.
fragment_src = """
# version 330
in vec3 v_color;
in vec2 v_texture;
out vec4 out_color;
uniform sampler2D s_texture;
void main()
{
out_color = texture(s_texture, v_texture) * vec4(v_color, 1.0f);
}
"""
# glfw callback functions
def window_resize(window, width, height):
glViewport(0, 0, width, height)
# initializing glfw library
if not glfw.init():
raise Exception("glfw can not be initialized!")
# creating the window
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window = glfw.create_window(w, h, "My OpenGL window", None, None)
# check if window was created
if not window:
glfw.terminate()
raise Exception("glfw window can not be created!")
# set window's position
glfw.set_window_pos(window, w, h)
# set the callback function for window resize
glfw.set_window_size_callback(window, window_resize)
# make the context current
glfw.make_context_current(window)
shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER),
compileShader(fragment_src, GL_FRAGMENT_SHADER))
# Step2: Create and bind VBO objects to transfer data
VBO = glGenBuffers(1) # request a buffer slot from GPU.
glBindBuffer(GL_ARRAY_BUFFER, VBO) # make this buffer the default one.
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW) # upload CPU data to GPU buffer.
# Step3: Create and bind EBO object to transfer data
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
# Step4: Specify the resolution method and enable vertex attributes
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(0))
# Vertex color attributes
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(12))
# Vertex texture attributes
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(24))
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
# Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
# load image
image = Image.open(tex_file_path)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
img_data = image.convert("RGBA").tobytes()
# Attach a texture image to the texture buffer.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
glUseProgram(shader)
glClearColor(1, 1, 1, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
model = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.0, 0.0, 0]))
rotation_loc = glGetUniformLocation(shader, "rotation")
# the main application loop
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
# save_image
data = glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE)
pil_image = Image.frombytes("RGBA", (w, h), data)
pil_image = ImageOps.flip(pil_image)
pil_image.save('output.png')
glfw.destroy_window(window)
glfw.terminate()
The saved result for this off-screen rendering is offscreen_output. It is cropped and padded so the resulting image dimension does not change.
I am wondering what causes these resizing and cropping problems. This only happens when the output dimension is big. I tried passing in smaller dimension (< 1000 x 1000) to glReadPixels() and the output images are fine (no resizing or cropping). I read somewhere that one can try using the frameBufferObject (FBO) for offscreen rendering instead of using glfw but since I do not know how to use FBO, the program crashes when I copying the FBO code from someone else's.
Any help is greatly appreciated. Thank you very much in advance.

How to render text with PyOpenGL?

I'm learning modern openGL, and at this moment I'm facing trouble with rendering text. I'm following this tutorial which is in C++, but I'm trying to implement in python.
Here is my code:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL import shaders
import glfw
import freetype
import glm
import numpy as np
from PIL import Image
import math
import time
class CharacterSlot:
def __init__(self, texture, glyph):
self.texture = texture
self.textureSize = (glyph.bitmap.width, glyph.bitmap.rows)
if isinstance(glyph, freetype.GlyphSlot):
self.bearing = (glyph.bitmap_left, glyph.bitmap_top)
self.advance = glyph.advance.x
elif isinstance(glyph, freetype.BitmapGlyph):
self.bearing = (glyph.left, glyph.top)
self.advance = None
else:
raise RuntimeError('unknown glyph type')
def _get_rendering_buffer(xpos, ypos, w, h, zfix=0.0):
return np.asarray([
xpos, ypos - h, zfix, 0.0, 1.0,
xpos, ypos, zfix, 0.0, 0.0,
xpos + w, ypos, zfix, 1.0, 0.0,
xpos, ypos - h, zfix, 0.0, 1.0,
xpos + w, ypos, zfix, 1.0, 0.0,
xpos + w, ypos - h, zfix, 1.0, 1.0
], np.float32)
VERTEX_SHADER = """
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
out vec2 TexCoords;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}
"""
FRAGMENT_SHADER = """
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
color = vec4(textColor, 1.0) * sampled;
}
"""
shaderProgram = None
Characters = dict()
VBO = None
VAO = None
def initliaze():
global VERTEXT_SHADER
global FRAGMENT_SHADER
global shaderProgram
global Characters
global VBO
global VAO
#compiling shaders
vertexshader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
#creating shaderProgram
shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
#get projection
#problem
shader_projection = glGetUniformLocation(shaderProgram, "projection")
projection = glm.ortho(0.0,640,0.0,640)
glUniformMatrix4fv(shader_projection, 1, GL_FALSE, glm.value_ptr(projection));
#disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
face = freetype.Face("Vera.ttf")
face.set_char_size( 48*64 )
#load first 128 characters of ASCII set
for i in range(0,128):
face.load_char(chr(i))
glyph = face.glyph
#generate texture
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
glyph.bitmap.width, glyph.bitmap.rows,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
glyph.bitmap.buffer)
#texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#now store character for later use
Characters[chr(i)] = CharacterSlot(texture,glyph)
glBindTexture(GL_TEXTURE_2D, 0);
#configure VAO/VBO for texture quads
VAO = glGenVertexArrays(1)
glBindVertexArray(VAO)
VBO = glGenBuffers(1);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, 6 * 4, None, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
def render_text(window,text,x,y,scale,color):
global shaderProgram
global Characters
global VBO
global VAO
face = freetype.Face("Vera.ttf")
face.set_char_size(48*64)
glUniform3f(glGetUniformLocation(shaderProgram, "textColor"),
color[0]/255,color[1]/255,color[2]/255)
glActiveTexture(GL_TEXTURE0);
for c in text:
ch = Characters[c]
w,h = ch.textureSize
w = w*scale
h = w*scale
vertices = _get_rendering_buffer(x,y,w,h)
#render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.texture);
#update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, len(vertices), vertices)
glBindBuffer(GL_ARRAY_BUFFER, 0);
#render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
#now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.advance+6)*scale;
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glfwSwapBuffers(window);
glfwPollEvents();
def main():
glfw.init()
window = glfw.create_window(640, 640,"EXAMPLE PROGRAM",None,None)
glfw.make_context_current(window)
initliaze()
while not glfw.window_should_close(window):
glfw.poll_events()
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
render_text(window,'hello',1,1,1,(100,100,100))
glfw.terminate()
if __name__ == '__main__':
main()
I'm facing trouble in two portion so far I can understand. The first problem in initliaze(), error raised for the following portion.
shader_projection = glGetUniformLocation(shaderProgram, "projection")
projection = glm.ortho(0.0,640,0.0,640)
glUniformMatrix4fv(shader_projection, 1, GL_FALSE, glm.value_ptr(projection));
I've commented out the above portion to ignore. The second problem is in render_text() function, error raised for the following portion.
glUniform3f(glGetUniformLocation(shaderProgram, "textColor"),
color[0]/255,color[1]/255,color[2]/255)
There could be problems in many more places. I don't understand that why text rendering will be so difficult. What am I missing here?
You missed to install the shader program by glUseProgram:
shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
glUseProgram(shaderProgram) # <---
The 2nd argument to glBufferData and the 3rd argument of glBufferSubData is the size in bytes:
glBufferData(GL_ARRAY_BUFFER, 6 * 4, None, GL_DYNAMIC_DRAW)
glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 4, None, GL_DYNAMIC_DRAW)
glBufferSubData(GL_ARRAY_BUFFER, 0, len(vertices), vertices)
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.nbytes, vertices)
The vertex attribute consist of a 2 dimension vertex coordinate (x, y) and a 2 dimensional texture coordinate. Remove the wird zfix from the array of vertex attribute data. Furthermore you have to flip the 2nd component of the texture coordinates (otherwise the text is upside down)
def _get_rendering_buffer(xpos, ypos, w, h, zfix=0.0):
return np.asarray([
xpos, ypos - h, 0, 0,
xpos, ypos, 0, 1,
xpos + w, ypos, 1, 1,
xpos, ypos - h, 0, 0,
xpos + w, ypos, 1, 1,
xpos + w, ypos - h, 1, 0
], np.float32)
The stride argument of glVertexAttribIPointer has to be specified in bytes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. Hence in your case stride has to be 16 or 0:
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4, 0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
face.load_char(chr(i)) generates a image with on color channel (1 byte per pixel). Use the internal format and format GL_RED rather than GL_RGB for generating the 2 dimensional texture image:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, glyph.bitmap.width, glyph.bitmap.rows, 0,
GL_RED, GL_UNSIGNED_BYTE, glyph.bitmap.buffer)
You have to bind the vertex array, before drawing the text:
glBindVertexArray(VAO)
for c in text:
# [...]
glDrawArrays(GL_TRIANGLES, 0, 6)
There is typo when you increment x, you have to use the >>-operator rather than the +-operator:
x += (ch.advance+6)*scale
x += (ch.advance>>6)*scale
and another typo when you compute h:
h = w*scale
h = h*scale
You have to enable alpha blending:
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
In NDC (normalized device coordinates) the left bottom is (-1, -1) and the right top is (1, 1). Set the orthographic projection in that way, that the top left of the window is at (0, 0):
projection = glm.ortho(0.0,640,0.0,640)
projection = glm.ortho(0, 640, 640, 0)
The reference point of the text is at the bottom. Hence you have to set a x coordinate greater than the text height:
render_text(window,'hello',1,1,1,(100,100,100))
render_text(window,'hello', 20, 50, 1, (255, 100, 100))
See the complete example (I've used a different font):
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL import shaders
import glfw
import freetype
import glm
import numpy as np
from PIL import Image
import math
import time
fontfile = "Vera.ttf"
#fontfile = r'C:\source\resource\fonts\gnu-freefont_freesans\freesans.ttf'
class CharacterSlot:
def __init__(self, texture, glyph):
self.texture = texture
self.textureSize = (glyph.bitmap.width, glyph.bitmap.rows)
if isinstance(glyph, freetype.GlyphSlot):
self.bearing = (glyph.bitmap_left, glyph.bitmap_top)
self.advance = glyph.advance.x
elif isinstance(glyph, freetype.BitmapGlyph):
self.bearing = (glyph.left, glyph.top)
self.advance = None
else:
raise RuntimeError('unknown glyph type')
def _get_rendering_buffer(xpos, ypos, w, h, zfix=0.0):
return np.asarray([
xpos, ypos - h, 0, 0,
xpos, ypos, 0, 1,
xpos + w, ypos, 1, 1,
xpos, ypos - h, 0, 0,
xpos + w, ypos, 1, 1,
xpos + w, ypos - h, 1, 0
], np.float32)
VERTEX_SHADER = """
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
out vec2 TexCoords;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}
"""
FRAGMENT_SHADER = """
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
color = vec4(textColor, 1.0) * sampled;
}
"""
shaderProgram = None
Characters = dict()
VBO = None
VAO = None
def initliaze():
global VERTEXT_SHADER
global FRAGMENT_SHADER
global shaderProgram
global Characters
global VBO
global VAO
#compiling shaders
vertexshader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
#creating shaderProgram
shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
glUseProgram(shaderProgram)
#get projection
#problem
shader_projection = glGetUniformLocation(shaderProgram, "projection")
projection = glm.ortho(0, 640, 640, 0)
glUniformMatrix4fv(shader_projection, 1, GL_FALSE, glm.value_ptr(projection))
#disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
face = freetype.Face(fontfile)
face.set_char_size( 48*64 )
#load first 128 characters of ASCII set
for i in range(0,128):
face.load_char(chr(i))
glyph = face.glyph
#generate texture
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, glyph.bitmap.width, glyph.bitmap.rows, 0,
GL_RED, GL_UNSIGNED_BYTE, glyph.bitmap.buffer)
#texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
#now store character for later use
Characters[chr(i)] = CharacterSlot(texture,glyph)
glBindTexture(GL_TEXTURE_2D, 0)
#configure VAO/VBO for texture quads
VAO = glGenVertexArrays(1)
glBindVertexArray(VAO)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 4, None, GL_DYNAMIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
def render_text(window,text,x,y,scale,color):
global shaderProgram
global Characters
global VBO
global VAO
face = freetype.Face(fontfile)
face.set_char_size(48*64)
glUniform3f(glGetUniformLocation(shaderProgram, "textColor"),
color[0]/255,color[1]/255,color[2]/255)
glActiveTexture(GL_TEXTURE0)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glBindVertexArray(VAO)
for c in text:
ch = Characters[c]
w, h = ch.textureSize
w = w*scale
h = h*scale
vertices = _get_rendering_buffer(x,y,w,h)
#render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.texture)
#update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.nbytes, vertices)
glBindBuffer(GL_ARRAY_BUFFER, 0)
#render quad
glDrawArrays(GL_TRIANGLES, 0, 6)
#now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.advance>>6)*scale
glBindVertexArray(0)
glBindTexture(GL_TEXTURE_2D, 0)
glfw.swap_buffers(window)
glfw.poll_events()
def main():
glfw.init()
window = glfw.create_window(640, 640,"EXAMPLE PROGRAM",None,None)
glfw.make_context_current(window)
initliaze()
while not glfw.window_should_close(window):
glfw.poll_events()
glClearColor(0,0,0,1)
glClear(GL_COLOR_BUFFER_BIT)
render_text(window,'hello', 20, 50, 1, (255, 100, 100))
glfw.terminate()
if __name__ == '__main__':
main()
See also FreeType / OpenGL text rendering

How to add texture to a triangle?

I'm trying to add woody texture to the triangle. Code works fine for only triangle. But raises error while I try to add texture. I think the problem is in the GLSL or in creating EBO/VBO (not sure). The whole screen remains black.
Here is the whole code. What am I doing wrong here?
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL import shaders
import glfw
import numpy as np
from PIL import Image
VERTEX_SHADER = """
#version 330
layout (location = 0) in vec4 position;
in vec2 InTexCoords;
out vec2 OutTexCoords;
void main(){
gl_Position = position;
OutTexCoords = InTexCoords;
}
"""
FRAGMENT_SHADER = """
#version 330
out vec4 FragColor;
uniform vec4 triangleColor;
in vec2 OutTexCoords;
uniform sampler2D sampleTex;
void main() {
FragColor = texture(sampleTex,OutTexCoords);
}
"""
shaderProgram = None
def initialize():
global VERTEXT_SHADER
global FRAGMENT_SHADER
global shaderProgram
#compiling shaders
vertexshader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
#creating shaderProgram
shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
#vertex and indices data
#triangle #texture
vertices = [-0.5, -0.5, 0.0, 0.0,0.0,
0.5, -0.5, 0.0, 1.0,0.0,
0.0, 0.5, 0.0, 0.5,1.0]
indices = [0,1,2]
vertices = np.array(vertices, dtype=np.float32)
indices = np.array(vertices, dtype=np.float32)
#add vertices to buffer
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
#add indices to buffer
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
position = 0
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
glEnableVertexAttribArray(position)
texCoords = 1
glBindAttribLocation( shaderProgram, texCoords, 'InTexCoords')
glVertexAttribPointer(texCoords,2, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
glEnableVertexAttribArray(texCoords)
#creating texture
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
image = Image.open("wood.jpg")
img_data = np.array(list(image.getdata()), np.uint8)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
def render(window):
global shaderProgram
glClearColor(0, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUseProgram(shaderProgram)
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, None)
glUseProgram(0)
glfw.swap_buffers(window)
def main():
glfw.init()
window = glfw.create_window(640, 640,"EXAMPLE PROGRAM",None,None)
glfw.make_context_current(window)
initialize()
while not glfw.window_should_close(window):
glfw.poll_events()
render(window)
glfw.terminate()
if __name__ == '__main__':
main()
I was trying to follow this tutorial learnopengl. But the tutorial is in C++. Besides, I had slightly different approach. I'm not adding color codes in vertices. But I don't think it is the problem in the way of adding the texture.
The stride argument of glVertexAttribPointer specifies the byte offset between consecutive generic vertex attributes. Your attributes consist of vertex coordinates with 3 components and texture coordinates with 2 components. Hence your stride argument has to 20 (5 * 4 bytes) rather than 24:
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 20, ctypes.c_void_p(0))
glVertexAttribPointer(texCoords,2, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
glVertexAttribPointer(texCoords,2, GL_FLOAT, GL_FALSE, 20, ctypes.c_void_p(12))
The data type of the indices has to be integral. The type in the draw call (glDrawElements(..., ..., GL_UNSIGNED_INT, ...)) has to match this type. Use uint32 rather than float (and vertices -> indices):
indices = np.array(vertices, dtype=np.float32)
indices = np.array(indices, dtype=np.uint32)
Associating a generic vertex attribute index with a named attribute variable (glBindAttribLocation) has to be done, before the program is linked (before glLinkProgram).
I recommend to set the attribute index by a Layout Qualifier:
layout (location = 0) in vec4 position;
layout (location = 1) in vec2 InTexCoords;

Mapping a texture onto a quad with OpenGL 4, Python, and vertex shaders

I'm trying to create a program with modern OpenGL code that displays a QUAD with a texture mapped onto it.
The texture should be stretched to match the quad size. Right now the texture repeats.
I've seen code that maps the texture to the quad if the each vertex and mapping is done individually in the code. However, I think now we are supposed to use vertex shaders? With OpenGL 4.5 or whatever, how is this supposed to be done?
"""
Open a window that displays a quad with an image on it.
"""
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
from math import *
from time import *
class MyApplication:
""" Main application class. """
def __init__(self):
self.vao = 0
def load_texture(self, file_name):
image = Image.open(file_name)
width = image.size[0]
height = image.size[1]
image_bytes = image.convert("RGBA").tobytes ( "raw", "RGBA", 0, -1)
texture = glGenTextures(1)
glBindTexture ( GL_TEXTURE_2D, texture )
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT )
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT )
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR )
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR )
gluBuild2DMipmaps ( GL_TEXTURE_2D, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image_bytes )
return texture
def compile_shaders(self):
""" Get the shaders ready. """
# Create a triangle with three (x, y, z, ?) points.
vertex_shader_source = """
#version 450 core
void main( void)
{
// Declare a hard-coded array of positions
const vec4 vertices[4] = vec4[4](vec4(-0.5, 0.5, 0.5, 1.0),
vec4( 0.5, 0.5, 0.5, 1.0),
vec4( 0.5, -0.5, 0.5, 1.0),
vec4(-0.5, -0.5, 0.5, 1.0));
// Index into our array using gl_VertexID
gl_Position = vertices[gl_VertexID];
}
"""
vertex_shader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertex_shader, vertex_shader_source)
glCompileShader(vertex_shader)
# Specify the color of our fragment (RGBA)
texture = self.load_texture("test_ship.png")
fragment_shader_source = """
#version 450 core
uniform sampler2D s;
out vec4 color;
void main(void)
{
color = texture(s, gl_FragCoord.xy / textureSize(s, 0));
}
"""
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragment_shader, fragment_shader_source)
glCompileShader(fragment_shader)
# --- Create a program
program = glCreateProgram()
glAttachShader(program, vertex_shader)
glAttachShader(program, fragment_shader)
glLinkProgram(program)
glGenVertexArrays(1, self.vao)
glBindVertexArray(self.vao)
# --- Clean up now that we don't need these shaders anymore.
glDeleteShader(vertex_shader)
glDeleteShader(fragment_shader)
return program
def startup(self):
self.rendering_program = self.compile_shaders()
self.vertex_array_object = GLuint()
glCreateVertexArrays(1, self.vertex_array_object)
def render(self):
# Support transparency
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
# Get a color based on the time
color = (sin(time()), cos(time()), 0)
# Clear the screen
glClearBufferfv(GL_COLOR, 0, color)
# Tell the computer what to render
glUseProgram(self.rendering_program)
glDrawArrays(GL_QUADS, 0, 4)
# Display
glutSwapBuffers()
def animate(self):
glutPostRedisplay()
def run(self):
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(500, 500)
glutInitWindowPosition(0, 0)
glutCreateWindow(b"Simple PyOpenGL example")
self.startup()
glutIdleFunc(self.animate)
glutDisplayFunc(self.render)
glutMainLoop()
my_application = MyApplication()
my_application.run()
I believe there are two problems here:
1) If you see a repeating pattern, given your current WRAP_S and WRAP_T settings, you can assume that your UV coordinates are wrong.
In your fragment shader, you get the UV coordinate using the following calculation:
color = texture(s, gl_FragCoord.xy / textureSize(s, 0));
However, looking at your quad coordinates, this is not going to map to a [0,1] interval, as required for texture coordinates. (if it goes below or beyond this interval, you will get a modulo of the value).
2) If you don't want it to repeat, use the following:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)

Categories