Repository navigation
Render Culling
I can’t directly write to the GitHub wiki from this session, but here is a ready-to-paste wiki page for the culling system.
Title: Render Culling
This page documents the camera-frustum culling logic used to skip drawing renderables that are outside the active camera view.
The culling system lives in:
source/core/src/main/com/csse3200/game/rendering/RenderCulling.javasource/core/src/main/com/csse3200/game/rendering/CullingRenderable.javasource/core/src/main/com/csse3200/game/rendering/RenderService.java
The goal is to reduce unnecessary draw calls by checking whether a renderable’s world bounds are visible before it is rendered.
The project has a lot of world objects and effects that may sit offscreen for long periods. Drawing them every frame wastes CPU and GPU time. Culling prevents hidden objects from being processed when the camera cannot see them.
This is especially useful for:
- static environment props
- background textures
- large world tiles
- low-priority decorative objects
- repeated render calls during heavy scenes
RenderCulling is a small utility class responsible for the actual visibility check. It performs a camera-frustum bounds test using a renderable’s position, width, height, and rotation.
Key behaviour:
- takes a
Frustumfrom the active camera - computes a rotated bounding box from the object’s dimensions
- tests whether the bounds intersect the camera’s visible region
- returns true when the object is visible, false otherwise
The method signature is:
static boolean isVisible(
Frustum frustum, float x, float y, float width, float height, float rotationDegrees)This allows the engine to approximate visibility without requiring a full per-pixel check.
The class determines the object’s half-width and half-height, then rotates those values to account for the entity’s current angle.
It uses:
Math.cos(rotation)Math.sin(rotation)rotatedHalfWidthrotatedHalfHeight
The final check is passed to:
frustum.boundsInFrustum(
x + width / 2f, y + height / 2f, 0f, rotatedHalfWidth, rotatedHalfHeight, 0f);This is a fast, efficient approximation suitable for world-space objects.
The CullingRenderable interface defines objects that can answer the visibility question:
public interface CullingRenderable extends Renderable {
boolean isVisible(Camera camera);
}This lets renderables opt into culling without forcing all renderables to have a visibility check.
The render layer now passes the active camera into the rendering step:
-
Renderer.render()callsrenderService.render(batch, camera.getCamera()) -
RenderService.render(SpriteBatch batch, Camera camera)checks each renderable - If a renderable is a
CullingRenderableand is not visible, it is skipped
This means culling is applied at the batch render stage and does not require changes to unrelated world logic.
The following render components were adapted to support visibility checks:
TextureRenderComponentDynamicTextureRenderComponentTiledRenderComponent
These classes now implement CullingRenderable and provide a camera-aware visibility result based on their transformed bounds.
This culling system improves performance by:
- reducing draw calls for offscreen content
- avoiding wasted work for objects outside the active view
- helping maintain frame rate in larger or busier scenes
- improving scalability when more world objects are added
A renderable can decide whether it should be drawn by returning:
return RenderCulling.isVisible(
camera.frustum, position.x, position.y, scale.x, scale.y, rotation);If the camera cannot see it, the render service will skip it entirely.
Entities and Components
Input Handling
Arrow Selection Wheel Arrow Selection Wheel — Sprint 3