1、了解OpenGL着色语言(OpenGL Shading Language)中的三种变量(uniform,attribute和varying)
①、uniform:是由程序传入给(vertex和fragment)shader的变量,只能使用,不能修改。
如果uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和fragment共享使用。(相当于一个被vertex和fragment shader共享的全局变量)。
通过函数glUniform**()来赋值。
uniform变量一般用来表示:变换矩阵(viewProjMatrix),材质(material),光照参数(light)和颜色(color)等信息。
②、attribute: 只在vertex shader,不在fragment shader
通过函数glBindAttribLocation()、glVertexAttribPointer()来绑定数据和赋值。
attribute变量一般用来表示:一些顶点的数据,如:顶点坐标(vertex),法线(normal),纹理坐标(texcoord),顶点颜色(vertex color)等。
③、varying: vertex和fragment shader之间传递数据。vertex改变,fragment变换。
varying变量在vertex和fragment shader二者之间的声明必须是一致。
2、解读ShaderHelper(着色器助手类)
编译(compileVertexShader和compileFragmentShader)--->链接(linkProgram)--->验证(validateProgram)
编译
/**
* 编译着色器
* @param type 着色器类型
* @param shaderCode 着色器代码
* @return
*/
private static int compileShader(int type, String shaderCode){
int shaderObjectId = glCreateShader(type);
if(shaderObjectId == 0){
if(LoggerConfig.ON){
Log.w(TAG, "Coult not create new Shader");
}
return 0;
}
glShaderSource(shaderObjectId, shaderCode);
glCompileShader(shaderObjectId);
int[] compileStatus = new int[1];
glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);
if(LoggerConfig.ON){
Log.v(TAG, "Result of compiling source:"+"\n"+shaderCode+"\n"+glGetShaderInfoLog(shaderObjectId));
}
if(compileStatus[0] == 0){
glDeleteShader(shaderObjectId);
if(LoggerConfig.ON){
Log.w(TAG, "Compilation of shader failed");
}
return 0;
}
return shaderObjectId;
}
链接
/**
* 链接程序
* @param vertexShaderId 顶点着色器Id
* @param fragmentShaderId 碎片着色器Id
* @return
*/
public static int linkProgram(int vertexShaderId, int fragmentShaderId){
int programObjectId = glCreateProgram();
if(programObjectId == 0){
if(LoggerConfig.ON){
Log.w(TAG, "Could not create new Program");
}
return 0;
}
// 附上着色器
glAttachShader(programObjectId, vertexShaderId);
glAttachShader(programObjectId, fragmentShaderId);
// 链接
glLinkProgram(programObjectId);
int[] linkStatus = new int[1];
glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0);
if(LoggerConfig.ON){
Log.v(TAG, "Results of linking program:\n"+glGetProgramInfoLog(programObjectId));
}
if(linkStatus[0] == 0){
glDeleteProgram(programObjectId);
if(LoggerConfig.ON){
Log.v(TAG, "Linking of program failed");
}
return 0;
}
return programObjectId;
}
验证
/**
* 验证程序
* @param programObjectId 链接后的程序Id
* @return
*/
public static boolean validateProgram(int programObjectId){
glValidateProgram(programObjectId);
int[] validateSatus = new int[1];
glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateSatus, 0);
Log.v(TAG, "Result of validating program:\n"+glGetProgramInfoLog(programObjectId));
return validateSatus[0] != 0;
}
3、开始使用opengl es程序
。。。
4、添加细节纹理(loadTexture)
①、创建纹理助手类(TextureHelper)
/**
* 加载纹理信息
* @param context 上下文对象
* @param resourceId 资源Id
* @return
*/
public static int loadTexture(Context context, int resourceId){
int[] textureObjectId = new int[1];
// 分配一个纹理对象Id
glGenTextures(1, textureObjectId, 0);
if(textureObjectId[0] == 0){
if(LoggerConfig.ON){
Log.w(TAG, "Could not generate a new OpenGL Texture Object");
}
return 0;
}
// 加载图片资源 绑定纹理数据
BitmapFactory.Options o = new BitmapFactory.Options();
o.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, o);
if(bitmap == null){
glDeleteTextures(resourceId, textureObjectId, 0);
if(LoggerConfig.ON){
Log.w(TAG, "Resource ID "+resourceId+" could not be decoded");
}
return 0;
}
// 绑定 纹理号 到 纹理目标
glBindTexture(GL_TEXTURE_2D, textureObjectId[0]);
// 设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 生成纹理
texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
glGenerateMipmap(GL_TEXTURE_2D);
// 解除绑定
glBindTexture(GL_TEXTURE_2D, 0);
// 返回纹理对象标识
return textureObjectId[0];
}
②、编写texture_vertex_shader.glsl
uniform mat4 u_Matrix;
attribute vec4 a_Position;
attribute vec2 a_TextureCoordinates;
varying vec2 v_TextureCoordinates;
void main()
{
v_TextureCoordinates = a_TextureCoordinates;
gl_Position = u_Matrix * a_Position;
}
③、编写texture_fragment_shader.glsl
precision mediump float;
uniform sampler2D u_TextureUnit;
varying vec2 v_TextureCoordinates;
void main()
{
gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);
}
④、创建VertexArray类
public class VertexArray extends Constants{
private final FloatBuffer floatBuffer;
public VertexArray(float[] vertexData) {
// TODO Auto-generated constructor stub
floatBuffer = ByteBuffer
.allocateDirect(vertexData.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
}
public void setVertexAttribPointer( int dataOffset, int attributeLocation, int componentCount, int stride) {
floatBuffer.position(dataOffset);
glVertexAttribPointer(attributeLocation, componentCount, GL_FLOAT, false, stride, floatBuffer);
glEnableVertexAttribArray(attributeLocation);
floatBuffer.position(0);
}
}
⑤、准备工作(数据,绑定,绘制)
package com.opengles.android.objects;
import static android.opengl.GLES20.*;
import com.opengles.android.Constants;
import com.opengles.android.data.VertexArray;
import com.opengles.android.programs.TextureShaderProgram;
public class Table extends Constants{
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
private static final int STRIDE = (POSITION_COMPONENT_COUNT
+ TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT;
private static final float[] VERTEX_DATA = {
// Order of coordinates: X, Y, S, T
// Triangle Fan
0f, 0f, 0.5f, 0.5f,
-0.5f, -0.8f, 0f, 0.9f,
0.5f, -0.8f, 1f, 0.9f,
0.5f, 0.8f, 1f, 0.1f,
-0.5f, 0.8f, 0f, 0.1f,
-0.5f, -0.8f, 0f, 0.9f };
private VertexArray vertexArray;
public Table() {
vertexArray = new VertexArray(VERTEX_DATA);
}
public void bindData(TextureShaderProgram textureProgram) {
vertexArray.setVertexAttribPointer(0, textureProgram.getPositionAttributeLocation(), POSITION_COMPONENT_COUNT, STRIDE);
vertexArray.setVertexAttribPointer(POSITION_COMPONENT_COUNT, textureProgram.getTextureCoordinatesAttributeLocation(), TEXTURE_COORDINATES_COMPONENT_COUNT, STRIDE);
}
public void draw() {
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
}
}
⑥、添加纹理着色器程序
package com.opengles.android.programs;
import static android.opengl.GLES20.*;
import com.opengles.android.R;
import android.content.Context;
public class TextureShaderProgram extends ShaderProgram {
// Uniform locations
private final int uMatrixLocation;
private final int uTextureUnitLocation;
// Attribute locations
private final int aPositionLocation;
private final int aTextureCoordinatesLocation;
public TextureShaderProgram(Context context) {
super(context, R.raw.texture_vertex_shader,
R.raw.texture_fragment_shader);
// Retrieve uniform locations for the shader program.
uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
uTextureUnitLocation = glGetUniformLocation(program, U_TEXTURE_UNIT);
// Retrieve attribute locations for the shader program.
aPositionLocation = glGetAttribLocation(program, A_POSITION);
aTextureCoordinatesLocation = glGetAttribLocation(program,
A_TEXTURE_COORDINATES);
}
public void setUniforms(float[] matrix, int textureId) {
// Pass the matrix into the shader program.
glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
// Set the active texture unit to texture unit 0.
glActiveTexture(GL_TEXTURE0);
// Bind the texture to this unit.
glBindTexture(GL_TEXTURE_2D, textureId);
// Tell the texture uniform sampler to use this texture in the shader by
// telling it to read from texture unit 0.
glUniform1i(uTextureUnitLocation, 0);
}
public int getPositionAttributeLocation() {
return aPositionLocation;
}
public int getTextureCoordinatesAttributeLocation() {
return aTextureCoordinatesLocation;
}
}
⑦、真正绘制纹理
// 加载纹理程序
textureProgram = new TextureShaderProgram(context);
// 加载纹理数据
texture = TextureHelper.loadTexture(context, R.drawable.air_hockey_surface);
// 设置纹理程序,并使用
textureProgram.useProgram();
textureProgram.setUniforms(projectionMatrix, texture);
// 绑定纹理程序,并绘制
table.bindData(textureProgram);
table.draw();