this is original 2d 256x256 image i am trying to texture on screen. but for some reason it does not rendering without glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) line ever. And when its rendering since pic is 2d i send attrib pointer uv is size of 2 with glVertexAttribPointer(attribute_texture, 2, GL_FLOAT, GL_FALSE, 0, None)
but its turns out this.
when i turn it to 3 just for trying sake its like this
what eer i try it did not change any better
what am i doing wrong here? i realy could use another pair of eyes. thank you.
And this is my code:
import glfw
from OpenGL.GL import *
# from OpenGL.GL.shaders import compileShader, compileProgram
import numpy as np
from math import radians
from pyrr import matrix44, Vector3
from PIL import Image
# ----------------------------------------------------------------------
if not glfw.init():
raise Exception("GLFW not initialized")
window = glfw.create_window(800, 600, "personal", None, None)
if not window:
glfw.terminate()
raise Exception("window did not created")
glfw.set_window_pos(window, xpos=200, ypos=50)
glfw.make_context_current(window)
# ----------------------------------------------------------------------
vertices = np.array([-0.7, 0.7, 0.0,
-0.7, -0.7, 0.0,
0.7, -0.7, 0.0,
0.7, 0.7, 0.0], dtype=np.float32)
indices = np.array([0, 1, 3,
3, 1, 2], dtype=np.uint32)
# color = np.array([0.0, 0.0, 0.0,
# 0.0, 0.0, 0.0,
# 0.0, 0.0, 0.0,
# 0.0, 0.0, 0.0], dtype=np.float32)
texture_coord = np.array([0, 0,
0, 1,
1, 1,
1, 0], dtype=np.uint32)
# --------------------------------------------------------------------- TRANSFORMATION CALCULATION
matrix = matrix44.create_identity(dtype=np.float32)
matrix = np.dot(matrix44.create_from_translation(Vector3([0.0, 0.0, 0.0])), matrix)
matrix = np.dot(matrix44.create_from_x_rotation(radians(0)), matrix)
matrix = np.dot(matrix44.create_from_y_rotation(radians(0)), matrix)
matrix = np.dot(matrix44.create_from_z_rotation(radians(0)), matrix)
matrix = np.dot(matrix44.create_from_scale(Vector3([1, 1, 1])), matrix)
# ---------------------------------------------------------------------
vertex_shader_src = """
#version 330 core
layout(location = 0)in vec3 position;
layout(location = 1)in vec2 texture;
//in vec3 color;//for using color equal it to toFColor
uniform mat4 trans;
out vec3 toFColor;
out vec2 passTexCoord;
void main(){
gl_Position = trans * vec4(position.x,position.y,position.z,1.0f);
//toFColor=color;
passTexCoord=texture;
}
"""
# ---------------------------------------------------------------------
fragment_shader_src = """
#version 330 core
//in vec3 toFColor;
in vec2 passTexCoord;
//uniform vec3 triColor;
uniform sampler2D texture_sampler;
out vec4 outColor;
void main(){
//outColor = vec4(toFColor,1.0);
outColor = texture(texture_sampler, passTexCoord);
}
"""
# ---------------------------------------------------------------------PyOpenGL working shader program
# shader_program = compileProgram(compileShader(vertex_shader_src, GL_VERTEX_SHADER),
# compileShader(fragment_shader_src, GL_FRAGMENT_SHADER))
# ---------------------------------------------------------------------tutorial way shader program
vertex_shader_id = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertex_shader_id, vertex_shader_src)
glCompileShader(vertex_shader_id)
if glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS) == GL_FALSE:
print(glGetShaderInfoLog(vertex_shader_id))
print("cant compile shader")
fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragment_shader_id, fragment_shader_src)
glCompileShader(fragment_shader_id)
if glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS) == GL_FALSE:
print(glGetShaderInfoLog(fragment_shader_id))
print("cant compile shader")
shader_program = glCreateProgram()
glAttachShader(shader_program, vertex_shader_id)
glAttachShader(shader_program, fragment_shader_id)
glBindAttribLocation(shader_program, 0, "position")
glBindAttribLocation(shader_program, 1, "texture")
glLinkProgram(shader_program)
glValidateProgram(shader_program)
glUseProgram(shader_program)
# --------------------------------------------------------------------- my trying for VAO vertex positions
VAO = glGenVertexArrays(1) # generate vao
glBindVertexArray(VAO) # ready VAO to use
VBO1 = glGenBuffers(1) # generate vbo
glBindBuffer(GL_ARRAY_BUFFER, VBO1) # binding vbo for use
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW) # setting VBO what to carry
attribute_position = glGetAttribLocation(shader_program, "position") # taking attribute name position from shader
glEnableVertexAttribArray(attribute_position) # ready to use attribute
glVertexAttribPointer(attribute_position, 3, GL_FLOAT, GL_FALSE, 0,
None) # telling OpenGL how to read data on given uniform
# ---------------------------------------------------------------------- indexing positions
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
# ---------------------------------------------------------------------- coloring instead of texture
# i am closing this because i will use texture
# VBO2 = glGenBuffers(1)
# glBindBuffer(GL_ARRAY_BUFFER, VBO2)
# glBufferData(GL_ARRAY_BUFFER, color.nbytes, color, GL_STATIC_DRAW)
# attribute_color = glGetAttribLocation(shader_program, "color") # taking uniform name color from shader
# glEnableVertexAttribArray(attribute_color) # ready to use uniform
# glVertexAttribPointer(attribute_color, 3, GL_FLOAT, GL_FALSE, 0,
# None) # telling OpenGL how to read data on given attribute
# ---------------------------------------------------------------------- Texture pressing
TEX_BO = glGenTextures(1)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, TEX_BO)
attribute_texture = glGetAttribLocation(shader_program, "texture")
glEnableVertexAttribArray(attribute_texture)
glVertexAttribPointer(attribute_texture, 3, GL_FLOAT, GL_FALSE, 0, None)
texture = Image.open("../res/pic1.png", "r")
texture = texture.transpose(Image.FLIP_TOP_BOTTOM)
image_data = texture.convert("RGBA").tobytes()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data)
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)
# ---------------------------------------------------------------------- TRANSFORMATION MATRIX -------------------------
loc_uniform_transformation = glGetUniformLocation(shader_program, "trans")
# ----------------------------------------------------------------------
while not glfw.window_should_close(window):
glfw.poll_events()
glClearColor(0.15, 0.15, 0.15, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glUniformMatrix4fv(loc_uniform_transformation, 1, GL_FALSE, matrix44.create_identity())
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
glfw.swap_buffers(window)
# ------------------------------------------------------------------------------ Cleaning
glDeleteTextures(1, int(TEX_BO))
glDetachShader(shader_program, vertex_shader_id)
glDetachShader(shader_program, fragment_shader_id)
glDeleteShader(vertex_shader_id)
glDeleteShader(fragment_shader_id)
glDeleteProgram(shader_program)
glDeleteBuffers(1, int(VBO1))
# glDeleteBuffers(1, int(VBO2)) # if use colors
glDeleteBuffers(1, int(EBO))
glDeleteVertexArrays(1, int(VAO))
# ------------------------------------------------------------------------------
glfw.destroy_window(window)
glfw.terminate()
You have to set glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) because the default minifying function is GL_NEAREST_MIPMAP_LINEAR. Since you do not generate mipmaps the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST or GL_LINEAR.
The type of the array of texture coordinates must be np.float32 rather than np.uint32:
texture_coord = np.array([0, 0,
0, 1,
1, 1,
1, 0], dtype=np.float32)
You missed to create the buffer object for the texture coordinates:
VBO2 = glGenBuffers(1) # generate vbo
glBindBuffer(GL_ARRAY_BUFFER, VBO2) # binding vbo for use
glBufferData(GL_ARRAY_BUFFER, texture_coord.nbytes, texture_coord, GL_STATIC_DRAW)
attribute_texture = glGetAttribLocation(shader_program, "texture")
glEnableVertexAttribArray(attribute_texture)
glVertexAttribPointer(attribute_texture, 2, GL_FLOAT, GL_FALSE, 0, None)
When glVertexAttribPointer is called, the buffer object currently bound to the target GL_ARRAY_BUFFER is associated to the specified vertex attribute.
Related
I have spent almost 2-3 hours trying to figure out why I am not getting a rectangle renderered. I am using pygame for making a window, and opengl for rendering onto the window.
what should be happening is a red background with a blue rectangle, but what I am seeing is just the empty red background.
this is the code I used below.
am I uploading things to the shader wrong? or did I miss something.
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
print("import sucessfull")
vertex = """
#version 460 core
layout (location=0) in vec3 position;
out vec4 fColor;
void main(){
fColor = vec4(0,1,0,1);
gl_Position = vec4(position, 1.0);
}
"""
fragment = """
#version 460 core
in vec4 fColor;
out vec4 color;
void main(){
color = fColor;
//gl_FragColor = fColor;
}
"""
def main():
clock = pygame.time.Clock()
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 1000)
glClearColor(1, 0,0,1)
glTranslatef(0,0,-5)
#############################3
vertexID = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexID, vertex)
fragmentID = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentID, fragment)
glCompileShader(vertexID)
glCompileShader(fragmentID)
program = glCreateProgram()
glAttachShader(program, vertexID)
glAttachShader(program, fragmentID)
glLinkProgram(program)
positions = [
0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
-0.5, -0.5, 0.0
]
indexes = [
2,1,0,
0,1,3
]
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW)
ebo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, np.array(indexes, dtype=np.float32), GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, 0)
glEnableVertexAttribArray(0)
################################
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
#render here
glUseProgram(program)
glBindVertexArray(vao)
glEnableVertexAttribArray(0)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glDisableVertexAttribArray(0)
glBindVertexArray(0)
glUseProgram(0)
#***********
pygame.display.flip()
clock.tick(40)
main()
The type of the indices must be integral and correspond to the type specified in the draw call (GL_UNSIGNED_INT). You have to create a NumPy array with the type uint32 instead of float32:
glBufferData(GL_ELEMENT_ARRAY_BUFFER, np.array(indexes, dtype=np.float32), GL_STATIC_DRAW)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, np.array(indexes, dtype=np.uint32), GL_STATIC_DRAW)
If a named buffer object is bound, then the 6th parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store. But the type of the parameter is a pointer anyway (c_void_p).
So if the offset is 0, then the 6th parameter can either be None or c_void_p(0) else the offset has to be caste to c_void_p(0):
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, 0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, None)
There is a similar problem with glDrawElements. The last argument is treated as a byte offset:
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
gluPerspective and glTranslatef set the deprecated fixed function pipeline matrices. This instructions do not make any sense when you use "modern" shader program. Remove this instructions. With modern OpenGL you have to use Uniform variables.
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.
I am trying to draw some traingles and render some texts in screen. But I've observed that memory(RAM) is gradually increasing just only for 6 draw calls. I've 8 GB RAM. When I run the program memory usage goes from 4.2 to 6 within 1 minute. Here is the full code.
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL import shaders
from shader import *
import glfw
import freetype
import glm
import numpy as np
from PIL import Image
import math
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)
def init_chars(shaderProgram,window_height,window_width,font_size=24,fontfile = "Vera.ttf"):
glUseProgram(shaderProgram)
#get projection
shader_projection = glGetUniformLocation(shaderProgram, "projection")
W = window_width
H = window_height
projection = glm.ortho(-W/2, W/2, -H/2, H/2)
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(font_size*64 )
#load first 128 characters of ASCII set
Characters = dict()
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)
glUseProgram(0)
return Characters
def render_text(window,shaderProgram,text,x,y,scale,Characters,color=(170,250,255)):
r,g,b = color
glUseProgram(shaderProgram)
#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_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
glUniform3f(glGetUniformLocation(shaderProgram, "textColor"),r/255,g/255,b/255)
glActiveTexture(GL_TEXTURE0)
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
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0)
#UNBIND and DELETE VAO/VBO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDeleteBuffers(1, id(VBO))
glDeleteBuffers(1, id(VAO))
def triangle(shaderProgram,window,x=0,y=0):
vertices = [-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0]
vertices = np.array(vertices, dtype=np.float32)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(0)
#use shader program
glUseProgram(shaderProgram)
#accessing ourColor variable from shaderProgram
vertexColorLoc = glGetUniformLocation(shaderProgram, "ourColor")
glUniform4f(vertexColorLoc, 255, 28/255.0, 20/255.0, 0.7);
#transform matrix
transform = glm.mat4(1)
transform = glm.translate(transform,glm.vec3(x,y,0))
MVP = glGetUniformLocation(shaderProgram, "MVP")
glUniformMatrix4fv(MVP, 1, GL_FALSE, glm.value_ptr(transform))
#drawing trangle
glLineWidth(3)
glDrawArrays(GL_TRIANGLES, 0, 3)
glUseProgram(0)
#UNBIND and DELETE VAO/VBO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDeleteBuffers(1, id(VBO))
def main():
glfw.init()
window = glfw.create_window(640, 640,"EXAMPLE PROGRAM",None,None)
glfw.make_context_current(window)
#initliaze shader programs
shaderProgram = get_shaderProgram()
text_shaderProgram = get_text_shaderProgram()
#load characters and VAO/VBO for text rendering
Characters = init_chars(text_shaderProgram,640,640)
#window loop
while not glfw.window_should_close(window):
glfw.poll_events()
#screen
glClearColor(0, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
#draw functions
render_text(window,text_shaderProgram,"TRIANGLE",-50,-200,1,Characters)
render_text(window,text_shaderProgram,"A",0,180,1,Characters)
render_text(window,text_shaderProgram,"B",-160,-180,1,Characters)
render_text(window,text_shaderProgram,"C",150,-180,1,Characters)
triangle(shaderProgram,window)
triangle(shaderProgram,window,x=0.5,y=0.5)
#swap buffers
glfw.swap_buffers(window)
glfw.swap_interval(1)
glfw.terminate()
if __name__ == '__main__':
main()
The shader program is here. But I think the problems is in buffer object. I've tried to unbind VAO/VBO and delete buffers by following code. But I see no change.
#UNBIND and DELETE VAO/VBO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDeleteBuffers(1, id(VBO))
glDeleteBuffers(1, id(VAO))
Here is the related problem where accepted answer suggested that glGenBuffers causes memory leak. The alternate function glCreateBuffers is not available in pyopengl. How can I solve this issue?
I can't see any good reason for recreating the Vertex Array Object and Array Buffer Object every time when render_text respectively triangle is called. The vertex specification and the number of vertices doesn't change, so it would be sufficient to update the content of the buffer.
Create the Vertex Array Object and the Array Buffer Object once at initialization:
def init_buffers():
global text_VAO, text_VBO, triangle_VAO, triangle_VBO
text_VAO = glGenVertexArrays(1)
glBindVertexArray(text_VAO)
text_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, text_VBO)
glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 4, None, GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
vertices = [-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0]
vertices = np.array(vertices, dtype=np.float32)
triangle_VAO = glGenVertexArrays(1)
glBindVertexArray(triangle_VAO)
triangle_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, triangle_VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(0)
Use then in the functions render_text and triangle:
def render_text(window,shaderProgram,text,x,y,scale,Characters,color=(170,250,255)):
# [...]
glBindVertexArray(text_VAO)
for c in text:
# [...]
glBindBuffer(GL_ARRAY_BUFFER, text_VBO)
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.nbytes, vertices)
# glDeleteBuffers(1, id(VBO)) <--- DELETE
# glDeleteBuffers(1, id(VAO)) <--- DELETE
def triangle(shaderProgram,window,x=0,y=0):
glBindVertexArray(triangle_VAO)
# [...]
# glDeleteBuffers(1, id(VBO)) <--- DELETE
Invoke init_buffers before the application loop:
def main():
# [...]
init_buffers()
while not glfw.window_should_close(window):
# [...]
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;
I got an error on glVertexAttribPointer maybe it because the value or anything (?)
does anyone know how to fix this?
import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy as np
from PIL import Image
def main():
if not glfw.init():
return
window = glfw.create_window(720, 720, "08_A_xxx: PyOpengl dan tekstur", None, None)
if not window:
glfw.terminate()
return
glfw.make_context_current(window)
#posisi warna koordinat tekstur
rectangle = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
-0.5, 0.5, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0]
# ubah ke 32 bit (float)
rectangle = np.array(rectangle, dtype=np.float32)
indices = [0,1,2,
2,3,0]
indices = np.array(indices, dtype = np.uint32)
VERTEX_SHADER = """
#version 330
in vec3 position;
in vec3 color;
in vec2 InTexCoords;
out vec3 newColor;
out vec2 OutTexCoords;
void main() {
gl_Position = vec4(position, 1.0);
newColor = color;
OutTexCoords = InTexCoords;
}
"""
FRAGMENT_SHADER = """
#version 330
in vec3 newColor;
in vec2 OutTexCoords;
out vec4 outColor;
uniform sampler2D samplerTex;
void main() {
outColor = texture(samplerTex, OutTexCoords);
}
"""
# Kompilasi program dan shaders
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER),
OpenGL.GL.shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER))
# Buat objek buffer dalam gpu
VBO = glGenBuffers(1)
# Bind the buffer
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, 128, rectangle, GL_STATIC_DRAW)
# Buat EBO
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
# mendapatkan posisi dari shader
position = glGetAttribLocation(shader, 'position')
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(0))
glEnableVertexAttribArray(position)
# mendapatkan warna dari shader
color = glGetAttribLocation(shader, 'color')
glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(12))
glEnableVertexAttribArray(color)
texCoords = glGetAttribLocation(shader, "InTexCoords")
glVertexAttribPointer(texCoords,2, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(24))
glEnableVertexAttribArray(texCoords)
# Buat Tekstur
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
# texture wrapping params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# texture filtering params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
image = Image.open("hello.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)
glUseProgram(shader)
glClearColor(0.0, 0.0, 0.0, 1.0)
while not glfw.window_should_close(window):
glfw.poll_events()
glClear(GL_COLOR_BUFFER_BIT)
# Gambar segiempat
glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_INT, None)
glfw.swap_buffers(window)
glfw.terminate()
if __name__ == "__main__":
main()
The attribute color is not an active program resource, because the attribute is not "used" in the shader program. The attribute is passed from the vertex to the fragment shader, but the fragment shader ignores the input variable newColor. The optimization algorithm sorts out the attribute color.
Hence glGetAttribLocation returns -1 and finally glVertexAttribPointer fails.
It is not necessary to specify the array of vertex attribute data for the attribute color, because it is not needed at all.
Evaluate if glGetAttribLocation returns a value greater or equal 0, to solve the issue:
color = glGetAttribLocation(shader, 'color')
if color >= 0:
glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 32, ctypes.c_void_p(12))
glEnableVertexAttribArray(color)