Content

NewoZero v3 - Postmortem

Page is part of Articles in which you can submit an article

written by owen on 2022-Nov-05.

Testing facades

Testing facades

Frustum cone

Frustum cone

AABB frustum

AABB frustum

Skybox ring

Skybox ring

New skybox textures

New skybox textures

Skyfox frames

Skyfox frames

New moons/suns

New moons/suns

Grid with transparent colour

Grid with transparent colour

Better colours

Better colours

related image
Shadow city

Shadow city

Building facades

Building facades


I jumped back into the NewoZero(NZ) code late in August 2022.  I was in a programming slump while working on a pointer based vector style tank game (which I will get back to at some point in the future).  I started out by doing mostly graphical tweaks to the textures used for the turn signals and an alternate track texture.  I sometimes like to go back to old games to see what i can improve based on new tricks i have learnt.

After playing around the code a bit I realised that there was a lot more that could be done in the NZ game engine so I started optimizing everything I could find.  Get ready for a wall of text and technical explanation.

New Colour management

I have always had an issue when brightening or darkening colours in code so I created a whole new set of functions to correct this problem. Some scenes is NZ called for specific colours to match the synthwave theme. Random colours would not work. The main idea is that I want to adjust any colour by slight amounts without overflowing.  So I came up with this function;

u32 colour_dark(u32 color, short percent) { //2022
float r=abs(percent)/100.0f;
return RGBA(R(color)*r,G(color)*r,B(color)*r,A(color));
}
In the past I would overflow into other colours(see image) if I increased by too much in some colours.  So I created these new functions to better dark and bright changes. In the past the simple trick I would use to get darker colours was to play with the alpha channel of the colour but now with these new functions I can easily achieve a similar effect without messing with transparency.   However there is still one advantage to using alpha transparency to create darker colours; if you allow them to overlap in a consistent way they gradually get brighter. This creates a pleasing overlap effect on horizons which does not happen with a solid colour.

New Skybox

In most of my games there is a flat plane in the background on which I draw the sky.  I rotate this plane so that it always faces the player.  In the prior month of "vector tank game" coding I had seen a tweet by Why485 that inspired me to change my entire skybox strategy.  I realised that I could use my draw line function to create a wall that sounds the player in all directions.  My line function isnt technically cheap because it calculates the distance between 2 points but the wii should be able to handle it without much effort.  With this new technique I could have 64 quads surrounding the player which ment I could do a skybox texture that scrolls left/right as the world turns. 

The simplest way I found to draw the circle around the player is bly stepping around in degrees;

        float frame_y=0;
        guVector start, next, last, first;

        short first_frame=horizon_first_frame,
                curr_frame=first_frame-1, max_frame=horizon_max_frame;        
        start=vector_move(focus_pos, vec(0,0,1), skybox_dist ); //position of the horizon fade        
        first=vector_zero(); //initialize it.
        
        skybox_reset_current();
        
        for(int i=0; i < steps;i++){
                next=vector_rotate_to_angle(start, focus_pos, 0, -(i*step_deg), 0); //rotate on one axis around a center
                if(i>0){ //start after first point s calc
                        if(frame_y==0) frame_y=vector_distance(next, last)*0.5f; //calc the dist between points and use to find y
                        next.y=last.y=frame_y; //always the same level                        
                        skybox_add(focus_pos, next, last, curr_frame, 0);
                }
                
                if(i==1) first=last; //we need to keep this
                last=next;
                
                curr_frame++; //cycle sprite frames
                if(curr_frame > (first_frame+max_frame-1) ) curr_frame=first_frame; //check for last frame and reset
        }        
        skybox_add(focus_pos, first, last, curr_frame, 0);

In NZ 2.16 I had 4 textures for the sun and 1 texture for the fade on the horizon.  The new setup in NZ v3 will allow for 8 background horizons (16 x 64 x 128), 32 suns (128x256px) and 8 foreground horizon objects. The new sprite sheet has taller sprites which is more flexible as it allows for sunsets, up/down positioning and more decorations such as rings, clouds/moons. trees?
Apparently the Wii hardware or the GRRLIB code does not like my 256x512px sun texture frames.

Menu / User Interface

I added a new menu to the display options for demo mode and background.  The background menu to allows you to disable the signs, buildings, skybox and track while also enabling high contrast black and white mode.  I get the ability to have a high contrast mode because I now have full control over all the colours used in the game through one central api - almost all the colours.

Building facades and repeating textures

I had always wanted to do texture tiling in GX but never really got a hand of it until I dug deeper into why it did not work.  The goal was to put little windows on the buildings.  I got the repeating textures working (all I had to do was use textcoords that are greater than 1) but in the end only a few buildings got them because I could not figure out the correct scale for the windows.  Here s a video with me playing around with windows.

The grid


The ground grid is a 8x8 grid but I would get some slow down in dolphin on the water stages so I decided to add some frustum culling to it. This reduced the total drawn segments by more than half. Anything that doesnt need to be drawn saves resources for something else.

Slowdown on complex levels

NZ v2.16 was very stable when it was released with only a few frame drops in Level 2+7 on Hard mode .  Level 7 is the most taxing level in the game (that I can easily remember) because it has a section of the track with multiple fly-overs that come into view at the same time causing the fps to drop below 50fps.  Not bad during gameplay because it only lasts for a couple seconds but it was a clear sign that something needed to be optimized.  The slow down occurs because the game engine has to check if there are other sections of the track that are near the player's view in order to render them at higher detail.  Usually only 15 pieces of track ahead of the player are in high detail.  On level 7 this can rise to about 30 so I had to find a solution in my frustum, scanning for new sections of track, or player_track collision detection.  The solution involved a multi-stage approach;
I do not scan/update for new track every frame so there is a 0.25 sec delay.  Because of this delay inherent in the scanning/updating new track I implemented a "cool down" hack.  This cool down involved skipping frustum tests for 8 track pieces that come after a piece that tested as "visible".  This ensured that there were always live track pieces ahead waiting to be retested even while the scan was far away.  This worked well but has one issue; the cool down only happened ahead of the player since the scan loop flows in one direction - not a big problem since 99% of the game play is from start to end.  The only time it would be a problem is if a part of the track was heading in the opposite direction.  This required another new unique hack.

static bool seek_back=false;
seek_back = !seek_back;
if(!seek_back) for(int i=0; i<TRACK_MAX; i++) game_track_seek(i);
if(seek_back) for(int i=TRACK_MAX-1; i>0; i--) game_track_seek(i);

I have never done this before in any game.  I realised that I needed to scan in reverse so I could find back-facing track pieces faster.   The best way to really demonstrate it is to look at at it in video form.  After this new double loop was implemented The cool down was able to work in both directions with no extra CPU load.  This implementation is probably 50% faster than the original while updating the track twice as fast.  There are no longer any fps drops/spikes because it works no matter how the track is laid out.  The workload is always the same but more efficient.  The track updates at 0.25 times a second and the scan is running at 0.05 times a second waking up a few track pieces each lap.  track pieces sleep longer based on distance/maxspeed and get checked once they get worked up by the scan (shown in green).

Conclusion

Most of the work in this version was under the hood but it was fun pushing the limits and creating new hacks. Download the latest version from; wiibrew.org/wiki/Newo_Zero follow me on youtube or twitter for the latest updates.

permanent link. Find similar posts in Articles.

comments

    Comment list is empty. You should totally be the first to Post your comments on this article.


comment