矩阵只是一组变换的参数的承载体:
比如我要让一个物体旋转——让这个物体和我的旋转矩阵运算。
比如我要让一个物体放大——让这个物体和我的拉伸矩阵运算。
比如我要让一个物体平移——让这个物体和我的平移矩阵运算。
如果一个矩阵同时承载了旋转,拉伸和平移的变换参数,那么物体和它运算之后,就会同时进行旋转,拉伸和平移。
OpenGL我的理解是它内置了一个矩阵链,属于系统级的矩阵链,或者叫矩阵栈。反正就是一串矩阵。
任何你执行的绘制操作,默认都会进行这一串矩阵进行的变换。系统矩阵里面最基本的两个矩阵就是投影矩阵和视图矩阵(或者叫模型变换矩阵)后面会讲到。
投影矩阵决定的是最后眼睛看到的屏幕的长宽比例等,因为屏幕大小是不固定的,有些人是宽屏,有些人是标屏,有些人19寸,有些人17寸。手机上只有3-5寸等等。
为了保证最后物体看上去大小比例都是合适的,需要进行一个拉伸压缩的转换,这个转换就是投影矩阵干的事。
视图矩阵起的作用是决定视角的,玩过CS或者CF就晓得了,人在场景里面往前走,实际上专业叫法就是视角和视点在移动。而OpenGL里面没有专门的视角和视点的算法,它是通过将整个世界进行移动、旋转,来模拟出人在里面行走漫游的效果。比如你向前走100米,实际上和把整个世界往后移100米,最后看到的效果是一样的。
以上说的两个矩阵在代码里都会用到,后面有详细的代码演示
public class MyGLSurfaceView extends GLSurfaceView implements Renderer {
public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyGLSurfaceView(Context context) {
super(context);
init();
}
private void init(){
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
public void onDrawFrame(GL10 gl) {
}
}
public class MainActivity extends Activity {
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
MyGLSurfaceView glsurface = new MyGLSurfaceView(this);
this.setContentView(glsurface);
}
}
private void init(){
this.setEGLContextClientVersion(1);
this.setRenderer(this);
}
这时候其实已经可以启动程序了,你会看到屏幕上什么都没有,但是onDrawFrame已经会不停的执行了,执行频率又叫帧率fps(frame per sesond)。
第三节 添加模型。
public void onSurfaceCreated(GL10 gl, EGLConfig config) {public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES10.glViewport(0, 0, width, height); // 设置视口宽度高度。
// {修改投影矩阵
GLES10.glMatrixMode(GLES10.GL_PROJECTION); // 修改投影矩阵
GLES10.glLoadIdentity(); // 复位,将投影矩阵归零
GLU.gluPerspective(gl, 60.0f, ((float) width) / height, 1.0f, 300.0f); // 最近和最远可以看到的距离,超过最远将不显示。
// }
}
第三个函数gluPerspective,注意它前缀是glu,它不属于标准OpenGLES的函数,属于辅助函数。它用于用人们很容易理解的方式来构建参数,而得到一个投影矩阵。
因为投影矩阵依然是一个float[16]的数组,我知道它是干什么的,却不知道该怎么填他们的值来达到我期望的效果,这个函数就是干这个的,你告诉它你要的效果,它帮你生成矩阵。
这个函数的原型如下:
void gluPerspective(GL10 gl, float fovy, float aspect, float zNear, float zFar);
它参数的含义如下:
从图上可以看出来,near 的值,视角度数的值,一起决定了最后物体在屏幕显示多大,也决定了单位的长度。
public void glmPerspective(float[] mResult, float fovy, float aspect, float zNear, float zFar) {
float top = zNear * (float) Math.tan(fovy * (Math.PI / 360.0));
float bottom = -top;
float left = bottom * aspect;
float right = top * aspect;
Matrix.frustumM(mResult, 0, left, right, bottom, top, zNear, zFar);
}
glBegin(GL_LINE_STRIP); //begin和end之间的顶点是画线
glVertex3f(width,0,-world_depth/2);
glVertex3f(width,0,world_depth/2);
glEnd();
private FloatBuffer vertexBuffer = null ;
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
float[] vertexs = new float[]{
-5.0f, 5.0f, -20.0f,
5.0f, -5.0f, -20.0f,
5.0f, 5.0f, -20.0f,
};
vertexBuffer = ByteBuffer.allocateDirect(vertexs.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuffer.put(vertexs);
vertexBuffer.position(0);
}
在OpenGL中,三角形的绘制逆时针的面为正面。里面三个定点的位置和顺序是 左上->右下->右上。
public void onDrawFrame(GL10 gl) {
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 清空场景为黑色。
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT);// 清空相关缓存。
GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer);
GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 3);
GLES10.glFlush();
}
GLES10.glMatrixMode(GLES10.GL_MODELVIEW); // 修改模型变换矩阵
GLES10.glLoadIdentity(); // 复位,将投影矩阵归零
GLU.gluLookAt(gl, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f);
public void onDrawFrame(GL10 gl) {
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 清空场景为黑色。
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT);// 清空相关缓存。
GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer);
GLES10.glMatrixMode(GLES10.GL_MODELVIEW); // 修改模型变换矩阵
GLES10.glLoadIdentity(); // 复位,将投影矩阵归零
GLU.gluLookAt(gl, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 3);
GLES10.glFlush();
}
private FloatBuffer vertexBuffer = null ;
private FloatBuffer vertexBuffer2 = null ;
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
float[] vertexs = new float[]{
-5.0f, 0.0f, -30.0f,
5.0f, -10.0f, -30.0f,
5.0f, 0.0f, -30.0f,
};
vertexBuffer = ByteBuffer.allocateDirect(vertexs.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuffer.put(vertexs);
vertexBuffer.position(0);
float[] vertexs2 = new float[]{
-4.0f, 12.0f, -30.0f,
4.0f, 4.0f, -30.0f,
4.0f, 12.0f, -30.0f,
};
vertexBuffer2 = ByteBuffer.allocateDirect(vertexs2.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuffer2.put(vertexs2);
vertexBuffer2.position(0);
}
public void onDrawFrame(GL10 gl) {
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 清空场景为黑色。
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT);// 清空相关缓存。
GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer);
GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 3);
GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer2);
GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 3);
GLES10.glFlush();
}
public void onDrawFrame(GL10 gl) {
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 清空场景为黑色。
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT);// 清空相关缓存。
GLES10.glMatrixMode(GLES10.GL_MODELVIEW); // 修改模型变换矩阵
GLES10.glLoadIdentity(); // 复位,将投影矩阵归零
GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer);
GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 3);
GLU.gluLookAt(gl, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f);
GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, vertexBuffer2);
GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 3);
GLES10.glFlush();
}