def __init__(self): self.fbo = gl.GLuint(0) self.rendered_texture = gl.GLuint(0) self.depthrenderbuffer = gl.GLuint(0) self.pickingbuffer = gl.GLuint(0) self.vertex_buffer = gl.GLuint(0) self.program = GlProgram(shaders.vertex_copy, shaders.fragment_copy) gl.glGenBuffers(1, pointer(self.vertex_buffer)) data = (gl.GLfloat * 16)(-1, -1, 0, 0, - 1, 1, 0, 1, 1, 1, 1, 1, 1, -1, 1, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertex_buffer) gl.glBufferData(gl.GL_ARRAY_BUFFER, sizeof(data), data, gl.GL_STATIC_DRAW) gl.glGenFramebuffers(1, pointer(self.fbo)) if not self.fbo: logging.error('failed fbo') gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.fbo) gl.glGenTextures(1, pointer(self.rendered_texture)) if not self.rendered_texture: logging.error('failed rendered_texture') gl.glGenRenderbuffers(1, pointer(self.depthrenderbuffer)) gl.glGenRenderbuffers(1, pointer(self.pickingbuffer)) self.resize(1, 1)
def createFramebuffer(width, height): """Function for setting up additional buffer""" # create a new framebuffer fboId = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(fboId)) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) # create a texture to render to, required for warping texId = GL.GLuint() GL.glGenTextures(1, ctypes.byref(texId)) GL.glBindTexture(GL.GL_TEXTURE_2D, texId) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA32F_ARB, int(width), int(height), 0, GL.GL_RGBA, GL.GL_FLOAT, None) GL.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, texId, 0) # create a render buffer rbId = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(rbId)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, rbId) GL.glRenderbufferStorage( GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, int(width), int(height)) GL.glFramebufferRenderbuffer( GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, rbId) GL.glFramebufferRenderbuffer( GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, rbId) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) # clear the buffer GL.glClear(GL.GL_COLOR_BUFFER_BIT) GL.glClear(GL.GL_STENCIL_BUFFER_BIT) GL.glClear(GL.GL_DEPTH_BUFFER_BIT) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) return fboId, texId, rbId
def __init__(self, width, height, internal_format, samples=1): """Create an instance of a Renderbuffer object.""" self._id = gl.GLuint() self._width = width self._height = height self._internal_format = internal_format gl.glGenRenderbuffers(1, self._id) gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, self._id) if samples > 1: gl.glRenderbufferStorageMultisample(gl.GL_RENDERBUFFER, samples, internal_format, width, height) else: gl.glRenderbufferStorage(gl.GL_RENDERBUFFER, internal_format, width, height) gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, 0)
def createMultisampleFBO(width, height, samples, colorFormat=GL.GL_RGBA8): """Create a multisample framebuffer for rendering. Objects drawn to the framebuffer will be anti-aliased if 'GL_MULTISAMPLE' is active. A combined depth and stencil buffer is created with 'GL_DEPTH24_STENCIL8' format. Multisampling is computationally intensive for your graphics hardware and consumes substantial amounts of VRAM. Furthermore, samples must be 'resolved' prior to display by copying (using blitFramebuffer, see Examples) to a non-multisample buffer. Parameters ---------- width : :obj:`int` Buffer width in pixels. height : :obj:`int` Buffer height in pixels. samples : :obj:`int` Number of samples for multi-sampling, should be >1 and power-of-two. Work with one sample, but will raise a warning. colorFormat : :obj:`int` Format for color renderbuffer data (e.g. GL_RGBA8). Returns ------- :obj:`list` of :obj:`int` List of OpenGL ids (FBO, Color RB, Depth/Stencil RB). Examples -------- # create a multisample FBO with 8 samples msaaFbo, colorRb, depthRb = createMultisampleFBO(800, 600, 8) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, msaaFbo) # bind it # resolve samples into another framebuffer texture GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, msaaFbo) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, fbo) gltools.blitFramebuffer((0, 0, 800, 600)) """ # determine if the 'samples' value is valid max_samples = getIntegerv(GL.GL_MAX_SAMPLES) if isinstance(samples, int): if (samples & (samples - 1)) != 0: raise ValueError( 'Invalid number of samples, must be power-of-two.') elif samples < 0 or samples > max_samples: raise ValueError( 'Invalid number of samples, must be <{}.'.format(max_samples)) elif samples == 1: # warn that you are creating a single sample texture, use a regular # FBO instead. logging.warning('Creating a multisample FBO with one sample!') elif isinstance(samples, str): if samples == 'max': samples = max_samples # create the FBO, bind it for attachments fboId = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(fboId)) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) # Color render buffer only instead of a texture. I can't think of a use case # to pass around a multisampled texture (yet). colorRbId = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(colorRbId)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, colorRbId) GL.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, colorFormat, int(width), int(height)) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_RENDERBUFFER, colorRbId) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) # setup the render buffer for depth and stencil depthRbId = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(depthRbId)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, depthRbId) GL.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, GL.GL_DEPTH24_STENCIL8, int(width), int(height)) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depthRbId) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, depthRbId) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) # clear VRAM garbage GL.glClear(GL.GL_STENCIL_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) # check completeness if not checkFramebufferComplete(fboId): # delete the framebuffer and all the resources associated with it GL.glDeleteRenderbuffers(1, colorRbId) GL.glDeleteRenderbuffers(1, depthRbId) GL.glDeleteFramebuffers(1, fboId) raise RuntimeError( 'Failed to create a multisample framebuffer. Exiting.') return fboId, colorRbId, depthRbId
def createFBO(width, height, colorFormat=GL.GL_RGBA8): """Generate a new Framebuffer object (FBO) for use as a render target. Parameters ---------- width : :obj:`int` Buffer width in pixels. height : :obj:`int` Buffer height in pixels. colorFormat : :obj:`int` Format for color renderbuffer data (e.g. GL_RGBA8). Returns ------- :obj:`list` of :obj:`int` List of OpenGL ids (FBO, Color Texture, Depth/Stencil RB). Examples -------- # create a FBO frameBuffer, frameTexture, stencilTexture = createFBO( 800, 600, GL.GL_RGBA32F_ARB) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer) # bind it """ # Create a texture render target for color data, same _setupFramebuffer() # # We should avoid creating a texture here in the future since we might want # to bind an existing texture from elsewhere and reuse the same FBO. # colorTextureId = GL.GLuint() GL.glGenTextures(1, ctypes.byref(colorTextureId)) GL.glBindTexture(GL.GL_TEXTURE_2D, colorTextureId) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, colorFormat, int(width), int(height), 0, GL.GL_RGBA, GL.GL_FLOAT, None) GL.glBindTexture(GL.GL_TEXTURE_2D, 0) fboId = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(fboId)) # attach texture to the frame buffer GL.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, colorTextureId, 0) # create depth and stencil render buffers depthRbId = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(depthRbId)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, depthRbId) GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, int(width), int(height)) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depthRbId) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, depthRbId) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) # clear VRAM garbage GL.glClear(GL.GL_STENCIL_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) # check completeness if not checkFramebufferComplete(fboId): # delete the framebuffer and all the resources associated with it GL.glDeleteTextures(1, colorTextureId) GL.glDeleteRenderbuffers(1, depthRbId) GL.glDeleteFramebuffers(1, fboId) raise RuntimeError('Failed to create a framebuffer. Exiting.') return fboId, colorTextureId, depthRbId
def create_frame_buffers(width, height, num_samples): """Create the frame buffer objects""" from pyglet import gl # Create a frame buffer (rendering target) multi_fbo = gl.GLuint(0) gl.glGenFramebuffers(1, byref(multi_fbo)) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, multi_fbo) # The try block here is because some OpenGL drivers # (Intel GPU drivers on macbooks in particular) do not # support multisampling on frame buffer objects try: if not gl.gl_info.have_version(major=3, minor=2): raise Exception('OpenGL version 3.2+ required for \ GL_TEXTURE_2D_MULTISAMPLE') # Create a multisampled texture to render into fbTex = gl.GLuint(0) gl.glGenTextures(1, byref(fbTex)) gl.glBindTexture(gl.GL_TEXTURE_2D_MULTISAMPLE, fbTex) gl.glTexImage2DMultisample(gl.GL_TEXTURE_2D_MULTISAMPLE, num_samples, gl.GL_RGBA32F, width, height, True) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D_MULTISAMPLE, fbTex, 0) # Attach a multisampled depth buffer to the FBO depth_rb = gl.GLuint(0) gl.glGenRenderbuffers(1, byref(depth_rb)) gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, depth_rb) gl.glRenderbufferStorageMultisample(gl.GL_RENDERBUFFER, num_samples, gl.GL_DEPTH_COMPONENT, width, height) gl.glFramebufferRenderbuffer(gl.GL_FRAMEBUFFER, gl.GL_DEPTH_ATTACHMENT, gl.GL_RENDERBUFFER, depth_rb) except: logger.debug('Falling back to non-multisampled frame buffer') # Create a plain texture texture to render into fbTex = gl.GLuint(0) gl.glGenTextures(1, byref(fbTex)) gl.glBindTexture(gl.GL_TEXTURE_2D, fbTex) gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_FLOAT, None) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, fbTex, 0) # Attach depth buffer to FBO depth_rb = gl.GLuint(0) gl.glGenRenderbuffers(1, byref(depth_rb)) gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, depth_rb) gl.glRenderbufferStorage(gl.GL_RENDERBUFFER, gl.GL_DEPTH_COMPONENT, width, height) gl.glFramebufferRenderbuffer(gl.GL_FRAMEBUFFER, gl.GL_DEPTH_ATTACHMENT, gl.GL_RENDERBUFFER, depth_rb) # Sanity check import pyglet if pyglet.options['debug_gl']: res = gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) assert res == gl.GL_FRAMEBUFFER_COMPLETE # Create the frame buffer used to resolve the final render final_fbo = gl.GLuint(0) gl.glGenFramebuffers(1, byref(final_fbo)) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, final_fbo) # Create the texture used to resolve the final render fbTex = gl.GLuint(0) gl.glGenTextures(1, byref(fbTex)) gl.glBindTexture(gl.GL_TEXTURE_2D, fbTex) gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_FLOAT, None) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, fbTex, 0) import pyglet if pyglet.options['debug_gl']: res = gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) assert res == gl.GL_FRAMEBUFFER_COMPLETE # Enable depth testing gl.glEnable(gl.GL_DEPTH_TEST) # Unbind the frame buffer gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) return multi_fbo, final_fbo
def createRenderbuffer(width, height, internalFormat=GL.GL_RGBA8, samples=1): """Create a new Renderbuffer Object with a specified internal format. A multisample storage buffer is created if samples > 1. Renderbuffers contain image data and are optimized for use as render targets. See https://www.khronos.org/opengl/wiki/Renderbuffer_Object for more information. Parameters ---------- width : :obj:`int` Buffer width in pixels. height : :obj:`int` Buffer height in pixels. internalFormat : :obj:`int` Format for renderbuffer data (e.g. GL_RGBA8, GL_DEPTH24_STENCIL8). samples : :obj:`int` Number of samples for multi-sampling, should be >1 and power-of-two. Work with one sample, but will raise a warning. Returns ------- :obj:`Renderbuffer` A descriptor of the created renderbuffer. Notes ----- The 'userData' field of the returned descriptor is a dictionary that can be used to store arbitrary data associated with the buffer. """ width = int(width) height = int(height) # create a new renderbuffer ID rbId = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(rbId)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, rbId) if samples > 1: # determine if the 'samples' value is valid maxSamples = getIntegerv(GL.GL_MAX_SAMPLES) if (samples & (samples - 1)) != 0: raise ValueError( 'Invalid number of samples, must be power-of-two.') elif samples > maxSamples: raise ValueError( 'Invalid number of samples, must be <{}.'.format(maxSamples)) # create a multisample render buffer storage GL.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, internalFormat, width, height) else: GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, internalFormat, width, height) # done, unbind it GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) return Renderbuffer(rbId, GL.GL_RENDERBUFFER, width, height, internalFormat, samples, samples > 1, dict())
def create_frame_buffers(width: int, height: int, num_samples: int) -> Tuple[int, int]: """Create the frame buffer objects""" # Create a frame buffer (rendering target) multi_fbo = gl.GLuint(0) gl.glGenFramebuffers(1, byref(multi_fbo)) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, multi_fbo) # The try block here is because some OpenGL drivers # (Intel GPU drivers on macbooks in particular) do not # support multisampling on frame buffer objects # noinspection PyBroadException try: # Create a multisampled texture to render into fbTex = gl.GLuint(0) gl.glGenTextures(1, byref(fbTex)) gl.glBindTexture(gl.GL_TEXTURE_2D_MULTISAMPLE, fbTex) gl.glTexImage2DMultisample(gl.GL_TEXTURE_2D_MULTISAMPLE, num_samples, gl.GL_RGBA32F, width, height, True) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D_MULTISAMPLE, fbTex, 0) # Attach a multisampled depth buffer to the FBO depth_rb = gl.GLuint(0) gl.glGenRenderbuffers(1, byref(depth_rb)) gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, depth_rb) gl.glRenderbufferStorageMultisample(gl.GL_RENDERBUFFER, num_samples, gl.GL_DEPTH_COMPONENT, width, height) gl.glFramebufferRenderbuffer(gl.GL_FRAMEBUFFER, gl.GL_DEPTH_ATTACHMENT, gl.GL_RENDERBUFFER, depth_rb) except BaseException as e: # logger.warning(e=traceback.format_exc()) logger.debug("Falling back to non-multisampled frame buffer") # Create a plain texture texture to render into fbTex = gl.GLuint(0) gl.glGenTextures(1, byref(fbTex)) gl.glBindTexture(gl.GL_TEXTURE_2D, fbTex) gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_FLOAT, None) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, fbTex, 0) # Attach depth buffer to FBO depth_rb = gl.GLuint(0) gl.glGenRenderbuffers(1, byref(depth_rb)) gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, depth_rb) gl.glRenderbufferStorage(gl.GL_RENDERBUFFER, gl.GL_DEPTH_COMPONENT, width, height) gl.glFramebufferRenderbuffer(gl.GL_FRAMEBUFFER, gl.GL_DEPTH_ATTACHMENT, gl.GL_RENDERBUFFER, depth_rb) # Sanity check if pyglet.options["debug_gl"]: res = gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) assert res == gl.GL_FRAMEBUFFER_COMPLETE # Create the frame buffer used to resolve the final render final_fbo = gl.GLuint(0) gl.glGenFramebuffers(1, byref(final_fbo)) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, final_fbo) # Create the texture used to resolve the final render fbTex = gl.GLuint(0) gl.glGenTextures(1, byref(fbTex)) gl.glBindTexture(gl.GL_TEXTURE_2D, fbTex) gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_FLOAT, None) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, fbTex, 0) if pyglet.options["debug_gl"]: res = gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) assert res == gl.GL_FRAMEBUFFER_COMPLETE # Enable depth testing gl.glEnable(gl.GL_DEPTH_TEST) # Unbind the frame buffer gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) return multi_fbo, final_fbo