一、流程
1.自定义类继承GLSurfaceView,在构造方法内:
this.setEGLContextClientVersion(2); //设置使用OPENGL ES2.0
mRenderer = new SceneRenderer(); //自定义场景渲染器
setRenderer(mRenderer); //设置渲染器为自已实现的场景渲染器
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); //设置渲染模式为主动渲染
2.自定场景渲染器,实现GLSurfaceView.Renderer中的onSurfaceCreated、onSurfaceChanged、onDrawFrame方法
onSurfaceCreated重写:
//设置屏幕背景色RGBA
GLES20.glClearColor(0.5f,0.5f,0.5f, 1.0f);
//创建3D物体对象
(1)初始化顶点数据:
// 创建顶点坐标数据缓冲
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());// 设置字节顺序
mVertexBuffer = vbb.asFloatBuffer();// 转换为Float型缓冲
mVertexBuffer.put(vertices);// 向缓冲区中放入顶点坐标数据
mVertexBuffer.position(0);// 设置缓冲区起始位置
// 创建顶点着色数据缓冲
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());// 设置字节顺序
mColorBuffer = cbb.asFloatBuffer();// 转换为Float型缓冲
mColorBuffer.put(colors);// 向缓冲区中放入顶点着色数据
mColorBuffer.position(0);// 设置缓冲区起始位置
(2)加载顶点与片元着色脚本:
// 加载顶点着色器的脚本内容
mVertexShader = ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
// 加载片元着色器的脚本内容
mFragmentShader = ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
// 基于顶点着色器与片元着色器创建程序
mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
// 获取程序中顶点位置属性引用id
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
// 获取程序中顶点颜色属性引用id
maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
// 获取程序中总变换矩阵引用id
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//打开深度检测
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//打开背面剪裁
GLES20.glEnable(GLES20.GL_CULL_FACE);
onSurfaceChanged重写:
//设置视窗大小及位置
GLES20.glViewport(0, 0, width, height);
//计算GLSurfaceView的宽高比
float ratio = (float) width / height;
//产生正交或透视投影矩阵
//正交投影
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
//透视投影
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
//产生摄像机9参数位置矩阵
Matrix.setLookAtm(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
//初始化变换矩阵
MatrixState.setInitStack();
onDrawFrame重写:
//清除深度缓冲与颜色缓冲
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
//绘制3D物体
// 制定使用某套shader程序
GLES20.glUseProgram(mProgram);
// 将最终变换矩阵传入shader程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
// 为画笔指定顶点位置数据
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
// 为画笔指定顶点着色数据
GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 4 * 4, mColorBuffer);
// 允许顶点位置数据数组
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glEnableVertexAttribArray(maColorHandle);
// 绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
或
x、y:视口矩形左上侧点在屏幕坐标系内的坐标
width、height:视口的宽度与高度
2.正交投影,近面与远面物来一样大小:
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
mProjMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
left、right、bottom、top:属于near面,中心点到左边距离为left,到右边距离为right,到上边距为top,到下边距为bottom
near:视点到near面的距离
far:视点到far面的距离
3.透视投影,近面比远面的物体体要小,成锥形:
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
mProjMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
left、right、bottom、top:属于near面,中心点到左边距离为left,到右边距离为right,到上边距为top,到下边距为bottom
near:视点到near面的距离
far:视点到far面的距离
4.设置摄像机位置:
Matrix.setLookAtm(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
mVMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
cx、cy、cz:摄像机位置的X、Y、Z坐标
tx、ty、tz:观察目标点的X、Y、Z坐标
upx、upy、upz:up向量在X、Y、Z轴上的分量
5.让坐标轴平移
Matrix.translateM(currMatrix, 0, x, y, z)
currMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
x、y、z:让原坐标轴沿x、y、z轴平移一定的位置
6.让坐标轴旋转
Matrix.rotateM(currMatrix, 0, angle, x, y, z)
currMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
angle:要旋转的角度
x、y、z:旋转轴对应的X、Y、Z坐标值分量
7.让坐标轴缩放
Matrix.scaleM(currMatrix, 0, x, y, z)
currMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
x、y、z:float类型倍数值,让原坐标轴沿x、y、z轴分别按不同的倍数进行缩放
8.绘制方式
顶点法:
GLES20.glDrawArrays(绘制方式, 起始位置, 顶点数);
此方法按照传入的顶点本身顺序以及选用的绘制方式将顶点组成图元,会有重复的顶点
索引法:
GLES20.glDrawArrays(绘制方式, 顶点数,类别,索引数组缓冲);
此方法按照索引序列排序,需要传入顶点以及索引数组
GLES20.GL_TRIANGLES
9.是否打开背面剪裁
GLES20.glEnable(GLES20.GL_CULL_FACE);//打开背面剪裁,位于摄像机背面的将不会绘制,效率高。
GLES20.glDisable(GLES20.GL_CULL_FACE);//关闭背面剪裁,所有面都绘制,效率低。
10.设置哪个面为正面
GLES20.glFrontFace(GLES20.GL_CCW);//设置逆时针卷绕为正面,默认,不用设置
(1)在onSurfaceCreated中初始化纹理:
//生成纹理ID
int[] textures = new int[1];
GLES20.glGenTextures(1, //产生的纹理id的数量
textures, //纹理id的数组
0 //偏移量
);
textureId=textures[0];
//绑定纹理ID
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
//设置MIN采样方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
//设置MAG采样方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
//设置S轴拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
//设置T轴拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
//通过输入流加载图片
InputStream is = this.getResources().openRawResource(R.drawable.wall);
Bitmap bmp = BitmapFactory.decodeStream(is);
is.close();
//实际加载纹理
GLUtils.texImage2D (
GLES20.GL_TEXTURE_2D, //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D
0, //纹理的层次,0表示基本图像层,可以理解为直接贴图
bmp, //纹理图像的Bitmap
0 //纹理边框尺寸
);
bmp.recycle(); //纹理加载成功后释放图片
(2)初始化顶点数据时,进行顶点纹理坐标数据的初始化:
float texCoor[]=new float[]//顶点颜色值数组,每个顶点4个色彩值RGBA { 0.5f,0, 0,1, 1,1
1.自定义类继承GLSurfaceView,在构造方法内:
this.setEGLContextClientVersion(2); //设置使用OPENGL ES2.0
mRenderer = new SceneRenderer(); //自定义场景渲染器
setRenderer(mRenderer); //设置渲染器为自已实现的场景渲染器
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); //设置渲染模式为主动渲染
2.自定场景渲染器,实现GLSurfaceView.Renderer中的onSurfaceCreated、onSurfaceChanged、onDrawFrame方法
onSurfaceCreated重写:
//设置屏幕背景色RGBA
GLES20.glClearColor(0.5f,0.5f,0.5f, 1.0f);
//创建3D物体对象
(1)初始化顶点数据:
// 创建顶点坐标数据缓冲
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());// 设置字节顺序
mVertexBuffer = vbb.asFloatBuffer();// 转换为Float型缓冲
mVertexBuffer.put(vertices);// 向缓冲区中放入顶点坐标数据
mVertexBuffer.position(0);// 设置缓冲区起始位置
// 创建顶点着色数据缓冲
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());// 设置字节顺序
mColorBuffer = cbb.asFloatBuffer();// 转换为Float型缓冲
mColorBuffer.put(colors);// 向缓冲区中放入顶点着色数据
mColorBuffer.position(0);// 设置缓冲区起始位置
(2)加载顶点与片元着色脚本:
// 加载顶点着色器的脚本内容
mVertexShader = ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
// 加载片元着色器的脚本内容
mFragmentShader = ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
// 基于顶点着色器与片元着色器创建程序
mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
// 获取程序中顶点位置属性引用id
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
// 获取程序中顶点颜色属性引用id
maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
// 获取程序中总变换矩阵引用id
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//打开深度检测
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//打开背面剪裁
GLES20.glEnable(GLES20.GL_CULL_FACE);
onSurfaceChanged重写:
//设置视窗大小及位置
GLES20.glViewport(0, 0, width, height);
//计算GLSurfaceView的宽高比
float ratio = (float) width / height;
//产生正交或透视投影矩阵
//正交投影
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
//透视投影
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
//产生摄像机9参数位置矩阵
Matrix.setLookAtm(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
//初始化变换矩阵
MatrixState.setInitStack();
onDrawFrame重写:
//清除深度缓冲与颜色缓冲
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
//绘制3D物体
// 制定使用某套shader程序
GLES20.glUseProgram(mProgram);
// 将最终变换矩阵传入shader程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
// 为画笔指定顶点位置数据
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
// 为画笔指定顶点着色数据
GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 4 * 4, mColorBuffer);
// 允许顶点位置数据数组
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glEnableVertexAttribArray(maColorHandle);
// 绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
或
GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, iCount, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer);
二、API说明
1.设置视窗大小及位置
x、y:视口矩形左上侧点在屏幕坐标系内的坐标
width、height:视口的宽度与高度
2.正交投影,近面与远面物来一样大小:
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
mProjMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
left、right、bottom、top:属于near面,中心点到左边距离为left,到右边距离为right,到上边距为top,到下边距为bottom
near:视点到near面的距离
far:视点到far面的距离
3.透视投影,近面比远面的物体体要小,成锥形:
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
mProjMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
left、right、bottom、top:属于near面,中心点到左边距离为left,到右边距离为right,到上边距为top,到下边距为bottom
near:视点到near面的距离
far:视点到far面的距离
4.设置摄像机位置:
Matrix.setLookAtm(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
mVMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
cx、cy、cz:摄像机位置的X、Y、Z坐标
tx、ty、tz:观察目标点的X、Y、Z坐标
upx、upy、upz:up向量在X、Y、Z轴上的分量
5.让坐标轴平移
Matrix.translateM(currMatrix, 0, x, y, z)
currMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
x、y、z:让原坐标轴沿x、y、z轴平移一定的位置
6.让坐标轴旋转
Matrix.rotateM(currMatrix, 0, angle, x, y, z)
currMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
angle:要旋转的角度
x、y、z:旋转轴对应的X、Y、Z坐标值分量
7.让坐标轴缩放
Matrix.scaleM(currMatrix, 0, x, y, z)
currMatrix:存储生成矩阵元素的float[]类型数组
0:填充起始偏移量
x、y、z:float类型倍数值,让原坐标轴沿x、y、z轴分别按不同的倍数进行缩放
8.绘制方式
顶点法:
GLES20.glDrawArrays(绘制方式, 起始位置, 顶点数);
此方法按照传入的顶点本身顺序以及选用的绘制方式将顶点组成图元,会有重复的顶点
索引法:
GLES20.glDrawArrays(绘制方式, 顶点数,类别,索引数组缓冲);
此方法按照索引序列排序,需要传入顶点以及索引数组
GLES20.GL_TRIANGLES
9.是否打开背面剪裁
GLES20.glEnable(GLES20.GL_CULL_FACE);//打开背面剪裁,位于摄像机背面的将不会绘制,效率高。
GLES20.glDisable(GLES20.GL_CULL_FACE);//关闭背面剪裁,所有面都绘制,效率低。
10.设置哪个面为正面
GLES20.glFrontFace(GLES20.GL_CCW);//设置逆时针卷绕为正面,默认,不用设置
GLES20.glFrontFace(GLES20.GL_CW);//设置顺时针卷绕为正面
三、纹理
1.流程(1)在onSurfaceCreated中初始化纹理:
//生成纹理ID
int[] textures = new int[1];
GLES20.glGenTextures(1, //产生的纹理id的数量
textures, //纹理id的数组
0 //偏移量
);
textureId=textures[0];
//绑定纹理ID
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
//设置MIN采样方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
//设置MAG采样方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
//设置S轴拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
//设置T轴拉伸方式
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
//通过输入流加载图片
InputStream is = this.getResources().openRawResource(R.drawable.wall);
Bitmap bmp = BitmapFactory.decodeStream(is);
is.close();
//实际加载纹理
GLUtils.texImage2D (
GLES20.GL_TEXTURE_2D, //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D
0, //纹理的层次,0表示基本图像层,可以理解为直接贴图
bmp, //纹理图像的Bitmap
0 //纹理边框尺寸
);
bmp.recycle(); //纹理加载成功后释放图片
(2)初始化顶点数据时,进行顶点纹理坐标数据的初始化:
float texCoor[]=new float[]//顶点颜色值数组,每个顶点4个色彩值RGBA { 0.5f,0, 0,1, 1,1