Assignment 13: Build System!

This week’s game: simple one-click download below, unzip, play, enjoy!

NancyNewren_ExampleGame 13

What’s new
Nothing from the player’s perspective. Just built using my new build system!

Controls
Main object: Use arrow keys to move main object left/right/up/down
Camera:  
Left/Right (A/D), Up/down (W/S), Zoom in/out (Q/E)
(When moving the camera things in the world will appear to move opposite. Thus when you move camera left, the world will appear to move right.)

About the Project

I freaking love my new build system! It saves so much time! I have a file where I list all my graphics assets that need to be built for the game. The build system then checks this list of assets to see if they already exist, if so if there is a newer source version or if the builder itself is newer, and then it will only build if necessary. That means once I build everything (which can take several minutes) it takes less than a second to build again because my system is being smart. It’s so nice!

There are big advantages to having a list of all the assets to build in their own file: it is quick and easy to update, and you don’t have to search through other code. It’s also easy to see any bugs, and to add new features as well.

Of course this list isn’t everything that needs to be built: there are licenses and settings files that need to be copied over into the playable game folder, but the system checks for those as well. It saves so much time! Especially since we have two different platforms and two different build configuration types, which means we have to build and test for four total different build configurations. When you have to wait several minutes every time you build, every time you test a simple change, it very quickly adds up to taking hours! I’m so grateful for this new build system. Thanks JP for having us do it! 🙂

Advertisements

Assignment 12: Binary Mesh Assets

Download this week’s game with the simple one-click download below! Once downloaded, unzip, play the executable, enjoy!

NancyNewren_ExampleGame 12

What’s new
Different main mesh: a Christmas cactus for my friend Felicia! Bring on the happy!

Controls
Main object: Use arrow keys to move main object left/right/up/down
Camera:  
Left/Right (A/D), Up/down (W/S), Zoom in/out (Q/E)
(When moving the camera things in the world will appear to move opposite. Thus when you move camera left, the world will appear to move right.)

About the Project

The advantage of the human readable file is that you can read, understand, and debug that file just by reading it, but they do take longer to load and are bigger files. So the idea is to load/store the assets in binary for two reasons: 1) It is more efficient (faster) to load from binary, and 2) it is also more economic (they are smaller) to store the files. So in our regular build and source files, human-readable: since a human needs to be able to interpret and debug them, but in our run-tim binary: because we’ve done all our testing and debugging and now only the computer needs to be able to read them.

There are four pieces of data that each mesh needs: number of indices, the indicies, the vertices, and the number of verticies. I chose to do the number of indicies first (since the binary read in needs to know how many indicies there are so it can jump to the next right place in the data), then the indicies next since they take up less space and are easier to read in a binary format as they are integers. Next I chose to do number of verticies, again because the read in needs to know how many vertices there are so we know the size of the memory, and then the verticies themselves. I could have done number indicies, number verticies, indicies, and then verticies, or a number of different configurations, but regardless of the order I chose, the number of indicies and verticies would always need to be stored before the index and vertex data.

Here is my floor’s binary file with the above listed order:

By default the human readable files are in OpenGL format. Previously I was swapping the UVs and winding orders after loading from the human readable files for D3D. But since I want a quick load at run time this swapping happens during the build for the binary. So the while the human readable files remain the same, the built meshes are different and cannot be swapped across platform. This does however make loading a binary file platform independent. This is how I load the binary data:

Lastly, enough talk! Let’s show the two advantages of the binary files: I made an object with 50436 index count, and 33616 vertex count. Here’s how they compare:

Human Readable File Binary
Size of file 4.61 MB 886 KB
Time to load (seconds) 0.256 0.002234

Acknowledgements

Thanks to Zeno who once again helped me with some of the C++ basics I’ve forgotten. It’s been a long time since I did file i/o with c++, and he was very helpful.

Assignment 11: Made Mesh Assets with Maya, Added Textures to 3D Objects

Download this week’s game with the simple one-click download below! Once downloaded, unzip, play the executable, enjoy!

