尝试渲染使用库加载的 .obj 时,我调用 glDrawArrays 时发生崩溃。我不知道发生了什么,因为这是我第一次使用 openGL ES。我的猜测是三角形的数量是错误的,在尝试使用 10 作为参数的 glDrawArrays 之后,我意识到这可能不是问题。
我的渲染器的代码:
private class RocketArrowRenderer implements GLSurfaceView.Renderer {
private final int mBytesPerFloat = 4;
private Context mContext;
private FloatBuffer mVertices;
private int mMVPMatrixHandle;
private int mPositionHandle;
private float[] mModelMatrix = new float[16];
private int mColorHandle;
private float[] mMVPMatrix = new float[16];
private final int mStrideBytes = 3 * mBytesPerFloat;
private final int mPositionOffset = 0;
private final int mPositionDataSize = 3;
private final int mColorOffset = 3;
private final int mColorDataSize = 4;
private float[] mViewMatrix = new float[16];
final String vertexShader =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "uniform 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"
+ " v_Color = a_Color; \n" // Pass the color through to the fragment shader.
// It will be interpolated across the triangle.
+ " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position.
+ " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in
+ "} \n"; // normalized screen coordinates.
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";
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = 25.0f;
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = 0.0f;
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
private boolean mObjLoaded = false;
public RocketArrowRenderer(Context context)
{
mContext = context;
new Thread(new Runnable() {
public void run() {
Resources res = mContext.getResources();
InputStream inputStream = res.openRawResource(R.raw.falcon_heavy_obj);
Obj obj = null;
try {
obj = ObjUtils.convertToRenderable(ObjReader.read(inputStream));
} catch (IOException e) {
e.printStackTrace();
}
mVertices = ObjData.getVertices(obj);
mObjLoaded = true;
}
}).start();
}
@Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if (vertexShaderHandle != 0)
{
GLES20.glShaderSource(vertexShaderHandle, vertexShader);
GLES20.glCompileShader(vertexShaderHandle);
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
}
}
if (vertexShaderHandle == 0)
{
throw new RuntimeException("Error creating vertex shader.");
}
// Load in the vertex shader.
int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if(fragmentShader != null){
GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
GLES20.glCompileShader(fragmentShaderHandle);
final int[] compileStatus2 = new int[1];
GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus2, 0);
if(compileStatus2[0] == 0){
GLES20.glDeleteShader(fragmentShaderHandle);
fragmentShaderHandle = 0;
}
}
if(fragmentShader == null){
throw new RuntimeException("Error creating fragment shader");
}
int programHandle = GLES20.glCreateProgram();
if (programHandle != 0)
{
GLES20.glAttachShader(programHandle, vertexShaderHandle);
GLES20.glAttachShader(programHandle, fragmentShaderHandle);
GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
GLES20.glLinkProgram(programHandle);
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0)
{
GLES20.glDeleteProgram(programHandle);
programHandle = 0;
}
}
if (programHandle == 0) {
throw new RuntimeException("Error creating program.");
}
mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
GLES20.glUseProgram(programHandle);
}
private float[] mProjectionMatrix = new float[16];
@Override
public void onSurfaceChanged(GL10 glUnused, int width, int height)
{
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 = 8.0f;
final float near = 1.0f;
final float far = 10.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
@Override
public void onDrawFrame(GL10 glUnused)
{
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setIdentityM(mModelMatrix, 0);
if(mObjLoaded){
draw();
}
}
private void draw() {
int numberOfTriangles = mVertices.position(0).remaining() / 3;
//mVertices.position(mPositionOffset);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
0, 0);
GLES20.glEnableVertexAttribArray(mPositionHandle);
//and later, in draw
GLES20.glUniform4f(mColorHandle, 1.0f, 0.0f, 0.0f, 1.0f); //red!
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, numberOfTriangles);
}
}