openGl-ES学习与使用心得-入门级
作者:快慢机
时间:2011-10-27
在OPENGL中采用的是三维笛卡尔坐标系。
坐标系如下:
Y ^
| /
| /
| /
---------------------|-------------------------------------àX
/ |
/ |
/ |
Z /
注意:
1. PC版本OpenGl支持多种多边形,但是在OpenGL ES下只支持三角形。
也就是说,所有图形都由三角形构建,类似积分的原理。
2. 每个坐标的表示为(x,y,z).
3. 有一种功能叫背面裁剪,所以规定逆向为正面,反向为反面,切记!。
支持两种投影。投影要在创建的时候设置。
透视投影
一个函数:
void glFrustum(GLdouble left,GLdouble Right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);
Ø 前四个参数是摄像头视口。正常情况是成比例的。
Ø 第五个是近平面:可以认为近平面就对应着屏幕视口,不过近平面是Y向上,屏幕视口是Y向下。
Ø 第六个是远平面:远平面的一个作用是做裁切用。只有在近平面,元平面之间的物体才被显示,超过的就裁切掉。
另一个函数:
void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear, GLdouble zFar);
Ø 参数fovy定义视野在X-Z平面的角度,范围是[0.0, 180.0];
Ø 参数aspect是投影平面宽度与高度的比率;
Ø 参数zNear和Far分别是远近裁剪面沿Z负轴到视点的距离,它们总为正值。
正射投影
正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大小尺寸不变。
函数:
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top, GLdouble near,GLdouble far)
一般投影变换放置位置举例:
@Override
public void onSurfaceChanged( GL10 gl, int width,int height){
m_width = width;
m_height = height;
gl.glViewport(0,0,width,height);
gl.glMatrixMode(GL10.GL_PROJECTION); // 透视投影
gl.glLoadIdentity();
float ratio = (float)width/height;
left=right=ratio;
top=bottom=1f;
near=2;
far=10;
// 透视矩阵
gl.glFrustumf(-left, right, -bottom, top, near, far);
//摄像机位置, 固定位置时这么写,不固定位置时写在别处
GLU.gluLookAt(gl,
0.0f, 0.0f, 2.0f,
0.0f, 0.0f, -10.0f,
0.0f, 1.0f, 0.0f);
}
在游戏的场景中,通常物体是不动的。比如NPC旁边的窝!但是通过调整摄像机可以查看这个窝!
模型如下:
设置摄像机的函数:
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble upx,GLdouble upy,GLdouble upz);
摄像机的设置
举例说明:
GLU.gluLookAt(gl,
0.0f, 0.0f, 2.0f,
0.0f, 0.0f, -10.0f,
0.0f, 1.0f, 0.0f);
Ø 前三个参数是摄像机位置:此处设置向Z轴移动2的距离。
Ø 中间三个是方向,指向(0,0,-10)这个点。
Ø 最后三个是Up方向,表示摄像头是正着放,还是倾斜角度放。
在默认情况下,摄像机的位置在原点(0,0,0)。方向为Z轴负方向。
法师扔过来一个旋转的大火球。此时摄像机相当于是固定的,是这个火球在运动。那就是模型在变换---位移,缩放,旋转。
1. 位移:
glTranslate(TYPE x,TYPE y,TYPE z);
该函数用指定的x,y,z值沿着x轴、y轴、z轴平移物体(或按照相同的量值移动局部坐标系)。
2. 缩放:
glScale(TYPE x,TYPE y,TYPE z);
该函数可以对物体沿着x,y,z轴分别进行放大缩小。函数中的三个参数分别是x、y、z轴方向的比例变换因子。缺省时都为1.0,即物体没变化。程序中物体Y轴比例为2.0,其余都为1.0,就是说将立方体变成长方体。
3. 旋转
glRotate(TYPE angle,TYPE x,TYPE,y,TYPE z);
该函数中第一个变量angle制定模型旋转的角度,单位为度,后三个变量表示以原点(0,0,0)到点(x,y,z)的连线为轴线逆时针旋转物体。例如,glRotatef(45.0,0.0,0.0,1.0)的结果是绕z轴旋转45度。
注意:
这里提出一个思想请体会:可以认为每一个物体都是在(0,0,0)点构建,通过位移扔到环境中。这么做的好处在于物体构建简单,旋转,缩放也简单,特别是当需要你知道物体某一个时刻的真实对应坐标的时候(如拾取的时候),有利于你手动计算。
当然摄像机的变动也同样是这个道理。也就是说你构建了一个虚拟的世界。这个虚拟的世界的每一个物体(摄像机,灯,物体灯),都有自己一个体系。你会觉得这个思想太美妙了!
为此OpenGL提供了:
gl.glPushMatrix();
物体.Draw();
gl.glPopMatrix();
这个是计算矩阵。意思是你可以绘制完了机器人左手,再绘制机器人的右手,多方便。
举例:
@Override
public void onDrawFrame( GL10 gl){
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glFrontFace(GL10.GL_CCW);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
for(int i=0;i<alBN.size();i++)
{
gl.glPushMatrix();
alBN.get(i).drawSelf(gl);
gl.glPopMatrix();
}
}
物体绘制
public void drawSelf(GL10 gl)
{
gl.glTranslatef(0,0, this.zOffset);
gl.glRotatef(mAngleY, 0, 1, 0);
gl.glScalef(Constant.BIGER_FACTER, Constant.BIGER_FACTER, Constant.BIGER_FACTER);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vCount);//绘制
}
给你的火球子贴图!
1. 指定纹理
gl.glEnable(GL10.GL_TEXTURE_2D);//开启纹理
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//允许使用纹理数组
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);//指定纹理数组
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);//绑定纹理
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vCount);//绘制
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//关闭纹理数组
gl.glDisable(GL10.GL_TEXTURE_2D);//关闭纹理
2. 资源载入
//@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config){
//初始化体纹理ID 六扇门---郭芙蓉她爹
DoorId1= loadTexture(gl,R.drawable.a);
DoorId2= loadTexture(gl,R.drawable.b);
DoorId3= loadTexture(gl,R.drawable.c);
…
}
public int loadTexture(GL10 gl, int drawableId) {
int textureID = 0;
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
textureID = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_REPLACE);
InputStream is = mContext.getResources()
.openRawResource(drawableId);
Bitmap bitmapTmp;
try {
bitmapTmp = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore.
}
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0);
bitmapTmp.recycle();
return textureID;
}
3. 纹理坐标制作
仅支持三角形。坐标与物体绘制坐标要相同。
纹理坐标分s,t方向:
s方向从图片的左上为0,向右侧。
T方向向下。
其中范围都是(0-1)。
比如绘制一个四边形的坐标为:
float[] vertices = new float[]{ // 注意逆向为正面
//1
-1.0f * x, 1.0f * y, 1.0f * z,
-1.0f * x, -1.0f * y, 1.0f * z,
1.0f * x, 1.0f * y, 1.0f * z,
1.0f * x, -1.0f * y, 1.0f * z,
可见是从左上->左下->右上->右下.(还记得我前面说过的正反面不?)
那么对应的纹理坐标就为:
float spriteTexcoords[] = {
0, 0, 0, 1, 1, 0, 1, 1
};
注意:纹理图片尺寸是有规定的,都是2的n次方,如(32*32) (256*512)
矩阵栈的操作
OpenGL的矩阵堆栈指的就是内存中专门用来存放矩阵数据的某块特殊区域。一般说来,矩阵堆栈常用于构造具有继承性的模型,即由一些简单目标构成的复杂模型。矩阵堆栈对复杂模型运动过程中的多个变换操作之间的联系与独立十分有利。因为所有矩阵操作函数如glLoadMatrix()、glMultMatrix()、glLoadIdentity()等只处理当前矩阵或堆栈顶部矩阵,这样堆栈中下面的其它矩阵就不受影响。堆栈操作函数有以下两个:
·void glPushMatrix(void);
该函数表示将所有矩阵依次压入堆栈中,顶部矩阵是第二个矩阵的备份;压入的矩阵数不能太多,否则出错。
·void glPopMatrix(void);
该函数表示弹出堆栈顶部的矩阵,令原第二个矩阵成为顶部矩阵,接受当前操作,故原顶部矩阵被破坏;当堆栈中仅存一个矩阵时,不能进行弹出操作,否则出错。
还想说点基础的… 时间有限就不说了,基础最重要。有机会继续更新。
对了,再说两点:
1. 关于图形构建,有的是INT,有的是FLOAT,两者要转换,FLOAT是真实的不转,INT的OpenGL帮你转了。不要糊涂!
2. 切忌旋转的时候math的是弧度,要转化地!