Skip to content

Instantly share code, notes, and snippets.

@marktani
Last active January 20, 2016 20:11
Show Gist options
  • Save marktani/532bfc8deb38fed021bf to your computer and use it in GitHub Desktop.
Save marktani/532bfc8deb38fed021bf to your computer and use it in GitHub Desktop.
CardboardCube article
import android.opengl.Matrix;
import java.util.ArrayList;
import java.util.List;
public class Cube {
private boolean isInitialized;
// PLANES
public static final int FACES_PER_CUBE = 6;
private Plane[] planes = new Plane[FACES_PER_CUBE];
// TRANSFORMS
private List<float[]> transforms = new ArrayList<>();
// SCALE
private static final int SIDE_LENGTH = 10;
private static final float HALF_SIDE_LENGTH = SIDE_LENGTH / 2.0f;
List<float[]> scales = new ArrayList<>();
// TRANSLATIONS
private static final float[] POSITION_AHEAD = {0, 0, HALF_SIDE_LENGTH};
private static final float[] POSITION_RIGHT = {-HALF_SIDE_LENGTH, 0, 0};
private static final float[] POSITION_BEHIND = {0, 0, -HALF_SIDE_LENGTH};
private static final float[] POSITION_LEFT = {HALF_SIDE_LENGTH, 0, 0};
private static final float[] POSITION_TOP = {0, HALF_SIDE_LENGTH, 0};
private static final float[] POSITION_BOTTOM = {0, -HALF_SIDE_LENGTH, 0};
List<float[]> translations = new ArrayList<>();
// ROTATIONS
private static final float[] ROTATION_AHEAD_FIRST = {90, 1, 0, 0};
private static final float[] ROTATION_AHEAD_SECOND = {180, 0, 1, 0};
private static final float[] ROTATION_RIGHT_FIRST = {-90, 0, 0, 1};
private static final float[] ROTATION_RIGHT_SECOND = {90, 1, 0, 0};
private static final float[] ROTATION_BEHIND_FIRST = {90, 1, 0, 0};
private static final float[] ROTATION_LEFT_FIRST = {90, 0, 0, 1};
private static final float[] ROTATION_LEFT_SECOND = {90, 1, 0, 0};
private static final float[] ROTATION_TOP_FIRST = {-90, 0, 1, 0};
private static final float[] ROTATION_TOP_SECOND = {180, 0, 0, 1};
private static final float[] ROTATION_BOTTOM_FIRST = {-90, 0, 1, 0};
List<float[]> rotations = new ArrayList<>();
// FACE CONSTANTS
public static final int FACE_AHEAD = 0;
public static final int FACE_RIGHT = 1;
public static final int FACE_BEHIND = 2;
public static final int FACE_LEFT = 3;
public static final int FACE_TOP = 4;
public static final int FACE_BOTTOM = 5;
public static final int[] FACES = {
FACE_AHEAD,
FACE_RIGHT,
FACE_BEHIND,
FACE_LEFT,
FACE_TOP,
FACE_BOTTOM
};
public Cube() {
initializeTransforms();
initializePlanes();
isInitialized = false;
}
private void initializeTranslations() {
translations.add(buildTranslationMatrix(POSITION_AHEAD));
translations.add(buildTranslationMatrix(POSITION_RIGHT));
translations.add(buildTranslationMatrix(POSITION_BEHIND));
translations.add(buildTranslationMatrix(POSITION_LEFT));
translations.add(buildTranslationMatrix(POSITION_TOP));
translations.add(buildTranslationMatrix(POSITION_BOTTOM));
}
private void initializeRotations() {
rotations.add(buildRotationMatrix(ROTATION_AHEAD_SECOND, ROTATION_AHEAD_FIRST));
rotations.add(buildRotationMatrix(ROTATION_RIGHT_SECOND, ROTATION_RIGHT_FIRST));
rotations.add(buildRotationMatrix(ROTATION_BEHIND_FIRST));
rotations.add(buildRotationMatrix(ROTATION_LEFT_SECOND, ROTATION_LEFT_FIRST));
rotations.add(buildRotationMatrix(ROTATION_TOP_SECOND, ROTATION_TOP_FIRST));
rotations.add(buildRotationMatrix(ROTATION_BOTTOM_FIRST));
}
private void initializeScales() {
scales.add(buildScaleMatrix(SIDE_LENGTH));
scales.add(buildScaleMatrix(SIDE_LENGTH));
scales.add(buildScaleMatrix(SIDE_LENGTH));
scales.add(buildScaleMatrix(SIDE_LENGTH));
scales.add(buildScaleMatrix(SIDE_LENGTH));
scales.add(buildScaleMatrix(SIDE_LENGTH));
}
private void initializeTransforms() {
initializeTranslations();
initializeRotations();
initializeScales();
for (int i = 0; i < FACES_PER_CUBE; ++i) {
transforms.add(computeTransform(translations.get(i), rotations.get(i), scales.get(i)));
}
}
private void initializePlanes() {
for (int i = 0; i < FACES_PER_CUBE; ++i) {
planes[i] = new Plane();
}
}
public void initialize() {
for (Plane plane : planes) {
plane.initializeProgram();
}
isInitialized = true;
};
public void draw(float[] mvpMatrix) {
if (!isInitialized)
throw new RuntimeException("Cube not initialized!");
float[] modelView = new float[16];
for (int i = 0; i < FACES_PER_CUBE; ++i) {
// transform mvpMatrix with the transform specific to this plane
Matrix.multiplyMM(modelView, 0, mvpMatrix, 0, transforms.get(i), 0);
planes[i].draw(modelView);
}
}
private float[] computeTransform(float[] translationMatrix, float[] rotationMatrix, float[] scaleMatrix) {
// R*S
float[] rsMatrix = new float[16];
Matrix.multiplyMM(rsMatrix, 0, rotationMatrix, 0, scaleMatrix, 0);
// T*R*S
float[] trsMatrix = new float[16];
Matrix.multiplyMM(trsMatrix, 0, translationMatrix, 0, rsMatrix, 0);
return trsMatrix;
}
private float[] buildTranslationMatrix(float[] translation) {
float[] translationMatrix = new float[16];
Matrix.setIdentityM(translationMatrix, 0);
Matrix.translateM(translationMatrix, 0, translation[0], translation[1], translation[2]);
return translationMatrix;
}
private float[] buildRotationMatrix(float[] rotation) {
float[] rotationMatrix = new float[16];
Matrix.setRotateM(rotationMatrix, 0, rotation[0], rotation[1], rotation[2], rotation[3]);
return rotationMatrix;
}
private float[] buildRotationMatrix(float[] rotation_l, float[] rotation_r) {
float[] L = buildRotationMatrix(rotation_l);
float[] R = buildRotationMatrix(rotation_r);
float[] rotationMatrix = new float[16];
Matrix.multiplyMM(rotationMatrix, 0, L, 0, R, 0);
return rotationMatrix;
}
private float[] buildScaleMatrix(float scale) {
float[] scaleMatrix = new float[16];
Matrix.setIdentityM(scaleMatrix, 0);
Matrix.scaleM(scaleMatrix, 0, scale, scale, scale);
return scaleMatrix;
}
public void randomizeColors() {
for (int i = 0; i < FACES_PER_CUBE; ++i) {
planes[i].randomizeColor();
}
}
}
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class Plane {
private static final int COORDS_PER_VERTEX = 3;
private static final int VERTICES_PER_PLANE = 4;
private static final float[] VERTICES = {
-0.5f, 0.0f, 0.5f, // left front
-0.5f, 0.0f, -0.5f, // left back
0.5f, 0.0f, 0.5f, // right front
0.5f, 0.0f, -0.5f // right back
};
private static final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private static final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private FloatBuffer vertexBuffer;
private int program;
// Handles
private int positionHandle;
private int mvpMatrixHandle;
private int colorHandle;
float color[] = new float[4];
public Plane() {
randomizeColor();
buildVertexBuffer();
}
public void randomizeColor() {
color[0] = (float) Math.random();
color[1] = (float) Math.random();
color[2] = (float) Math.random();
color[3] = 1.0f;
}
private void buildVertexBuffer() {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES_PER_PLANE * COORDS_PER_VERTEX * Float.SIZE);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(VERTICES);
vertexBuffer.position(0);
}
public void initializeProgram() {
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
// create empty OpenGL ES Program
program = GLES20.glCreateProgram();
// add the vertex shader to program
GLES20.glAttachShader(program, vertexShader);
// add the fragment shader to program
GLES20.glAttachShader(program, fragmentShader);
// creates OpenGL ES program executables
GLES20.glLinkProgram(program);
}
private static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void draw(float[] mvpMatrix) {
GLES20.glUseProgram(program);
// get handles
positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
mvpMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
colorHandle = GLES20.glGetUniformLocation(program, "vColor");
// prepare coordinates
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer);
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
// Set color for the plane
GLES20.glUniform4fv(colorHandle, 1, color, 0);
// Draw the plane
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTICES_PER_PLANE);
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment