(March 2025) Monthly WIP Screenshot Thread

Hi, I’ve been working on a portal occlusion system to optimize my FPS game framework.

Here’s is how it works. There are volumes delimiting “areas” or nodes forming a graph which are connected by “portals” as edges.
The algorithm starts by traversing the graph from the area where the camera is located. Then finds if any portal is inside the frustum (yellow), if so it “shrinks” the frustum according to the size of the portal and creates a new frustum (cyan) which is used to check the area behind the portal.
All the spatials inside any of the frustrums are set with CullHint.Never or Always if outside.
Here’s a visualization:
Imgur
Imgur

camera view, all the red boxes seen here would be occluded by the system
Imgur

Here’s in my test game:

With portals off 115 objects are rendered:
Imgur

With portals enabled it’s reduced to 58, about half.
Imgur

Here is a debug view. The yellow line shows the area limits and the red boxes are the portal frustums, because the frustums are clipped in screen space they always look rectangular.
Imgur

The portal data is generated from my level editor very simply by marking lines in a top-down view. White and yellow lines define the area limits and Magenta is where the portals are added.
Imgur

The algorithm is very simple, but the math took me some time to get right.
Thankfully I found this blog post that explains it in very easy terms and I just followed that guide step by step.
I wrote the code as a separate library in case someone find this useful: repo. I plan to make some improvements and share more detail in another post.

14 Likes

No new screenshots but another optimization update.
I applied Texture Arrays to my game maps, since most textures are of the same size I can bound them all together into an array, batched all into a one geometry and it allowed me to save a lot of render calls.
For instance in the screenshot above I lowered it from 58 objects to 36.
Doing a more realistic test in my under development game I measured the same scene: it had 207 objects before portals, 110 after portals and now 59 with texture arrays.
I’m using the SteamDeck as reference system and each optimization improved framerate by 16%, so around 32% in total.

I didn’t know about this technique before, seems very useful. It allows to bound an array of textures to a single texture parameter, then add a third component to the UV coors with the index in the array and use it to sample the texture. The limitation is that all textures must be of the same size and format.
I followed TestTextureArray.java as reference and modified my already modified Lighting.j3md shaders to optionally accept a new “DiffuseArray” param and read the text coords as vec3 (in case the array param is defined). Since I’m not using normal maps I didn’t bother to change that part, but it’d the same.

One small extra thing I had to do. I set a special param to my materials that’s not used by the shaders but by some visual effects (step sounds, particles and damage decals, etc.), so since I merged all the materials together I could only have one value for the whole geometry. So instead I added a new vertex buffer to the geometry (Usage.CpuOnly) and copy the effect id value for each vertex.
Then whenever I need to find the effect I pick the geometry and take the value from one of the vertices of the colliding triangle, neat!.

6 Likes

finally got a decently looking base for bullet impact :smiley:

turns out i was using an ancient version of particlemonkey that had a couple bugs. If anyone is interested how to use the latest one but is not very familiar with gradle, heres how :slight_smile:

// settings.gradle

rootProject.name = 'bullet_impact_test'
include 'assets'
sourceControl {

    gitRepository(new URI("https://github.com/Jeddic/particlemonkey.git")) {
        producesModule("com.epagagames:particlemonkey")
    }
}
// build.gradle

dependencies {
    // your usual other dependencies
    implementation  ('com.epagagames:particlemonkey:1.1.1') {
        version {
            branch = "master"
        }
    }
}
6 Likes

WIP Quantized Mesh Loader for highly detailed terrain

12 Likes

integrated the bullet impact vfx with the main project, also improved the recoil and it feels much better (it doesnt feel perfect yet, but doesnt make you nauseous)

8 Likes

You Are Captured - Trailer

3 Likes