之前有過幾個(gè)案例曙痘,使用的著色器都寫在游戲中腰耙,一般的我們會(huì)寫在一個(gè)文件中,通過文件來讀取shader枪芒。然后會(huì)說明一個(gè)特殊的區(qū)域ByteBuffer轿钠,介紹為什么需要使用他們,然后介紹著色器的加載編譯病苗,程序的創(chuàng)建,附著症汹,鏈接以及使用硫朦。形成一個(gè)完整的復(fù)用代碼、
文件加載
public String uRes(String path){
if (mRes == null) System.out.println("八嘎!");
StringBuilder result=new StringBuilder();
try{
InputStream is=mRes.getAssets().open(path);
int ch;
byte[] buffer=new byte[1024];
while (-1!=(ch=is.read(buffer))){
result.append(new String(buffer,0,ch));
}
}catch (Exception e){
return null;
}
return result.toString().replaceAll("\\r\\n","\n");
}
將讀入的結(jié)果變?yōu)橐粋€(gè)字符串背镇。這個(gè)通過上下文讀取asset文件夾下的文件咬展,讓按照字節(jié)讀取泽裳,然后變?yōu)橐粋€(gè)字符串輸出;
ByteBuffer
它是一個(gè)字節(jié)緩沖區(qū)破婆,它的屬性和方法涮总。
- mark:記錄了當(dāng)前所標(biāo)記的索引下標(biāo)
- position:表示下次讀取下標(biāo)或者是寫入下標(biāo)
- limit:結(jié)束位置
在open gl es使用的過程中,需要數(shù)組排序用nativeOrder,根據(jù)本地的排列順序祷舀,
操作過程:
ByteBuffer bb = ByteBuffer.allocateDirect( triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
創(chuàng)建著色器
創(chuàng)建著色器在步驟:
- 創(chuàng)建著色器
- 添加代碼
- 編譯
- 檢查錯(cuò)誤
public int loadShader(int type, String shaderCode){
//根據(jù)type創(chuàng)建頂點(diǎn)著色器或者片元著色器
int shader = GLES20.glCreateShader(type);
//將資源加入到著色器中瀑梗,并編譯
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
int []arr = new int[1];
GLES20.glGetShaderiv(shader,GLES20.GL_COMPILE_STATUS,arr,0);
int i = arr[0];
if (i == 0){
//失敗了
int [] length = new int[1];
GLES20.glGetShaderiv(shader,GLES20.GL_INFO_LOG_LENGTH,length,0);
if (length[0]>0){
String s = GLES20.glGetShaderInfoLog(shader);
System.out.println(s);
}
}
return shader;
}
創(chuàng)建程序
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram,vertexShader);
GLES20.glAttachShader(mProgram,fragmentShader);
GLES20.glLinkProgram(mProgram);
int lin[] = new int[1];
GLES20.glGetProgramiv(mProgram,GLES20.GL_LINK_STATUS,lin,0);
if (lin[0] == 0){
String s = GLES20.glGetProgramInfoLog(mProgram);
System.out.println(s);
}
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
在鏈接之后,著色器就可以被刪除了裳扯。
BaseScrren基本的代碼就折磨多了抛丽。一個(gè)完整的代碼:
package com.example.myapplication.learn.shape.base;
import android.content.res.Resources;
import android.opengl.GLES20;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public abstract class BaseGameScreen {
protected float color[];
protected float triangleCoords[];
protected String fragmentShaderCode;
protected String vertexShaderCode;
protected FloatBuffer vertexBuffer;
protected FloatBuffer colorBuffer;
protected int mProgram ;
private Resources mRes;
public BaseGameScreen(){}
public BaseGameScreen(Resources resources){
this.mRes = resources;
}
public int loadShader(int type, String shaderCode){
//根據(jù)type創(chuàng)建頂點(diǎn)著色器或者片元著色器
int shader = GLES20.glCreateShader(type);
//將資源加入到著色器中,并編譯
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
int []arr = new int[1];
GLES20.glGetShaderiv(shader,GLES20.GL_COMPILE_STATUS,arr,0);
int i = arr[0];
if (i == 0){
//失敗了
int [] length = new int[1];
GLES20.glGetShaderiv(shader,GLES20.GL_INFO_LOG_LENGTH,length,0);
if (length[0]>0){
String s = GLES20.glGetShaderInfoLog(shader);
System.out.println(s);
}
}
return shader;
}
public abstract void render();
public void create(){
ByteBuffer bb = ByteBuffer.allocateDirect(
triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(color.length*4);
byteBuffer.order(ByteOrder.nativeOrder());
colorBuffer = byteBuffer.asFloatBuffer();
colorBuffer.put(color);
colorBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram,vertexShader);
GLES20.glAttachShader(mProgram,fragmentShader);
GLES20.glLinkProgram(mProgram);
int lin[] = new int[1];
GLES20.glGetProgramiv(mProgram,GLES20.GL_LINK_STATUS,lin,0);
if (lin[0] == 0){
String s = GLES20.glGetProgramInfoLog(mProgram);
System.out.println(s);
}
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
}
public abstract void surfaceChange(int width,int height);
public abstract void dispose();
public void resume() {
}
public String uRes(String path){
if (mRes == null) System.out.println("八嘎!");
StringBuilder result=new StringBuilder();
try{
InputStream is=mRes.getAssets().open(path);
int ch;
byte[] buffer=new byte[1024];
while (-1!=(ch=is.read(buffer))){
result.append(new String(buffer,0,ch));
}
}catch (Exception e){
return null;
}
return result.toString().replaceAll("\\r\\n","\n");
}
}
補(bǔ)充個(gè)東西
有時(shí)候我們?cè)邳c(diǎn)擊一個(gè)按鈕之后執(zhí)繪制線程中的操作就崩了饰豺,這個(gè)時(shí)候一般的操作是:點(diǎn)擊之后將事件操作保存起來亿鲜,然后在幀刷新的時(shí)候取出來執(zhí)行。