NancyNewren_ExampleGame 11

What’s new
Gameplay movement is the same but faster, and I updated the 3D objects’ colors and shape and added textures! Time for winter!

Controls
Main object: Use arrow keys to move main object left/right/up/down
Camera:  
Left/Right (A/D), Up/down (W/S), Zoom in/out (Q/E)
(When moving the camera things in the world will appear to move opposite. Thus when you move camera left, the world will appear to move right.)

About the Project

This week I created a Maya plugin, based on code provided to us by our professor, to export objects created in Maya to my Lua based human readable file format (which I made last week) which then imported the meshes into the game.

The Maya plugin code was a project we added to our solution called MayMeshExporter (MME). Once importing it into my code solution and assigning the proper property sheets, as well as setting the path environment variables for maya and for the maya plugin, no other settings were required (i.e. no project build dependencies nor references). This is because, while the game relies on the output from Maya via the plugin for the mesh data, the output of the MayaMeshExporter is the plugin for Maya, not the mesh data itself. So once the exporter is built we can manually export our objects, and then build the solution to have the MeshBuilder project “build” the mesh files. Essentially as long as we have some files for our meshes, either from the MME or manually made, at build time then we have what we need for our game. And since the MME doesn’t rely on any of the projects in our solution, no references were needed.

I think it’s neat that you can use Visual Studio to debug running programs. I did this with my maya plugin. Here I put a breakpoint inside the “initializePlugin” which is used to load the plugin in Maya.

I’ve used this (the attach debugger to process) frequently when debugging code for Unity and Unreal based projects.  It’s incredibly helpful to be able to step through your code this way.

With the MME working, I had a plugin to export data. So I created my plane and a new object for the player game object in Maya, set some vertex colors, and exported. This is what I had:

Maya creates more data than I was using: tangent, bitangent, texcoords, and normals. I chose to export all of them as it was a simple process to export them into my human readable file, and they are just ignored by the mesh import. I decided to do this so that if I chose to include these things in the future in my game it would be one less step I’d have to code in. This was actually helpful then when I added textures to my 3D objects…

The last thing I did was add textures to the meshes. This was a fairly straightforward process, though there were several steps involved, since I had done this previously for the UI elements, and didn’t take that long. This change touched code in graphics  (the renderer thread, meshes, and the shaders), to the game graphic objects (where the 3DObjects are stored), to the game itself, but I’m really liking the result!

After applying textures to the meshes the game looks like this:

And… it’s ready for snowfall!

Assignment 10: Mesh Asset Now Loads from File Using Lua, Still in 3D!

This week’s game. One-click download, unzip, play, enjoy! 😀

NancyNewren_ExampleGame 10

What’s New
The only gameplay changes from last week are the colors. Enjoy! 😀

Controls
Main object: Use arrow keys to move
Camera:  
Left/Right (A/D), Up/down (W/S), Zoom in/out (Q/E)
(When moving the camera things in the world will appear to move opposite. Thus when you move camera left, the world will appear to move right.)

About the Project

This week I moved the creation of mesh assets from hard coded to Lua files… and then played with updating the colors just using the Lua files. It was fun! (At least the last part. Ha ha!) Having the Lua files for the assets is really neat because this opens the possibility to having other tools and programs create the asset files. More than making asset files data driven though, the idea of the raw asset file is to be human readable to make it easy to read, understand, and most importantly debug. In the future I’ll take the human readable file and a binary, but the important thing is when you run into a problem with an asset you want a human readable file that you can quickly and easily read and understand so you can quickly and easily get to debugging.

For instance, this is my floor mesh file:


The order of the indices for the index buffer matters, so it was an easy decision to make the indices an array type table. For the vertices, since the order of the indices maters, that means, that though the vertices can be listed in any order they must be listed in a predictable order, so the vertices table also needed to be an array (as a lua table type dictionary has no predictable order).  I decided to group vertex values all together (i.e. a vertex is defined as a position and a color), as I believed that this would make debugging simpler when there are over 100 vertices.

