opengl 制作 3D 彩色旋转三角形
来源:互联网 发布:淘宝网企业店铺 编辑:程序博客网 时间:2024/06/11 19:36
原文:
[置顶] OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
链接:http://blog.csdn.net/shulianghan/article/details/17020359
目录(?)[+]
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 .
案例下载地址 : http://download.csdn.net/detail/han1202012/6651095 需要SDK-10 版本2.3.3
一. 程序介绍
1. 样例展示
该程序打开之后会出现一个旋转的三角形, 该三角形一直绕x轴z方向旋转 如图 :
2. 程序结构
本程序中定义了四个类 : ShaderUtil , Triangle , MyTDView , MainActivity .
在Activity中加载myTDView对象, MyTDView对象中绘制Triangle 三角形图形, Triangle调用ShaderUtil加载着色脚本并创建着色程序.
四个类之间的关系 :
3. 方法介绍
(1) ShaderUtil方法
a. 加载着色器方法 : 根据着色器类型 和 着色器脚本字符串获取着色器
- public static int loadShader(int shaderType , String source)
流程 : 创建着色器 -> 加载着色器脚本 -> 编译着色器 -> 获取着色器编译结果
b. 检查错误方法 : 检查每一步是否出现错误
- public static void checkGLError(String op)
c. 创建着色器方法 : 根据顶点着色器和片元着色器创建着色程序
- public static int createProgram(String vertexSource , String fragmentSource)
d. 获取着色脚本 : 从assets目录中的着色脚本中获取着色脚本的字符串信息
- public static String loadFromAssetsFile(String fileName, Resources resources)
二 ShaderUtils类介绍
1.安卓基本API
(1) 创建assets目录中文件的输入流
- InputStream is = resources.getAssets().open(fileName);
返回值 : 着色脚本文件的输入流;
作用 : 使用该输入流可以读取着色脚本信息
(2)带缓冲区的输出流
- 创建一个带缓冲区的输出流, 每次读取一个字节, 注意这里字节读取用的是int类型
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- 逐个字节读取数据, 并将读取的数据放入缓冲器中
- while((ch = is.read()) != -1){
- baos.write(ch);
- }
- 将缓冲区中的数据转为字节数组, 并将字节数组转换为字符串
- byte[] buffer = baos.toByteArray();
读写单位 : 这个输出流读取字节的单位是int, 这里要特别注意;
读取方法 : read()方法每次读取一个字节, 并返回读取到的字节;
写出方法 : write()方法将一个字节写入到ByteArrayOutputStream的缓冲区中;
导出数据 : 调用toByteArray()方法可以将缓冲区中的数据转为字节数组, 并返回这个数组;
2.着色器相关API介绍
(1)创建着色程器
- int shader = GLES20.glCreateShader(shaderType);
返回值 : 该方法返回的是着色器的引用
(2)加载着色器源代码
- GLES20.glShaderSource(shader, source);
(3)编译着色器
- GLES20.glCompileShader(shader);
(4)获取着色器编译情况
- int complied[] = new int[1];
- GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, complied, 0);
- shader : 着色器引用 , 这个着色器已经加载了着色脚本字符串以及经过了编译 ;
- pname : GLES20.GL_COMPILE_STATUS : 获取信息类型代码 : 我们要获取编译情况 , 这里是编译状态的代码
- params[] : compile : 存放结果数组
- index : 存放结果索引 , 将编译成功的脚本数放在数组的哪个索引下
(5)删除着色器
- GLES20.glDeleteShader(shader);
3.着色程序相关的API
(1)创建OpenGL程序
- int program = GLES20.glCreateProgram();
(2)获取OpenGL中的错误信息
- GLES20.glGetError();
(3)向程序中加入着色器
- GLES20.glAttachShader(program, vertextShader);
(4)连接程序
- GLES20.glLinkProgram(program);
(5)获取链接程序结果
- int[] linkStatus = new int[1];
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
(6)删除着色程序
- GLES20.glDeleteProgram(program);
4. 源码
- package shuliang.han.rotatetriangle;
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
- import android.content.res.Resources;
- import android.opengl.GLES20;
- import android.util.Log;
- /*
- * 这个工具类用来加载定点着色器与片元着色器
- */
- public class ShaderUtil {
- /**
- * 加载着色器方法
- *
- * 流程 :
- *
- * ① 创建着色器
- * ② 加载着色器脚本
- * ③ 编译着色器
- * ④ 获取着色器编译结果
- *
- * @param shaderType 着色器类型,顶点着色器(GLES20.GL_FRAGMENT_SHADER), 片元着色器(GLES20.GL_FRAGMENT_SHADER)
- * @param source 着色脚本字符串
- * @return 返回的是着色器的引用, 返回值可以代表加载的着色器
- */
- public static int loadShader(int shaderType , String source){
- //1.创建一个着色器, 并记录所创建的着色器的id, 如果id==0, 那么创建失败
- int shader = GLES20.glCreateShader(shaderType);
- if(shader != 0){
- //2.如果着色器创建成功, 为创建的着色器加载脚本代码
- GLES20.glShaderSource(shader, source);
- //3.编译已经加载脚本代码的着色器
- GLES20.glCompileShader(shader);
- int[] compiled = new int[1];
- //4.获取着色器的编译情况, 如果结果为0, 说明编译失败
- GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
- if(compiled[0] == 0){
- Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":");
- Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));
- //编译失败的话, 删除着色器, 并显示log
- GLES20.glDeleteShader(shader);
- shader = 0;
- }
- }
- return shader;
- }
- /**
- * 检查每一步的操作是否正确
- *
- * 使用GLES20.glGetError()方法可以获取错误代码, 如果错误代码为0, 那么就没有错误
- *
- * @param op 具体执行的方法名, 比如执行向着色程序中加入着色器,
- * 使glAttachShader()方法, 那么这个参数就是"glAttachShader"
- */
- public static void checkGLError(String op){
- int error;
- //错误代码不为0, 就打印错误日志, 并抛出异常
- while( (error = GLES20.glGetError()) != GLES20.GL_NO_ERROR ){
- Log.e("ES20_ERROR", op + ": glError " + error);
- throw new RuntimeException(op + ": glError " + error);
- }
- }
- /**
- * 创建着色程序
- *
- * ① 加载顶点着色器
- * ② 加载片元着色器
- * ③ 创建着色程序
- * ④ 向着色程序中加入顶点着色器
- * ⑤ 向着色程序中加入片元着色器
- * ⑥ 链接程序
- * ⑦ 获取链接程序结果
- *
- * @param vertexSource 定点着色器脚本字符串
- * @param fragmentSource 片元着色器脚本字符串
- * @return
- */
- public static int createProgram(String vertexSource , String fragmentSource){
- //1. 加载顶点着色器, 返回0说明加载失败
- int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
- if(vertexShader == 0)
- return 0;
- //2. 加载片元着色器, 返回0说明加载失败
- int fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
- if(fragShader == 0)
- return 0;
- //3. 创建着色程序, 返回0说明创建失败
- int program = GLES20.glCreateProgram();
- if(program != 0){
- //4. 向着色程序中加入顶点着色器
- GLES20.glAttachShader(program, vertexShader);
- checkGLError("glAttachShader");
- //5. 向着色程序中加入片元着色器
- GLES20.glAttachShader(program, fragShader);
- checkGLError("glAttachShader");
- //6. 链接程序
- GLES20.glLinkProgram(program);
- int[] linkStatus = new int[1];
- //获取链接程序结果
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
- if(linkStatus[0] != GLES20.GL_TRUE){
- Log.e("ES20.ERROR", "链接程序失败 : ");
- Log.e("ES20.ERROR", GLES20.glGetProgramInfoLog(program));
- //如果链接程序失败删除程序
- GLES20.glDeleteProgram(program);
- program = 0;
- }
- }
- return program;
- }
- /**
- * 从assets中加载着色脚本
- *
- * ① 打开assets目录中的文件输入流
- * ② 创建带缓冲区的输出流
- * ③ 逐个字节读取文件数据, 放入缓冲区
- * ④ 将缓冲区中的数据转为字符串
- *
- * @param fileName assets目录中的着色脚本文件名
- * @param resources 应用的资源
- * @return
- */
- public static String loadFromAssetsFile(String fileName, Resources resources){
- String result = null;
- try {
- //1. 打开assets目录中读取文件的输入流, 相当于创建了一个文件的字节输入流
- InputStream is = resources.getAssets().open(fileName);
- int ch = 0;
- //2. 创建一个带缓冲区的输出流, 每次读取一个字节, 注意这里字节读取用的是int类型
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- //3. 逐个字节读取数据, 并将读取的数据放入缓冲器中
- while((ch = is.read()) != -1){
- baos.write(ch);
- }
- //4. 将缓冲区中的数据转为字节数组, 并将字节数组转换为字符串
- byte[] buffer = baos.toByteArray();
- baos.close();
- is.close();
- result = new String(buffer, "UTF-8");
- result = result.replaceAll("\\r\\n", "\n");
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- }
三. Triangle 3D三角形数据
1. 顶点数据容器相关api
(1) 创建ByteBuffer对象
- ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4)
(2) 设置字节缓冲区顺序
- vbb.order(ByteOrder.nativeOrder());
(3) 将字节缓冲区转为浮点缓冲区
- mVertexBuffer = vbb.asFloatBuffer();
(4) 向字节缓冲区中存入数据
- mColorBuffer.put(colors);
(5)指定浮点型缓冲区起始位置
- mColorBuffer.position(0);
2. 初始化着色器相关api
(1) 获取着色器属性变量引用
- int maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
(2) 获取着色器一直变量引用
- float[] muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
3. 绘制3D图形相关api
(1) 指定着色器程序
- GLES20.glUseProgram(mProgram);
(2) 设置旋转初始情况
- Matrix.setRotateM(float[] rm, int rmOffset, float a, float x, float y, float z)
(3) 设置位移
- Matrix.translateM(float[] m, int mOffset, float x, float y, float z)
(4) 设置旋转矩阵
- Matrix.rotateM(float[] m, int mOffset, float a, float x, float y, float z)
(5) 应用投影和视口变换
- GLES20.glUniformMatrix4fv(int location, int count, boolean transpose, float[] value, int offset)
(6) 将顶点数据传进渲染管线
- GLES20.glVertexAttribPointer(
- maPositionHandle,
- 3,
- GLES20.GL_FLOAT,
- false,
- 3 * 4,
- mVertexBuffer
- );
(7) 启用传入的数据
- GLES20.glEnableVertexAttribArray(maPositionHandle);
(8) 执行绘制方法
- GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
4. 矩阵计算相关api
- Matrix.multiplyMM(float[] result, int resultOffset, float[] lhs, int lhsOffset, float[] rhs, int rhsOffset)
5. 源码
- package shuliang.han.rotatetriangle;
- import java.nio.ByteBuffer;
- import java.nio.ByteOrder;
- import java.nio.FloatBuffer;
- import android.opengl.GLES20;
- import android.opengl.Matrix;
- public class Triangle {
- public static float[] mProjMatrix = new float[16]; //4 * 4 投影矩阵
- public static float[] mVMatrix = new float[16]; //摄影机位置朝向参数矩阵
- public static float[] mMVPMatrix; //最后起作用的总变换矩阵
- int mProgram; //自定义渲染管线着色程序id
- /*
- * 下面的三个变量是顶点着色器中定义的三个变量
- * 其中的总变换矩阵属性 是 一致变量
- * 顶点位置 和 颜色属性 是 属性变量
- */
- int muMVPMatrixHandle; //总变换矩阵的引用
- int maPositionHandle; //顶点位置属性引用
- int maColorHandle; //顶点颜色属性引用
- String mVertexShader; //顶点着色器脚本代码
- String mFragmentShader; //片元着色器脚本代码
- /*
- * 这个变换矩阵 在设置变换 , 位移 , 旋转的时候 将参数设置到这个矩阵中去
- */
- static float[] mMMatrix = new float[16]; //具体物体的3D变换矩阵, 包括旋转, 平移, 缩放
- /*
- * 这两个缓冲获得方法
- * ①创建ByteBuffer, 创建时赋予大小 设置顺序
- * ②将ByteBuffer 转为FloatBuffer
- * ③给FloatBuffer设置值, 设置起始位置
- */
- FloatBuffer mVertexBuffer; //顶点坐标数据缓冲
- FloatBuffer mColorBuffer; //顶点着色数据缓冲
- int vCount = 0; //顶点数量
- float xAngle = 0; //绕x轴旋转角度
- /**
- * 构造方法
- * @param mv GLSurfaceView子类对象, 显示3D画面的载体
- */
- public Triangle(MyTDView mv){
- initVertexData();
- initShader(mv);
- }
- /**
- * 初始化顶点数据
- *
- * 该方法制定顶点坐标和颜色数据, 并将数据输入到缓冲区
- *
- * 创建一个ByteBuffer缓冲区, 然后将ByteBuffer缓冲区转为FloatBuffer缓冲区
- * a. 创建float数组, 将对应的顶点(颜色)数据放到数组中去;
- * b. 创建ByteBuffer对象, 根据之前创建的float数组的字节大小创建这个ByteBuffer对象,使用allocateDirect(int)分配大小
- * c. 设置ByteBuffer对象的顺序, 调用order(ByteOrder.nativeOrder),设置为本地操作系统顺序
- * d. 将ByteBuffer对象转为FloatBuffer对象, 调用asFloatBuffer()方法;
- * e. 给FloatBuffer对象设置数组, 将开始创建的float数组设置给FloatBuffer对象;
- * f. 设置FloatBuffer对象缓冲区的起始位置为0
- */
- public void initVertexData() {
- //设置定点数为3
- vCount = 3;
- //计算三角形顶点的单位
- final float UNIT_SIZE = 0.2f;
- /*
- * 这个float数组9个浮点数, 每3个为一个顶点的坐标
- */
- float vertices[] = new float[]{
- -4 * UNIT_SIZE, 0 , 0, //x轴左边的坐标
- 0, -4 * UNIT_SIZE, 0, //y轴坐标
- 4 * UNIT_SIZE, 0, 0 //x轴右边的坐标
- };
- /*
- * 创建一个ByteBuffer对象, 这个对象中缓冲区大小为vertices数组大小的4倍
- * 因为每个float占4个字节, 创建的缓冲区大小正好将vertices装进去
- */
- ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
- //设置字节顺序为本地操作系统顺序
- vbb.order(ByteOrder.nativeOrder());
- //将该缓冲区转换为浮点型缓冲区
- mVertexBuffer = vbb.asFloatBuffer();
- //将顶点的位置数据写入到顶点缓冲区数组中
- mVertexBuffer.put(vertices);
- //设置缓冲区的起始位置为0
- mVertexBuffer.position(0);
- /*
- * 顶点颜色数组
- * 每四个浮点值代表一种颜色
- */
- float colors[] = new float[]{
- 1, 1, 1, 0,
- 0, 0, 1, 0,
- 0, 1, 0, 0
- };
- ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);//创建ByteBuffer
- cbb.order(ByteOrder.nativeOrder());//设置字节顺序
- mColorBuffer = cbb.asFloatBuffer();//将字节缓冲转为浮点缓冲
- mColorBuffer.put(colors);
- mColorBuffer.position(0);
- }
- /**
- * 初始化着色器
- *
- * 流程 :
- * ① 从资源中获取顶点 和 片元着色器脚本
- * ② 根据获取的顶点 片元着色器脚本创建着色程序
- * ③ 从着色程序中获取顶点位置引用 , 顶点颜色引用, 总变换矩阵引用
- *
- * @param mv MyTDView对象, 是GLSurfaceView对象
- */
- public void initShader(MyTDView mv){
- /*
- * mVertextShader是顶点着色器脚本代码
- * 调用工具类方法获取着色器脚本代码, 着色器脚本代码放在assets目录中
- * 传入的两个参数是 脚本名称 和 应用的资源
- * 应用资源Resources就是res目录下的那写文件
- */
- mVertexShader = ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
- mFragmentShader = ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
- /*
- * 创建着色器程序, 传入顶点着色器脚本 和 片元着色器脚本 注意顺序不要错
- */
- mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
- /*
- * 从着色程序中获取 属性变量 顶点坐标(颜色)数据的引用
- * 其中的"aPosition"是顶点着色器中的顶点位置信息
- * 其中的"aColor"是顶点着色器的颜色信息
- */
- maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
- maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
- /*
- * 从着色程序中获取一致变量 总变换矩阵
- * uMVPMatrix 是顶点着色器中定义的一致变量
- */
- muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
- }
- /**
- * 绘制三角形方法
- *
- * 绘制流程 :
- * ① 指定着色程序
- * ② 设置变换矩阵
- * ③ 将顶点位置 颜色 数据传进渲染管线
- * ④ 启动顶点位置 颜色 数据
- * ⑤ 执行绘制
- */
- public void drawSelf(){
- //根据着色程序id 指定要使用的着色器
- GLES20.glUseProgram(mProgram);
- /*
- * 设置旋转变化矩阵
- * 参数介绍 : ① 3D变换矩阵 ② 矩阵数组的起始索引 ③旋转的角度 ④⑤⑥
- */
- Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0);
- /*
- * 设置沿z轴正方向位移
- * 参数介绍 : ① 变换矩阵 ② 矩阵索引开始位置 ③④⑤设置位移方向z轴
- */
- Matrix.translateM(mMMatrix, 0, 0, 0, 1);
- /*
- * 设置绕x轴旋转
- * 参数介绍 : ① 变换矩阵 ② 索引开始位置 ③ 旋转角度 ④⑤⑥ 设置绕哪个轴旋转
- */
- Matrix.rotateM(mMMatrix, 0, xAngle, 1, 0, 0);
- /*
- * 应用投影和视口变换
- */
- GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFianlMatrix(mMMatrix), 0);
- /*
- * 将顶点位置数据传送进渲染管线, 为画笔指定定点的位置数据
- */
- GLES20.glVertexAttribPointer(
- maPositionHandle, //顶点位置数据引用
- 3, //每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);
- }
- /**
- * 计算最终投影的矩阵
- * @param spec
- * @return
- */
- public static float[] getFianlMatrix(float[] spec){
- mMVPMatrix = new float[16];
- /*
- * 计算矩阵变换投影
- *
- * 参数介绍 :
- * ① 总变换矩阵 ② 总变换矩阵起始索引
- * ③ 摄像机位置朝向矩阵 ④ 摄像机朝向矩阵起始索引
- * ⑤ 投影变换矩阵 ⑥ 投影变换矩阵起始索引
- */
- Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, spec, 0);
- Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
- return mMVPMatrix;
- }
- }
四. GLSurfaceView相关api
1. 相关api
(1) 设置OpenGL版本
- GLSurfaceView.setEGLContextClientVersion(int version)
(2) 设置背景颜色
- GLES20.glClearColor(0, 0, 0, 1.0f);
(3) 设置视口大小
- GLES20.glViewport(int x, int y, int width, int height)
(4) 设置透视矩阵
- Matrix.frustumM(float[] m, int offset, float left, float right, float bottom, float top, float near, float far)
(5) 设置摄像机参数
- Matrix.setLookAtM(float[] rm, int rmOffset, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
(6) 清除深度缓冲与颜色缓冲
- GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
2. 源码
- package shuliang.han.rotatetriangle;
- import javax.microedition.khronos.egl.EGLConfig;
- import javax.microedition.khronos.opengles.GL10;
- import android.content.Context;
- import android.opengl.GLES20;
- import android.opengl.GLSurfaceView;
- import android.opengl.Matrix;
- public class MyTDView extends GLSurfaceView {
- private final float ANGLE_SPAN = 0.375f; //三角形每次旋转的角度
- private RotateThread mRotateThread; //该线程用来改变图形角度
- private SceneRenderer mSceneRender; //渲染器
- public MyTDView(Context context) {
- super(context);
- //设置OpenGLES版本为2.0
- this.setEGLContextClientVersion(2);
- //设置渲染器 渲染模式
- mSceneRender = new SceneRenderer();
- this.setRenderer(mSceneRender);
- this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
- }
- /**
- * 渲染器
- * 实现了下面三个方法 :
- * 界面创建 :
- * 界面改变 :
- * 界面绘制 :
- * @author HanShuliang
- *
- */
- private class SceneRenderer implements Renderer{
- Triangle triangle;
- @Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- //设置屏幕背景色
- GLES20.glClearColor(0, 0, 0, 1.0f);
- //创建三角形对象
- triangle = new Triangle(MyTDView.this);
- //打开深度检测
- GLES20.glEnable(GLES20.GL_DEPTH_TEST);
- mRotateThread = new RotateThread();
- mRotateThread.start();
- }
- @Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- //设置视窗大小及位置
- GLES20.glViewport(0, 0, width, height);
- //计算GLSurfaceView的宽高比
- float ratio = (float)width/height;
- /*
- * 产生透视矩阵
- * 参数介绍 :
- * ① 4 * 4 投影矩阵
- * ② 投影矩阵的起始位置
- * 后面的四个参数分别是 左 右 下 上 的距离
- * 最后两个参数是 近视点 和 远视点 距离
- */
- Matrix.frustumM(Triangle.mProjMatrix, 0,
- -ratio, ratio,
- -1, 1,
- 1, 10);
- /*
- * 设置摄像机参数矩阵
- * 参数介绍 :
- * 前两个参数是摄像机参数矩阵 和 矩阵数组的起始位置
- * 后面三个一组是三个空间坐标 先后依次是 摄像机的位置 看的方向 摄像机上方朝向
- */
- Matrix.setLookAtM(Triangle.mVMatrix, 0,
- 0f,0f,3f,
- 0f,0f,0f,
- 0f,1.0f,0.0f);
- }
- @Override
- public void onDrawFrame(GL10 gl) {
- //清除深度缓冲与颜色缓冲
- GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
- //绘制三角形
- triangle.drawSelf();
- }
- }
- /**
- * 这个线程是用来改变三角形角度用的
- */
- public class RotateThread extends Thread{
- public boolean flag = true;
- @Override
- public void run() {
- while(flag){
- mSceneRender.triangle.xAngle = mSceneRender.triangle.xAngle + ANGLE_SPAN;
- try {
- Thread.sleep(20);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
五 MainActivity相关
1. 相关api
(1) 设置界面为竖屏
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
(2) 界面获取焦点
- View.requestFocus()
(3) 设置可获取焦点
- View.setFocusableInTouchMode(boolean focusableInTouchMode)
2. 源码
- package shuliang.han.rotatetriangle;
- import android.app.Activity;
- import android.content.pm.ActivityInfo;
- import android.os.Bundle;
- public class MainActivity extends Activity {
- private MyTDView myTDView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //设置界面显示为竖屏
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- //创建OpenGL的显示界面
- myTDView = new MyTDView(this);
- myTDView.requestFocus();
- myTDView.setFocusableInTouchMode(true);
- //将OpenGL显示界面设置给Activity
- setContentView(myTDView);
- }
- @Override
- public void onResume() {
- super.onResume();
- myTDView.onResume();
- }
- @Override
- public void onPause() {
- super.onPause();
- myTDView.onPause();
- }
- }
六. 着色器脚本
- uniform mat4 uMVPMatrix; //总变换矩阵
- attribute vec3 aPosition; //顶点位置
- attribute vec4 aColor; //顶点颜色
- varying vec4 vColor; //用于传递给片元着色器的变量
- void main()
- {
- gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
- vColor = aColor;//将接收的颜色传递给片元着色器
- }
片元着色器 :
- precision mediump float;
- varying vec4 vColor; //接收从顶点着色器过来的参数
- void main()
- {
- gl_FragColor = vColor;//给此片元颜色值
- }
案例下载地址 : http://download.csdn.net/detail/han1202012/6651095 需要SDK-10 版本2.3.3
- opengl 制作 3D 彩色旋转三角形
- 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
- WordPress 3D旋转彩色标签云
- 【附源码】【Android 3D OpenGL】开发之二——旋转的三角形【MacroCheng原创】
- 3D编程-旋转的三角形
- OpenGl制作3D效果
- opengl 鼠标3D旋转简单实现
- OpenGL 鼠标3D旋转简单实现
- OpenGL 创建3D魔方 旋转 问题
- opengl 鼠标3D旋转简单实现
- Qt OpenGL----着色、3D和旋转
- [OpenGL(C)] - 旋转立体三角形
- OpenGL绘制旋转三角形实例
- OpenGL绘制旋转三角形实例
- 制作一个旋转的三角形
- unity制作一个3d旋转菜单
- 制作3D旋转导航综合练习题
- 制作3D旋转视频展示区
- Essbase学习笔记
- 获取本地的对外ip
- SCANV团队发布橙色安全警报:警惕Discuz! X高危漏洞
- 用DynaBean减除不必要的VO和FormBean
- gdb与可视化gdb工具insight
- opengl 制作 3D 彩色旋转三角形
- iOS 动画3
- UICollectionView-添加自定义交互(如手势等)
- PInvoke调用导致堆栈不对称 c#调用C++win32非托管dll的问题深度分析
- javaFX实例1-webView实现简单浏览器
- 职场中14个坏习惯可能让你丢掉工作
- 回溯算法(BackTracking)--八皇后问题
- 和菜鸟一起学产品之产品经理的工作职责
- 插入排序总结