OpenGLES3.0 Android Studio创建三角形

主要有三个类:

  1. MainActivity:创建GLSurfaceView对象
  2. HelloTriangleRenderer:实现GLSurfaceView.Renderer接口(渲染程序类)
  3. MyGLSurfaceView:创建GLSurfaceView的拓展类,用以实现诸如触摸事件处理的操作(具体解释:
    https://developer.android.com/training/graphics/opengl/environment?hl=zh-cn#glsurfaceview)

MainActivity

package com.example.opengl_triangle;

import androidx.appcompat.app.AppCompatActivity;

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private final int CONTEXT_CLIENT_VERSION = 3;

    @Override
    protected void onCreate ( Bundle savedInstanceState )
    {
        super.onCreate ( savedInstanceState );
        //创建MyGLSurfaceView对象
        mGLSurfaceView = new MyGLSurfaceView( this );

        if ( detectOpenGLES30() )
        {
            // Tell the surface view we want to create an OpenGL ES 3.0-compatible
            // context, and set an OpenGL ES 3.0-compatible renderer.
            mGLSurfaceView.setEGLContextClientVersion ( CONTEXT_CLIENT_VERSION );
            mGLSurfaceView.setRenderer ( new HelloTriangleRenderer ( this ) );
        }
        else
        {
            Log.e ( "HelloTriangle", "OpenGL ES 3.0 not supported on device.  Exiting..." );
            finish();
        }

        setContentView ( mGLSurfaceView );
    }

    private boolean detectOpenGLES30()
    {
        ActivityManager am =
                ( ActivityManager ) getSystemService ( Context.ACTIVITY_SERVICE );
        ConfigurationInfo info = am.getDeviceConfigurationInfo();
        return ( info.reqGlEsVersion >= 0x30000 );
    }

    @Override
    protected void onResume()
    {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onResume();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause()
    {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onPause();
        mGLSurfaceView.onPause();
    }

    private GLSurfaceView mGLSurfaceView;
}

MyGLSurfaceView 

package com.example.opengl_triangle;

import android.content.Context;
import android.opengl.GLSurfaceView;

//创建GLSurfaceView的拓展类MyGLSurfaceView,用以拓展例如触摸事件的处理
//https://developer.android.com/training/graphics/opengl/environment?hl=zh-cn#glsurfaceview
class MyGLSurfaceView extends GLSurfaceView {
        public MyGLSurfaceView(Context context){
            //引用父类构造函数
            super(context);
    }
}

重点介绍HelloTriangleRenderer类:

package com.example.opengl_triangle;

import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class HelloTriangleRenderer implements GLSurfaceView.Renderer
{
    ///
    // Constructor
    //
    public HelloTriangleRenderer ( Context context )
    {
        //获取Activity传入的Context上下文
        mContext = context;
        mVertices = ByteBuffer
                .allocateDirect ( mVerticesData.length * 4 ) //直接分配 native 内存,不会被gc
                .order ( ByteOrder.nativeOrder() )//和本地平台保持一致的字节序(大/小端)
                .asFloatBuffer();//将底层字节映射到FloatBuffer实例,方便使用
        mVertices
                .put ( mVerticesData )//将顶点拷贝到 native 内存中
                .position ( 0 );//每次 put position 都会 + 1,需要在绘制前重置为0
    }

    private int compileShader(int shader_type, String shaderString){

        // This compiles the shader from the string
        // 编译保存在 string 中的 shader 内容
        int shader = GLES30.glCreateShader(shader_type);
        GLES30.glShaderSource(shader, shaderString);
        GLES30.glCompileShader(shader);

        // This checks for for compilation errors
        // 检查是否出现编译错误
        int[] compiled = new int[1];
        GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            String log = GLES30.glGetShaderInfoLog(shader);

            Log.e(TAG, "Shader compilation error: ");
            Log.e(TAG, log);
        }
        return shader;
    }

    //从 AssetFile 中读取已经编写好的着色器文件(vertexShader and fragmentShader)到 string
    public String loadStringFromAssetFile(Context context, String filePath) {
        StringBuilder shaderSource = new StringBuilder();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filePath)));
            String line;
            while((line = reader.readLine()) != null){
                shaderSource.append(line).append("\n");
            }
            reader.close();
            return shaderSource.toString();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "Could not load shader file");
            return null;
        }
    }

    //调用一次以设置视图的 OpenGL ES 环境
    @Override
    public void onSurfaceCreated ( GL10 glUnused, EGLConfig config )
    {

        // Load shaders from file
        String vertexShaderString = loadStringFromAssetFile(mContext, "triangle_vertex_shader.glsl");
        String fragmentShaderString = loadStringFromAssetFile(mContext, "triangle_fragment_shader.glsl");

        // Compile shaders
        int vertexShader = compileShader(GLES30.GL_VERTEX_SHADER, vertexShaderString);
        int fragmentShader = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderString);

        int programObject;
        int[] linked = new int[1];

        // Create the program object
        // 创建渲染程序对象
        programObject = GLES30.glCreateProgram();

        if ( programObject == 0 )
        {
            return;
        }

        GLES30.glAttachShader ( programObject, vertexShader );
        GLES30.glAttachShader ( programObject, fragmentShader );

        // Bind vPosition to attribute 0
        //绑定属性位置 vPosition :0 着色器中没有设定属性位置时使用
        GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );

        // Link the program
        GLES30.glLinkProgram ( programObject );

        // Check the link status
        GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );

        if ( linked[0] == 0 )
        {
            Log.e ( TAG, "Error linking program:" );
            Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
            GLES30.glDeleteProgram ( programObject );
            return;
        }

        // Store the program object
        mProgramObject = programObject;

        GLES30.glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
    }

    // /
    // Draw a triangle using the shader pair created in onSurfaceCreated()
    //
    @Override
    public void onDrawFrame ( GL10 glUnused )
    {
        // Set the viewport
        GLES30.glViewport ( 0, 0, mWidth, mHeight );

        // Clear the color buffer
        GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT );

        // Use the program object
        GLES30.glUseProgram ( mProgramObject );

        // Load the vertex data
        GLES30.glVertexAttribPointer ( 0, 3, GLES30.GL_FLOAT, false, 0, mVertices );
        GLES30.glEnableVertexAttribArray ( 0 );

        GLES30.glDrawArrays ( GLES30.GL_TRIANGLES, 0, 3 );
    }

    // /
    // Handle surface changes
    //
    @Override
    public void onSurfaceChanged ( GL10 glUnused, int width, int height )
    {
        mWidth = width;
        mHeight = height;
    }

    // Member variables
    private Context mContext;
    private int mProgramObject;
    private int mWidth;
    private int mHeight;
    private FloatBuffer mVertices;
    private static String TAG = "HelloTriangleRenderer";

    private final float[] mVerticesData =
            { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f };
}

主要作用:

载入着色器文件(assets文件夹中读取已经写好了的着色器文件,一般默认工程没有此文件夹,需自行创建):

顶点着色器(triangle_vertex_shader.glsl)、片段着色器(triangle_fragment_shader.glsl)

着色器文件(vertexShaser和fragmentShader)

triangle_fragment_shader.glsl

#version 300 es
precision mediump float;
out vec4 fragColor;
void main()
{
    fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );
}

 triangle_vertex_shader.glsl

#version 300 es
in vec4 vPosition;
void main()
{
   gl_Position = vPosition;
}

 这两个着色器文件在使用时,可以在HelloTriangleRenderer中读取文件内容到string,然后再进行compile等处理,具体代码参考 loadStringFromAssetFile,需要注意的是读取文件时需要传入Activity的Context,否则无法使用 getAssets() 方法

效果:

参考资料:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值