I want to impement a pyramid which has different texture in each side.
The pyramid with the textures is correct without using an index data array. When i use the indexdata the textures get mixed with each other. Do i have to correct the AttribPointer? (My texture is a collage image of 5 different images)
*I want to keep the indexData array
Here is a part of the code
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import numpy as np
from framework import *
from PIL import Image
from math import tan, cos, sin
# A 1-D array of 3 4-D vertices (X,Y,Z,W)
# Note that this must be a numpy array, since as of
# 170111 support for lists has not been implemented.
vertexData = np.array(
[ 0.0, 0.5, -1.3, 1.0, #0
0.3, 0.0, -1.0, 1.0, #1
-0.3, 0.0, -1.0, 1.0, #2
-0.3, 0.0, -1.6, 1.0, #3
0.3, 0.0, -1.6, 1.0, #4
0.0, 0.0, -1.3, 1.0, #5
#texture
0.8, 0.0,
1.0, 0.0,
0.8, 0.4,
0.0, 0.3,
0.3, 0.3,
0.3, 0.0,
0.5, 1.0,
0.5, 0.5,
0.6, 1.0,
0.1, 1.0,
0.4, 1.0,
0.0, 0.4,
0.0, 0.0,
0.0, 0.3,
0.3, 0.0,
0.0, 0.0,
0.0, 0.3,
0.3, 0.0,
0.0, 0.0,
0.0, 0.3, #leukos toixos
0.3, 0.0,
0.0, 0.0,
0.0, 0.3,
0.3, 0.0,
],
dtype='float32'
)
indexData = np.array(
[0,1,2,
0,2,3,
0,3,4,
0,4,1,
5,2,1,
5,1,4,
5,4,3,
5,3,2],)
vertexDim = 4
texcoordDim = 2
nVertices = 8*3
# Global variable to represent the compiled shader program, written in GLSL
theProgram = None
# Global variable to represent the buffer that will hold the position vectors
vertexBufferObject = None
sampleTexture = None
texUnitUniform = None
# Global variables to store the location of the shader's uniform variables
perspectiveMatrixUnif = None
WorldtoCameraMatrixUnif = None
# Global display variables
perspectiveMatrix = None
CameraMatrix = None
fFrustumScale = 1.0
def loadTexture(path):
img = Image.open(path).transpose(Image.FLIP_TOP_BOTTOM) #anoigoume tin eikona
#img.show()
img_data = np.frombuffer(img.tobytes(), np.uint8)
width, height = img.size
# glTexImage2D expects the first element of the image data to be the
# bottom-left corner of the image. Subsequent elements go left to right,
# with subsequent lines going from bottom to top.
# However, the image data was created with PIL Image tostring and numpy's
# fromstring, which means we have to do a bit of reorganization. The first
# element in the data output by tostring() will be the top-left corner of
# the image, with following values going left-to-right and lines going
# top-to-bottom. So, we need to flip the vertical coordinate (y).
texture = glGenTextures(1)
#glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glBindTexture(GL_TEXTURE_2D, texture)#ginetai sundesi me to antikeimeno pou ftiaxtike
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)#parametroi gia tin ufi
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)#gia na exw digrammiko filtrarisma
#glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
#glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)#sundesi twn dedomenwn
#glGenerateMipmap(GL_TEXTURE_2D)
return texture
# Set up the list of shaders, and call functions to compile them
def initializeProgram():
shaderList = []
shaderList.append(loadShader(GL_VERTEX_SHADER, "Texture.vert"))
shaderList.append(loadShader(GL_FRAGMENT_SHADER, "Texture.frag"))
global theProgram
theProgram = createProgram(shaderList)
for shader in shaderList:
glDeleteShader(shader)
global perspectiveMatrixUnif
perspectiveMatrixUnif = glGetUniformLocation(theProgram, "perspectiveMatrix")
global WorldtoCameraMatrixUnif
WorldtoCameraMatrixUnif = glGetUniformLocation(theProgram, "cameraMatrix")
global sampleTexture
global texUnitUniform
sampleTexture = loadTexture('pic.jpg') #i eikona
texUnitUniform = glGetUniformLocation(theProgram, "texUnit")#gia na vrethei apo ton fragment shader
fzNear = 0.5
fzFar = 3.0
global CameraMatrix
CameraPos=np.array([0.8, 0.8, -1.0])
CameraTarget=np.array([1.0, 1.0, 0.0])
CameraUp=np.array([-1.0, 1.0, 0.0])
CameraTarget=CameraTarget/np.linalg.norm(CameraTarget)
CameraRight=np.cross(CameraUp, CameraTarget)
CameraRight=CameraRight/np.linalg.norm(CameraRight)
CameraUp=np.cross(CameraTarget, CameraRight)
CameraRotMatrix=np.vstack((CameraRight, CameraUp, CameraTarget,[0.0, 0.0, 0.0]))
CameraRotMatrix=np.hstack((CameraRotMatrix, [[0.0], [0.0], [0.0], [1.0]]))
CameraTranMatrix=np.eye(4)
CameraTranMatrix[0][3]=-CameraPos[0]
CameraTranMatrix[1][3]=-CameraPos[1]
CameraTranMatrix[2][3]=-CameraPos[2]
CameraMatrix=np.matmul(CameraRotMatrix,CameraTranMatrix)
global perspectiveMatrix
perspectiveMatrix = np.zeros(16, dtype='float32')
perspectiveMatrix[0] = fFrustumScale
perspectiveMatrix[5] = fFrustumScale
perspectiveMatrix[10] = (fzFar + fzNear) / (fzNear - fzFar)
perspectiveMatrix[14] = (2 * fzFar * fzNear) / (fzNear - fzFar)
perspectiveMatrix[11] = -1.0
glUseProgram(theProgram)
glActiveTexture(GL_TEXTURE0)#energi tin monada ufis pou me endiaferei
glBindTexture(GL_TEXTURE_2D, sampleTexture)#sundesi tis ufis me ton stoxo
glUniform1i(texUnitUniform, 0)#sundesi tis metavlitis me tin monada 0
glUniformMatrix4fv(perspectiveMatrixUnif, 1, GL_FALSE, perspectiveMatrix)
glUniformMatrix4fv(WorldtoCameraMatrixUnif, 1, GL_TRUE, CameraMatrix)
glUseProgram(0)
# Set up the vertex buffer that will store our vertex coordinates for OpenGL's access
def initializeVertexBuffer():
global vertexBufferObject
vertexBufferObject = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject)
glBufferData( # PyOpenGL allows for the omission of the size parameter
GL_ARRAY_BUFFER,
vertexData,
GL_STREAM_DRAW
)
glBindBuffer(GL_ARRAY_BUFFER, 0)
indexBufferObject = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject)
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
indexData,
GL_STATIC_DRAW
)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
def computeAngleRad(fElapsedTime, fLoopDuration):
fScale = 3.14159 * 2.0 / fLoopDuration
fCurrTimeThroughLoop = fElapsedTime % fLoopDuration
return fCurrTimeThroughLoop * fScale
def rotateZ(fElapsedTime):
fAngRad = computeAngleRad(fElapsedTime, 4.0)
fCos = cos(fAngRad)
fSin = sin(fAngRad)
# Initialize the OpenGL environment
def init():
initializeProgram()
initializeVertexBuffer()
glBindVertexArray(glGenVertexArrays(1))
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glFrontFace(GL_CW)
glEnable(GL_DEPTH_TEST)
# Called to update the display.
# Because we are using double-buffering, glutSwapBuffers is called at the end
# to write the rendered buffer to the display.
def display():
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUseProgram(theProgram)
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject)
glEnableVertexAttribArray(0)
glEnableVertexAttribArray(1)
glVertexAttribPointer(0, vertexDim, GL_FLOAT, GL_FALSE, 0, None)
# a ctype void pointer must be used to pass in the offset into the bound GL_ARRAY_BUFFER
# also note that python's underlying float type is usally 64-bit, but
# we have specified that our vertex array contains float32 data.
texcoordOffset = c_void_p(vertexDim*nVertices*4)
glVertexAttribPointer(1, texcoordDim, GL_FLOAT, GL_FALSE, 0, texcoordOffset)
fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 2000.0
AngRad = computeAngleRad(fElapsedTime, 2.0)
worldMatrix = np.identity(4, dtype='float32')
worldMatrix[0][0] = cos(AngRad)
worldMatrix[0][2] = sin(AngRad)
worldMatrix[2][0] = -sin(AngRad)
worldMatrix[2][2] = cos(AngRad)
matTrans1 = np.identity(4, dtype='float32')
matTrans1[2][3] = 1.3
matTrans2 = np.identity(4, dtype='float32')
matTrans2[2][3] = -1.3
newTransformA= np.matmul(worldMatrix,matTrans1)
newTransformB = np.matmul (matTrans2,newTransformA)
transformMatrix = newTransformB
glUniformMatrix4fv(WorldtoCameraMatrixUnif, 1, GL_FALSE, transformMatrix.transpose())
glDrawArrays(GL_TRIANGLES, 0, nVertices)
glDisableVertexAttribArray(0)
glDisableVertexAttribArray(1)
glUseProgram(0)
glutSwapBuffers()
glutPostRedisplay()
# keyboard input handler: exits the program if 'esc' is pressed
def keyboard(key, x, y):
if ord(key) == 27: # ord() is needed to get the keycode
glutLeaveMainLoop()
return
# Called whenever the window's size changes (including once when the program starts)
def reshape(w, h):
global perspectiveMatrix
perspectiveMatrix[0] = fFrustumScale / (w / float(h))
perspectiveMatrix[5] = fFrustumScale
glUseProgram(theProgram)
glUniformMatrix4fv(perspectiveMatrixUnif, 1, GL_FALSE, perspectiveMatrix)
glUseProgram(0)
glViewport(0, 0, w, h)
# The main function
def main():
glutInit()
displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL;
glutInitDisplayMode (displayMode)
width = 500;
height = 500;
glutInitWindowSize (width, height)
glutInitWindowPosition (300, 200)
window = glutCreateWindow(b"Tutorial Window")
init()
glutDisplayFunc(display)
glutReshapeFunc(reshape)
glutKeyboardFunc(keyboard)
glutMainLoop();
if __name__ == '__main__':
main()
About my project: I am working with OpenGL3.2 on Linux and I have built a basic application using GTK3 with a GLArea widget. The program is written in Python using the PyCharm IDE. The project interpreter is set to Python 3.8 and I have loaded up the following packages: Pillow 7.1.2, PyGObject 3.36.1, PyOpenGL 3.1.5, numpy 1.18, pyrr 0.10.3 and glfw 1.11.2
(see image at bottom)
My Problem:
I have a program that runs correctly using GLFW but will not run correctly using GTK3's GLArea. I am trying to render to a texture using a custom framebuffer object The GTK3 based program does not successfully render to the custom framebuffer. However, the GLFW based program renders just fine. There is no difference in the OpenGL code. I am only changing the windowing code. Is there something I need to enable with GTK3 in order to use custom framebuffers? The documentation for GTK3 (here) only indicates that special flags need to be set to enable the depth buffer and the stencil buffer (I have enabled both of these) but nothing related to custom texture buffers.
Any and all insights greatly appreciated.
Here is the problematic GTK3 GLArea program:
import sys
import gi, pyrr
import numpy
gi.require_version('Gtk', '3.0')
from pyrr import matrix44, Vector3
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram
from PIL import Image
class GLCanvas(Gtk.GLArea):
def __init__(self):
Gtk.GLArea.__init__(self)
self.set_required_version(3, 2) # Sets the version of OpenGL required by this OpenGL program
self.connect("realize", self.on_initialize) # This signal is used to initialize the OpenGL state
self.connect("render", self.on_render) # This signal is emitted for each frame that is rendered
self.add_tick_callback(self.tick) # This is a frame time clock that is called each time a frame is rendered
self.set_start_time = False # Boolean to track whether the clock has been initialized
self.set_has_depth_buffer(True)
self.set_has_stencil_buffer(True)
def tick(self, widget, frame_clock):
self.current_frame_time = frame_clock.get_frame_time() # Gets the current timestamp in microseconds
if self.set_start_time == False: # Initializes the timer at the start of the program
self.starting_time = self.current_frame_time # Stores the timestamp set when the program was initalized
self.set_start_time = True # Prevents the initialization routine from running again in this instance
self.application_clock = (self.current_frame_time - self.starting_time)/1000000 # Calculate the total number of seconds that the program has been running
return True # Returns true to indicate that tick callback should contine to be called
def on_initialize(self, gl_area):
# Prints information about our OpenGL Context
opengl_context = self.get_context() # Retrieves the Gdk.GLContext used by gl_area
opengl_context.make_current() # Makes the Gdk.GLContext current to the drawing surfaced used by Gtk.GLArea
major, minor = opengl_context.get_version() # Gets the version of OpenGL currently used by the opengl_context
print("\033[93m OpenGL context created successfully.\n -- Using OpenGL Version \033[94m" + str(major) + "." + str(minor) + "\033[0m")
# Checks to see if there were errors creating the context
if gl_area.get_error() != None:
print(gl_area.get_error())
# Get information about current GTK GLArea canvas
window = gl_area.get_allocation()
w_width, w_height = window.width, window.height
self.aspect_ratio = w_width / w_height
self.cube_positions = [(1.0, 1.0, 0.0), (0.0, 0.0, 0.0), (2.0, 0.0, 0.0)]
self.plane_position = matrix44.create_from_translation(Vector3([-3.0, 1.0, 0.0]))
cube = [-0.5, -0.5, 0.5, 0.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0,
-0.5, 0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, -0.5, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0,
0.5, 0.5, -0.5, 1.0, 1.0,
-0.5, 0.5, -0.5, 0.0, 1.0,
0.5, -0.5, -0.5, 0.0, 0.0,
0.5, 0.5, -0.5, 1.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0,
0.5, -0.5, 0.5, 0.0, 1.0,
-0.5, 0.5, -0.5, 0.0, 0.0,
-0.5, -0.5, -0.5, 1.0, 0.0,
-0.5, -0.5, 0.5, 1.0, 1.0,
-0.5, 0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, -0.5, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0,
0.5, -0.5, 0.5, 1.0, 1.0,
-0.5, -0.5, 0.5, 0.0, 1.0,
0.5, 0.5, -0.5, 0.0, 0.0,
-0.5, 0.5, -0.5, 1.0, 0.0,
-0.5, 0.5, 0.5, 1.0, 1.0,
0.5, 0.5, 0.5, 0.0, 1.0]
cube = numpy.array(cube, dtype=numpy.float32)
self.cube_indices = [0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20]
self.cube_indices = numpy.array(self.cube_indices, dtype=numpy.uint32)
plane = [-0.5, -0.5, 0.0, 0.0, 0.0,
2.0, -0.5, 0.0, 1.0, 0.0,
2.0, 1.0, 0.0, 1.0, 1.0,
-0.5, 1.0, 0.0, 0.0, 1.0]
plane = numpy.array(plane, dtype=numpy.float32)
self.plane_indices = [0, 1, 2, 2, 3, 0]
self.plane_indices = numpy.array(self.plane_indices, dtype=numpy.uint32)
vertex_shader = """
#version 330
in layout(location = 0) vec3 position;
in layout(location = 1) vec2 textCoords;
uniform mat4 vp;
uniform mat4 model;
out vec2 outText;
void main()
{
gl_Position = vp * model * vec4(position, 1.0f);
outText = textCoords;
}
"""
fragment_shader = """
#version 330
in vec2 outText;
out vec4 outColor;
uniform sampler2D renderedTexture;
void main()
{
outColor = texture(renderedTexture, outText);
}
"""
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))
# cube VAO
self.cube_vao = glGenVertexArrays(1)
glBindVertexArray(self.cube_vao)
cube_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO)
glBufferData(GL_ARRAY_BUFFER, cube.itemsize * len(cube), cube, GL_STATIC_DRAW)
cube_EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.cube_indices.itemsize * len(self.cube_indices), self.cube_indices, GL_STATIC_DRAW)
# position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# textures
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(12))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
# plane VAO
self.plane_vao = glGenVertexArrays(1)
glBindVertexArray(self.plane_vao)
plane_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, plane_VBO)
glBufferData(GL_ARRAY_BUFFER, plane.itemsize * len(plane), plane, GL_STATIC_DRAW)
plane_EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.plane_indices.itemsize * len(self.plane_indices), self.plane_indices,
GL_STATIC_DRAW)
# position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# textures
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(12))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
###########################################################################################
self.plane_texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.plane_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)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_width, w_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
glBindTexture(GL_TEXTURE_2D, 0)
depth_buff = glGenRenderbuffers(1)
glBindRenderbuffer(GL_RENDERBUFFER, depth_buff)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w_width, w_height)
self.FBO = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.plane_texture, 0)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buff)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
###########################################################################################
self.crate_texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.crate_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("models/crate.jpg")
img_data = numpy.array(list(image.getdata()), numpy.uint8)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
glBindTexture(GL_TEXTURE_2D, 0)
###########################################################################################
glEnable(GL_DEPTH_TEST)
view = matrix44.create_from_translation(Vector3([0.0, 0.0, -5.0]))
projection = matrix44.create_perspective_projection_matrix(45.0, self.aspect_ratio, 0.1, 100.0)
vp = matrix44.multiply(view, projection)
glUseProgram(shader)
vp_loc = glGetUniformLocation(shader, "vp")
self.model_loc = glGetUniformLocation(shader, "model")
glUniformMatrix4fv(vp_loc, 1, GL_FALSE, vp)
return True
def on_render(self, gl_area, gl_context):
glClearColor(0.2, 0.25, 0.27, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
rot_y = pyrr.Matrix44.from_y_rotation(self.application_clock * 2)
# draw to the default frame buffer
glBindVertexArray(self.cube_vao)
glBindTexture(GL_TEXTURE_2D, self.crate_texture)
for i in range(len(self.cube_positions)):
model = matrix44.create_from_translation(self.cube_positions[i])
if i == 0:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
elif i == 1:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
else:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)
# draw to the custom frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
for i in range(len(self.cube_positions)):
model = matrix44.create_from_translation(self.cube_positions[i])
if i == 0:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
elif i == 1:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
else:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)
glBindVertexArray(0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
# draw the plane
glBindVertexArray(self.plane_vao)
glBindTexture(GL_TEXTURE_2D, self.plane_texture)
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, self.plane_position)
glDrawElements(GL_TRIANGLES, len(self.plane_indices), GL_UNSIGNED_INT, None)
glBindVertexArray(0)
self.queue_draw() # Schedules a redraw for Gtk.GLArea
class RootWindow(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
def do_activate(self):
window = Gtk.Window(application=self)
window.set_title("Render To Texture")
window.set_default_size(1280, 720)
window.set_position(Gtk.WindowPosition.CENTER)
window.add(GLCanvas())
window.show_all()
win = RootWindow()
exit_status = win.run(sys.argv)
sys.exit(exit_status)
Here is the full working GLFW program (original source):
import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy
import pyrr
from pyrr import matrix44, Vector3
from PIL import Image
def window_resize(window, width, height):
glViewport(0, 0, width, height)
cube_positions = [(1.0, 1.0, 0.0), (0.0, 0.0, 0.0), (2.0, 0.0, 0.0)]
plane_position = matrix44.create_from_translation(Vector3([-3.0, 1.0, 0.0]))
def main():
if not glfw.init():
return
w_width, w_height = 1280, 720
aspect_ratio = w_width / w_height
window = glfw.create_window(w_width, w_height, "My OpenGL window", None, None)
if not window:
glfw.terminate()
return
glfw.make_context_current(window)
glfw.set_window_size_callback(window, window_resize)
cube = [-0.5, -0.5, 0.5, 0.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0,
-0.5, 0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, -0.5, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0,
0.5, 0.5, -0.5, 1.0, 1.0,
-0.5, 0.5, -0.5, 0.0, 1.0,
0.5, -0.5, -0.5, 0.0, 0.0,
0.5, 0.5, -0.5, 1.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0,
0.5, -0.5, 0.5, 0.0, 1.0,
-0.5, 0.5, -0.5, 0.0, 0.0,
-0.5, -0.5, -0.5, 1.0, 0.0,
-0.5, -0.5, 0.5, 1.0, 1.0,
-0.5, 0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, -0.5, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0,
0.5, -0.5, 0.5, 1.0, 1.0,
-0.5, -0.5, 0.5, 0.0, 1.0,
0.5, 0.5, -0.5, 0.0, 0.0,
-0.5, 0.5, -0.5, 1.0, 0.0,
-0.5, 0.5, 0.5, 1.0, 1.0,
0.5, 0.5, 0.5, 0.0, 1.0]
cube = numpy.array(cube, dtype=numpy.float32)
cube_indices = [ 0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20]
cube_indices = numpy.array(cube_indices, dtype=numpy.uint32)
plane = [-0.5, -0.5, 0.0, 0.0, 0.0,
2.0, -0.5, 0.0, 1.0, 0.0,
2.0, 1.0, 0.0, 1.0, 1.0,
-0.5, 1.0, 0.0, 0.0, 1.0]
plane = numpy.array(plane, dtype=numpy.float32)
plane_indices = [0, 1, 2, 2, 3, 0]
plane_indices = numpy.array(plane_indices, dtype=numpy.uint32)
vertex_shader = """
#version 330
in layout(location = 0) vec3 position;
in layout(location = 1) vec2 textCoords;
uniform mat4 vp;
uniform mat4 model;
out vec2 outText;
void main()
{
gl_Position = vp * model * vec4(position, 1.0f);
outText = textCoords;
}
"""
fragment_shader = """
#version 330
in vec2 outText;
out vec4 outColor;
uniform sampler2D renderedTexture;
void main()
{
outColor = texture(renderedTexture, outText);
}
"""
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))
# cube VAO
cube_vao = glGenVertexArrays(1)
glBindVertexArray(cube_vao)
cube_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO)
glBufferData(GL_ARRAY_BUFFER, cube.itemsize * len(cube), cube, GL_STATIC_DRAW)
cube_EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, cube_indices.itemsize * len(cube_indices), cube_indices, GL_STATIC_DRAW)
# position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# textures
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(12))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
# plane VAO
plane_vao = glGenVertexArrays(1)
glBindVertexArray(plane_vao)
plane_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, plane_VBO)
glBufferData(GL_ARRAY_BUFFER, plane.itemsize * len(plane), plane, GL_STATIC_DRAW)
plane_EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, plane_indices.itemsize * len(plane_indices), plane_indices, GL_STATIC_DRAW)
# position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# textures
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(12))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
###########################################################################################
plane_texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, plane_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)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_width, w_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
glBindTexture(GL_TEXTURE_2D, 0)
depth_buff = glGenRenderbuffers(1)
glBindRenderbuffer(GL_RENDERBUFFER, depth_buff)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w_width, w_height)
FBO = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, FBO)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, plane_texture, 0)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buff)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
###########################################################################################
crate_texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, crate_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("res/crate.jpg")
img_data = numpy.array(list(image.getdata()), numpy.uint8)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
glBindTexture(GL_TEXTURE_2D, 0)
###########################################################################################
glEnable(GL_DEPTH_TEST)
view = matrix44.create_from_translation(Vector3([0.0, 0.0, -5.0]))
projection = matrix44.create_perspective_projection_matrix(45.0, aspect_ratio, 0.1, 100.0)
vp = matrix44.multiply(view, projection)
glUseProgram(shader)
vp_loc = glGetUniformLocation(shader, "vp")
model_loc = glGetUniformLocation(shader, "model")
glUniformMatrix4fv(vp_loc, 1, GL_FALSE, vp)
while not glfw.window_should_close(window):
glfw.poll_events()
glClearColor(0.2, 0.25, 0.27, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
rot_y = pyrr.Matrix44.from_y_rotation(glfw.get_time() * 2)
# draw to the default frame buffer
glBindVertexArray(cube_vao)
glBindTexture(GL_TEXTURE_2D, crate_texture)
for i in range(len(cube_positions)):
model = matrix44.create_from_translation(cube_positions[i])
if i == 0:
glUniformMatrix4fv(model_loc, 1, GL_FALSE, rot_y * model)
elif i == 1:
glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)
else:
glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(cube_indices), GL_UNSIGNED_INT, None)
# draw to the custom frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, FBO)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
for i in range(len(cube_positions)):
model = matrix44.create_from_translation(cube_positions[i])
if i == 0:
glUniformMatrix4fv(model_loc, 1, GL_FALSE, rot_y * model)
elif i == 1:
glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)
else:
glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(cube_indices), GL_UNSIGNED_INT, None)
glBindVertexArray(0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
# draw the plane
glBindVertexArray(plane_vao)
glBindTexture(GL_TEXTURE_2D, plane_texture)
glUniformMatrix4fv(model_loc, 1, GL_FALSE, plane_position)
glDrawElements(GL_TRIANGLES, len(plane_indices), GL_UNSIGNED_INT, None)
glBindVertexArray(0)
glfw.swap_buffers(window)
glfw.terminate()
if __name__ == "__main__":
main()
Solution
It turns out that GLArea is not using framebuffer 0 as the default. The issue here is resetting the framebuffer back to 0 at the end of the rendering loop with glBindFramebuffer(GL_FRAMEBUFFER, 0). Instead, use default_ID = glGetIntegerv(GL_FRAMEBUFFER_BINDING) at the beginning of the rendering loop to get the current default ID. At the end of the loop, reset to the default framebuffer using glBindFramebuffer(GL_FRAMEBUFFER, default_ID).
import sys
import gi, pyrr
import numpy
gi.require_version('Gtk', '3.0')
from pyrr import matrix44, Vector3
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram
from PIL import Image
class GLCanvas(Gtk.GLArea):
def __init__(self):
Gtk.GLArea.__init__(self)
self.set_required_version(3, 2) # Sets the version of OpenGL required by this OpenGL program
self.connect("realize", self.on_initialize) # This signal is used to initialize the OpenGL state
self.connect("render", self.on_render) # This signal is emitted for each frame that is rendered
self.add_tick_callback(self.tick) # This is a frame time clock that is called each time a frame is rendered
self.set_start_time = False # Boolean to track whether the clock has been initialized
self.set_has_depth_buffer(True)
self.set_has_stencil_buffer(True)
def tick(self, widget, frame_clock):
self.current_frame_time = frame_clock.get_frame_time() # Gets the current timestamp in microseconds
if self.set_start_time == False: # Initializes the timer at the start of the program
self.starting_time = self.current_frame_time # Stores the timestamp set when the program was initalized
self.set_start_time = True # Prevents the initialization routine from running again in this instance
self.application_clock = (self.current_frame_time - self.starting_time)/1000000 # Calculate the total number of seconds that the program has been running
return True # Returns true to indicate that tick callback should contine to be called
def on_initialize(self, gl_area):
# Prints information about our OpenGL Context
opengl_context = self.get_context() # Retrieves the Gdk.GLContext used by gl_area
opengl_context.make_current() # Makes the Gdk.GLContext current to the drawing surfaced used by Gtk.GLArea
major, minor = opengl_context.get_version() # Gets the version of OpenGL currently used by the opengl_context
# https://stackoverflow.com/questions/287871/how-to-print-colored-text-in-terminal-in-python
print("\033[93m OpenGL context created successfully.\n -- Using OpenGL Version \033[94m" + str(major) + "." + str(minor) + "\033[0m")
# Checks to see if there were errors creating the context
if gl_area.get_error() != None:
print(gl_area.get_error())
# Get information about current GTK GLArea canvas
window = gl_area.get_allocation()
w_width, w_height = window.width, window.height
self.aspect_ratio = w_width / w_height
self.cube_positions = [(1.0, 1.0, 0.0), (0.0, 0.0, 0.0), (2.0, 0.0, 0.0)]
self.plane_position = matrix44.create_from_translation(Vector3([-3.0, 1.0, 0.0]))
cube = [-0.5, -0.5, 0.5, 0.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0,
-0.5, 0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, -0.5, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0,
0.5, 0.5, -0.5, 1.0, 1.0,
-0.5, 0.5, -0.5, 0.0, 1.0,
0.5, -0.5, -0.5, 0.0, 0.0,
0.5, 0.5, -0.5, 1.0, 0.0,
0.5, 0.5, 0.5, 1.0, 1.0,
0.5, -0.5, 0.5, 0.0, 1.0,
-0.5, 0.5, -0.5, 0.0, 0.0,
-0.5, -0.5, -0.5, 1.0, 0.0,
-0.5, -0.5, 0.5, 1.0, 1.0,
-0.5, 0.5, 0.5, 0.0, 1.0,
-0.5, -0.5, -0.5, 0.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0,
0.5, -0.5, 0.5, 1.0, 1.0,
-0.5, -0.5, 0.5, 0.0, 1.0,
0.5, 0.5, -0.5, 0.0, 0.0,
-0.5, 0.5, -0.5, 1.0, 0.0,
-0.5, 0.5, 0.5, 1.0, 1.0,
0.5, 0.5, 0.5, 0.0, 1.0]
cube = numpy.array(cube, dtype=numpy.float32)
self.cube_indices = [0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20]
self.cube_indices = numpy.array(self.cube_indices, dtype=numpy.uint32)
plane = [-0.5, -0.5, 0.0, 0.0, 0.0,
2.0, -0.5, 0.0, 1.0, 0.0,
2.0, 1.0, 0.0, 1.0, 1.0,
-0.5, 1.0, 0.0, 0.0, 1.0]
plane = numpy.array(plane, dtype=numpy.float32)
self.plane_indices = [0, 1, 2, 2, 3, 0]
self.plane_indices = numpy.array(self.plane_indices, dtype=numpy.uint32)
vertex_shader = """
#version 330
in vec3 position;
in vec2 textCoords;
uniform mat4 vp;
uniform mat4 model;
out vec2 outText;
void main()
{
gl_Position = vp * model * vec4(position, 1.0f);
outText = textCoords;
}
"""
fragment_shader = """
#version 330
in vec2 outText;
out vec4 outColor;
uniform sampler2D renderedTexture;
void main()
{
outColor = texture(renderedTexture, outText);
}
"""
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))
# cube VAO
self.cube_vao = glGenVertexArrays(1)
glBindVertexArray(self.cube_vao)
cube_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO)
glBufferData(GL_ARRAY_BUFFER, cube.itemsize * len(cube), cube, GL_STATIC_DRAW)
cube_EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.cube_indices.itemsize * len(self.cube_indices), self.cube_indices, GL_STATIC_DRAW)
# position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# textures
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(12))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
# plane VAO
self.plane_vao = glGenVertexArrays(1)
glBindVertexArray(self.plane_vao)
plane_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, plane_VBO)
glBufferData(GL_ARRAY_BUFFER, plane.itemsize * len(plane), plane, GL_STATIC_DRAW)
plane_EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.plane_indices.itemsize * len(self.plane_indices), self.plane_indices,
GL_STATIC_DRAW)
# position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
# textures
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(12))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
###########################################################################################
self.plane_texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.plane_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)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_width, w_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
glBindTexture(GL_TEXTURE_2D, 0)
depth_buff = glGenRenderbuffers(1)
glBindRenderbuffer(GL_RENDERBUFFER, depth_buff)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w_width, w_height)
self.FBO = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.plane_texture, 0)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buff)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
###########################################################################################
self.crate_texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.crate_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("models/crate.jpg")
img_data = numpy.array(list(image.getdata()), numpy.uint8)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
glBindTexture(GL_TEXTURE_2D, 0)
###########################################################################################
glEnable(GL_DEPTH_TEST)
view = matrix44.create_from_translation(Vector3([0.0, 0.0, -5.0]))
projection = matrix44.create_perspective_projection_matrix(45.0, self.aspect_ratio, 0.1, 100.0)
vp = matrix44.multiply(view, projection)
glUseProgram(shader)
vp_loc = glGetUniformLocation(shader, "vp")
self.model_loc = glGetUniformLocation(shader, "model")
glUniformMatrix4fv(vp_loc, 1, GL_FALSE, vp)
return True
def on_render(self, gl_area, gl_context):
default_ID = glGetIntegerv(GL_FRAMEBUFFER_BINDING)
glClearColor(0.2, 0.25, 0.27, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
rot_y = pyrr.Matrix44.from_y_rotation(self.application_clock * 2)
# draw to the default frame buffer
glBindVertexArray(self.cube_vao)
glBindTexture(GL_TEXTURE_2D, self.crate_texture)
for i in range(len(self.cube_positions)):
model = matrix44.create_from_translation(self.cube_positions[i])
if i == 0:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
elif i == 1:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
else:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)
# draw to the custom frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
for i in range(len(self.cube_positions)):
model = matrix44.create_from_translation(self.cube_positions[i])
if i == 0:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
elif i == 1:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
else:
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)
glBindFramebuffer(GL_FRAMEBUFFER, default_ID)
glBindVertexArray(0)
# draw the plane
glBindVertexArray(self.plane_vao)
glBindTexture(GL_TEXTURE_2D, self.plane_texture)
glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, self.plane_position)
glDrawElements(GL_TRIANGLES, len(self.plane_indices), GL_UNSIGNED_INT, None)
glBindVertexArray(0)
self.queue_draw() # Schedules a redraw for Gtk.GLArea
class RootWindow(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
def do_activate(self):
window = Gtk.Window(application=self)
window.set_title("Render To Texture")
window.set_default_size(1280, 720)
window.set_position(Gtk.WindowPosition.CENTER)
window.add(GLCanvas())
window.show_all()
win = RootWindow()
exit_status = win.run(sys.argv)
sys.exit(exit_status)