我正在学习 OpenGL ES 2 进行定向研究,有些事情我不明白。我不太明白传递给 glVertexAttribPointer 的步幅是多少。我也能够绘制一个纯色四面体,但现在我正在尝试扩展它以使每张脸都有不同的颜色。进展不顺利。有人可以帮助解决我在着色器方面做错的事情以及为什么它会绘制时髦/不正确旋转的颜色。我使用http://www.learnopengles.com/android-lesson-two-ambient-and-diffuse-lighting/作为理解绘图工作原理的基础。任何有关了解着色器如何工作和步幅等以及我做错了什么的帮助将不胜感激。
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);
}
}