Android OpenGL纹理
来源:互联网 发布:java方法4种分类 编辑:程序博客网 时间:2024/03/29 14:33
Android OpenGL纹理
首先申明下,本文为笔者学习《OpenGL ES应用开发实践指南》的笔记,并加入笔者自己的理解和归纳总结。
1、纹理
纹理就是一个图像或照片,它们可以被加载进OpenGL中。每个二维的纹理都有其自己的坐标空间,按照惯例,一个维度叫做S,而另一个叫做T。
大多数计算机图像都有一个默认的方法,通常是y轴向下,y随着向图像的底部移动而增加。
2、纹理过滤
当纹理大小被扩大或缩小时,我们还需要使用纹理过滤。(1) 最近邻过滤
这个方式为每个片段选择最近的纹理元素。
(2) 双线性过滤
使用双线性插值平滑像素之间的过渡,使用四个邻接的纹理元素,并在它们之间用一个线性插值算法做插值。
双线性过滤很适合处理放大。
(3) MIP贴图
对于缩小处理,双线性过滤值给每个片段使用四个纹理元素,将会失去很多细节。
MIP贴图,可以生成一组优化过的不同大小的纹理。当生成这组纹理的时候,OpenGL会使用所有的纹理元素生成每个级别的纹理,当过滤纹理时,还要确保所有的纹理元素都能被使用。在渲染时,OpenGL会根据每个片段的纹理元素为每个片段选择最适合的解绑。
(4) 三线性过滤
三线性过滤,在最邻近的MIP贴图级别之间也要插值,这样,每个片段总共使用8个纹理元素插值,有助于消除每个MIP贴图级别之间的过渡,并且得到一个更平滑地图像。
3、加载纹理
(1) 生成新的纹理对象int[] textureObjectIds = new int[1];GLES20.glGenTextures(1, textureObjectIds, 0);(2) 设置过滤参数
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);OpenGL纹理过滤模式
GL_NEAREST最近邻过滤GL_NEAREST_MIPMAP_NEAREST使用MIP贴图的最近邻过滤GL_NEAREST_MIPMAP_LINEAR使用MIP贴图级别之间插值的最近邻过滤GL_LINEAR双线性过滤GL_LINEAR_MIPMAP_NEAREST使用MIP贴图的双线性过滤GL_LINEAR_MIPMAP_LINEAR三线性过滤(使用MIP贴图级别之间插值的双线性过滤)每种情况下允许的纹理过滤模式
缩小
GL_NEAREST
GL_NEAREST_MIPMAP_NEAREST
GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR
放大GL_NEAREST
GL_LINEAR
(3) 绑定图片GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);(4) 加载纹理
protected int loadTexture(int resId) {// 生成一个新的OpenGL纹理的IDint[] textureObjectIds = new int[1];GLES20.glGenTextures(1, textureObjectIds, 0);if (textureObjectIds[0] == 0) {LogUtil.log("OpenGL", "Could not generate a new OpenGL texture object.");return 0;}BitmapFactory.Options options = new BitmapFactory.Options();// 需要原始的图像数据,而不是缩放版options.inScaled = false;Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId, options);if (bitmap == null) {LogUtil.log("OpenGL", "Resource ID " + resId + " could not be decoded.");// 如果失败,删除纹理对象GLES20.glDeleteTextures(1, textureObjectIds, 0);return 0;}// 我们需要告诉后面的纹理调用,都应该应用于这个纹理对象GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureObjectIds[0]);// 设置过滤参数GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR_MIPMAP_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);// 加载纹理到OpenGL,并生成MIP贴图GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);// 回收图片bitmap.recycle();// 与当前纹理解除绑定,防止被修改GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);return textureObjectIds[0];}
4、着色器文件
(1) 顶点着色器,texture_vertex_shader.glsl文件a_TextureCoordinates是纹理坐标,有两个分量:S坐标和T坐标
uniform mat4 u_Matrix;attribute vec4 a_Position;attribute vec2 a_TextureCoordinates;varying vec2 v_TextureCoordinates;void main(){ v_TextureCoordinates = a_TextureCoordinates; gl_Position = u_Matrix * a_Position;}(2) 片段着色器,texture_fragment_shader文件
u_textureUnit被定义为一个sampler2D,这个变量类型指的是一个二维纹理数据的数组。
precision mediump float;uniform sampler2D u_textureUnit;varying vec2 v_TextureCoordinates;void main(){ gl_FragColor = texture2D(u_textureUnit, v_TextureCoordinates);}
4、绘制着色器
(1) 顶点数据纹理数据采用不同的坐标方式
float[] tableVertices = { 0f, 0f, 0.5f, 0.5f,-0.5f, -0.8f, 0f, 0.9f, 0.5f, -0.8f, 1f, 0.9f, 0.5f, 0.8f, 1f, 0.1f,-0.5f, 0.8f, 0f, 0.1f,-0.5f, -0.8f, 0f, 0.9f,};(2) 绘制纹理
// 把活动的纹理单元设置为纹理单元0GLES20.glActiveTexture(GLES20.GL_TEXTURE0);// 把纹理绑定到这个单元GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);// 把被选择的纹理单元传递给片段着色器中的GLES20.glUniform1i(uTextureUnitLocation, 0);(3) 绘制不同着色器
Resource类,包含一个顶点数据类VertexArray,bindData方法用来绑定属性,draw方法用来绘制界面。
public class Resource { protected VertexArray mVertextArray; public Resource(float[] vertexData) { mVertextArray = new VertexArray(vertexData); } public void bindData(int attributeLocation, int dataOffset, int componentCount, int stride) { mVertextArray.setVertexAttribPointer(attributeLocation, dataOffset, componentCount, stride); } public void draw() { }}VertexArray类,保存顶点数据
public class VertexArray { public static final int BYTES_PER_FLOAT = 4; private final FloatBuffer floatBuffer; public VertexArray(float[] vertexData) { floatBuffer = ByteBuffer .allocateDirect(vertexData.length * BYTES_PER_FLOAT) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); floatBuffer.put(vertexData); } public void setVertexAttribPointer(int attributeLocation, int dataOffset, int componentCount, int stride) { floatBuffer.position(dataOffset); GLES20.glVertexAttribPointer(attributeLocation, componentCount, GLES20.GL_FLOAT, false, stride, floatBuffer); floatBuffer.position(0); GLES20.glEnableVertexAttribArray(attributeLocation); }}Table类,绘制桌子
public class Table extends Resource { private final static int POSITION_COMPONENT_COUNT = 2; private final static int TEXTURE_COMPONENT_COUNT = 2; private final static int STRIDE = (POSITION_COMPONENT_COUNT + TEXTURE_COMPONENT_COUNT) * VertexArray.BYTES_PER_FLOAT; private final static float[] vertexData = new float[]{ 0f, 0f, 0.5f, 0.5f, -0.5f, -0.8f, 0f, 0.9f, 0.5f, -0.8f, 1f, 0.9f, 0.5f, 0.8f, 1f, 0.1f, -0.5f, 0.8f, 0f, 0.1f, -0.5f, -0.8f, 0f, 0.9f, }; public Table() { super(vertexData); } public void bindData(TextureProgram program) { bindData(program.getPositionLocation(), 0, POSITION_COMPONENT_COUNT, STRIDE); bindData(program.getTextureCoordLocation(), POSITION_COMPONENT_COUNT, TEXTURE_COMPONENT_COUNT, STRIDE); } @Override public void draw() { GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6); }}Mallet类,暂用点代替
public class Mallet extends Resource { private final static int POSITION_COMPONENT_COUNT = 2; private final static int COLOR_COMPONENT_COUNT = 3; private final static int STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * VertexArray.BYTES_PER_FLOAT; private final static float[] vertexData = new float[]{ 0f, -0.25f, 0f, 0f, 1f, 0f, 0.25f, 1f, 0f, 0f }; public Mallet() { super(vertexData); } public void bindData(ColorProgram program) { bindData(program.getPositionLocation(), 0, POSITION_COMPONENT_COUNT, STRIDE); bindData(program.getColorLocation(), POSITION_COMPONENT_COUNT, COLOR_COMPONENT_COUNT, STRIDE); } @Override public void draw() { GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 2); }}Program类,保留顶点数据,加载着色器程序
public class Program { protected int mProgramId; public Program(Context context, int vertexShaderResId, int fragmentShaderResId) { mProgramId = useProgram(context, vertexShaderResId, fragmentShaderResId); } public void setUniform(float[] projectionMatrix) { } protected String readShaderFromRaw(Context context, int resId) { BufferedReader br = null; StringBuffer stringBuffer = new StringBuffer(); try { br = new BufferedReader(new InputStreamReader( context.getResources().openRawResource(resId))); String line = null; while ((line = br.readLine()) != null) { stringBuffer.append(line + "\n"); } } catch (IOException e) { } finally { if (br != null) { try { br.close(); } catch (IOException e) { } } } return stringBuffer.toString(); } protected int compileShader(int type, String shaderCode) { // 创建一个新的着色器对象 int shaderObjectId = GLES20.glCreateShader(type); if (shaderObjectId == 0) { // 创建失败 return 0; } // 上传和编译着色器代码 GLES20.glShaderSource(shaderObjectId, shaderCode); GLES20.glCompileShader(shaderObjectId); // 获取编译状态 int[] compileStatus = new int[1]; GLES20.glGetShaderiv(shaderObjectId, GLES20.GL_COMPILE_STATUS, compileStatus, 0); // 获取着色器信息日志 LogUtil.log("OpenGL", GLES20.glGetShaderInfoLog(shaderObjectId)); if (compileStatus[0] == 0) { // 如果失败,删除着色器对象 GLES20.glDeleteShader(shaderObjectId); return 0; } return shaderObjectId; } protected int linkProgram(int vertexShaderId, int fragmentShaderId) { // 创建一个新的程序对象 int programId = GLES20.glCreateProgram(); if (programId == 0) { return 0; } // 新建程序对象附上着色器,并链接程序 GLES20.glAttachShader(programId, vertexShaderId); GLES20.glAttachShader(programId, fragmentShaderId); GLES20.glLinkProgram(programId); // 获取链接状态 int[] linkStatus = new int[1]; GLES20.glGetProgramiv(programId, GLES20.GL_LINK_STATUS, linkStatus, 0); // 获取着程序链接信息日志 LogUtil.log("OpenGL", GLES20.glGetProgramInfoLog(programId)); if (linkStatus[0] == 0) { // 如果链接失败,删除程序对象 GLES20.glDeleteProgram(programId); return 0; } return programId; } protected boolean validateProgram(int programId) { // 验证程序,只在开发阶段需要 GLES20.glValidateProgram(programId); LogUtil.log("OpenGL", GLES20.glGetProgramInfoLog(programId)); int[] validateStatus = new int[1]; GLES20.glGetProgramiv(programId, GLES20.GL_VALIDATE_STATUS, validateStatus, 0); return validateStatus[0] != 0; } protected int useProgram(Context context, int vertexShaderResId, int fragmentShaderResId) { String vertexShaderCode = readShaderFromRaw(context, vertexShaderResId); String fragmentShaderCode = readShaderFromRaw(context, fragmentShaderResId); int vertexShaderId = compileShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShaderId = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); int programId = linkProgram(vertexShaderId, fragmentShaderId); validateProgram(programId); GLES20.glUseProgram(programId); return programId; }}ColorProgram类,绘制颜色着色器
public class ColorProgram extends Program { private final static String A_POSITION = "a_Position"; private final static String A_COLOR = "a_Color"; private final static String U_MATRIX = "u_Matrix"; private int aPositionLocation, aColorLocation, uMatrixLocation; public ColorProgram(Context context) { super(context, R.raw.ortho_vertex_shader, R.raw.ortho_fragment_shader); aPositionLocation = GLES20.glGetAttribLocation(mProgramId, A_POSITION); aColorLocation = GLES20.glGetAttribLocation(mProgramId, A_COLOR); uMatrixLocation = GLES20.glGetUniformLocation(mProgramId, U_MATRIX); } @Override public void setUniform(float[] projectionMatrix) { GLES20.glUseProgram(mProgramId); GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0); } public int getPositionLocation() { return aPositionLocation; } public int getColorLocation() { return aColorLocation; }}TextureProgram类,绘制纹理着色器
public class TextureProgram extends Program { private final static String A_POSITION = "a_Position"; private final static String A_TEXTURRE_COORDINATES = "a_TextureCoordinates"; private final static String U_MATRIX = "u_Matrix"; private final static String U_TEXTURE_UNIT = "u_TextureUnit"; private int aPositionLocation, aTextureCoordLocation, uMatrixLocation, uTextureUnitLocation; private int mTextureId; public TextureProgram(Context context, int resId) { super(context, R.raw.texture_vertex_shader, R.raw.texture_fragment_shader); aPositionLocation = GLES20.glGetAttribLocation(mProgramId, A_POSITION); aTextureCoordLocation = GLES20.glGetAttribLocation(mProgramId, A_TEXTURRE_COORDINATES); uMatrixLocation = GLES20.glGetUniformLocation(mProgramId, U_MATRIX); uTextureUnitLocation = GLES20.glGetUniformLocation(mProgramId, U_TEXTURE_UNIT); mTextureId = loadTexture(context, resId); } protected int loadTexture(Context context, int resId) { // 生成一个新的OpenGL纹理的ID int[] textureObjectIds = new int[1]; GLES20.glGenTextures(1, textureObjectIds, 0); if (textureObjectIds[0] == 0) { LogUtil.log("OpenGL", "Could not generate a new OpenGL texture object."); return 0; } BitmapFactory.Options options = new BitmapFactory.Options(); // 需要原始的图像数据,而不是缩放版 options.inScaled = false; Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId, options); if (bitmap == null) { LogUtil.log("OpenGL", "Resource ID " + resId + " could not be decoded."); // 如果失败,删除纹理对象 GLES20.glDeleteTextures(1, textureObjectIds, 0); return 0; } // 我们需要告诉后面的纹理调用,都应该应用于这个纹理对象 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureObjectIds[0]); // 设置过滤参数 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); // 加载纹理到OpenGL,并生成MIP贴图 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D); // 回收图片 bitmap.recycle(); // 与当前纹理解除绑定,防止被修改 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); return textureObjectIds[0]; } @Override public void setUniform(float[] projectionMatrix) { GLES20.glUseProgram(mProgramId); GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0); // 把活动的纹理单元设置为纹理单元0 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); // 把纹理绑定到这个单元 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId); // 把被选择的纹理单元传递给片段着色器中的 GLES20.glUniform1i(uTextureUnitLocation, 0); } public int getPositionLocation() { return aPositionLocation; } public int getTextureCoordLocation() { return aTextureCoordLocation; }}(4) OpenGLTextureShaderRender类
class OpenGLTextureShaderRender implements GLSurfaceView.Renderer {private float[] projectionMatrix = new float[16];private float[] modelMatrix = new float[16];private float[] modelProjectionMatrix = new float[16];private TextureProgram mTextureProgram;private ColorProgram mColorProgram;private Table mTable;private Mallet mMallet;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);mTable = new Table();mMallet = new Mallet();mTextureProgram = new TextureProgram(OpenGLTextureShaderActivity.this,R.drawable.air_hockey_surface);mColorProgram = new ColorProgram(OpenGLTextureShaderActivity.this);}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES20.glViewport(0, 0, width, height);// 创建透视投影Matrix.perspectiveM(projectionMatrix, 0, 45, (float)width / (float)height, 1, 10);// 定义模型矩阵Matrix.setIdentityM(modelMatrix, 0);// z轴平移-2.8Matrix.translateM(modelMatrix, 0, 0, 0, -2.8f);Matrix.rotateM(modelMatrix, 0, -60, 1f, 0f, 0f);// 把投影矩阵和模型矩阵相乘Matrix.multiplyMM(modelProjectionMatrix, 0, projectionMatrix, 0, modelMatrix, 0);}@Overridepublic void onDrawFrame(GL10 gl) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);mTextureProgram.setUniform(modelProjectionMatrix);mTable.bindData(mTextureProgram);mTable.draw();mColorProgram.setUniform(modelProjectionMatrix);mMallet.bindData(mColorProgram);mMallet.draw();}}显示如下
阅读全文
0 0
- Android OpenGL中的纹理
- Android OpenGL中的纹理
- Android OpenGL添加纹理
- Android OpenGL纹理
- Android opengl 立方体 多纹理
- Android OpenGL ES (2) -- 纹理
- android opengl压缩纹理读入
- android openGl纹理的使用
- Android OpenGL ES(七)----理解纹理与纹理过滤
- android opengl es 正方体纹理效果
- android opengl es--纹理映射,光照
- Android OpenGl es 纹理坐标设定
- android opengl es 纹理贴图资料
- Android 3D opengl 立方体 多纹理
- android opengl es绘制三角形+纹理
- android OpenGl Es实现正方体多纹理
- Android Opengl ES 2.0 纹理贴图
- Android OpenGL ES(二)纹理
- JSTL实现分页页码功能
- 怎么在百度地图上标注公司地址
- SparkSQL---Dataframe(Reflection)
- Android 简捷地为RecyclerView添加上拉加载
- Lucas 定理
- Android OpenGL纹理
- mysql中all privileges包含哪些权限
- ARM 学习笔记(四) 快速上下文切换(FCSE)技术
- oracle归档模式
- python基础(五)--文件的相关操作
- Freemarker遍历Set集合
- 自定义React图片上传组件
- java-打印出所有的“水仙花数”
- 常见排序算法小结一(C++实现)(未完)