着色器在OpenGL中起着很重要的角色,前面我们也对着色器基本认识,图像渲染的,用来替代固定渲染管线的可编程程序。着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编程性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。这极大的提高了图像的画质。
一、流程
着色器函数介绍
着色器使用示例
二、具体介绍
1、着色器函数介绍
glGetAttribLocation
函数原型:int glGetAttribLocation(int var0, String var1)
var0:获得着色器程序id
var1:顶点着色器的变量 如vPosition
glGetUniformLocation
函数原型:int glGetUniformLocation(int var0, String var1)
var0:获得着色器程序id
var1:顶点着色器的变量 如vPosition
glVertexAttribPointer
画笔设置顶点、颜色、纹理数据
函数原型:void glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, Buffer ptr)
indx:指定要修改的顶点属性的索引值
size:指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
type:指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
normalized:指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)。
stride:指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。
ptr:需要赋的值指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0。
glEnableVertexAttribArray
开启顶点和纹理绘制,激活属性字段
函数原型:void glEnableVertexAttribArray(int var0)
var0:着色器顶点数据
glActiveTexture
该函数选择一个纹理单元,线面的纹理函数将作用于该纹理单元上,参数为符号常量GL_TEXTUREi ,i的取值范围为0~K-1,K是OpenGL实现支持的最大纹理单元数,和GLES20.glUniform1f(vTexture, i)相对应。
glBindTexture
绑定纹理数据
函数原型:glBindTexture(int var0, int var1);
var0:纹理类型
var1:纹理数据
glDrawArrays
执行绘制
函数原型:GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
mode:绘制方式,OpenGL2.0以后提供以下参数:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
first:从数组缓存中的哪一位开始绘制,一般为0。
count:数组中顶点的数量。
mode | 说明 |
---|---|
GL_LINES_STRIP(条带线) | 按照顶点顺序连接顶点 |
GL_TRIANGLES(循环线) | 按照顶点顺序连接顶点,最后一个点连接第一点 |
GL_TRIANGLES(三角形) | 三个点一组,如果不够三个点就会舍弃 多余的点 |
GL_TRIANGLE_STRIP(三角形带) | 顶点按照顺序依次 组成三角形绘制,最后实际形成的是一个三角型带 |
GL_TRIANGLE_FAN(三角形扇面) | 将第一个点作为中心点,其他点作为边缘点,绘制一系列的组成扇形的三角形 |
glCreateShader
函数原型:int glCreateShader(int type)
type:GLES20.GL_VERTEX_SHADER或GLES20.GL_FRAGMENT_SHADER
glShaderSource
函数原型:int glShaderSource(int shader, String source)
shader:着色器id
source:着色器String文件
加载着色器资源
glCompileShader
函数原型:void glCompileShader (int shader)
shader:片元着色器或顶点着色器id
编译着色器
glDeleteShader
函数原型:void glDeleteShader (int shader)
shader:片元着色器或顶点着色器id
删除着色器
glCreateProgram
函数原型:int glCreateProgram ()
在连接着色器之前,应该先创建着色器接收程序的容器,该方法相当于就是创建一个容器。
如果创建成功,返回一个正整数作为该着色器程序的id。
glAttachShader
函数原型:void glAttachShader (int program, int shader)
绑定顶点着色器着色器和片元着色器,绑定到容器中。它们都是同一个方法。
glLinkProgram
函数原型:void glLinkProgram (int program)
链接程序
glGetProgramiv
函数原型:void glGetProgramiv(int var0, int var1, int[] var2, int var3)
获取program的连接情况
在这里创建着色器程序的代码基本介绍完毕了,在CreateProgram方法中,返回一个int类型的变量,我暂时把这个int类型的变量叫做变量A,在使用时,还会用到glUseProgram。
glUseProgram
函数原型:void glUseProgram(int var0);
它的作用就是使用某套share程序
Matrix
在MatrixState自定义的类中,封装了对变换矩阵的常用方法
public class MatrixState {
private static float[] mProjMatrix = new float[16];//4x4矩阵 投影用
private static float[] mVMatrix = new float[16];//摄像机位置朝向9参数矩阵
private static float[] mMVPMatrix;//最后起作用的总变换矩阵
static float[] mMMatrix = new float[16];//具体物体的移动旋转矩阵
//获取不变换初始矩阵
public static void setInitStack() {
Matrix.setRotateM(mMMatrix, 0, 0, 1, 0, 0);
}
//设置沿xyz轴移动
public static void transtate(float x, float y, float z) {
Matrix.translateM(mMMatrix, 0, x, y, z);
}
//设置绕xyz轴转动
public static void rotate(float angle, float x, float y, float z) {
Matrix.rotateM(mMMatrix, 0, angle, x, y, z);
}
/**
* 作用:设置摄像机
* 前三个:摄像机位置x y z
* 中间三个:摄像机目标点x y z
* 后三个:摄像机UP向量X分量,摄像机UP向量Y分量,摄像机UP向量Z分量
*/
public static void setCamera(float cx, float cy, float cz, float tx, float ty, float tz, float upx, float upy, float upz) {
Matrix.setLookAtM(mVMatrix, 0,
cx, cy, cz,
tx, ty, tz,
upx, upy, upz);
}
/**
* 作用:设置透视投影参数
* 前四个:near面的left,right,bottom,top
* 后两个:near面距离,far面距离
*/
public static void setProject(float left, float right, float bottom, float top, float near, float far) {
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
}
//获取具体物体的总变换矩阵( // 合并投影和视口矩阵 )
public static float[] getFinalMatrix() {
mMVPMatrix = new float[16];
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
return mMVPMatrix;
}
}
2、着色器使用示例
创建着色器片段
public int loadshader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
//加载shader的源代码
GLES20.glShaderSource(shader, source);
//编译shader
GLES20.glCompileShader(shader);
//声明一个数组存放着色器
int[] shaderNum = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, shaderNum, 0);
if (shaderNum[0] != 0) {
Log.e("zxx", "Could not compile shader " + shaderType + ":");
Log.e("zxx", GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
创建着色器程序
/**
*返回着色器程序id
*/
public int CreateProgram(String vertexSource, String fragmentSource) {
//加载顶点着色器
int vertexProgram = loadshader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertexProgram == 0) {
return 0;
}
//加载片元着色器
int fragmentProgram = loadshader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentProgram == 0) {
return 0;
}
//创建程序
int program = GLES20.glCreateProgram();
//若程序创建成功则向程序中加入顶点着色器与片元着色器
if (program != 0) {
//绑定顶点着色器
GLES20.glAttachShader(program, vertexProgram);
checkGlError("glAttachShader");//检测错误
//绑定片元着色器
GLES20.glAttachShader(program, fragmentProgram);
checkGlError("fragmentProgram");//检测错误
GLES20.glLinkProgram(program);//链接程序
//---------实际这一步都已经成功了,只是要检测错误的着色器
//存放连接错误的数据
int[] linkstatus = new int[1];
//获取program的连接情况
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkstatus, 0);
if (linkstatus[0] != GLES20.GL_TRUE) {
Log.e("zxx", "Could not link program: ");
Log.e("zxx", GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
//检测错误
public void checkGlError(String op) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e("zxx", op + ": glError " + error);
throw new RuntimeException(op + ": glError " + error);
}
}
使用着色器
//初始化着色器
public void initShader(Context context) {
//加载顶点着色器的脚本内容
String vertexSource = OpenUtils.readRawTextFile(context, R.raw.camera_vertex);
//加载片元着色器的脚本内容
String fragSource = OpenUtils.readRawTextFile(context, R.raw.camera_frag);
//基于顶点着色器与片元着色器创建程序
mProgram = CreateProgram(mVertexShader, mFragmentShader);
//获取程序中顶点位置属性引用id
vPosition = GLES20.glGetAttribLocation(mProgram, "vPosition");
//获取程序中顶点纹理坐标属性引用id
vCoord = GLES20.glGetAttribLocation(mProgram, "vCoord");
//获取程序中总变换矩阵引用id
vMatrix = GLES20.glGetUniformLocation(mProgram, "vMatrix");
}