package yeah.test.opengl.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import jp.co.cyberagent.android.gpuimage.util.OpenGlUtils;
import yeah.test.R;
import yeah.test.util.LogTag;
/**
* @author: heweiyan
* @date : 2020/11/1
*/
public class OpenGLTestSurfaceView extends GLSurfaceView implements GLSurfaceView.Renderer {
// 测试用的顶点着色器
public static final String TEST_VERTEX_SHADER ="" +
// 含四个浮点型数据的向量,顶点坐标
"attribute vec4 vPosition;\n" +
// 纹理坐标,从图片上采集像素的位置
"attribute vec2 vCoord;\n" +
" \n" +
// 易变坐标,通过varing传给片元着色器varing修饰的变量
"varying vec2 aCoord;\n" +
" \n" +
"void main()\n" +
"{\n" +
" gl_Position = vPosition;\n" +
" aCoord = vCoord;\n" +
"}";
// 测试用的片元着色器
public static final String TEST_FRAGMENT_SHADER ="" +
// 跟顶点着色器的aCoord对应起来,一定要有
"varying highp vec2 aCoord;\n" +
// 2D纹理采样器(代表一层纹理,一般就是一张图片)
"uniform sampler2D vTexture;\n" +
"uniform highp float red;\n" +
"uniform highp float green;\n" +
"uniform highp float blue;\n" +
"\n" +
"void main()\n" +
"{\n" +
// 采集vTexutre画布的aCoord位置的像素
" highp vec4 textureColor = texture2D(vTexture, aCoord);\n" +
" \n" +
" gl_FragColor = vec4(textureColor.r * red, textureColor.g * green, textureColor.b * blue, 1.0);\n" +
"}";
public OpenGLTestSurfaceView(Context context) {
this(context,null);
}
public OpenGLTestSurfaceView(Context context,AttributeSet attrs) {
super(context, attrs);
init();
}
// 片元着色器的纹理变量ID
private int vTexture;
private int[]colorsID =new int[3];
// 用于绑定画布的纹理变量ID
private int mBitmapTextureID;
private void init() {
// OpenGL ES版本设为2
setEGLContextClientVersion(2);
// 设置渲染器
setRenderer(this);
// // 按需渲染,当requestRender()时才会回调Renderer的onDrawFrame()
// setRenderMode(RENDERMODE_WHEN_DIRTY);
// 连续渲染
setRenderMode(RENDERMODE_CONTINUOUSLY);
}
@Override
public void onSurfaceCreated(GL10 gl,EGLConfig config) {
Log.e(LogTag.TEST_OPENGL,"onSurfaceCreated()");
// 先清空画布
glClear();
initGLSL();
}
/**
* 清空一下OpenGL画布
*/
private void glClear() {
GLES20.glClearColor(0,0,0,0);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
/**
* 初始化OpenGL的GLSL(着色器语言)
* GLSL是面向过程的语言
*/
private void initGLSL() {
// 根据顶点着色器和片元着色器创建一个着色器程序ID
int program =OpenGlUtils.loadProgram(TEST_VERTEX_SHADER,TEST_FRAGMENT_SHADER);
// 应用该程序
GLES20.glUseProgram(program);
// 获取顶点着色器的参数ID
int vPosition =GLES20.glGetAttribLocation(program,"vPosition");
int vCoord =GLES20.glGetAttribLocation(program,"vCoord");
// 获取片元着色器的图片参数ID
vTexture =GLES20.glGetUniformLocation(program,"vTexture");
colorsID[0] =GLES20.glGetUniformLocation(program,"red");
colorsID[1] =GLES20.glGetUniformLocation(program,"green");
colorsID[2] =GLES20.glGetUniformLocation(program,"blue");
mBitmapTextureID =OpenGlUtils.NO_TEXTURE;
initCoord(vPosition,vCoord);
}
/**
* 设置顶点和纹理坐标数据
*
* @param vPositon 顶点坐标变量ID
* @param vCoord 纹理坐标变量ID
*/
private void initCoord(int vPositon,int vCoord) {
// 给vPosition赋值
FloatBuffer vertexBuffer =ByteBuffer.allocateDirect(VERTEX.length *4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(VERTEX);
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(vPositon,2,GLES20.GL_FLOAT,false,0,vertexBuffer);
GLES20.glEnableVertexAttribArray(vPositon);
// 给vCoord赋值
FloatBuffer textureBuffer =ByteBuffer.allocateDirect(TEXTURE.length *4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(TEXTURE);
textureBuffer.position(0);
GLES20.glVertexAttribPointer(vCoord,2,GLES20.GL_FLOAT,false,0,textureBuffer);
GLES20.glEnableVertexAttribArray(vCoord);
}
@Override
public void onSurfaceChanged(GL10 gl,int width,int height) {
Log.e(LogTag.TEST_OPENGL,"onSurfaceChanged()");
GLES20.glViewport(0,0, width, height);
}
private float VERTEX[] = {
-1.0f,1.0f,
1.0f,1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
};
private float TEXTURE[] = {
0.0f,0.0f,
1.0f,0.0f,
0.0f,1.0f,
1.0f,1.0f,
};
private Bitmap mBitmap;
private int[]rgbArry =new int[]{100,0,0};
@Override
public void onDrawFrame(GL10 gl) {
Log.e(LogTag.TEST_OPENGL,"onDrawFrame()");
if (mBitmap ==null ||mBitmap.isRecycled()) {
Log.e(LogTag.TEST_OPENGL,"Create bitmap.");
mBitmap =BitmapFactory.decodeResource(getResources(),R.drawable.beauty);
// 根据Bitmap创建一个纹理ID
mBitmapTextureID =OpenGlUtils.loadTexture(mBitmap,mBitmapTextureID,false);
}
// 清空一下画布
glClear();
for (int i =0; i
if (rgbArry[i] !=0) {
rgbArry[i] -=1;
if (rgbArry[i] ==0) {
rgbArry[(i +1) %rgbArry.length] =100;
}
break;
}
}
for (int i =0; i
GLES20.glUniform1f(colorsID[i],rgbArry[i] /100f);
}
// 激活一个0号画布
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// 把创建好的图片画到画布上去
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mBitmapTextureID);
// 把画好东西的画布赋值给片元着色器的vTexture
// 第二个参数是画布的序号,和上面激活的画布序号要对应
GLES20.glUniform1i(vTexture,0);
// 通知GLSL画画
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mBitmap !=null && !mBitmap.isRecycled()) {
mBitmap.recycle();
mBitmap =null;
}
}
}
网友评论