Last active
January 20, 2016 20:11
-
-
Save marktani/532bfc8deb38fed021bf to your computer and use it in GitHub Desktop.
CardboardCube article
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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