Android Opengles2.0 多纹理融合
来源:互联网 发布:郑大网络远程教育中心 编辑:程序博客网 时间:2024/06/05 17:45
demo:
http://download.csdn.net/download/keen_zuxwang/10041401
1、创建顶点位置、纹理数组
2、创建、编译、加载shader程序,获得shader中各变量的句柄(如获取纹理采样sampler2D变量的句柄)
3、程序通过program给shader传递各参量,如:顶点位置、纹理坐标,激活、绑定纹理,传递模型/视图/投影矩阵等, 然后通过glDrawArrays()/glDrawElements()绘制图元(片元着色器通过这些参量计算出每个像素的值、然后通过底层EGL 渲染到相应的ANativeWindow)
1)、vertex shader:
attribute vec4 vPosition; //顶点位置attribute vec2 vCoord; //顶点纹理uniform mat4 vMatrix; //变化矩阵//传递量-->fragment shadervarying vec2 varyTexCoord; varying vec2 varyPostion;void main(){ gl_Position = vPosition; //vMatrix*vPosition varyPostion = vPosition.xy; varyTexCoord = vCoord;}
fragment shader:
precision mediump float; // 必须定义float精度(若有使用float 变量,或者定义float变量时指定精度)uniform sampler2D vTexture; // 2D纹理采样器变量uniform sampler2D vTexture0;uniform sampler2D vTexture1;uniform float mratio; // 融合系数//定义左上角矩形融合区域,参考顶点位置坐标定义(顶点位置一般范围[-1,1])const vec2 leftBottom = vec2(-0.99, 0.79);const vec2 rightTop = vec2(-0.70, 0.99);varying vec2 varyTexCoord;varying vec2 varyPostion;void main() { //矩形区域内的融合 if (varyPostion.x >= leftBottom.x && varyPostion.x <= rightTop.x && varyPostion.y >= leftBottom.y && varyPostion.y <= rightTop.y) { vec2 tex0 = vec2((varyPostion.x-leftBottom.x)/(rightTop.x-leftBottom.x), 1.0-(varyPostion.y-leftBottom.y)/(rightTop.y-leftBottom.y)); vec4 color = texture2D(vTexture1, tex0); gl_FragColor = color*color.a + texture2D(vTexture, 1.0-varyTexCoord)*(1.0-color.a); // 以color的透明度color.a 进行mix } //矩形区域外的融合 else { vec4 color1 = texture2D(vTexture, varyTexCoord); //texture2D 纹理采样,获取纹理的像素信息 vec4 color2 = texture2D(vTexture0, varyTexCoord); gl_FragColor = mix(color1, color2, mratio); }}
2)、shader的工具类:
//加载shader //shader类型: GLES20.GL_VERTEX_SHADER & GLES20.GL_FRAGMENT_SHADER //sourcesh: shader的脚本字符串资源 public static int loadShader(int shaderType, String source) { //创建shader int shader = GLES20.glCreateShader(shaderType); //若创建成功则加载shader if (shader != 0) { //加载shader的源代码 GLES20.glShaderSource(shader, source); //编译shader GLES20.glCompileShader(shader); //存放编译成功shader数量的数组 int[] compiled = new int[1]; //获取Shader的编译情况 Get Shader invalidate GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) {//若编译失败则显示错误日志并删除此shader Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":"); Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } } return shader; } //创建shader程序program public static int createProgram(String vertexSource, String fragmentSource) { //加载顶点着色器 int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } //加载片元着色器 int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } int program = GLES20.glCreateProgram(); //创建程序 //若程序创建成功则向程序中加入顶点着色器与片元着色器 if (program != 0) { //向程序中加入顶点着色器 GLES20.glAttachShader(program, vertexShader); checkGlError("glAttachShader"); //向程序中加入片元着色器 GLES20.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); //链接程序 GLES20.glLinkProgram(program); //存放链接成功program数量的数组 int[] linkStatus = new int[1]; //获取program的链接情况 Get Program invalidate GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); //若链接失败则报错并删除程序 if (linkStatus[0] != GLES20.GL_TRUE) { Log.e("ES20_ERROR", "Could not link program: "); Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } } return program; } //检查错误 public static void checkGlError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e("ES20_ERROR", op + ": glError " + error); throw new RuntimeException(op + ": glError " + error); } } //从assets加载shader public static String loadFromAssetsFile(String fname,Resources r) { String result=null; try { InputStream in=r.getAssets().open(fname); int ch=0; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while((ch=in.read())!=-1) { baos.write(ch); } byte[] buff=baos.toByteArray(); baos.close(); in.close(); result=new String(buff,"UTF-8"); result=result.replaceAll("\\r\\n","\n"); } catch(Exception e) { e.printStackTrace(); } return result; }
3)、顶点、纹理、矩阵、shader操作类, 该类最终将在GLSurfaceView的GLSurfaceView.Renderer 类的OnDrawFrame()中调用glDrawArrays()/glDrawElements()绘制图元
public class IconObj { private static final String TAG="Filter"; protected int mProgram; protected int mHPosition; protected int mHCoord; protected int mMVPMatrix; protected int mHTexture; protected int mHTexture0; protected int mHTexture1; protected int mRatio; public float ratio=0.5f; private float[] matrix=new float[16]; private float[] mMatrix=new float[16]; //纹理缓存 protected FloatBuffer mVerBuffer; //纹理缓存 protected FloatBuffer mTexBuffer; //顶点绘制索引 protected ShortBuffer drawListBuffer; //纹理id private int textureId=-1; private int textureId0=-1; private int textureId1=-1; //顶点位置坐标 private float pos[] = { -0.9f, 0.9f, -0.9f, 0.7f, -0.7f, 0.7f, -0.7f, 0.9f, }; //纹理坐标 private float[] coord={ 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, }; //顶点位置坐标 private final float[] sPos={ -1.0f,1.0f, //左上角 -1.0f,-1.0f, //左下角 1.0f,1.0f, //右上角 1.0f,-1.0f //右下角 }; //顶点纹理坐标 private final float[] sCoord={ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f, }; private static short drawOrder[] = {0, 1, 2, 0, 2, 3}; Context context; public IconObj(Context context){ this.context=context; initBuffer(); createProgram(); textureId = initTexture(R.drawable.earth); textureId0 = initTexture(R.drawable.bg); textureId1 = initTexture(R.drawable.opengles); Matrix.setIdentityM(mMatrix, 0); matrix = flip(mMatrix, true, false); } //闀滃儚 public float[] flip(float[] m,boolean x,boolean y){ if(x||y){ Matrix.scaleM(m,0,x?-1:1,y?-1:1,1); } return m; } protected void initBuffer(){ ByteBuffer a=ByteBuffer.allocateDirect(sPos.length*4); a.order(ByteOrder.nativeOrder()); //变化成本地字节序 mVerBuffer=a.asFloatBuffer(); mVerBuffer.put(sPos); mVerBuffer.position(0); ByteBuffer b=ByteBuffer.allocateDirect(sCoord.length*4); b.order(ByteOrder.nativeOrder()); mTexBuffer=b.asFloatBuffer(); mTexBuffer.put(sCoord); mTexBuffer.position(0); ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); } protected void createProgram(){ String mVertexShader=ShaderUtil.loadFromAssetsFile("base_vertex.sh", context.getResources()); ShaderUtil.checkGlError("==ss=="); //加载片元着色器的脚本内容 String mFragmentShader=ShaderUtil.loadFromAssetsFile("base_fragment.sh", context.getResources()); //基于顶点着色器与片元着色器创建程序 ShaderUtil.checkGlError("==ss=="); mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader); //glGetAttribLocation获取属性句柄(或可称为属性索引),glGetUniformLocation获取着色器中的常量值,它一般存储各种着色器需要的数据,如:转换矩阵、光照参数或者颜色等 mHPosition= GLES20.glGetAttribLocation(mProgram, "vPosition"); mHCoord=GLES20.glGetAttribLocation(mProgram,"vCoord"); mMVPMatrix=GLES20.glGetUniformLocation(mProgram,"vMatrix"); mHTexture=GLES20.glGetUniformLocation(mProgram,"vTexture"); mHTexture0=GLES20.glGetUniformLocation(mProgram,"vTexture0"); mHTexture1=GLES20.glGetUniformLocation(mProgram,"vTexture1"); mRatio = GLES20.glGetUniformLocation(mProgram,"mratio"); } public int initTexture(int drawableId) { //生成纹理ID int[] textures = new int[1]; GLES20.glGenTextures ( 1, //产生的纹理id的数量 textures, //纹理id的数组 0 //偏移量 ); int textureId = textures[0]; Log.i(TAG, " initTexture textureId = " + textureId); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST); // 纹素放大、缩小设置GL_LINEAR对应线性滤波,GL_NEAREST对应最近邻滤波方式 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE); // 纹理边界处理,当纹理坐标超出[0,1]的范围时该怎么处理,GL_CLAMP_TO_EDGE --- 纹理坐标会被截断到[0,1]之间。坐标值大的被截断到纹理的边缘部分,形成了一个拉伸的边缘 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE); //加载图片 InputStream is = context.getResources().openRawResource(drawableId); Bitmap bitmapTmp; try { bitmapTmp = BitmapFactory.decodeStream(is); } finally { try { is.close(); } catch(IOException e) { e.printStackTrace(); } } //实际加载纹理 GLUtils.texImage2D ( GLES20.GL_TEXTURE_2D, //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D 0, //纹理的层次,0表示基本图像层,可以理解为直接贴图 bitmapTmp, //纹理图像 0 //纹理边框尺寸 ); bitmapTmp.recycle(); //纹理加载成功后释放图片 return textureId; } public void drawSelf() { GLES20.glUseProgram(mProgram); // 使用shader program //顶点属性一般包括位置、颜色、法线、纹理坐标 GLES20.glEnableVertexAttribArray(mHPosition); // 使能相应的顶点位置句柄/索引的顶点属性数组 --- 即为顶点位置属性attribute变量赋值 GLES20.glVertexAttribPointer(mHPosition,2, GLES20.GL_FLOAT, false, 0,mVerBuffer); // 指定(或绑定)该顶点位置句柄关联的顶点属性数组 GLES20.glEnableVertexAttribArray(mHCoord); // 使能相应的纹理坐标句柄的顶点属性数组 GLES20.glVertexAttribPointer(mHCoord, 2, GLES20.GL_FLOAT, false, 0, mTexBuffer); // 指定(或绑定)该纹理坐标句柄关联的顶点属性数组 --- 即为顶点纹理坐标属性attribute变量赋值 //GLES20.glUniformMatrix4fv(mMVPMatrix,1,false,matrix,0); GLES20.glUniform1f(mRatio, ratio); //绑定纹理 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); GLES20.glUniform1i(mHTexture, 0); //绑定纹理 GLES20.glActiveTexture(GLES20.GL_TEXTURE1); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId0); GLES20.glUniform1i(mHTexture0, 1); //绑定纹理 GLES20.glActiveTexture(GLES20.GL_TEXTURE2); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId1); GLES20.glUniform1i(mHTexture1, 2); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4); //GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); GLES20.glDisableVertexAttribArray(mHPosition); GLES20.glDisableVertexAttribArray(mHCoord); }}
GLSurfaceView.Renderer 接口实现中进行shader操作类的创建、绘制
SeekBar seekBar = (SeekBar) findViewById(R.id.id_seekBar); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub if(iconObj != null) { iconObj.ratio = progress/100.0f; } ratio = progress/100.0f; } @Override public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } @Override public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } }); IconObj iconObj; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { iconObj = new IconObj(context); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); //视窗设置 } @Override public void onDrawFrame(GL10 gl) { GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //设置清除颜色 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); //GL_COLOR_BUFFER_BIT 设置窗口颜色 //GL_DEPTH_BUFFER_BIT 设置深度缓存--把所有像素的深度值设置为最大值(一般为远裁剪面) iconObj.drawSelf(); }
demo 效果:
阅读全文
0 0
- Android Opengles2.0 多纹理融合
- OpenglES2.0 for Android:纹理映射
- opengles2.0中的纹理
- OpenglES2.0 for Android:再谈纹理映射
- IOS OpenGLES2.0 入门04 加载纹理
- Android OpenGLES2.0(八)——纹理贴图之显示图片
- Android opengles2.0 背景透明
- OpenglES2.0 for Android:来画个圆吧
- OpenglES2.0 for Android:来画个球吧
- OpenGLES2.0 Iphone开发指引:第二部分,纹理贴图
- Android OpenGLES2.0(一)——了解OpenGLES2.0
- Android OpenGLES2.0(一)——了解OpenGLES2.0
- android下opengles2.0多线程问题
- android模拟器运行opengles2.0程序
- OpenglES2.0 for Android:来画个三角形吧
- OpenglES2.0 for Android:来画个矩形吧
- OpenglES2.0 for Android:来画个立方体吧
- OpenglES2.0 for Android:各种变换来一波
- python爬虫<将scrapy的请求设置为同步>
- JAVA基础题
- Android Studio3.0 Android Profiler分析器(cpu memory network 分析器)
- Java Druid大数据连接池的实例应用 和工具类
- 更快、更强——解析Hadoop新一代MapReduce框架Yarn
- Android Opengles2.0 多纹理融合
- ionic 常用插件
- ubuntu 12.04下MRPT安装
- QGis二次开发基础 -- 根据属性查询要素
- sublime text打造python 编译环境,并且让python2和python3共存
- 枚举类的模板代码-Java实现
- TQ210开发板通过NRF24L01模块和51单片机通讯
- c#最新验证是否电话号码和手机号码
- Greenplum 数据库备份,pg_dump:schema with OID 17660566 does not exist