1 前言
【OpenGL ES】繪制三角形 中介紹了繪制普通三角形的方法,本文將介紹繪制彩色三角形的方法。
本文完整代碼資源見→【OpenGL ES】繪制彩色三角形
項(xiàng)目目錄如下:

2 案例
MainActivity.java
package com.zhyan8.triangle;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGlSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGlSurfaceView = new MyGLSurfaceView(this);
setContentView(mGlSurfaceView);
mGlSurfaceView.setRenderer(new MyRender(this));
}
@Override
protected void onResume() {
super.onResume();
mGlSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mGlSurfaceView.onPause();
}
}
MyGLSurfaceView.java
package com.zhyan8.triangle;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
public class MyGLSurfaceView extends GLSurfaceView {
public MyGLSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(3);
}
public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(3);
}
}
MyRender.java
package com.zhyan8.triangle;
import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRender implements GLSurfaceView.Renderer {
private FloatBuffer vertexBuffer;
private FloatBuffer colorBuffer;
private GLUtils mGLUtils;
public MyRender(Context context) {
mGLUtils = new GLUtils(context);
getFloatBuffer();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
//設(shè)置背景顏色
GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);
//編譯著色器
final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);
final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);
//鏈接程序片段
int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);
GLES30.glUseProgram(programId);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//設(shè)置視圖窗口
GLES30.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
//將顏色緩沖區(qū)設(shè)置為預(yù)設(shè)的顏色
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glLineWidth(5);
//啟用頂點(diǎn)的數(shù)組句柄
GLES30.glEnableVertexAttribArray(0);
GLES30.glEnableVertexAttribArray(1);
//準(zhǔn)備頂點(diǎn)坐標(biāo)和顏色數(shù)據(jù)
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
GLES30.glVertexAttribPointer(1, 4, GLES30.GL_FLOAT, false, 0, colorBuffer);
// GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3); //繪制三角形的三個(gè)頂點(diǎn)
// GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 3); //繪制三角形的三條邊
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3); //繪制三角形的內(nèi)部
//禁止頂點(diǎn)數(shù)組句柄
GLES30.glDisableVertexAttribArray(0);
GLES30.glDisableVertexAttribArray(1);
}
private void getFloatBuffer() {
float[] vertex = new float[] {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
float[] color = {
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
vertexBuffer = mGLUtils.getFloatBuffer(vertex);
colorBuffer = mGLUtils.getFloatBuffer(color);
}
}
GLUtils.java
package com.zhyan8.triangle;
import android.content.Context;
import android.opengl.GLES30;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class GLUtils {
private Context mContext;
public GLUtils(Context context) {
mContext = context;
}
public FloatBuffer getFloatBuffer(float[] floatArr) {
FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
fb.put(floatArr);
fb.position(0);
return fb;
}
//通過(guò)代碼片段編譯著色器
public int compileShader(int type, String shaderCode){
int shader = GLES30.glCreateShader(type);
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
//通過(guò)外部資源編譯著色器
public int compileShader(int type, int shaderId){
String shaderCode = readShaderFromResource(shaderId);
return compileShader(type, shaderCode);
}
//鏈接到著色器
public int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
//將頂點(diǎn)著色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//將片元著色器加入到程序
GLES30.glAttachShader(programId, fragmentShaderId);
//鏈接著色器程序
GLES30.glLinkProgram(programId);
return programId;
}
//從shader文件讀出字符串
private String readShaderFromResource(int shaderId) {
InputStream is = mContext.getResources().openRawResource(shaderId);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
}
vertex_shader.glsl
#version 300 es
layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec4 aColor;
out vec4 vColor;
void main() {
gl_Position = vPosition;
gl_PointSize = 20.0; //頂點(diǎn)大?。℅L_POINTS模式下才會(huì)生效)
vColor = aColor;
}
location 定義了頂點(diǎn)屬性的索引,如:位置屬性 index 為 0,顏色屬性 index 為 1。
頂點(diǎn)著色器的作用:進(jìn)行矩陣變換位置、根據(jù)光照公式計(jì)算頂點(diǎn)顏?、?成 / 變換紋理坐標(biāo),并且把位置和紋理坐標(biāo)發(fā)送到片元著色器。
頂點(diǎn)著色器中,如果沒(méi)有指定默認(rèn)精度,則 int 和 float 的默認(rèn)精度都為 highp。
fragment_shader.glsl
#version 300 es
precision mediump float; //聲明float型變量的精度為mediump
in vec4 vColor;
out vec4 fragColor;
void main() {
fragColor = vColor;
}
片元著色器的作用:處理經(jīng)光柵化階段生成的每個(gè)片元,計(jì)算每個(gè)像素的顏色和透明度。
在片元著色器中,浮點(diǎn)值沒(méi)有默認(rèn)的精度值,每個(gè)著色器必須聲明一個(gè)默認(rèn)的 float 精度。
注意: fragment_shader.glsl 與 vertex_shader.glsl 中的 “vColor” 可以換其他變量名,但必須一致。
運(yùn)行結(jié)果:
1)GL_POINTS 模式

2)GL_LINE_LOOP 模式

3)GL_TRIANGLES 模式

聲明:本文轉(zhuǎn)自【OpenGL ES】繪制彩色三角形