先看一段代码,对于学习OpenGL的童鞋来说,下面这段代码还算熟悉,但是可能不知道其中的参数的含义,下面针对这些参数进行说明讲解:
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//计算宽高比
float ratio=(float)width/height;
//设置透视投影
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 20);
//设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 10.0f, 0f, 0f, 0f, 1.0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
}
学习这两个方法需要先了解openGL的3D坐标系,可以自行百度
Matrix.setLookAtM
需要填充的参数
float cx, //相机位置x
float cy, /相机位置y
float cz, //相机位置z
float tx, //相机目标点x
float ty, //相机目标点y
float tz, //相机目标点z
float upx, //相机UP向量X分量
float upy, //相机UP向量Y分量
float upz //相机UP向量Z分量
这个方法看起来很抽象,设几组参数对比一下效果,相机目标点,即绘制的3D图像,tx,ty, tz,为图像的中心位置设置到原点即 tx = 0,ty = 0, tz = 0; 相机的位置,即观察者眼睛的位置, 我们设置在目标点的正前方(位置z轴正方向),cx = 0, cy = 0, cz = 10; 接着是摄像机顶部的方向了
例如设置up方向为y轴正方向,upx = 0,upy = 1,upz = 0。这是相机正对着目标图像,则绘制出来的效果相当于我们在Y轴方向看目标。代码如下:
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
如果设置up方向为x轴正方向,upx = 1,upy = 0,upz = 0,绘制的图像就会相当于我们在X轴方向看目标
代码如下:
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5.0f, 0f, 0f, 0f, 1.0f, 0f, 0.0f);
如果设置up方向为x轴正方向,upx = 1,upy = 1,upz = 0,绘制的图像就会相当于我们在X轴与Y轴的分割线方向看目标,代码如下:
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5.0f, 0f, 0f, 0f, 1.0f, 1.0f, 0.0f);
注意:如果设置在z轴方向,图像就会看不见。Matrix.setLookAtM,的作用大体就是这样。
Matrix.frustumM
需要填充的参数有
float left, //near面的left
float right, //near面的right
float bottom, //near面的bottom
float top, //near面的top
float near, //near面距离
float far //far面距离
设置这些参数能起到的作用:先是left,right和bottom,top,这4个参数会影响图像左右和上下缩放比,所以往往会设置的值分别-(float) width / height和(float) width / height,top和bottom和top会影响上下缩放比,如果left和right已经设置好缩放,则bottom只需要设置为-1,top设置为1,这样就能保持图像不变形。也可以将left,right 与bottom,top交换比例,即bottom和top设置为 -height/width 和 height/width, left和right设置为-1和1。
near和far参数稍抽象一点,就是一个立方体的前面和后面,near和far需要结合拍摄相机即观察者眼睛的位置来设置,例如setLookAtM中设置cx = 0, cy = 0, cz = 10,near设置的范围需要是小于10才可以看得到绘制的图像,如果大于10,图像就会处于了观察这眼睛的后面,这样绘制的图像就会消失在镜头前,far参数,far参数影响的是立体图形的背面,far一定比near大,一般会设置得比较大,如果设置的比较小,一旦3D图形尺寸很大,这时候由于far太小,这个投影矩阵没法容纳图形全部的背面,这样3D图形的背面会有部分隐藏掉的。
以上是 Matrix.frustumM和Matrix.setLookAtM参数详解,可能同学会问 Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);这个函数的参数说明,这个等下次再进行讲解。
附上完整代码,绘制一个正三角形,供大家参考学习,可直接运行:
/**
* Description:
*/
public class TriangleWithCamera extends Shape {
private FloatBuffer vertexBuffer;
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;"+
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private int mProgram;
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = {
0.5f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
};
private int mPositionHandle;
private int mColorHandle;
private float[] mViewMatrix=new float[16];
private float[] mProjectMatrix=new float[16];
private float[] mMVPMatrix=new float[16];
//顶点个数
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
//顶点之间的偏移量
private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
private int mMatrixHandler;
//设置颜色,依次为红绿蓝和透明通道
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
public TriangleWithCamera(View mView) {
super(mView);
ByteBuffer bb = ByteBuffer.allocateDirect(
triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
//创建一个空的OpenGLES程序
mProgram = GLES20.glCreateProgram();
//将顶点着色器加入到程序
GLES20.glAttachShader(mProgram, vertexShader);
//将片元着色器加入到程序中
GLES20.glAttachShader(mProgram, fragmentShader);
//连接到着色器程序
GLES20.glLinkProgram(mProgram);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//计算宽高比
float ratio=(float)width/height;
//设置透视投影
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 20);
//设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
}
@Override
public void onDrawFrame(GL10 gl) {
//将程序加入到OpenGLES2.0环境
GLES20.glUseProgram(mProgram);
//获取变换矩阵vMatrix成员句柄
mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");
//指定vMatrix的值
GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);
//获取顶点着色器的vPosition成员句柄
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//启用三角形顶点的句柄
GLES20.glEnableVertexAttribArray(mPositionHandle);
//准备三角形的坐标数据
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
//获取片元着色器的vColor成员的句柄
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
//设置绘制三角形的颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
public abstract class Shape implements GLSurfaceView.Renderer {
protected View mView;
public Shape(View mView){
this.mView=mView;
}
public int loadShader(int type, String shaderCode){
//根据type创建顶点着色器或者片元着色器
int shader = GLES20.glCreateShader(type);
//将资源加入到着色器中,并编译
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
刚开始学习OpenGL,有什么描述错误的地方请指正