My final decision was to use an array type table for both position and color values as position in math is always ordered (x,y,z), and anyone who knows graphics, when they see 3{4} color values expects (r,g,b,(a)), so I didn’t feel the need to make the color and position tables dictionaries, but it could have been done. I felt though that it was more readable to see the values without extra “x=” and “a=” to clutter the tables.

Additionally

The Lua asset loading took longer than I expected to implement. I thought the hardest part would be switching meshes from pointers to handles (since they now are loading from file like the textures), but turns out it was reading in the Lua files! It’s hard to keep track of the stack! I got stuck being worried I’d lose the stack, so I finally drew myself a picture of all the load and pop points and coded them right the first try! Booyah!

When I started the implementation to Lua file loading, I confused myself quite completely. Zeno helped straighten me out though so I didn’t waste any time. I also have struggled a bit throughout the semester remembering all the c++ syntax as it has been about three years since I last coded in it regularly. While I have been improving all semester, I still got stuck on a couple things, but Zeno was right there with those pieces of c++ syntax I got stuck on right when I needed them.

One More Thing!

Since the Lua files store color as values [0.0f, 1.0f], and the vertex struct expects uint8_t’s, there was a simple conversion of the float * 255. But since computers don’t round, you can end up with numbers like 234.99 and the uint8_t will store 234, not 235. An incredibly simple way around this is, after doing your multiplication, just add 0.5f. Then 234.99 is now 235.49, which truncates to 235. Done and done.

Assignment 9: Now in 3D!

NancyNewren_ExampleGame 09

(Simple one-click download. Once downloaded, unzip, play the executable, enjoy!)

Movement

Main object: Use arrow keys to move left/right and up/down
Camera:  
Left/Right (A/D), Up/down (W/S), Zoom in/out (Q/E)
(When moving the camera things in the world will appear to move opposite. Thus when you move camera left, the world will appear to move right.)

About the Project

This week I completed the transformation of the game to 3D. To accomplish this I added a third dimension: depth. Then added three matrix transformations to take 3D objects from their local space (at their origin and facing forward), to world space (where the object is in relation to the origin of the world), to camera space (where the object in the world is in relation to the observer, or camera).

Local space is essentially where a 3D mesh’s vertices are in relation  to its origin, and we place the object facing forward as convention so we know automatically how to rotate things and how they should appear without even seeing them initially.

World space is where an object is in the world of the game: if we have a city then we have streets and buildings, and we may use the same mesh to represent all those buildings, at the same local space, but in the world they can be all over the map. World space gives us an object in the map of a game.

Finally we have an observer: world space really doesn’t mean anything until we have an observer. In 2D space what we draw to screen is the world we’ve made, but in 3D what we draw to screen depends entirely upon the perspective we are looking at since we are taking something that has 3 dimensions and moving it to two. Without the observer there’s no way to know how to flatten the world. There must be an observer. In this case we call the observer the camera. Since the camera is looking at the world, when the camera moves the world appears to move in the opposite direction (up:down, left:right, forward:back, clockwise:counterclockwise, etc.). To make the math simple, and since moving the camera is just moving the world inversely to the camera: we take the world to the camera.

The last transform we need then is the one to flatten the world to render on screen.

Here’s how the platform independent transform from local space to world space (localToWorld) in the shader looks:

float4 verPosWorld = MultiplyMV(g_transform_localToWorld, float4(i_position, 1.0));

The last thing I did was implement depth buffering so that instead of the last mesh drawn just covering up the previous one, you can actually have meshes covering up parts of each other. This allows us to render the plane and the cube intersecting (without depth buffering the cube or the plane would be covering the other up):

Additionally…

I chose to make the plane double sided: so I used the same four vertices but sent the index buffer 12 points (instead of six) so that you can see the plane from underneath as well as on top, but the plane is still flat (no sides).

I didn’t have time for any optional challenges this week. I had wanted to do camera rotation, but I ended up spending my extra hours on a Visual Studio bug. I was relieved to discover that the bug wasn’t in my implementation, but still the time was gone. Maybe next time.