Nintendo 3DS #Nindie game development blog 002
August: 2D Elements, Performance Testing & Health




This is not homebrew, it’s #Nindie

Continuing from my previous post, I got a basic 3D engine running on the 3DS with basic colour (RGA) and textured (with transparency) polygons.


Who is this for?

It’s mostly a commentary about my random and youtube posts.
I’ll try and keep the dev blogs not so wordy and long.
It will be technical but not in great detail.
I guess this blog is mostly for other game developers, programmers and gamers interested in how the ‘console’ game sausage is made?
Regardless, it reminds me of the few times I updated my Net Yaroze members site, so so many years ago!


2D Elements

Normally, text and user interface elements are rendered on screen using NDC (Normalized Device Coordinates) which is in 2D (X & Y) and in -1.0 to 1.0 range, which is very easy to work with.
But, because I’m rendering everything on a single draw call it has to be in 3D space (view & projection space).


Text via 3D world coord…. don’t ask
(Matrix x (Cam Y rotation)) x Text vertices = so it’s perpendicular
Inverse Cam matrix x (Screen unit point) = Text position in front of camera.

My text is just a quad(2 triangles) with the letter’s UV coordinates.
To render it in the center of the screen, get an identity matrix and multiply it by the camera’s Y rotation.
Then multiply all the quad’s 4 vertices with this matrix or just apply the rotation directly.
This will make the quad perpendicular to the camera, this effect is typically called billboarding, which is how 2.5D games like Doom are made.
The next problem to solve is putting the quad in the right place.
We do this by cloning the camera matrix and inversing it, next we multiply this matrix with the position of the 2D element (which are in NDC -1 to 1, XY);

But the first time I got this working it didn’t look like this but instead looked like this:

Twitter: Transparency needs to be rendered last, or it’ll use the clear colour. #GraphicsProgramming

My clear colour is pink, it’s just a quick way to see any graphical errors.
If the graphics card gets a texture with transparancy and there’s no previously drawn/sorted polygons, it will default to the clear colour.
The fix is easy, sort the polygon list with transparent polygons last.

Continuing with the 2D elements, the center is pretty easy, it’s always 0,0 but that’s not practical for text.
It needs to start rendering at -1.17, 0.637 which is left, top respectively.
Because I’m not using true NDC, I need to specify the z coordinate in front of the camera (left handed) as 0.050;

Rending a string, is pretty easy just looping through the string changing the UV letter coordinate and incrementing the position.
Just make sure you do the math in the right process, or it’ll look very creative like this:



Colour is applied via the RGBA values, which I think looks pretty cool.
My font map is very simple:


The more observant readers would have noticed the last screen shot included two numbers on the bottom screen, these are current frame and FPS.
So now I can see actual performance instead of guessing!


Performance Testing

This is the fun (and hard) part of console development, it’s the exploration phase of what the programmer can actually do with the hardware!
If you are interested in this subject matter, I recommend reading the experiences of the Crash Bandicoot development team on the PlayStation.

I typically use two threads:
1) The gameMain function, which is the creation of the rendering lists, this takes a lot of CPU time.
2) The render function (also will be used for the audio process), which just send a polygon soup to the graphics card.
This takes very few CPU cycles and doesn’t wait for the GPU to finish because it uses double buffering.
But it does have to wait for VSYNC to start.

I’m still a noob so optimization hasn’t been a concern as yet.
There is no gameplay code, just a static 3D scene and text.
No frame locking (ie 30FPS or 60FPS).
VSNC is on (which waits for hardware to be ready for rendering, instead of starting mid drawing, aka screen tearing).

Here are some images of my performance testing:
The original 3DS (268MHz core)
The New 3DS (804MHz core)
Gpu & Cpu in millisecond/100
Total, 58 is 60FPS to 174 is 15FPS
The P values are polygons(triangles) sent to be rendered.

Original 3DS                                                                                                          New 3DS



Video of all the above tests in action


UPATE: The world is a 200×200 polygons mesh divided into 100 objects (10×10) which the engine loops through doing a visibility test on each.
That’s fine on a PC but on an embedded device.. that’s a lot of cycles to process.
So I hacked a Chunk list of a grid of 5×5 (25) each with a list of 4 Objects.
Now it only loops through 25 and if it’s visible, it loops through the 4 Objects in that chunk, a good improvement!

typedef struct {
Object obj;
Object_ptr list[LEVEL_CHUNKS]; //4
}Chunk, *Chuck_ptr;

The number of polygons (triangles) is limited to 512.
The threading makes no difference with the original 3DS, and renders about 15 frames per second (dipping down to 8 at times) which is really bad.
This is all CPU bound, which is just too slow for my unoptimized programming and pretty much rules out original 3DS support for now :(

On the New 3DS, with the render on a different core it can render mostly in 60FPS.

The rendering core sometimes takes 2 VSYNC’s which drops the frame rate to 30FPS.
It’s not because of the number of polygons, I’m guessing it could be a GPU texture cache or ordering issue, ie high number of texture swapping.
Update: it was extra CPU load (ie sort) which pushed it over into 2 VSYNC’s.

The second core isn’t fast enough to process entire gameMain and it’s interesting that it also slows down the GPU processing but still doesn’t effect the frame rate.


Health

I’ve been coding for 20+ years now and I’m starting to feel it!
I asked Dino Dini on his discord if he had any tips.
He writes:

Hi Mike, it does not seem to effect me much, I guess I am lucky.
With eye strain, make sure you use reading glasses or see an optician.
I use two different strengths and switch between them from time to time;
not only does it stop your eyes focusing always at the same distance, but you also position you body differently.

And GalliFromHell posted his tips, so here are mine tips from my home office:

I watch or listen to my laptop with headphones on.

I have a step there also which I use with youtube videos.

I use a standing desk (not shown, it’s too messy) I do recommend standing!
And if you are going to stand, I recommend good shoes, but more importantly are good insoles!
These are my cheap shoes, which I only use to stand at my desk and walk around the house.

Next to my desk is a stepper, I get on it on breaks, ie toilet, food, mental, etc.
I do 50 on the counter (it’s actually 100 steps) before getting off.
I highly recommend this also!

On my desk is this hand strengthener/tension thing.
Very cheap and great for relieving stress and hand RSI!

Push ups.. for upper body strength!


Next month’s todo

Optimization
User interface, menus
Audio
Gameplay


Well, that’s it for another month.
Thanks for reading!


Mike.
@mgarcia_org

PS: Any questions, comments, feedback or corrections, feel free to leave a comment below.