- 基本框架
編寫一個(gè)類來(lái)繼承GLSurfaceView.Renderer检号,并實(shí)現(xiàn)其中的三個(gè)方法onSurfaceCreated每瞒、onSurfaceChanged云稚、onDrawFrame涵妥。
/**
* 基本框架
* Created by mazaiting on 2017/8/9.
*/
public class GLRenderer implements GLSurfaceView.Renderer {
/**
* 在窗口被創(chuàng)建時(shí)被調(diào)用个初,需要做一些必要的初始化工作:
*/
@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 啟動(dòng)陰影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 黑色背景乖寒,設(shè)置清楚屏幕時(shí)所用的顏色取值:RGBA.0f-1.0f
gl.glClearColor(0, 0, 0, 1.0f);
// 設(shè)置深度緩存--決定哪個(gè)物體先畫
gl.glClearDepthf(1.0f);
// 啟動(dòng)深度測(cè)試
gl.glEnable(GL10.GL_DEPTH_TEST);
// 所作深度測(cè)試的類型
gl.glDepthFunc(GL10.GL_LEQUAL);
// 告訴系統(tǒng)對(duì)透視進(jìn)行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
}
/**
* 當(dāng)窗口大小發(fā)生改變時(shí)被調(diào)用,不管窗口的大小是否已經(jīng)改變院溺,在程序開始時(shí)至少運(yùn)行一次楣嘁。
*/
@Override public void onSurfaceChanged(GL10 gl, int width, int height) {
float ratio = (float) width / height;
// 設(shè)置OpenGL場(chǎng)景的大小
gl.glViewport(0, 0, width, height);
// 設(shè)置投影矩陣--增加透視
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重置投影矩陣--恢復(fù)原始狀態(tài)
gl.glLoadIdentity();
// 設(shè)置視圖的大小
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
// 選擇模型觀察矩陣
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型觀察矩陣
gl.glLoadIdentity();
}
/**
* 在窗口內(nèi)進(jìn)行繪圖操作。 在繪圖之前珍逸,需要將屏幕清楚成前面指定的顏色逐虚,清楚深度緩存并且重置場(chǎng)景
*/
@Override public void onDrawFrame(GL10 gl) {
// 清楚屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置當(dāng)前的模型觀察矩陣
gl.glLoadIdentity();
// 具體繪圖開始...
}
/**
* OpenGL 是一個(gè)非常底層的畫圖接口,它所使用的緩沖區(qū)存儲(chǔ)結(jié)構(gòu)是和我們的 java 程序中不相同的谆膳。
* Java 是大端字節(jié)序(BigEdian)叭爱,而 OpenGL 所需要的數(shù)據(jù)是小端字節(jié)序(LittleEdian)。
* 所以漱病,我們?cè)趯?Java 的緩沖區(qū)轉(zhuǎn)化為 OpenGL 可用的緩沖區(qū)時(shí)需要作一些工作买雾。建立buff的方法如下
**/
public Buffer bufferUtil(int []arr){
// 先初始化buffer,數(shù)組的長(zhǎng)度*4,因?yàn)橐粋€(gè)int占4個(gè)字節(jié)
ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
// 數(shù)組排列用nativeOrder
qbb.order(ByteOrder.nativeOrder());
// 將ByteBuffer轉(zhuǎn)換為IntBuffer
IntBuffer mBuffer = qbb.asIntBuffer();
// 將數(shù)組設(shè)置進(jìn)去
mBuffer.put(arr);
//mBuffer.position(0);
// 重置
mBuffer.flip();
return mBuffer;
}
}
其中都是一些具體的配置,在主Activity中杨帽,我們首先創(chuàng)建出一個(gè)GLRenderer對(duì)象 漓穿,并創(chuàng)建GLSurfaceView對(duì)象,將GLRenderer對(duì)象設(shè)置在GLSurfaceView對(duì)象中注盈。器净、
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 基礎(chǔ)框架
GLSurfaceView.Renderer renderer = new GLRenderer();
GLSurfaceView glView = new GLSurfaceView(this);
glView.setRenderer(renderer);
// 設(shè)置布局
setContentView(glView);
}
}
至此,我們將OpenGL開發(fā)時(shí)所要做的配置已完成当凡,接下來(lái)我們?cè)趯懶碌腞enderer時(shí),只需要繼承在GLRenderer纠俭,重寫onDrawFrame(GL10 gl)方法即可沿量。
- 繪制多邊形
實(shí)現(xiàn)此類后,要想看到效果冤荆,務(wù)必將主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();
的此行代碼更改為GLSurfaceView.Renderer renderer = new PolygonRenderer();
/**
* 繪制多邊形
* Created by mazaiting on 2017/8/9.
*/
public class PolygonRenderer extends GLRenderer{
int one = 0x00010000;
//三角形三個(gè)頂點(diǎn)
private int[] triggerBuffer = new int[] {
0, one, 0,//上頂點(diǎn)
- one, -one, 0, //左下點(diǎn)
one, -one, 0,}; //右下點(diǎn)
//正方形的4個(gè)頂點(diǎn)
private int[] quaterBuffer = new int[]{
one,one,0,
-one,one,0,
one,-one,0,
-one,-one,0};
@Override public void onDrawFrame(GL10 gl) {
super.onDrawFrame(gl);
// 此函數(shù)朴则,就是將畫筆沿X軸左移1.5f個(gè)單位,Y軸保持不變钓简,Z軸向屏幕里面移動(dòng)6.0f個(gè)單位乌妒。
//gl.glTranslatef(-1.5f, 0.0f, -6.0f);
// 左移 1.5 單位,并移入屏幕 6.0
gl.glTranslatef(-1.5f, 0.0f, -6.0f);// z 軸值小于-1.0f
// 允許設(shè)置頂點(diǎn)
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 設(shè)置三角形
gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(triggerBuffer));
// 繪制三角形
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
// 重置當(dāng)前模型觀察矩陣
gl.glLoadIdentity();
// 右移 1.5 單位外邓,并移入屏幕 6.0
gl.glTranslatef(1.5f, 0.0f, -6.0f);// z 軸值小于-1.0f
// 設(shè)置四邊形
gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(quaterBuffer));
// 繪制四邊形
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
//取消頂點(diǎn)設(shè)置
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
// 重置當(dāng)前的模型觀察矩陣
gl.glLoadIdentity();
}
}
效果圖:
繪制多邊形.png
- 繪制顏色
實(shí)現(xiàn)此類后撤蚊,要想看到效果,務(wù)必將主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();
的此行代碼更改為GLSurfaceView.Renderer renderer = new ColorRenderer();
/**
* 繪制顏色
* Created by mazaiting on 2017/8/9.
*/
public class ColorRenderer extends GLRenderer {
int one = 0x10000;
//三角形三個(gè)頂點(diǎn) (r,g,b,a)
private int[] triggerBuffer = new int[] {
0, one, 0,//上頂點(diǎn)
- one, -one, 0, //左下點(diǎn)
one, -one, 0,}; //右下點(diǎn)
//正方形的4個(gè)頂點(diǎn)
private int[] quaterBuffer = new int[]{
one,one,0,
-one,one,0,
one,-one,0,
-one,-one,0};
//三角形的頂點(diǎn)顏色值(r,g,b,a)
private int[] colorBuffer = new int[]{
one,0,0,one,
0,one,0,one,
0,0,one,one,
};
@Override public void onDrawFrame(GL10 gl) {
super.onDrawFrame(gl);
// 左移 1.5 單位损话,并移入屏幕 6.0
gl.glTranslatef(-1.5f,0.0f,-6.0f);
//設(shè)置定點(diǎn)數(shù)組
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//設(shè)置顏色數(shù)組 -- 開啟顏色渲染功能.
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 設(shè)置三角形頂點(diǎn)的顏色
gl.glColorPointer(4,GL10.GL_FIXED,0,bufferUtil(colorBuffer));
// 設(shè)置三角形頂點(diǎn)
gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(triggerBuffer));
gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
//關(guān)閉顏色數(shù)組 -- 關(guān)閉顏色渲染功能.
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glLoadIdentity();
// 右移 1.5 單位侦啸,并移入屏幕 6.0
gl.glTranslatef(1.5f,0.0f,-6.0f);
// 設(shè)置當(dāng)前色為藍(lán)色
gl.glColor4f(0.0f,0.5f,1.0f,1.0f);
//設(shè)置和繪制正方形
gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(quaterBuffer));
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
//取消頂點(diǎn)數(shù)組
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
效果圖:
繪制顏色.png
- 繪制旋轉(zhuǎn)
實(shí)現(xiàn)此類后槽唾,要想看到效果,務(wù)必將主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();
的此行代碼更改為GLSurfaceView.Renderer renderer = new RotateRenderer();
/**
* 繪制旋轉(zhuǎn)圖形
* Created by mazaiting on 2017/8/9.
*/
public class RotateRenderer extends GLRenderer {
int one = 0x00010000;
//三角形三個(gè)頂點(diǎn)
private int[] triggerBuffer = new int[] {
0, one, 0,//上頂點(diǎn)
- one, -one, 0, //左下點(diǎn)
one, -one, 0,}; //右下點(diǎn)
@Override public void onDrawFrame(GL10 gl) {
super.onDrawFrame(gl);
gl.glTranslatef(-1.5f,0.0f,-6.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glRotatef(180f,0,0,0);//旋轉(zhuǎn)180
gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(triggerBuffer));
gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glLoadIdentity();
}
}
效果圖:
繪制旋轉(zhuǎn).png
- 繪制三棱錐
實(shí)現(xiàn)此類后光涂,要想看到效果庞萍,務(wù)必將主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();
的此行代碼更改為GLSurfaceView.Renderer renderer = new PyramidRenderer();
/**
* 四棱錐
* Created by mazaiting on 2017/8/9.
*/
public class PyramidRenderer extends GLRenderer {
int one = 0x10000;
// 四棱錐頂點(diǎn)數(shù)組:
private int[] triggerBuffer = new int[] {
0, one, 0,
-one, -one, one,
one, -one, one,
0,one, 0,
one,-one, one,
one, -one, -one,
0, one, 0,
one, -one, -one,
-one, -one, -one,
0, one, 0,
-one, -one, -one,
-one, -one, one
};
/**
* Every vertex has got its own color, described by 4 values
* R(ed)
* G(green)
* B(blue)
* A(lpha)
*/
int colors[] = {
0, 0, 0, one, one, 0, 0, one, one, one, 0, one, 0, one, 0, one, 0, 0, one, one, one, 0, one,
one, one, one, one, one, 0, one, one, one,
};
/**
* The last thing is that we need to describe some Triangles.
* A triangle got 3 vertices.
* The confusing thing is, that it is important in which order
* the vertices of each triangle are described.
* So describing a triangle through the vertices: "0, 4, 5"
* will not result in the same triangle as: "0, 5, 4"
* You probably ask: Why the hell isn't that the same ???
* The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);"
* which means, that we have to describe the "visible" side of the
* triangles by naming its vertices in a ClockWise order!
* From the other side, the triangle will be 100% lookthru!
* You can create a kind of magic mirror with that
**/
byte indices[] = {
0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3,
0, 1, 3, 1, 2
};
@Override public void onSurfaceChanged(GL10 gl, int width, int height) {
super.onSurfaceChanged(gl, width, height);
// 設(shè)置透視范圍
GLU.gluPerspective(gl, 45.0f, ((float) width) / height, 0.1f, 10f);
}
float xRot = 0.0f;
float yRot = 0.0f;
@Override public void onDrawFrame(GL10 gl) {
super.onDrawFrame(gl);
gl.glMatrixMode(GL10.GL_MODELVIEW);// 切換至模型觀察矩陣
gl.glLoadIdentity();// 重置當(dāng)前的模型觀察矩陣
GLU.gluLookAt(gl, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1f, 0f);//設(shè)置視點(diǎn)和模型中心位置
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(triggerBuffer));
gl.glRotatef(xRot,1f,0f,0f);// 繞著(0,0,0)與(1,0,0)即x軸旋轉(zhuǎn)
gl.glRotatef(yRot,0f,1f,0f);
gl.glColor4f(1.0f,0.0f,0.0f,1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
gl.glColor4f(0.0f,1.0f,0.0f,1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 3, 3);
gl.glColor4f(0.0f,0.0f,1.0f,1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 6, 3);
gl.glColor4f(1.0f,0.0f,1.0f,1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 9, 3);
xRot += 1.0f;
yRot += 0.5f;
}
}
效果圖:
三棱錐.png
- 繪制正方體
實(shí)現(xiàn)此類后,要想看到效果忘闻,務(wù)必將主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();
的此行代碼更改為GLSurfaceView.Renderer renderer = new CubeRenderer();
/**
* 繪制正方體
* Created by mazaiting on 2017/8/10.
*/
public class CubeRenderer extends GLRenderer{
float box[] = new float[] {
// FRONT
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// BACK
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// LEFT
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
// RIGHT
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// TOP
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// BOTTOM
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
};
FloatBuffer cubeBuff;
float xRot = 0.0f;
float yRot = 0.0f;
public CubeRenderer(){
cubeBuff = makeFloatBuffer(box);//轉(zhuǎn)換為float數(shù)組
}
@Override public void onSurfaceChanged(GL10 gl, int width, int height) {
super.onSurfaceChanged(gl, width, height);
// 設(shè)置透視范圍
GLU.gluPerspective(gl,45.0f,((float)width)/height,0.1f,10f);
}
@Override public void onDrawFrame(GL10 gl) {
super.onDrawFrame(gl);
gl.glMatrixMode(GL10.GL_MODELVIEW);// 切換至模型觀察矩陣
gl.glLoadIdentity();// 重置當(dāng)前的模型觀察矩陣
GLU.gluLookAt(gl,0f,0f,3f,0f,0f,0f,0f,1f,0f);//設(shè)置視點(diǎn)和模型中心位置
gl.glVertexPointer(3,GL10.GL_FLOAT, 0,cubeBuff);//設(shè)置頂點(diǎn)數(shù)據(jù)
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glRotatef(xRot,1f,0f,0f);// 繞著(0,0,0)與(1,0,0)即x軸旋轉(zhuǎn)
gl.glRotatef(yRot,0f,1f,0f);
gl.glColor4f(1.0f,0f,0f,1.0f);//設(shè)置顏色钝计,紅色
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);//繪制正方形FRONT面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,4,4);
gl.glColor4f(0f,1.0f,0f,1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,8,4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,12,4);
gl.glColor4f(0f,0f,1.0f,1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,16,4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,20,4);
xRot += 1.0f;
yRot += 0.5f;
}
/**
* 將float數(shù)組轉(zhuǎn)換為存儲(chǔ)在字節(jié)緩沖數(shù)組
* @param arr
* @return
*/
public FloatBuffer makeFloatBuffer(float[] arr){
// 分配緩沖空間,一個(gè)float占4個(gè)字節(jié)
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(arr.length*4);
// 設(shè)置字節(jié)順序齐佳,其中ByteOrder.nativeOrder()是獲取本機(jī)字節(jié)順序
byteBuffer.order(ByteOrder.nativeOrder());
// 轉(zhuǎn)換為float型
FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
// 添加數(shù)據(jù)
floatBuffer.put(arr);
// 設(shè)置數(shù)組的起始位置
floatBuffer.position(0);
return floatBuffer;
}
}
效果圖:
立方體.png