OpenGL ES 3.0學(xué)習(xí)實踐
- android平臺下OpenGL ES 3.0從零開始
- android平臺下OpenGL ES 3.0繪制純色背景
- android平臺下OpenGL ES 3.0繪制圓點瓣履、直線和三角形
- android平臺下OpenGL ES 3.0繪制彩色三角形
- android平臺下OpenGL ES 3.0從矩形中看矩陣和正交投影
- android平臺下OpenGL ES 3.0著色語言基礎(chǔ)知識(上)
- android平臺下OpenGL ES 3.0著色語言基礎(chǔ)知識(下)
- android平臺下OpenGL ES 3.0實例詳解頂點屬性框都、頂點數(shù)組
- android平臺下OpenGL ES 3.0實例詳解頂點緩沖區(qū)對象(VBO)和頂點數(shù)組對象(VAO)
- android平臺下OpenGLES3.0繪制立方體的幾種方式
目錄
繪制圖元的幾個方法
OpenGL ES
中有5個繪制圖元的API調(diào)用:
glDrawArrays的诵、gIDrawElements祖凫、glDrawRangeHonents、 glDrawArraysInstanced和glDrawElementsInstanced
。
glDrawArrays
用元素索引為first
到first+count-1
的元素指定的頂點繪制mode指定的圖元。
調(diào)用
glDrawArrays(GL_TRIANGLES, 0, 6)
將繪制兩個三角形:一個三角形由元素索引(0, 1, 2)
指定梁丘,另一個三角形由元素索引(3, 4, 5)
指定。
調(diào)用glDrawArrays(GL_TRIANGLE_STRIP旺韭,0, 5)
將繪制3個三角形:一個由元素索引(0, 1, 2)
指定氛谜,第二個三角形由元素索引(2, 1, 3)
指定,最后一個三角形由元素索引(2, 3, 4)
指定区端。
基于線段的方式
基于之前的工程項目值漫,新建LineCubeRenderer.java
類
/**
* @anchor: andy
* @date: 2018-11-09
* @description:
*/
public class LineCubeRenderer implements GLSurfaceView.Renderer {
private final FloatBuffer vertexBuffer;
private int mProgram;
private static final int POSITION_COMPONENT_COUNT = 3;
/**
* 點的坐標(biāo)
*/
private float[] vertexPoints = new float[]{
0.25f, 0.25f, 0.0f, //V0
-0.75f, 0.25f, 0.0f, //V1
-0.75f, -0.75f, 0.0f, //V2
0.25f, -0.75f, 0.0f, //V3
0.75f, -0.25f, 0.0f, //V4
0.75f, 0.75f, 0.0f, //V5
-0.25f, 0.75f, 0.0f, //V6
-0.25f, -0.25f, 0.0f, //V7
-0.25f, 0.75f, 0.0f, //V6
-0.75f, 0.25f, 0.0f, //V1
0.75f, 0.75f, 0.0f, //V5
0.25f, 0.25f, 0.0f, //V0
-0.25f, -0.25f, 0.0f, //V7
-0.75f, -0.75f, 0.0f, //V2
0.75f, -0.25f, 0.0f, //V4
0.25f, -0.75f, 0.0f //V3
};
public LineCubeRenderer() {
//分配內(nèi)存空間,每個浮點型占4字節(jié)空間
vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的坐標(biāo)數(shù)據(jù)
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//設(shè)置背景顏色
GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
//編譯
final int vertexShaderId = ShaderUtils.compileVertexShader(ResReadUtils.readResource(R.raw.vertex_linecube_shader));
final int fragmentShaderId = ShaderUtils.compileFragmentShader(ResReadUtils.readResource(R.raw.fragment_linecube_shader));
//鏈接程序片段
mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
//使用程序片段
GLES30.glUseProgram(mProgram);
GLES30.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GLES30.GL_FLOAT, false, 0, vertexBuffer);
GLES30.glEnableVertexAttribArray(0);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES30.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
//指定線寬
GLES30.glLineWidth(5);
GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 4);
GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 4, 4);
GLES30.glDrawArrays(GLES30.GL_LINES, 8, 8);
}
}
頂點著色器
#version 300 es
layout (location = 0) in vec4 vPosition;
out vec4 vColor;
void main() {
gl_Position = vPosition;
gl_PointSize = 10.0;
vColor = vec4(0.8,0.8,0.8,1.0);
}
片段著色器
#version 300 es
precision mediump float;
in vec4 vColor;
out vec4 fragColor;
void main() {
fragColor = vColor;
}
上面的坐標(biāo)點注釋已經(jīng)很清楚了,可以對照下面這張圖來理解對應(yīng)的坐標(biāo)
基于頂點法繪制立方體
/**
* @anchor: andy
* @date: 2018-11-09
* @description:
*/
public class ColorCubeRenderer implements GLSurfaceView.Renderer {
private final FloatBuffer vertexBuffer, colorBuffer;
private int mProgram;
private static final int VERTEX_POSITION_SIZE = 3;
private static final int VERTEX_COLOR_SIZE = 4;
/**
* 點的坐標(biāo)
*/
private float[] vertexPoints = new float[]{
//背面矩形
0.75f, 0.75f, 0.0f, //V5
-0.25f, 0.75f, 0.0f, //V6
-0.25f, -0.25f, 0.0f, //V7
0.75f, 0.75f, 0.0f, //V5
-0.25f, -0.25f, 0.0f, //V7
0.75f, -0.25f, 0.0f, //V4
//左側(cè)矩形
-0.25f, 0.75f, 0.0f, //V6
-0.75f, 0.25f, 0.0f, //V1
-0.75f, -0.75f, 0.0f, //V2
-0.25f, 0.75f, 0.0f, //V6
-0.75f, -0.75f, 0.0f, //V2
-0.25f, -0.25f, 0.0f, //V7
//底部矩形
0.75f, -0.25f, 0.0f, //V4
-0.25f, -0.25f, 0.0f, //V7
-0.75f, -0.75f, 0.0f, //V2
0.75f, -0.25f, 0.0f, //V4
-0.75f, -0.75f, 0.0f, //V2
0.25f, -0.75f, 0.0f, //V3
//正面矩形
0.25f, 0.25f, 0.0f, //V0
-0.75f, 0.25f, 0.0f, //V1
-0.75f, -0.75f, 0.0f, //V2
0.25f, 0.25f, 0.0f, //V0
-0.75f, -0.75f, 0.0f, //V2
0.25f, -0.75f, 0.0f, //V3
//右側(cè)矩形
0.75f, 0.75f, 0.0f, //V5
0.25f, 0.25f, 0.0f, //V0
0.25f, -0.75f, 0.0f, //V3
0.75f, 0.75f, 0.0f, //V5
0.25f, -0.75f, 0.0f, //V3
0.75f, -0.25f, 0.0f, //V4
//頂部矩形
0.75f, 0.75f, 0.0f, //V5
-0.25f, 0.75f, 0.0f, //V6
-0.75f, 0.25f, 0.0f, //V1
0.75f, 0.75f, 0.0f, //V5
-0.75f, 0.25f, 0.0f, //V1
0.25f, 0.25f, 0.0f //V0
};
//立方體的頂點顏色
private float[] colors = {
//背面矩形顏色
1f, 0f, 1f, 1f,
1f, 0f, 1f, 1f,
1f, 0f, 1f, 1f,
1f, 0f, 1f, 1f,
1f, 0f, 1f, 1f,
1f, 0f, 1f, 1f,
//左側(cè)矩形顏色
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
//底部矩形顏色
1f, 0f, 0.5f, 1f,
1f, 0f, 0.5f, 1f,
1f, 0f, 0.5f, 1f,
1f, 0f, 0.5f, 1f,
1f, 0f, 0.5f, 1f,
1f, 0f, 0.5f, 1f,
//正面矩形顏色
0.2f, 0.3f, 0.2f, 1f,
0.2f, 0.3f, 0.2f, 1f,
0.2f, 0.3f, 0.2f, 1f,
0.2f, 0.3f, 0.2f, 1f,
0.2f, 0.3f, 0.2f, 1f,
0.2f, 0.3f, 0.2f, 1f,
//右側(cè)矩形顏色
0.1f, 0.2f, 0.3f, 1f,
0.1f, 0.2f, 0.3f, 1f,
0.1f, 0.2f, 0.3f, 1f,
0.1f, 0.2f, 0.3f, 1f,
0.1f, 0.2f, 0.3f, 1f,
0.1f, 0.2f, 0.3f, 1f,
//頂部矩形顏色
0.3f, 0.4f, 0.5f, 1f,
0.3f, 0.4f, 0.5f, 1f,
0.3f, 0.4f, 0.5f, 1f,
0.3f, 0.4f, 0.5f, 1f,
0.3f, 0.4f, 0.5f, 1f,
0.3f, 0.4f, 0.5f, 1f
};
public ColorCubeRenderer() {
//分配內(nèi)存空間,每個浮點型占4字節(jié)空間
vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的坐標(biāo)數(shù)據(jù)
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
//分配內(nèi)存空間,每個浮點型占4字節(jié)空間
colorBuffer = ByteBuffer.allocateDirect(colors.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的數(shù)據(jù)
colorBuffer.put(colors);
colorBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//設(shè)置背景顏色
GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
//編譯
final int vertexShaderId = ShaderUtils.compileVertexShader(ResReadUtils.readResource(R.raw.vertex_colorcube_shader));
final int fragmentShaderId = ShaderUtils.compileFragmentShader(ResReadUtils.readResource(R.raw.fragment_colorcube_shader));
//鏈接程序片段
mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
//使用程序片段
GLES30.glUseProgram(mProgram);
GLES30.glVertexAttribPointer(0, VERTEX_POSITION_SIZE, GLES30.GL_FLOAT, false, 0, vertexBuffer);
//啟用位置頂點屬性
GLES30.glEnableVertexAttribArray(0);
GLES30.glVertexAttribPointer(1, VERTEX_COLOR_SIZE, GLES30.GL_FLOAT, false, 0, colorBuffer);
//啟用顏色頂點屬性
GLES30.glEnableVertexAttribArray(1);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES30.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 36);
}
}
輸出顯示如下:
聰明的你一定發(fā)現(xiàn)了珊燎,其實繪制立方體我們只需要繪制外層的三個面就可以了惭嚣,去掉頂點位置和顏色屬性
中的,背面悔政,左側(cè)以及底部相關(guān)的屬性
晚吞,只保留最外層的三個可見面,運行試試看谋国,結(jié)果也是一樣
基于索引法繪制立方體
/**
* @anchor: andy
* @date: 2018-11-09
* @description: 基于索引法繪制立方體
*/
public class IndicesCubeRenderer implements GLSurfaceView.Renderer {
private final FloatBuffer vertexBuffer, colorBuffer;
private final ShortBuffer indicesBuffer;
private int mProgram;
private static final int VERTEX_POSITION_SIZE = 3;
private static final int VERTEX_COLOR_SIZE = 4;
/**
* 點的坐標(biāo)
*/
private float[] vertexPoints = new float[]{
//正面矩形
0.25f, 0.25f, 0.0f, //V0
-0.75f, 0.25f, 0.0f, //V1
-0.75f, -0.75f, 0.0f, //V2
0.25f, -0.75f, 0.0f, //V3
//背面矩形
0.75f, -0.25f, 0.0f, //V4
0.75f, 0.75f, 0.0f, //V5
-0.25f, 0.75f, 0.0f, //V6
-0.25f, -0.25f, 0.0f //V7
};
/**
* 定義索引
*/
private short[] indices = {
//背面
5, 6, 7, 5, 7, 4,
//左側(cè)
6, 1, 2, 6, 2, 7,
//底部
4, 7, 2, 4, 2, 3,
//頂面
5, 6, 7, 5, 7, 4,
//右側(cè)
5, 0, 3, 5, 3, 4,
//正面
0, 1, 2, 0, 2, 3
};
//立方體的頂點顏色
private float[] colors = {
0.3f, 0.4f, 0.5f, 1f, //V0
0.3f, 0.4f, 0.5f, 1f, //V1
0.3f, 0.4f, 0.5f, 1f, //V2
0.3f, 0.4f, 0.5f, 1f, //V3
0.6f, 0.5f, 0.4f, 1f, //V4
0.6f, 0.5f, 0.4f, 1f, //V5
0.6f, 0.5f, 0.4f, 1f, //V6
0.6f, 0.5f, 0.4f, 1f //V7
};
public IndicesCubeRenderer() {
//分配內(nèi)存空間,每個浮點型占4字節(jié)空間
vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的坐標(biāo)數(shù)據(jù)
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
//分配內(nèi)存空間,每個浮點型占4字節(jié)空間
colorBuffer = ByteBuffer.allocateDirect(colors.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的數(shù)據(jù)
colorBuffer.put(colors);
colorBuffer.position(0);
//分配內(nèi)存空間,每個浮點型占4字節(jié)空間
indicesBuffer = ByteBuffer.allocateDirect(indices.length * 4)
.order(ByteOrder.nativeOrder())
.asShortBuffer();
//傳入指定的數(shù)據(jù)
indicesBuffer.put(indices);
indicesBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//設(shè)置背景顏色
GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
//編譯
final int vertexShaderId = ShaderUtils.compileVertexShader(ResReadUtils.readResource(R.raw.vertex_colorcube_shader));
final int fragmentShaderId = ShaderUtils.compileFragmentShader(ResReadUtils.readResource(R.raw.fragment_colorcube_shader));
//鏈接程序片段
mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
//使用程序片段
GLES30.glUseProgram(mProgram);
GLES30.glVertexAttribPointer(0, VERTEX_POSITION_SIZE, GLES30.GL_FLOAT, false, 0, vertexBuffer);
//啟用位置頂點屬性
GLES30.glEnableVertexAttribArray(0);
GLES30.glVertexAttribPointer(1, VERTEX_COLOR_SIZE, GLES30.GL_FLOAT, false, 0, colorBuffer);
//啟用顏色頂點屬性
GLES30.glEnableVertexAttribArray(1);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES30.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indicesBuffer);
}
}
輸出如下:
如果我們采用glDrawArrays
的方式槽地,需要給這個立方體指定很多的頂點,而使用glDrawElements
方法繪制的時候芦瘾,我們只需要指定8個頂點即可捌蚊,因此當(dāng)涉及到頂點共享的時候,應(yīng)該盡可能的使用glDrawElements
方法完成繪制近弟。
項目地址:
https://github.com/byhook/opengles4android
參考:
《OpenGL ES 3.0 編程指南第2版》
《OpenGL ES應(yīng)用開發(fā)實踐指南Android卷》