Uniform variables are used to communicate with the vertex or fragment shader from "outside". Using a uniform we can access the position of our objects inside the shader from our c++ code. We use this to manipulate the co-ordinates of the object to change the position it is rendered on screen. The uniform functions as a pool of resources that are always available, thus they can be changed after the mesh is built. Rather than changing the vertex data every frame (which is expensive) we can simply add an offset to its position using the uniform and change the place where they are rendered on screen. This is also useful if our mesh is very large. For more vertices, we have a large number of vertex data stored. Iterating through every vertex to modify it every frame is expensive.
My build now looks like in the image below.
You can download the DirectX_64 version here.
You can download the OpenGL_32 version here.
Controls: Use Arrow keys on the keyboard to move the square around.
For this week's assignment the objective was to convert our human readable mesh file into a binary data format which can be accessed at run time to generate our meshes in the game.
The image shows the format of my binary file. I have placed the data in the following order:
Number of vertices
Number of Triangles
I chose this particular format because that was the order in which I was reading the files from the human readable mesh files. So it was convenient to just write it into the binary file in the same order.
The number of elements in the array need to be in the file before the array data so that when reading the data we know how many bytes contain vertex data. In this file the triangle mesh contains 3 vertices as shown with the first 8 digits (03 00 00 00) corresponding to 4 bytes (32 bits) of data. Since each vertex contains 2 floats (x,y) and 4 colors (r, g, b, a), a total of 12 bytes of data, we know that the next 12x3 bytes of data contain data about the 3 vertices.
Here are some of the advantages of using binary files:
The build binary mesh files are different for each platform. The only difference I had in my files was the winding order of the indices. Since OpenGL uses a winding order opposite to DirectX when I write to my binary files I have a different winding order for each platform based on whether it uses a clockwise (Direct_X) or counter-clockwise (OpenGL) format so that it can be read easily during run-time without having to worry about the order of the listed indices.
The image below shows my implementation of extracting the data from the binary file at run time.
I am creating a current pointer to the location that starts at the beginning of the file. I know the first 4 bytes are the number of vertices (3 in this case) I have in my mesh so I read the first 4 bytes into the corresponding variable. I then increment the current pointer to point to the address location after the first 4 bytes. That gives me the vertex data for each of the 3 vertices I have, and so on...
We also set up our shader system so it has a platform independent interface. I created a struct that has the following functionality to load the shaders into the game.
- LoadEffect (sEffect, "data/fragment.shader", "data/vertex.shader");
- SetEffect (sEffect);
The LoadEffect function takes in the paths for the shader files and loads the vertex shader and fragment shader. The SetEffect function is used to set the shaders to display our meshes on screen. The function calls remain the same regardless of the platform.
Download the DirectX_64 build here
Download the OpenGL_32 build here