【OpenGL ES】绘制彩色三角形

1 前言

【OpenGL ES】绘制三角形 中介绍了绘制普通三角形的方法,本文将介绍绘制彩色三角形的方法。

本文完整代码资源见→【OpenGL ES】绘制彩色三角形

项目目录如下:

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) {
 //设置背景颜色
 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) {
 //设置视图窗口
 GLES30.glViewport(0, 0, width, height);
 }

 @Override
 public void onDrawFrame(GL10 gl) {
 //将颜色缓冲区设置为预设的颜色
 GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 GLES30.glLineWidth(5);
 //启用顶点的数组句柄
 GLES30.glEnableVertexAttribArray(0);
 GLES30.glEnableVertexAttribArray(1);
 //准备顶点坐标和颜色数据
 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); //绘制三角形的三个顶点
//        GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 3); //绘制三角形的三条边
 GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3); //绘制三角形的内部
 //禁止顶点数组句柄
 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;
 }

 //通过代码片段编译着色器
 public int compileShader(int type, String shaderCode){
 int shader = GLES30.glCreateShader(type);
 GLES30.glShaderSource(shader, shaderCode);
 GLES30.glCompileShader(shader);
 return shader;
 }

 //通过外部资源编译着色器
 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();
 //将顶点着色器加入到程序
 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; //顶点大小(GL_POINTS模式下才会生效)
 vColor = aColor;
}

location 定义了顶点属性的索引,如:位置属性 index 为 0,颜色属性 index 为 1。

顶点着色器的作用:进行矩阵变换位置、根据光照公式计算顶点颜⾊⽣成 / 变换纹理坐标,并且把位置和纹理坐标发送到片元着色器。

顶点着色器中,如果没有指定默认精度,则 int 和 float 的默认精度都为 highp。

fragment_shader.glsl

#version 300 es
precision mediump float; //声明float型变量的精度为mediump
in vec4 vColor;
out vec4 fragColor;
void main() {
 fragColor = vColor;
}

片元着色器的作用:处理经光栅化阶段生成的每个片元,计算每个像素的颜色和透明度

在片元着色器中,浮点值没有默认的精度值,每个着色器必须声明一个默认的 float 精度。

注意: fragment_shader.glsl 与 vertex_shader.glsl 中的 “vColor” 可以换其他变量名,但必须一致。

运行结果:

1)GL_POINTS 模式

2)GL_LINE_LOOP 模式

3)GL_TRIANGLES 模式

声明:本文转自【OpenGL ES】绘制彩色三角形

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容