OpenGl学习(一)

1、创建activity

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

import test.audio.com.opengldemo.render.Circle;

public class MainActivity extends AppCompatActivity {

    private  GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        glSurfaceView = new GLSurfaceView(this);  //创建 GLSurfaceView
        glSurfaceView.setEGLContextClientVersion(2); //设置OpenGl版本
        glSurfaceView.setRenderer(new Circle()); //设置自定义Render
        setContentView(glSurfaceView); //添加到activity
    }


    @Override
    protected void onResume() {
        super.onResume();
        glSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        glSurfaceView.onPause();
    }
    } 
复制代码

2、创建render类

2.1 渲染器接口定义的方法

onSurfaceCreated(GL10 gl, EGLConfig config)
当surface被创建的时候,GLSurfaceView会调用这个方法,发生在程序第一次运行的时时候,在设备被唤醒或者从其他activity回来时也可能会调用,所以在程序运行时该方法可能被多次调用。 onSurfaceChanged(GL10 gl, int width, int height)
在surface创建以后,在surface尺寸发生变化时被调用,在横竖屏切换时也会被调用 onDrawFrame(GL10 gl)
当绘制一帧时,该方法被调用\

2.2、定义顶点

在OpenGL里面只能绘制点、直线、三角形,在OpenGl中是右手系坐标,无论是x或者y,都会映射到[-1,1]的范围内,屏幕左边代表着-1,屏幕右边代表着1,屏幕顶部代表着1,底部代表着-1。

2.3、使数据可以被OpenGl存取

因为代码运行环境和OpenGl运行的环境使用了不同的语言,OpenGl无法完成存取
1、当我们在模拟器或者设备编译和运行java代码时,它并不是直接运行在硬件上的,而是虚拟机上运行的,运行在虚拟机上的程序不能直接访问本地代码,除非通过特定APi。 2、虚拟机有垃圾回收机制,而本地环境则不是这样的,内存块不会自动释放。

2.3.1 从Java调用本地代码

如果Java代码需要调用本地代码,有两种方法可以调用,第一种是通过Jni调用,另外种就是把内存从Java堆复制到本地堆,Java有一个特殊的类集合,可以分配本地内存块并且把Java的数据复制到本地内存,本地内存可以被本地环境存取,而不受垃圾回收器的影响。在自定义Renderer中有这样的代码:

        private FloatBuffer vertexBuffer;

        ByteBuffer bb = ByteBuffer.allocateDirect(
                triangleCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());

        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(triangleCoords);
复制代码

使用ByteBuffer.allocateDirect分配了一块本地内存,这个方法需要传入分配多少字节的内存块,因为所有的顶点都存储在一个浮点数组里面,每个浮点数有四个字节,所以这块的内存大小就为triangleCoords.length * 4,而Order方法告诉字节缓冲区(byte buffer)按照本地字节序组织它的内容,而调用asFloatBuffer方法得到一个可以反映底层字节的FloatBuffer实例, 最终调用vertexBuffer.put(triangleCoords)把数据从DalviK的内存复制到本地内存了。
顶点着色器 生成每个顶点的最终位置,针对每个顶点,都会执行一次,一旦最终位置确定了,就可以根据这些顶点组装成点,直线,以及三角形 片元着色器 为组成点,直线,三角形的每个片段生成最终的颜色,针对每个片段都会执行一次

public class Triangle implements GLSurfaceView.Renderer {
    private static final String TAG = "Triangle";

    private FloatBuffer vertexBuffer;
    private final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private int mProgram;

    static final int COORDS_PER_VERTEX = 3;
    static float triangleCoords[] =
            {
                    -0.5f, 0.5f, 0.0f, // top left
                    -0.5f, -0.5f, 0.0f, // bottom left
                    0.5f, -0.5f, 0.0f, // bottom right
            };

    private int mPositionHandle;
    private int mColorHandle;

    private float[] mViewMatrix = new float[16];

    //顶点个数
    private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
    //顶点之间的偏移量
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节


    //设置颜色,依次为红绿蓝和透明通道
    float color[] = {1.0f, 1.0f, 1.0f, 1.0f};

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        Log.i(TAG, "onSurfaceCreated: ");
        gl.glClearColor(1,0,0,0); //设置屏幕清空用的颜色
        ByteBuffer bb = ByteBuffer.allocateDirect(
                triangleCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());

        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(triangleCoords);
        vertexBuffer.position(0);
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        //创建一个空的OpenGLES程序
        mProgram = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(mProgram, vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(mProgram, fragmentShader);
        //连接到着色器程序
        GLES20.glLinkProgram(mProgram);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        Log.i(TAG, "onSurfaceChanged: ");
        gl.glViewport(0, 0, width, height); //设置视图尺寸,告诉OpenGL用来渲染的视图大小
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        Log.i(TAG, "onDrawFrame: ");
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT); //擦除屏幕上所有的颜色,并用之前glClearColor设置的颜色填充整个屏幕

        //将程序加入到OpenGLES2.0环境
        GLES20.glUseProgram(mProgram);

        //获取顶点着色器的vPosition成员句柄
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        //启用三角形顶点的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);
        //获取片元着色器的vColor成员的句柄
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        //设置绘制三角形的颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        //绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCount);
        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }

    public int loadShader(int type, String shaderCode) {
        //根据type创建顶点着色器或者片元着色器
        int shader = GLES20.glCreateShader(type);
        //将资源加入到着色器中,并编译
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

}
复制代码

2.3.4最终实现

转载于:https://juejin.im/post/5b8f90935188255c8f067b66

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值