Voidglow


image

Voidglow

2021

Tools

Blender
Unity

Languages

C#

Collaborated with the development of a simple horror game in Unity

Blog


As support for Syntax' 2021 Game Jam, me and Eder Chua decided to join the event. After all, at the time Eder Chua was the president of Syntax, a CIIT coding organization. Given a week, we created a simple horror game using assets from my other project, the VRChat-like version for CIIT. Since we already have a model of the CIIT building and other related assets at our disposal, we decided to use it instead of creating new assets.

I wrote a basic lore so that things would be more immersive and would make sense instead of the game being a playable map.

Lore

An unidentifiable object spanned through the skies, as billions of eyes watch the impending extinction of everyone. It wasn’t anything like a meteor or any rock formation. No flames, just pure brightness. It shone so bright and even brighter, so much that it burns- no, disintegrates everything into atoms, but not to humans. When it finally reached the surface of the Earth, it was like swimming in divinity. People are floating in nothing except pure light. Confused. Lost.

Moments later and down came a sonic boom, a screech of frequency which scratched everyone’s hearing, and then the lights when dark.

I woke up alone, in front of my beloved school. There’s nothing left. Not even a single bit of the nature’s aspect. I don’t understand how this building still stands. It’s all ruined, but I can still reconstruct what’s missing between the cracks and gaps of every wall and glass. The universe kisses me with a little bit of light, yet it feels like void, burning through my very soul. I guess part of it is agony of isolated existence.

Between the cracks of these wall I can see what seems to be blackholes devouring up light, and orbs with pure divine but does not blind. Maybe if I fill these darkness with light, I can bring back everything, or atleast what’s left of this reality.

Optimization

We also used the same game for our Asset Optimization subject, where we were tasked to optimize an existing game and document it. Here's a summary of all the things we did:

Decreased Asset Polygon Count

One of the main problems we immediately fixed after learning asset optimization are the debris flying out from the building. Each one of the debris is its own object. We collected all debris into one collection and counted 280 objects. This is clearly unacceptable since it will eat up most draw calls, which is unnecessary since they are just purely aesthetic and does not need to be separate objects.

We immediately fixed this problem by selecting all children of the collection we made and joined all selection into one object.

screenshot 2023 12 12 224004

Defined Static Objects

Since all of the objects (except the Player, Slendervoid, and the orbs) are not moving, we set all those objects as static. This will help in pre-computing data to decrease unnecessary re-computations at runtime. After doing so, most of the draw calls are now called “Static Batch”, which seems like static objects with the same lighting is being drawn in a group, instead of individually. This resulted in a decrease of draw calls from 994 to 279 in separate tests, looking the same camera location.

Occlusion

Looking at the Frame Debugger, we have observed that even after decreasing the object count of the debris, the game is still calling a lot of draws. We have then identified that even when in floor 1, the objects at floor 2 is still being drawn even if the camera does not visually see it. We tested pointing the camera to nothing and resulted in 291 draw calls. Since we have already defined the static objects beforehand, we also set which objects are occluders and occludees. Occlusion is really helpful in our game since the map is mostly blocked by floors, ceilings, and walls.

Material GPU Instancing

Even after setting up the static objects, we have recognized that the tables and chairs are still being drawn individually. Unity provided us with a reason as to why they can’t draw these objects by static batches. It seems like even though the objects are the same, the materials they have are still needed to be drawn individually. Unity gave us a hint that the material “doesn’t have GPU instancing enabled”. This was an easy fix- for each material, we just need to enable GPU instancing.

screenshot 2023 12 12 224702

This was no problem for materials that have been created in Unity (e.g. materials with flat colors). However, the materials on the tables and chairs are embedded in the FBX models when it was exported from Blender. Conveniently, Unity allows for the extraction of embedded materials from imported models.

screenshot 2023 12 12 224746

After extracting all materials, it is now easy to enable GPU instancing. GPU instancing allows Unity to render similar objects that uses the same materials in one draw call, much like static batches.

Enabling Material GPU instancing dropped the draw calls to around 139 from around 290.

Crunch Compression

There are materials that make use of textures instead of solid colors, such as the cement material, Slendervoid’s skin, and the skybox material. We have enabled Crunch Compression for all textures. Although the loss in quality is reasonably identifiable when zoomed in, it won’t really matter much on runtime due to the eerie lighting and environment of the game.

side-by-side comparison of original and compressed cement texture (left to right)
side-by-side comparison of original and compressed cement texture (left to right)

On the left is the original file of the cement texture, which is 2.7mb. Enabling crunch compression dropped it to 0.6mb, which is a 77.78% decrease in file size.

A skybox consists of 6 sides (sides of a square). A single side for our skybox is 2.7mb which turns to 423.1kb, a very big decrease of 84%. Considering all sides, the original total size of the skybox is 6*2.7mb (sides *size/side) = 16.2mb, while the crunch-compressed skybox is around 2.5mb.

Baked Lightmaps

Last in our list of optimizations is baking the lightmaps, which is also convenient similar to the reason for setting up static meshes: nearly every asset in our game does not move, except for the enemy and the player.