利用opengl es画立方体的简单流程

最近在学习opengl es,其中弄了一个小Demo,画了个天空盒,并在场景里加了个立方体,下面主要介绍下画立方体的流程。

一、在Android中使用opengl es,主要是使用GLSurfaceView和GLSurfaceView.Renderer。

GLSurfaceView继承自SurfaceView,通过该类来使用opengl es,为Android提供view。


通过setContentView(mGLSurfaceView)来实现的,这里我用MySurfaceViewGLSurfaceView进行了一下封装,放到自己建的类中。

二、连通了opengl esAndroidview,那么具体的内容将由GLSurfaceView.Renderer来提供,它是渲染器,也是我们要实现的一个接口,完成它的三个方法:

a. onSurfaceCreated,在Surface创建的时候调用

b.onSurfaceChanged, 在Surface改变的的时候调用

c. onDrawFrame, 在Surface上绘制的时候调用,也代表着画面的每一帧

在自己建立的MySurfaceView类中使用内部类SceneRenderer来实现Renderer接口

针对要实现的三个方法进行介绍,直接上代码,代码中注释很清晰,主要说一下图中后两行,使用的矩阵后面在介绍,而最后一行,该类将在onDrawFrame中完成立方体的绘制




下面这一段代码就运行在onDrawFrame绘制立方体




下面是重点的内容部分,也是使用opengl es绘制的流程

构造函数中利用两个方法完成2项准备工作,第一个是准备模型(立方体)的顶点坐标和颜色坐标,只给出了一部分,立方体一个面的位置坐标和颜色坐标。

final float cubePosition[] =
        {
                // Front face
                
-1.0f, 1.0f, 1.0f,
                -1.0f, -1.0f, 1.0f,
                1.0f, 1.0f, 1.0f,
                -1.0f, -1.0f, 1.0f,
                1.0f, -1.0f, 1.0f,
                1.0f, 1.0f, 1.0f,

……,};

final float[] cubeColor =
        {
                // Front face (red)
                
1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,

…….,};

mCubePositions = ByteBuffer.allocateDirect(cubePosition.length * 4)
        .order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubePositions.put(cubePosition).position(0);
mCubeColors = ByteBuffer.allocateDirect(cubeColor.length * 4)
        .order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeColors.put(cubeColor).position(0);

有了坐标之后将这些坐标放到mCubePositionsmCubeColors两个buffer可以理解为opengl es在画立方体时,从buffer的开始位置取坐标开始绘制。

另一个主要工作就是准备shader,为Vertex Shader Fragment Shader ,分别是顶点着色器和片段着色器,是可编程管线中两部分,可以理解为通过流水线上的两个位置,我们要完成的一些工作,向管线中提供相应所需要的东西。



vertex_tex_S.sh和frag_tex_S.sh是两个脚本语言加载之后创建程序然后定位到我们要提供信息的地方即程序中的三个索引id(你也可以用0123…来表示),位置、mvp(模型-视图-透视)矩阵颜色

下面的一大段就是创建并链接着色器的过程,从上面给出的脚本语言来创建,创建之后再glAttachShader,顶点着色器和片段着色器都要创建和glAttachShader,然后再将他们GLES20.glLinkProgram(program),这是opengl中固定的流程

public static int createProgram(String vertexSource, String fragmentSource)
{
    //加载顶点着色器
    
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
    if (vertexShader == 0)
    {
        return 0;
    }
    //加载片元着色器
    
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
    if (pixelShader == 0)
    {
        return 0;
    }
    //创建程序
    
int program = GLES20.glCreateProgram();
    //若程序创建成功则向程序中加入顶点着色器与片元着色器
    
if (program != 0)
    {
        //向程序中加入顶点着色器
        
GLES20.glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        //向程序中加入片元着色器
        
GLES20.glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        //链接程序
        
GLES20.glLinkProgram(program);
        //存放链接成功program数量的数组
        
int[] linkStatus = new int[1];
        //获取program的链接情况
        
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
        //若链接失败则报错并删除程序
        
if (linkStatus[0] != GLES20.GL_TRUE)
        {
            Log.e("ES20_ERROR", "Could not link program: ");
            Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program));
            GLES20.glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

//检查每一步操作是否有错误的方法
public static void checkGlError(String op)
{
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)
    {
        Log.e("ES20_ERROR", op + ": glError " + error);
        throw new RuntimeException(op + ": glError " + error);
    }
}

最后一步就是画立方体了先是使用创建好的着色器程序然后传递给一个mvp矩阵该矩阵就是将立方体显示在手机屏幕上首先画出的是在立方体自己坐标系下的model矩阵需要变换到世界坐标系这里世界坐标系和立方体自己坐标系重合然后再变换到相机坐标系中(通过view的矩阵),最后在变换到屏幕坐标系中(使用透视矩阵),变换的过程使用矩阵相乘的形式。图中已用红线表示,从buffer中取数据方法指定标示的地方,最后就是开始绘图了,由于采用三角面开始画,每个面6个点,画两个三角形,6个面36个点。





猜你喜欢

转载自blog.csdn.net/u011371324/article/details/61618954