opengl es3.0學習篇三:簡單寫一個三角形展現

資料來源:java

OpenGL ES 2 for Android —a Quick-Start Guideandroid

https://developer.android.com/guide/topics/graphics/openglgit

本章文章只是簡單的畫一個三角形到手機端中,比較簡單,直接看着官網資料就能寫出來,下面是代碼:github

Manifest中聲明使用的opengl es版本:緩存

<uses-feature android:glEsVersion="0x00030000" android:required="true" />

xml中直接聲明一個全屏的GLSurfaceView,這裏不就貼了。ide

在MainActivity中:ui

private GLSurfaceView mSurfaceView;

    @Override
    protected void onPause() {
        super.onPause();
        if (mSurfaceView != null) {
            mSurfaceView.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mSurfaceView != null) {
            mSurfaceView.onResume();
        }
    }
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intGL();
    }

    private void intGL() {
        mSurfaceView = findViewById(R.id.gl);

        mSurfaceView.setEGLContextClientVersion(3);
        mSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        mSurfaceView.setRenderer(new MyRenderer());
        //RenderMode 有兩種,RENDERMODE_WHEN_DIRTY 和 RENDERMODE_CONTINUOUSLY,
        // 前者是懶惰渲染,須要手動調用 glSurfaceView.requestRender() 纔會進行更新,然後者則是不停渲染。
        mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }


    private static class MyRenderer implements GLSurfaceView.Renderer {
        private Triangle mSquare;

        @Override
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            mSquare = new Triangle();
        }

        @Override
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            //設置 Screen space 的大小
            GLES30.glViewport(0, 0, width, height);
        }

        //繪製的過程其實就是爲 shader 代碼變量賦值,並調用繪製命令的過程
        @Override
        public void onDrawFrame(GL10 unused) {
            mSquare.onDraw();
        }
    }

Triangle文件:this

public class Triangle {
    private FloatBuffer vertexBuffer;
    private final String vertexShaderCode =
            "#version 300 es  \n" +
                    "layout(location = 0) in vec4 vPosition;\n" +
                    "layout(location = 1) in vec4 aColor;\n"+
                    "out vec4 vColor;"+
                    "void main() {\n" +
                    "gl_Position = vPosition;\n" +
                    "vColor=aColor;\n" +
                    "}";

    private final String fragmentShaderCode =
            "#version 300 es  \n" +
                    "precision mediump float;\n" +
                    "out vec4 fragColor;\n" +
                    "in vec4 vColor;" +
                    "void main() {\n" +
                    "fragColor = vColor;\n" +
                    "}";
    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
    static float triangleCoords[] = {   // in counterclockwise order:
            0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
            0.5f, -0.311004243f, 0.0f  // bottom right
    };
    private final int mProgram;
    // Set color with red, green, blue and alpha (opacity) values
    float color[] = { 1.0f,0.0f,0.0f, 1.0f };
    public static int loadShader(int type, String shaderCode){

        // create a vertex shader type (GLES30.GL_VERTEX_SHADER)
        // or a fragment shader type (GLES30.GL_FRAGMENT_SHADER)
        int shader = GLES30.glCreateShader(type);

        // add the source code to the shader and compile it
        GLES30.glShaderSource(shader, shaderCode);
        GLES30.glCompileShader(shader);

        return shader;
    }
    public Triangle() {
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (number of coordinate values * 4 bytes per float)
                triangleCoords.length * 4);
        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder());

        // create a floating point buffer from the ByteBuffer
        vertexBuffer = bb.asFloatBuffer();
        // add the coordinates to the FloatBuffer
        vertexBuffer.put(triangleCoords);
        // set the buffer to read the first coordinate
        vertexBuffer.position(0);
        int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        // create empty OpenGL ES Program
        mProgram = GLES30.glCreateProgram();

        // add the vertex shader to program
        GLES30.glAttachShader(mProgram, vertexShader);

        // add the fragment shader to program
        GLES30.glAttachShader(mProgram, fragmentShader);

        // creates OpenGL ES program executables
        GLES30.glLinkProgram(mProgram);
    }
    private int mPositionHandle;
    private int mColorHandle;

    private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
    public void onDraw(){
        // Add program to OpenGL ES environment
        GLES30.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
        // Enable a handle to the triangle vertices
        GLES30.glEnableVertexAttribArray(mPositionHandle);
        // Prepare the triangle coordinate data
        GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES30.GL_FLOAT, false,
                vertexStride, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor");

        // Set color for drawing the triangle
        GLES30.glVertexAttrib4fv(mColorHandle,  color, 0);

        // Draw the triangle
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);

        // Disable vertex array
        GLES30.glDisableVertexAttribArray(mPositionHandle);
    }
}

