Reputation: 334
I'm learning OpenGL ES 2 for a directed study and there are some things i'm not understanding. I don't quite understand what stride is that is passed to glVertexAttribPointer. Also i was able to draw a solid color tetrahedron, but now i'm trying to expand it to make every face a different color. It is not going well. Could someone help with what i'm doing wrong in terms of the shaders and why it draws the colors funky/doesn't rotate right. I was using http://www.learnopengles.com/android-lesson-two-ambient-and-diffuse-lighting/ as a base for understanding how drawing works. Any help with understanding how shaders work and the stride and so forth and what i'm doing wrong would be greatly appreciated.
package com.example.lab5task1;
//middle of screen is 0,0. To left/right is -/+ x, up/down is +/- y
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Point;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
public class MyGLRenderer implements GLSurfaceView.Renderer
{
private static final String TAG = "MyGLRenderer";
private Tetrahedron mTet;
private float height, width;
public float xTouch, yTouch;
Random rand = new Random();
private final float[] mMVPMatrix = new float[16]; //model view and projection matrix
private final float[] mProjMatrix = new float[16]; //projection matrix
private final float[] mVMatrix = new float[16]; //view matrix
private final float[] mRotationMatrix = new float[16]; //rotation matrix
private float[] drawColor = { rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), 1f };
private float[] mModelMatrix = new float[16];
@SuppressLint("NewApi")
MyGLRenderer(Context context)
{
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
//used for correct drawing and touch
this.height = size.y;
this.width = size.x;
this.xTouch = this.yTouch = 0;
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Use culling to remove back faces.
GLES20.glEnable(GLES20.GL_CULL_FACE);
// Enable depth testing
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//eye positions
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = -3f;
// We are looking toward the distance
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = -1.0f;
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
// Set the view matrix. This matrix can be said to represent the camera position.
Matrix.setLookAtM(mVMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
}
@Override
public void onDrawFrame(GL10 unused)
{
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
long time = SystemClock.uptimeMillis() % 10000L;
float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
mTet = new Tetrahedron();
// Draw the triangle facing straight on.
Matrix.setIdentityM(mRotationMatrix, 0);
Matrix.rotateM(mRotationMatrix, 0, angleInDegrees, .5f, .5f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
mTet.draw(mMVPMatrix);
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height)
{
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES20.glViewport(0, 0, width, height);
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 10.0f;
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
}
public 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 static void checkGlError(String glOperation)
{
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)
{
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
class Tetrahedron
{
enum STYLE
{
OLD, NEW
};
private STYLE codeType = STYLE.NEW;
private final FloatBuffer vertexBuffer;
private final FloatBuffer mColors;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private int mMVMatrixHandle;
private final String vertexShaderCode = "uniform mat4 uMVPMatrix;" + " attribute vec4 vPosition;" + "void main() {" + " gl_Position = vPosition * uMVPMatrix;" + "}";
private final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}";
// number of coordinates per vertex in this array
// 72d angles at center, 108 angle at vertex
static final int COORDS_PER_VERTEX = 3;
static final int COLOR_DATA_SIZE = 4;
static float tetCoords[] = { 0.0f, 0.622008459f, 0.0f,//
-0.5f, -0.311004243f, 0.0f,//
0.5f, -0.311004243f, 0.0f,//
0.0f, 0.0f, .622008459f };
static float colors[] = {
//face one
1.0f, 0.0f, 0.0f, 1.0f,//
1.0f, 0.0f, 0.0f, 1.0f,//
1.0f, 0.0f, 0.0f, 1.0f,//
//face two
0.0f, 1.0f, 0.0f, 1.0f,//
0.0f, 1.0f, 0.0f, 1.0f,//
0.0f, 1.0f, 0.0f, 1.0f,//
//face three
0.0f, 0.0f, 1.0f, 1.0f,//
0.0f, 0.0f, 1.0f, 1.0f,//
0.0f, 0.0f, 1.0f, 1.0f,//
//face four
1.0f, 1.0f, 0.0f, 1.0f,//
1.0f, 1.0f, 0.0f, 1.0f,//
1.0f, 1.0f, 0.0f, 1.0f,//
};
String[] attributes = { "a_Position", "a_Color" };
private short drawOrder[] = { 0, 1, 2, 3, 0, 1 };
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private final int colorStride = COLOR_DATA_SIZE * 4;
float color[] = { .5f, .5f, .5f, 1f };
public Tetrahedron()
{
// initialize vertex byte buffer for shape coordinates
//this.color = color;
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
tetCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(tetCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
// (# of coordinate values * 2 bytes per short)
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
mColors = ByteBuffer.allocateDirect(colors.length * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer();
mColors.put(colors);
mColors.position(0);
if (codeType == STYLE.NEW)
{
final String vertexShader = getVertexShader();
final String fragmentShader = getFragmentShader();
int vertexShaderHandle = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShader);
int fragmentShaderHandle = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShader);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShaderHandle);
GLES20.glAttachShader(mProgram, fragmentShaderHandle);
for (int i = 0; i < attributes.length; i++)
{
GLES20.glBindAttribLocation(mProgram, i, attributes[i]);
}
GLES20.glLinkProgram(mProgram);
}
else
{
int vertexShaderHandle = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShaderHandle = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShaderHandle);
GLES20.glAttachShader(mProgram, fragmentShaderHandle);
for (int i = 0; i < attributes.length; i++)
{
GLES20.glBindAttribLocation(mProgram, i, attributes[i]);
}
GLES20.glLinkProgram(mProgram);
}
}
protected String getVertexShader()
{
// TODO: Explain why we normalize the vectors, explain some of the vector math behind it all. Explain what is eye space.
final String vertexShader = "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "uniform mat4 u_MVMatrix; \n" // A constant representing the combined model/view matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
// Transform the vertex into eye space.
+ " vec3 modelViewVertex = vec3(u_MVMatrix * a_Position); \n"
// Multiply the color by the illumination level. It will be interpolated across the triangle.
+ " v_Color = a_Color; \n"
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
+ " gl_Position = u_MVPMatrix * a_Position; \n" + "} \n";
return vertexShader;
}
protected String getFragmentShader()
{
final String fragmentShader = "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
// triangle per fragment.
+ "void main() \n" // The entry point for our fragment shader.
+ "{ \n" + " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline.
+ "} \n";
return fragmentShader;
}
public void draw(float[] mvpMatrix)
{
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
if (codeType == STYLE.NEW)
{
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVMatrix");
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");
mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color");
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
false, vertexStride, vertexBuffer);
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false,
colorStride, mColors);
GLES20.glEnableVertexAttribArray(mColorHandle);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
}
else
{
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
false, vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
}
// Draw the square
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT,
drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
Upvotes: 0
Views: 1900
Reputation: 457
You're passing 4 vertices, and 12 colours. You're specifying 1 vec4 colour for verts 0-11, and only drawing triangles between indices 0-3, so only the first 4 of your colours are being used.
Upvotes: 1
Reputation: 4950
The stride is the distance between attributes in bytes, and is used if you are packing more than one attribute into the same array. It seems that you're using one array per attribute here, so you could pass in 0 as the stride to tell OpenGL that the attributes are tightly packed.
Your position and color arrays should be the same length in terms of components. i.e. one position for one color. This is probably why the colors are not coming out as you expect.
If you want each face to be a different, solid, color, setup the vertices so that each triangle is distinct, and draw with GL_TRIANGLES. For example:
{ 0f, 1f, 0f, // Left
-1, 0f, 1f,
-1, 0f, -1f,
0f, 1f, 0f, // Right
1f, 0f, 1f,
1f, 0f, 1f,
0f, 1f, 0f, // Near
-1f, 0f, 1f,
1f, 0f, 1f,
0f, 1f, 0f, // Far
-1f, 0f, -1f,
1f, 0f, -1f }
and draw with GL_TRIANGLES. Let us know if this leads to an improvement!
Upvotes: 0