def _generate_incident_textures_and_fbos(self): """Two FBOs used for lightmap generation. The first one gets the sample buffer drawn to it. The other one is 4x4px and is used to work out the total incident light. """ tex_fbo_list = [] for size in self.sample_size, 4: # Create the texture tex = pyglet.image.Texture.create_for_size(GL_TEXTURE_2D, size, size, GL_RGBA) glBindTexture(GL_TEXTURE_2D, tex.id) # Create the FBO fbo = GLuint() glGenFramebuffersEXT(1, fbo) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo) # Add a depth buffer depth_buffer = GLuint() glGenRenderbuffersEXT(1, depth_buffer) glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_buffer) glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size, size) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_buffer) # Attach the texture to the FBO glBindTexture(GL_TEXTURE_2D, tex.id) glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex.id, 0) status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) assert status == GL_FRAMEBUFFER_COMPLETE_EXT # Reset the state glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) # We'll be scaling it down to average the pixels, so use linear # minification. glEnable(GL_TEXTURE_2D) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) glGenerateMipmapEXT(GL_TEXTURE_2D) # Add a tuple of texture and FBO to the list tex_fbo_list.append((tex, fbo)) return tex_fbo_list
def average_hardware(self): """With the scene already drawn to the main sample FBO, use OpenGL to get an average of the values of every pixel. """ # Generate a mipmap of the sample buffer - the 4x4 level will contain # the information we need to work out the incident. glBindTexture(GL_TEXTURE_2D, self.sample_tex.id) glGenerateMipmapEXT(GL_TEXTURE_2D) # Draw the sample buffer to a 4x4 rect on the other buffer. Mip-mapping # will mean it contains the average of the full sample buffer. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, self.sample_fbo_b) glMatrixMode(GL_PROJECTION) glLoadIdentity() glMatrixMode(GL_MODELVIEW) glLoadIdentity() glViewport(0, 0, 4, 4) glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0) glBindTexture(GL_TEXTURE_2D, self.sample_tex.id) utils.draw_rect() # The target texture now contains a tiny 4x4 hemicube in the corner. # Read the values back. pixel_data = (GLubyte * (4 * 4 * 4))(0) glReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data) # Reset the state glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) # Average the RGB values for the cubemap (so ignore the corner pixels) red_value = 0 green_value = 0 blue_value = 0 for y in xrange(4): for x in xrange(4): if y in (0, 3) and x in (0, 3): # Ignore corner pixels continue pixel_index = y * 4 + x pixel_index *= 4 # 4 channels red_value += pixel_data[pixel_index] green_value += pixel_data[pixel_index + 1] blue_value += pixel_data[pixel_index + 2] # We've sampled 12 pixels. Divide to 12 to get the mean, and by 255 # to normalise. red_value /= 12.0 * 255.0 green_value /= 12.0 * 255.0 blue_value /= 12.0 * 255.0 return (red_value, green_value, blue_value)