Why hello there! Welcome to this new installment of your favourite blog!
To be honest with you, this one isn't supposed to be noticeable (at least for the first part). To put it simply, this week was really a modelling one. Most of the time I worked on different LOD models of most of my meshes.
Secondly, I've also implemented some fancy affine mapping for my textured meshes, mimicking PlayStation's own texturing method, with all those juicy deformations and all.
So let's get right to it then!
LOD
For those who didn't know, rendering a mesh takes resources. The number of resources used depends on the complexity of a mesh. Generally speaking, the more vertices the more resource intensive the rendering is.
However, sometimes the rendering process is simply too complex for the number of pixels the mesh actually has. This makes the game run generally slower.
The solution? LOD grouping.
Basically, we can create different meshes with different levels of details (i.e. different mesh complexity). We can then tell the game which meshes to use based on how much space the model takes on screen.
This means that objects that are generally far away can use a simpler geometry altogether. if they're far enough they might even get culled altogether.
With all that, it can ease the rendering process just a bit. I still need to add some type of dynamic occlusion system to get really noticable performance boosts, but using LODs generally helps.
Affine Mapping
Next, I want to talk about affine mapping.
Vaporwave, in general, is supposed to invoke feelings of nostalgia in general. In videogames, there are a lot of ways to create that, but most of the time we need to invoke the 5th console generation (N64 and PlayStation generally speaking).
While the N64 can have nice graphics the PlayStation is by far the most interesting of them.
Basically, the PlayStation uses a mapping technique called affine mapping. This technique was usually one of the fastest of them all (at least at the time). But this came with a cost...
Using this mapping algorithm induce noticable distortion on any primitives that have weird viewing angle (such as looking at it almost perpendicular or really close to it)
It was a nice trade-off. This meant that 3D rendering was fast enough for the PlayStation's hardware while still being somehow fully 3D.
Today we've mostly moved on. There are far better mapping techniques that don't induce distortions.
But for this game, I'm trying to get them back.
PSX Shaders
One of the things to understand is that affine mapping wasn't a shader: it was an algorithm. This means that in our age of DirectX and OpenGL we need to make a shader that adds those distortions back in.
Thankfully there's already some PSX emulation shader available for Unity.
It's just a matter of integrating the specific feature of those shaders into mine, which isn't too complex at all...
So here's what I've got:
void vert(inout appdata_full v, out Input o) {
float4 snapToPixel = UnityObjectToClipPos(v.vertex);
float4 vertex = snapToPixel;
vertex.xyz = snapToPixel.xyz / snapToPixel.w;
vertex.x = floor(160 * vertex.x) / 160;
vertex.y = floor(120 * vertex.y) / 120;
vertex.xyz *= snapToPixel.w;
float distance = length(UnityObjectToViewPos(v.vertex));
//Affine Texture Mapping
float4 affinePos = vertex; //vertex;
o.affineLength = (distance + (vertex.w*(UNITY_LIGHTMODEL_AMBIENT.a * 8)) / distance / 2).r;
v.texcoord *= distance + (vertex.w*(UNITY_LIGHTMODEL_AMBIENT.a * 8)) / distance / 2;
}
inline float2 mapping(float2 mainMap, Input IN) {
return mainMap / IN.affineLength;
}
void surf (Input IN, inout SurfaceOutputStandard o) {
o.Albedo = tex2D(_MainTex, mapping(IN.uv_MainTex, IN);
}
Basically, we're doing a bunch of calculation based on the distance of vertices to the center of the object and changing the texture coordinates accordingly.
Later on, we simply divide again to get the right texture scale and voilà: a nice affine shader.
Here's a nice video of it:
We can also change the amount of distortion by changing the alpha value of the ambient colour.
In my case, it wasn't an issue at all, but I'm pretty sure that we could technically change that and put it as a shader property.
However, there's a catch: on low-poly meshes, the shader applies too much distortion, and even while changing the distortion parameter...
The simplest solution is to simply subdivide the meshes. This way the distortion becomes relatively sane.
Paired with Point filtering and low-res texture this makes for quite the PlayStation experience!
Minor Changes
- Fixed bugs with the grass colour not matching their wetness levels
- Continued the Shader .cginc refactors
- Fixed a bug with the Analog blur creating strange dark artifacts on lighted surfaces
- Added a bunch of shader optimizations, especially with instancing
-
Added some billboarding balls to bridge poles
- Refactored the mall floors so that they have simpler geometries that use normal maps rather than actual geometries.
- Resized textures to make them as much low-res I can get away with
- Resolve a bug with picked up items not properly making their pick up sounds
- Added an enemy failsafe so that enemies below the level that somehow survived the chasm will still get killed
- Change most material property changing scripts to also apply properties changes to their LODs
Next Week
We're continuing on the refactor train. I'm also not done with LODs in general, so I'm also planning to complete those as well.
Otherwise, I'm also starting to think that I need other types of enemies... Fighting the same enemy can really be repetitive sometimes...
Aside from that, there are our traditional usual suspects (Capacities, equipment, relics, etc.)
But keep in mind that next week could be potentially slow, as it IS spring break after all, and there are a bunch of little ones running around...
Looking great as usual.