我正在开发一个使用OpenGL ES 2.0的Android应用程序
由于这是我第一次使用OpenGL(我曾经使用过WebGL),因此我制作了一个自定义且非常简单的API,如THREE.js,它包含Object3D
和Geometry
个对象。
基本上,我所做的是:将形状存储在Geometry
对象中,并使用里面的几何实例创建Mesh
个对象。此外,在Mesh
内,我有:Vector3
对象:position
,scale
,rotation
。
我创建了一个圆圈进行测试,这就是正在发生的事情
如果我不改变任何东西,那么圆圈在屏幕上是完美的。如果我在创建圆圈时更改顶点位置,圆圈仍然是正常的。
但是,当我进行一些转换(更改属性位置,缩放或旋转)或Object3D(在本例中为Mesh)时,圆圈变为“strech”。
所以,我认为projectionMatrix存在一些问题,但是如果我不对它进行转换就可以了。
我的矩阵代码有问题吗?我应该将旋转,平移和缩放矩阵发送到GPU吗?
也许我让事情变得复杂,但由于这是我在阅读大量信息后第一次使用OpenGL,所以这是可以接受的......
这是Object3D代码:
public class Object3D {
public Vector3 position = new Vector3();
public Vector3 rotation = new Vector3();
public Vector3 scale = new Vector3();
public Color color = new Color();
public float[] getMVMatrix(){
// Initialize matrix with Identity
float[] mvMatrix = new float[16];
Matrix.setIdentityM(mvMatrix, 0);
// apply scale
Matrix.scaleM(mvMatrix, 0, scale.x, scale.y, scale.z);
// set rotation
Matrix.setRotateM(mvMatrix, 0, rotation.x, 1f, 0, 0);
Matrix.setRotateM(mvMatrix, 0, rotation.y, 0, 1f, 0);
Matrix.setRotateM(mvMatrix, 0, rotation.z, 0, 0, 1f);
// apply translation
Matrix.translateM(mvMatrix, 0, position.x, position.y, position.z);
return mvMatrix;
}
}
这是Geometry类,它简化了三角形的使用:
public class Geometry {
// Public, to allow modifications
public ArrayList<Vector3> vertices;
public ArrayList<Face3> faces;
// Type of Geometry
public int triangleType = GLES20.GL_TRIANGLES;
[...]
public FloatBuffer getVerticesBuffer(){
if(verticesBuffer == null || verticesBufferNeedsUpdate){
/*
* Cache faces
*/
int size = vertices.size();
// (size of Vector3 list) * (3 for each object) * (4 bytes per float)
ByteBuffer bb = ByteBuffer.allocateDirect( size * 3 * 4 );
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// Get the ByteBuffer as a floatBuffer
verticesBuffer = bb.asFloatBuffer();
for(int i = 0; i < size; i++)
verticesBuffer.put(vertices.get(i).toArray());
verticesBufferNeedsUpdate = false;
}
verticesBuffer.position(0);
return verticesBuffer;
}
public ShortBuffer getFacesBuffer(){
if(facesBuffer == null || facesBufferNeedsUpdate){
/*
* Cache faces
*/
int size = faces.size();
// Log.i(TAG, "FACES Size: "+size);
// (size of Vector3 list) * (3 for each object) * (2 bytes per short)
ByteBuffer bb = ByteBuffer.allocateDirect( size * 3 * 2 );
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// Get the ByteBuffer as a floatBuffer
facesBuffer = bb.asShortBuffer();
for(int i = 0; i < size; i++)
facesBuffer.put(faces.get(i).toArray());
facesBufferNeedsUpdate = false;
}
facesBuffer.position(0);
return facesBuffer;
}
}
此外,Mesh类负责重新定位Geometry
个对象:
public class Mesh extends Object3D{
[...]
public void draw(float[] projectionMatrix, int shaderProgram){
float[] MVMatrix = getMVMatrix();
Matrix.multiplyMM(projectionMatrix, 0, projectionMatrix, 0, MVMatrix, 0);
// Check if geometry is set
if(geometry == null){
Log.i(TAG, "Geometry is null. skiping");
return;
}
// Add program to OpenGL environment
GLES20.glUseProgram(shaderProgram);
// Get, enable and Set the position attribute
positionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
GLES20.glEnableVertexAttribArray(positionHandle);
// Prepare the triangles coordinate data
Buffer vertexBuffer = geometry.getVerticesBuffer();
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
COORDS_PER_VERTEX*4,
vertexBuffer);
// get handle to fragment shader's vColor member
int mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color.toArray(), 0);
// get handle to shape's transformation matrix
int mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
ChwaziSurfaceView.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, projectionMatrix, 0);
ChwaziSurfaceView.checkGlError("glUniformMatrix4fv");
// Draw the triangles
if(geometry.triangleType == GLES20.GL_TRIANGLES){
Buffer indexesBuffer = geometry.getFacesBuffer();
GLES20.glDrawElements(
GLES20.GL_TRIANGLES,
geometry.faces.size()*3,
GL10.GL_UNSIGNED_SHORT,
indexesBuffer);
}else{
GLES20.glDrawArrays(geometry.triangleType, 0, geometry.vertices.size());
ChwaziSurfaceView.checkGlError("glDrawArrays");
}
// Disable vertex array
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
这是我测试它是否正常工作(只是翻译)的示例代码
// Inside my Renderer...
@Override
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK);
// Set the camera position (View matrix)
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);
// Create a rotation for the triangle
long time = SystemClock.uptimeMillis();// % 4000L;
myMesh.position.x = (time%4000)/4000f;
myMesh.draw(mMVPMatrix, shaderProgram.getProgram());
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// this projection matrix is applied to object coordinates
Matrix.orthoM(mProjMatrix, 0, -1, 1, -1, 1, 0, 10);
}
修改
着色器代码:
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
" gl_Position = vPosition * uMVPMatrix;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";