這樣就會在GlSurfaceView當中繪製出一個三角形了。spa

這裏順便記錄一下對應的glVertexAttrib4fv()glUniform4fv()的區別:.net

private final String vertexShaderCode =
            "#version 300 es  \n" +
                    "layout(location = 0) in vec4 vPosition;\n" +
                    "layout(location = 1) in vec4 aColor;\n"+ //和下面代碼的區別
                    "out vec4 vColor;"+
                    "void main() {\n" +
                    "gl_Position = vPosition;\n" +
                    "vColor=aColor;\n" +
                    "}";

    private final String fragmentShaderCode =
            "#version 300 es  \n" +
                    "precision mediump float;\n" +
                    "out vec4 fragColor;\n" +
                    "in vec4 vColor;" +
                    "void main() {\n" +
                    "fragColor = vColor;\n" +
                    "}";
...
  // get handle to fragment shader's vColor member
        mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor");

        // Set color for drawing the triangle
        GLES30.glVertexAttrib4fv(mColorHandle,  color, 0);

上述代碼中在glsl語言中使用了in vec4 aColor;說明這個變量經由外部傳遞,是個可變的參數(即咱們在第一次刷新能夠設置爲紅色,第二次刷新能夠改變成藍色),使用的方法則是經過glVertexAttrib4fv()或者glVertexAttrib4f()來進行傳遞 ,而若是使用了底下的代碼的話:

private final String vertexShaderCode =
            "#version 300 es  \n" +
                    "layout(location = 0) in vec4 vPosition;\n" +
                    "void main() {\n" +
                    "gl_Position = vPosition;\n" +
                    "}";

    private final String fragmentShaderCode =
            "#version 300 es  \n" +
                    "precision mediump float;\n" +
                    "out vec4 fragColor;\n" +
                    "uniform vec4 vColor;\n"+ //區別
                    "void main() {\n" +
                    "fragColor = vColor;\n" +
                    "}";
					....
        mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
        // Set color for drawing the triangle
//        GLES30.glVertexAttrib4fv(mColorHandle,  color, 0);
        GLES30.glUniform4fv(mColorHandle, 1, color, 0);

那麼永遠都只會是一種顏色,由於uniform設置至關於java裏的final和c中的const,即常量的概念。

若是講的不太清楚,引用一下大牛的博客(基於opengl es2.0,3.0中使用in類型來表明attribute):

attribute(屬性)變量和uniform變量的不一樣之處在於attribute 變量中包含頂點的具體數據,當每次執行shader調用時會從頂點緩存中從新加載一個新的值。而uniform類型的變量在整個繪製調用中始終使用同一個變量。這意味着你在繪製調用前加載的值在每一個vertex shader調用時能訪問到相同的值。uniform變量在存儲光照參數(光照位置、方向等)、變換矩陣、紋理對象句柄等這一類型的數據時很是有用。

來源:https://blog.csdn.net/Rongbo_J/article/details/45112187

效果圖:

opengl_demo

代碼連接:

https://github.com/JerryChan123/LearnOEL/tree/gl30

相關文章
相關標籤/搜索