Esempio n. 1
0
    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
Esempio n. 2
0
    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)