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() 方法

效果:

参考资料:

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中使用OpenGL ES 3.0加载纹理有以下步骤: 1. 初始化OpenGL ES环境:在OpenGL ES操作前,需要初始化OpenGL ES环境,创建GLSurfaceView实例,并设置渲染器。 2. 创建纹理对象:使用OpenGL ES函数glGenTextures生成纹理对象ID,并绑定到当前活动的纹理单元。 3. 加载纹理图像:通过Android的Bitmap对象加载纹理图像,可以使用BitmapFactory类的decodeResource方法从资源中加载或使用Bitmap类的createBitmap方法动态创建。调用glTexImage2D将图像数据传输到纹理对象中。 4. 设置纹理过滤器:可以使用glTexParameteri函数设置纹理的放大缩小过滤器,如GL_LINEAR或GL_NEAREST。 5. 设置纹理包裹模式:可以使用glTexParameteri函数设置纹理的包裹模式,如GL_CLAMP_TO_EDGE或GL_REPEAT。 6. 加载纹理坐标:通过定义纹理坐标数组,确定纹理映射到对象的哪个部分。在顶点着色器中使用纹理坐标进行纹理采样。 7. 绘制纹理:在绘制OpenGL场景时,通过在顶点着色器和片段着色器中使用纹理坐标,并利用纹理采样器将纹理应用到对象上。 8. 释放纹理资源:当纹理不再使用时,需要调用glDeleteTextures函数释放纹理对象。 总之,使用OpenGL ES 3.0加载纹理需要创建纹理对象、加载纹理图像、设置纹理过滤器与包裹模式、加载纹理坐标,并在绘制时通过纹理采样器将纹理应用到对象上。记得释放纹理资源,以避免内存泄漏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值