流程
1、编写着色器(顶点着色器和片元着色器)
2、设置顶点、纹理坐标
3、加载着色器
4、创建纹理
5、渲染图片
OpenGL ES 中的顶点坐标与纹理坐标
绘制四边形
规定:图形环绕方向必须一致
参数属性:三角形 GL_TRIANGLES:
v1, v2, v3,
v3, v2, v4,
参数属性:三角形扇 GL_TRIANGLE_STRIP:
偶数:n-1, n-2, n
奇数:n-2, n-1, n
顶点内存数组
1、绘制坐标范围:
float[] vertexData = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f };
2、为坐标分配本地内存地址:
FloatBuffer vertexBuffer;
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
vertex_shader.glsl 顶点着色器shader
attribute vec4 v_Position; //顶点坐标
attribute vec2 f_Position; //纹理坐标
varying vec2 ft_Position; //
void main() {
ft_Position = f_Position;
gl_Position = v_Position;
}
attribute 只能在vertex中使用varying 用于vertex顶点着色器 和 fragment片元着色器之间传递值
fragment_shader.glsl 片元着色器shader
precision mediump float; //绘制精度
varying vec2 ft_Position; //与顶点着色器中传值
uniform sampler2D sTexture; //图片
void main() {
gl_FragColor=texture2D(sTexture, ft_Position);
}
注: uniform 用于在application中向vertex和fragment中传递值。
OpenGL ES加载Shader
1、创建shader( shaderType 着色器类型:顶点或片元)
int shader = GLES20.glCreateShader(shaderType);
2、加载shader源码并编译shader
GLES20.glShaderSource(shader, source); //source 着色器语言中的字符串
GLES20.glCompileShader(shader); //编译
3、检查是否编译成功:
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
4、创建一个渲染程序:
int program = GLES20.glCreateProgram();
5、将着色器程序添加到渲染程序中:
GLES20.glAttachShader(program, vertexShader); //将指定的顶点/纹理添加至程序里面
6、链接源程序:
GLES20.glLinkProgram(program);
7、检查链接源程序是否成功
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
8、得到着色器中的属性:
int vPosition = GLES20.glGetAttribLocation(program, "v_Position");
9、使用源程序:
GLES20.glUseProgram(program);
10、使顶点属性数组有效:
GLES20.glEnableVertexAttribArray(vPosition);
11、为顶点属性 vPosition 赋值:
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8 ,vertexBuffer); // 2 两个属性确定一个点 GL_FLOAT类型 false是否需要归一化 8两点之间的跨度 vertexBuffer本地缓存
// 取8位变成2个点
12、绘制图形:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); //三角形带
工具方法
// 1 .从raw文件中获取字符串
public static String getRawResource(Context context, int rawId) {
InputStream inputStream = context.getResources().openRawResource(rawId);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb = new StringBuffer();
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
//2 .根据顶点着色器字符串和片元着色器字符串创建 shader
private static int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] compile = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compile, 0);
if (compile[0] != GLES20.GL_TRUE) {
GLES20.glDeleteShader(shader);
shader = 0;
}
return shader;
} else {
return 0;
}
}
//3 .根据shader创建program
public static int createProgram(String vertexSource, String fragmentSoruce) {
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSoruce);
if (vertexShader != 0 && fragmentShader != 0) {
int program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
return program;
}
return 0;
}
GImgVideoView
package com.example.glivepush.opengl;
import android.content.Context;
import android.util.AttributeSet;
import com.example.glivepush.egl.GEGLSurfaceView;
public class OpenGLView extends GEGLSurfaceView {
public OpenGLView(Context context) {
this(context, null);
}
public OpenGLView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public OpenGLView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setRender(new OpenGLRender(context));
}
}
GImgVideoRender
package com.example.glivepush.opengl;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import com.example.glivepush.R;
import com.example.glivepush.egl.GEGLSurfaceView;
import com.example.glivepush.egl.GShaderUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class OpenGLRender implements GEGLSurfaceView.GGLRender {
private Context context;
//顶点坐标 主要用来在本地开辟内存
private float[] vertexData = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f
};
//生成的本地内存
private FloatBuffer vertexBuffer;
//纹理坐标
private float[] fragmentData = {
0f, 1f,
1f, 1f,
0f, 0f,
1f, 0f
};
//生成的本地内存
private FloatBuffer fragmentBuffer;
private int program;
private int vPosition;
private int fPosition;
private int textureid;
private int sampler;
public OpenGLRender(Context context) {
this.context = context;
//生成的本地内存
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(fragmentData);
fragmentBuffer.position(0);
}
@Override
public void onSurfaceCreated() {
//工具方法加载代码
String vertexSource = GShaderUtil.getRawResource(context, R.raw.vertex_shader_screen);
String fragmentSource = GShaderUtil.getRawResource(context, R.raw.fragment_shader_screen);
//工具方法创建program
program = GShaderUtil.createProgram(vertexSource, fragmentSource);
if (program > 0) {
//取出顶点坐标
vPosition = GLES20.glGetAttribLocation(program, "v_Position");
//取出纹理坐标
fPosition = GLES20.glGetAttribLocation(program, "f_Position");
sampler = GLES20.glGetUniformLocation(program, "sTexture");
}
//生成纹理
int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0);
textureid = textureIds[0];
//绑定纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureid);
//绑定至第0位
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//将sampler绑定至第0位
GLES20.glUniform1f(sampler, 0);
//设置环绕过滤方法
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//绘制图片
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.img_1);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
bitmap = null;
//解绑
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
@Override
public void onSurfaceChanged(int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame() {
//清屏
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(1f, 0f, 0f, 1f);
//使程序生效
GLES20.glUseProgram(program);
//重新绑定
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureid);
//使顶点属性数组有效
GLES20.glEnableVertexAttribArray(vPosition);
//为顶点属性赋值
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8,
vertexBuffer);
//使纹理属性数组有效
GLES20.glEnableVertexAttribArray(fPosition);
//为顶点属性赋值
GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8,
fragmentBuffer);
//绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
//解绑
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
}