- Cardboard VR Projects for Android
- Jonathan Linowes Matt Schoen
- 784字
- 2021-07-16 10:54:11
Hello, cube!
A flat triangle floating in 3D space may be amazing, but it's nothing compared to what we're going to do next: a 3D cube!
The cube model data
The triangle, with just three vertices, was declared in the MainActivity
class to keep the example simple. Now, we will introduce more complex geometry. We'll put it in a class named Cube
.
Okay, it's just a cube that is composed of eight distinct vertices, forming six faces, right?
Well, GPUs prefer to render triangles rather than quads, so subdivide each face into two triangles; that's 12 triangles in total. To define each triangle separately, that's a total of 36 vertices, with proper winding directions, defining our model, as shown in CUBE_COORDS
. Why not just define eight vertices and reuse them? We'll show you how to do this later.
In Android Studio, in the Android project hierarchy pane on the left-hand side, find your Java code folder (such as com.cardbookvr.cardboardbox
). Right-click on it, and go to New | Java Class. Then, set Name: Cube, and click on OK. Then, edit the file, as follows (remember that the code for the projects in this book are available for download from the publisher's website and from the book's public GitHub repositories):
package com.cardbookvr.cardboardbox; 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, }; }
Cube code
Returning to the MainActivity
file, we'll just copy/paste/edit the triangle code and reuse it for the cube. Obviously, this isn't ideal, and once we see a good pattern, we can abstract out some of this into reusable methods. Also, we'll use the same shaders as those of the triangle, and then in the next section, we'll replace them with a better lighting model. That is to say, we'll implement lighting or what a 2D artist might call shading, which we haven't done so far.
Like the triangle, we declare a bunch of variables that we are going to need. The vertex count, obviously, should come from the new Cube.CUBE_COORDS
array:
// Model variables private static float cubeCoords[] = Cube.CUBE_COORDS; private final int cubeVertexCount = cubeCoords.length / COORDS_PER_VERTEX; private float cubeColor[] = { 0.8f, 0.6f, 0.2f, 0.0f }; // yellow-ish private float[] cubeTransform; private float cubeDistance = 5f; // Viewing variables private float[] cubeView; // Rendering variables private FloatBuffer cubeVerticesBuffer; private int cubeProgram; private int cubePositionParam; private int cubeColorParam; private int cubeMVPMatrixParam;
Add the following code to onCreate
:
cubeTransform = new float[16]; cubeView = new float[16];
Add the following code to onSurfaceCreated
:
prepareRenderingCube();
Write the prepareRenderingCube
method, as follows:
private void prepareRenderingCube() { // Allocate buffers ByteBuffer bb = ByteBuffer.allocateDirect(cubeCoords.length * 4); bb.order(ByteOrder.nativeOrder()); cubeVerticesBuffer = bb.asFloatBuffer(); cubeVerticesBuffer.put(cubeCoords); cubeVerticesBuffer.position(0); // Create GL program cubeProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(cubeProgram, simpleVertexShader); GLES20.glAttachShader(cubeProgram, simpleFragmentShader); GLES20.glLinkProgram(cubeProgram); GLES20.glUseProgram(cubeProgram); // Get shader params cubePositionParam = GLES20.glGetAttribLocation(cubeProgram, "a_Position"); cubeColorParam = GLES20.glGetUniformLocation(cubeProgram, "u_Color"); cubeMVPMatrixParam = GLES20.glGetUniformLocation(cubeProgram, "u_MVP"); // Enable arrays GLES20.glEnableVertexAttribArray(cubePositionParam); }
We will position the cube 5 units away and rotate it 30 degrees on a diagonal axis of (1, 1, 0). Without the rotation, we'll just see the square of the front face. Add the following code to initializeScene
:
// Rotate and position the cube Matrix.setIdentityM(cubeTransform, 0); Matrix.translateM(cubeTransform, 0, 0, 0, -cubeDistance); Matrix.rotateM(cubeTransform, 0, 30, 1, 1, 0);
Add the following code to onDrawEye
to calculate the MVP matrix, including the cubeTransform
matrix, and then draw the cube:
Matrix.multiplyMM(cubeView, 0, view, 0, cubeTransform, 0); Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, cubeView, 0); drawCube();
Write the drawCube
method, which is very similar to the drawTri
method, as follows:
private void drawCube() { GLES20.glUseProgram(cubeProgram); GLES20.glUniformMatrix4fv(cubeMVPMatrixParam, 1, false, modelViewProjection, 0); GLES20.glVertexAttribPointer(cubePositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, cubeVerticesBuffer); GLES20.glUniform4fv(cubeColorParam, 1, cubeColor, 0); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, cubeVertexCount); }
Build and run it. You will now see a 3D view of the cube, as shown in the following screenshot. It needs shading.

- Linux KVM虛擬化架構實戰指南
- INSTANT ForgedUI Starter
- 計算機組裝與維護(第3版)
- 面向對象分析與設計(第3版)(修訂版)
- Neural Network Programming with Java(Second Edition)
- 數字媒體專業英語(第2版)
- Arduino項目開發:智能生活
- 微控制器的應用
- Mastering Quantum Computing with IBM QX
- Blender for Video Production Quick Start Guide
- 計算機組裝、維護與維修項目教程
- Learning Microsoft Cognitive Services
- PIC系列單片機的流碼編程
- 微型計算機原理及應用教程(第2版)
- Spring微服務實戰(第2版)