For demonstration purposes, we'll start with a simple cube. Later on, we'll improve it with lighting. In Chapter 3, Cardboard Box, we defined a Cube
model. We'll start by using the same class and data structure here. You can even copy the code, but it's shown in the following text. Create a Cube
Java class in the renderbox/components/
folder:
// File: renderbox/components/Cube.java public class Cube { public static final float[] CUBE_COORDS = new float[] { // Front face -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // Right face 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, // Back face 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, // Left face -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // Top face -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, // Bottom face 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, }; public static final float[] CUBE_COLORS_FACES = new float[] { // Front, green 0f, 0.53f, 0.27f, 1.0f, // Right, blue 0.0f, 0.34f, 0.90f, 1.0f, // Back, also green 0f, 0.53f, 0.27f, 1.0f, // Left, also blue 0.0f, 0.34f, 0.90f, 1.0f, // Top, red 0.84f, 0.18f, 0.13f, 1.0f, // Bottom, also red 0.84f, 0.18f, 0.13f, 1.0f }; /** * Utility method for generating float arrays for cube faces * * @param model - float[] array of values per face. * @param coords_per_vertex - int number of coordinates per vertex. * @return - Returns float array of coordinates for triangulated cube faces. * 6 faces X 6 points X coords_per_vertex */ public static float[] cubeFacesToArray(float[] model, int coords_per_vertex) { float coords[] = new float[6 * 6 * coords_per_vertex]; int index = 0; for (int iFace=0; iFace < 6; iFace++) { for (int iVertex=0; iVertex < 6; iVertex++) { for (int iCoord=0; iCoord < coords_per_vertex; iCoord++) { coords[index] = model[iFace*coords_per_vertex + iCoord]; index++; } } } return coords; } }
We list the coordinates for each face of the cube. Each face is made up of two triangles, resulting in 12 triangles, or a total of 36 sets of coordinates to define the cube.
We also list the different colors for each face of the cube. Rather than duplicating the colors 36 times, there's the cubeFacesToArray
method to generate them.
Now, we need to upgrade Cube
for RenderBox
.
First, add the words extends
RenderObject
. This will provide the super()
method in the constructor and allow you to call the draw()
method:
public class Cube extends RenderObject {
Allocate buffers for its vertices and colors, and create the Material
class that'll be used for rendering:
public static FloatBuffer vertexBuffer; public static FloatBuffer colorBuffer; public static final int numIndices = 36; public Cube(){ super(); allocateBuffers(); createMaterial(); } public static void allocateBuffers(){ //Already setup? if (vertexBuffer != null) return; vertexBuffer = allocateFloatBuffer(CUBE_COORDS); colorBuffer = allocateFloatBuffer(cubeFacesToArray(CUBE_COLORS_FACES, 4)); } public void createMaterial(){ VertexColorMaterial mat = new VertexColorMaterial(); mat.setBuffers(vertexBuffer, colorBuffer, numIndices); material = mat; }
We ensure that allocateBuffers
is run only once by checking whether vertexBuffer
is null
.
We plan to use the VertexColorMaterial
class for rendering most cubes. That will be defined next.
A Camera
component will call the draw
method of the Cube
class (inherited from RenderObject
), which, in turn, calls the Material
class's draw
method. The draw
method will be called from the main Camera
component as it responds to the Cardboard SDK's onDrawEye
hook.