Skip to content

framebuffer

FreeBodyEngine.graphics.gl33.framebuffer #

GL_ATTACHMENT_FORMAT = {AttachmentFormat.R8: GL_R8, AttachmentFormat.RGBA8: GL_RGBA8, AttachmentFormat.RGBA16F: GL_RGBA16F, AttachmentFormat.RGBA32F: GL_RGBA32F, AttachmentFormat.RGB10_A2: GL_RGB10_A2, AttachmentFormat.R32F: GL_R32F, AttachmentFormat.RG32F: GL_RG32F, AttachmentFormat.DEPTH24: GL_DEPTH_COMPONENT24, AttachmentFormat.DEPTH32F: GL_DEPTH_COMPONENT32F, AttachmentFormat.STENCIL8: GL_STENCIL_INDEX8, AttachmentFormat.DEPTH24_STENCIL8: GL_DEPTH24_STENCIL8} module-attribute #

GL_ATTACHMENT_TYPE = {AttachmentFormat.R8: (GL_RED, GL_UNSIGNED_BYTE), AttachmentFormat.RGBA8: (GL_RGBA, GL_UNSIGNED_BYTE), AttachmentFormat.RGBA16F: (GL_RGBA, GL_FLOAT), AttachmentFormat.RGBA32F: (GL_RGBA, GL_FLOAT), AttachmentFormat.RGB10_A2: (GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV), AttachmentFormat.R32F: (GL_RED, GL_FLOAT), AttachmentFormat.RG32F: (GL_RG, GL_FLOAT), AttachmentFormat.DEPTH24: (GL_DEPTH_COMPONENT, GL_UNSIGNED_INT), AttachmentFormat.DEPTH32F: (GL_DEPTH_COMPONENT, GL_FLOAT), AttachmentFormat.STENCIL8: (GL_STENCIL_INDEX, GL_UNSIGNED_BYTE), AttachmentFormat.DEPTH24_STENCIL8: (GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8)} module-attribute #

GL_CHANNEL_COUNT = {GL_RED: 1, GL_RG: 2, GL_RGB: 3, GL_RGBA: 4} module-attribute #

GLFramebuffer(width, height, attachments, transparent=False) #

Bases: Framebuffer

The GL 3.3 implementation of Framebuffer: a real glGenFramebuffers object with one GL_TEXTURE_2D per color attachment (so it can also be sampled from later, e.g. a G-buffer channel) and a single shared renderbuffer for whichever depth/stencil/depth-stencil attachment was requested. self.attachments[name] (inherited from the base class) is repurposed here to hold each color attachment's actual GL_COLOR_ATTACHMENT0 + n enum rather than the (AttachmentType, AttachmentFormat) pair the constructor received - that original pair is kept separately in self._attachments since resize() needs it again to recreate storage at the new size.

Creates the FBO and, for every requested attachment, the backing GL object: a mipmapless linear-filtered GL_TEXTURE_2D for each COLOR attachment (bound to consecutive GL_COLOR_ATTACHMENTn slots), or one shared renderbuffer for a DEPTH/STENCIL/DEPTH_STENCIL attachment. Color attachments are also collected into draw_buffers and wired up via glDrawBuffers so a shader with multiple @output fields actually renders to all of them; with no color attachments at all, glDrawBuffer(GL_NONE)/glReadBuffer(GL_NONE) are set instead (a depth-only FBO, e.g. a shadow map). Raises RuntimeError if the finished FBO fails glCheckFramebufferStatus. transparent enables standard alpha blending for subsequent draws into this FBO.

depth_renderbuffer = glGenRenderbuffers(1) instance-attribute #

depth_texture_name = name instance-attribute #

fbo = glGenFramebuffers(1) instance-attribute #

num_color_attachments = color_attachment_index instance-attribute #

textures = {} instance-attribute #

bind() #

Binds this FBO as the current GL_FRAMEBUFFER and sets the GL viewport to its full size, so subsequent draws render into it at the correct resolution instead of whatever viewport the previously-bound target left set.

clear_color_attachment(name, value=(0.0, 0.0, 0.0, 0.0)) #

Clears the named color attachment to value via glClearBufferfv(GL_COLOR, draw_buffer_index, ...), targeting only that attachment's own draw-buffer index rather than every bound draw buffer at once (the effect a plain glClear(GL_COLOR_BUFFER_BIT) would have) - see the abstract method's docstring for why that distinction matters for a multi-attachment G-buffer.

draw(attachment, size=None) #

Draw a named attachment to the screen.

get_attachment_texture(attachment_name) #

Returns the raw GL texture id backing the named color attachment (there's nothing to return for a depth/stencil attachment - those are renderbuffers, not textures - so only entries in self.textures apply).

read(attachment_name) #

Reads back the named color attachment's pixels via glReadPixels, always as GL_FLOAT regardless of the attachment's own storage type, and reshapes the raw buffer into a (height, width, channels) float32 array (channels derived from the attachment's GL format via GL_CHANNEL_COUNT). This is a synchronous GPU->CPU stall - see the abstract method's docstring for when that's acceptable.

resize(size) #

Recreates every attachment's storage at the new size, mirroring init's attachment loop: each color texture is deleted and regenerated at the new dimensions (a GL texture's storage can't be resized in place), and the shared depth/stencil renderbuffer is likewise deleted and regenerated if one exists. Also re-runs the draw-buffers wiring and completeness check init does, and updates the GL viewport to match. Raises RuntimeError if the resized FBO is incomplete.

set_draw_buffers(names) #

See Framebuffer.set_draw_buffers. Assumes this FBO is already bound.

Builds the same full-width, position-equals-attachment-index array WebGL2Framebuffer.set_draw_buffers() is forced to use (GL_NONE at every color attachment not in names) rather than the more compact [self.attachments[n] for n in names] this used to be - desktop GL doesn't require that shape (it can remap an arbitrary subset onto sequential fragment-output locations starting at 0), but PBRPipeline's shaders (see graphics/pbr/shaders.py's LIGHTING_COMPOSITE_FRAG/default_forward.fbfrag) declare their real @output field at whatever location its physical attachment index is - padded with unused leading fields to get there - specifically so the same FBUSL source compiles correctly on WebGL2, which has no remapping at all (see WebGL2Framebuffer.set_draw_buffers()'s own docstring). Matching that convention here means one shared assumption ("output location N always means physical attachment N") holds on both backends instead of desktop silently tolerating a mismatch WebGL2 can't.

unbind() #

Rebinds the default framebuffer (0), i.e. the window's own backbuffer.