环境 基于 Android GLSurfaceView
实践内容 :
绘制6个矩形。
1.指定2个纹理图像。每3个矩形使用同一纹理。
2.对同一纹理的两个矩形,分别按照:重复显示部分图像、拉伸、clamp方式显示。
3.再绘制一个矩形,其纹理为2个纹理的混合。(混合方式由用户指定)
最终效果如下 :
以下是 GLSurfaceView的绘图,
读取Bitmap 和绑定Texture 在 OnCreat中进行
摄像机使用的是投影矩阵,注意这里画矩形的时候,因为卷绕方向为背面,所以把背面剔除关了~~,
分别画了 7个矩矩形
package com.talentgame.openglestexture;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import java.io.InputStream;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import utils.MatrixState;
/**
* Created by 54560 on 2016/10/11.
*/
public class MyGLSurfaceView extends GLSurfaceView {
int[] textures = new int[7];
DrawRect[] rect = new DrawRect[6];
DrawRect mutRect;
public MyGLSurfaceView(Context context) {
super(context);
this.setEGLContextClientVersion(2);
ZjRenderer zjRenderer = new ZjRenderer();
this.setRenderer(zjRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
private class ZjRenderer implements GLSurfaceView.Renderer
{
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
MatrixState.PushMatrix();
MatrixState.scale(1.1f,1.1f,1.1f);
MatrixState.translate(0,0.4f,0);
MatrixState.PushMatrix();
MatrixState.translate(0,0.8f,0);
rect[0].DrawSelf();
MatrixState.PopMatrix();
MatrixState.PushMatrix();
MatrixState.translate(0,0.4f,0);
rect[1].DrawSelf();
MatrixState.PopMatrix();
MatrixState.PushMatrix();
MatrixState.translate(0,0.0f,0);
rect[2].DrawSelf();
MatrixState.PopMatrix();
MatrixState.PushMatrix();
MatrixState.translate(0,-0.4f,0);
rect[3].DrawSelf();
MatrixState.PopMatrix();
MatrixState.PushMatrix();
MatrixState.translate(0,-0.8f,0);
rect[4].DrawSelf();
MatrixState.PopMatrix();
MatrixState.PushMatrix();
MatrixState.translate(0,-1.2f,0);
rect[5].DrawMutSelf();
MatrixState.PopMatrix();
MatrixState.PushMatrix();
MatrixState.translate(0,-1.6f,0);
mutRect.DrawMutSelf();
MatrixState.PopMatrix();
MatrixState.PopMatrix();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
InitTexture();
GLES20.glClearColor(0,0,0,1.0f);
//开启深度测试
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//开启背面剔除
//GLES20.glEnable(GLES20.GL_CULL_FACE);
rect[0] = new DrawRect(MyGLSurfaceView.this,textures[0]);
rect[1] = new DrawRect(MyGLSurfaceView.this,textures[0]);
rect[1].SetBigUv();
rect[2] = new DrawRect(MyGLSurfaceView.this,textures[1]);
rect[2].SetBigUv();
rect[3] = new DrawRect(MyGLSurfaceView.this,textures[2]);
rect[4] = new DrawRect(MyGLSurfaceView.this,textures[2]);
rect[4].SetBigUv();
rect[5] = new DrawRect(MyGLSurfaceView.this,textures[3]);
rect[5].SetBigUv();
mutRect = new DrawRect(MyGLSurfaceView.this,textures[0],textures[2]);
//初始化成单位矩阵
MatrixState.SetInit();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0,0,width,height);
float ratio = (float)width/height; //计算宽高比
MatrixState.setProjectFrustum(-ratio,ratio, -1, 1, 1, 100);
MatrixState.SetCamera(0, 0, 1.5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
public void InitTexture()
{
//文件中加载图片
Bitmap bitmap1 = LoadImageFromAsset("myTex.jpg");
Bitmap bitmap2 = LoadImageFromAsset("myTex2.jpg");
//生成7张贴图
GLES20.glGenTextures(
4,
textures,
0
);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.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);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(
GLES20.GL_TEXTURE_2D,
0,
bitmap1,
0
);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[1]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.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_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);
GLUtils.texImage2D(
GLES20.GL_TEXTURE_2D,
0,
bitmap1,
0
);
//第二张图片
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[2]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.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);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(
GLES20.GL_TEXTURE_2D,
0,
bitmap2,
0
);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[3]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.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_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);
GLUtils.texImage2D(
GLES20.GL_TEXTURE_2D,
0,
bitmap2,
0
);
if(bitmap1 != null)
bitmap1.recycle();
if(bitmap2 != null)
bitmap2.recycle();
}
public Bitmap LoadImageFromAsset(String file)
{
Bitmap bitmap = null;
try{
InputStream is = getResources().getAssets().open(file);
bitmap = BitmapFactory.decodeStream(is);
//加载贴图进显存
is.close();
}catch (Exception e)
{
e.printStackTrace();
}
return bitmap;
}
}
}
矩形的绘制比较简单,但要记住,OpenGL任何的面都是三角形,所以这里有6个顶点。
为了让 贴图可以展示出 Repeat,Clamp,和原图,需要2份Uv坐标 ,因为只有Uv坐标大于 1,才可以体现出来
注意:
Uv坐标系 从 左上角开始 S-T , S相当于X轴,T相当于Y轴,范围是 0~1.
多重纹理:
多重纹理使用了 另一份Shader,注意,这里为了让2张贴图不混乱,需要对Shader 里 Uniform 中 Sampler2D 进行赋值,且使int值,0,1。。怎么赋值就不说了
以下是2个贴图的 片元着色器
varying vec2 vTexCoor;
uniform sampler2D tex1;
uniform sampler2D tex2;
void main() {
//正片叠底
gl_FragColor = texture2D(tex1,vTexCoor) + texture2D(tex2,vTexCoor);
}
以下是DrawRect 画矩形,顶点是6个,因为矩形是2个三角形~
package com.talentgame.openglestexture;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import utils.MatrixState;
import utils.ShaderUtls;
/**
* Created by 54560 on 2016/10/11.
*/
public class DrawRect {
private MyGLSurfaceView myGLSurfaceView;
public float UnitSize = 1.5f;
public FloatBuffer vertBuffer;
public FloatBuffer uvBuffer;
//顶点指针
public int mVertPosHandle;
public int mUvHandle;
public int mMvpMatrixHandle;
public int mTex1Handle;
public int mTex2Handle;
public int mProgram;
public String mVertShader;
public String mFragShader;
//顶点数量
public int vCount;
//贴图Id
public int[] texIds = new int[2];
public DrawRect(MyGLSurfaceView myGLSurfaceView,int texId)
{
this.myGLSurfaceView = myGLSurfaceView;
InitVertex();
InitShader();
texIds[0] = texId;
}
public DrawRect(MyGLSurfaceView myGLSurfaceView,int texId0,int texId1)
{
this.myGLSurfaceView = myGLSurfaceView;
InitVertex();
InitMutShader();
texIds[0] = texId0;
texIds[1] = texId1;
}
public void SetBigUv()
{
uvBuffer.clear();
float[] uv = new float[]{
0,0,
2,0,
2,1,
2,1,
0,1,
0,0,
};
ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(uv.length * 4);
uvBuffer = byteBuffer1.order(ByteOrder.nativeOrder()).asFloatBuffer();
uvBuffer.put(uv);
uvBuffer.position(0);
}
public void InitVertex()
{
//初始化顶点数据
float[] vertexs = new float[]{
-0.2f,0.1f,0,
0.2f,0.1f,0,
0.2f,-0.1f,0,
0.2f,-0.1f,0f,
-0.2f,-0.1f,0f,
-0.2f,0.1f,0f
};
//乘与单位
for (int i=0;i<vertexs.length;i++)
vertexs[i]*= UnitSize;
vCount = vertexs.length /3;
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertexs.length * 4);
vertBuffer = byteBuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
vertBuffer.put(vertexs);
vertBuffer.position(0);
float[] uv = new float[]{
0,0,
1,0,
1,1,
1,1,
0,1,
0,0,
};
ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(uv.length * 4);
uvBuffer = byteBuffer1.order(ByteOrder.nativeOrder()).asFloatBuffer();
uvBuffer.put(uv);
uvBuffer.position(0);
}
public void InitShader()
{
mVertShader = ShaderUtls.LoadShaderFromAsset("rectVert.glsl",myGLSurfaceView.getResources());
mFragShader = ShaderUtls.LoadShaderFromAsset("rectFrag.glsl",myGLSurfaceView.getResources());
mProgram = ShaderUtls.CreatProgram(mVertShader,mFragShader);
mVertPosHandle = GLES20.glGetAttribLocation(mProgram,"aPosition");
mUvHandle = GLES20.glGetAttribLocation(mProgram,"aUv");
mMvpMatrixHandle = GLES20.glGetUniformLocation(mProgram,"uMvpMatirx");
}
public void InitMutShader()
{
mVertShader = ShaderUtls.LoadShaderFromAsset("rectVert.glsl",myGLSurfaceView.getResources());
mFragShader = ShaderUtls.LoadShaderFromAsset("mutTextureFrag.glsl",myGLSurfaceView.getResources());
mProgram = ShaderUtls.CreatProgram(mVertShader,mFragShader);
mVertPosHandle = GLES20.glGetAttribLocation(mProgram,"aPosition");
mUvHandle = GLES20.glGetAttribLocation(mProgram,"aUv");
mTex1Handle = GLES20.glGetUniformLocation(mProgram,"tex1");
mTex2Handle = GLES20.glGetUniformLocation(mProgram,"tex2");
mMvpMatrixHandle = GLES20.glGetUniformLocation(mProgram,"uMvpMatirx");
}
public void DrawSelf() {
GLES20.glUseProgram(mProgram);
GLES20.glVertexAttribPointer(mVertPosHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, vertBuffer);
GLES20.glVertexAttribPointer(mUvHandle, 2, GLES20.GL_FLOAT, false, 2 * 4, uvBuffer);
GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, MatrixState.GetMVPMatrix(), 0);
GLES20.glEnableVertexAttribArray(mVertPosHandle);
GLES20.glEnableVertexAttribArray(mUvHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
public void DrawMutSelf() {
GLES20.glUseProgram(mProgram);
GLES20.glVertexAttribPointer(mVertPosHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, vertBuffer);
GLES20.glVertexAttribPointer(mUvHandle, 2, GLES20.GL_FLOAT, false, 2 * 4, uvBuffer);
GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, MatrixState.GetMVPMatrix(), 0);
GLES20.glEnableVertexAttribArray(mVertPosHandle);
GLES20.glEnableVertexAttribArray(mUvHandle);
GLES20.glUniform1i(mTex1Handle,0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
GLES20.glUniform1i(mTex1Handle,1);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[1]);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
}