Programming/OpenGL ES

OpenGL ES 2.0 Practice 5 : Simple Texture

데굴데굴여기 2016. 10. 23. 10:39

OpenGL ES 2.0 Practice 5 : Simple Texture

두 개의 Triangle 에 Texture를 맵핑합니다. Texture 맵핑을 위해 Texture Binding, Texture Coordinate 설정, Shader 코드에 sampler 를 추가 합니다.  

첫번째 Texture 초기화 코드 입니다. 

    private void initTexture(Bitmap image) {

        int name[] = new int[1];

        GLES20.glGenTextures(1, name, 0);


        if ( name[0] > 0 ) {

            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, name[0]);


            // setting parameters

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);


            // use gl utils to load texture by Bitmap

            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, image, 0);


            // texture binding to 0

            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);


            mTextureName = name[0];

        }

        else {

            Log.e(TAG, "Fail to bind texture");

        }

    }

Texture 초기화 시 Image 데이터는 Bitmap을 이용하여 로딩 합니다. 


다음은 Vertex(Position) 별 Texture mapping 정보(Texture Coordinate)를 설정합니다.

    public SimpleTexture(Context context) {


        // create shader program

        mProgram = createProgram(SHADER_TYPE_TEXTURE);


        float position[] = {

                -0.5f, 0.5f, 0.0f,

                -0.5f, -0.5f, 0.0f,

                0.5f, -0.5f, 0.0f,

                -0.5f, 0.5f, 0.0f,

                0.5f, -0.5f, 0.0f,

                0.5f, 0.5f, 0.0f

        };


        // same direction (z direction)

        float normal[] = {

                0.0f, 0.0f, 1.0f,

                0.0f, 0.0f, 1.0f,

                0.0f, 0.0f, 1.0f,

                0.0f, 0.0f, 1.0f,

                0.0f, 0.0f, 1.0f,

                0.0f, 0.0f, 1.0f,

        };


        // texture coordinate

        float texCoord[] = {

                0.0f, 0.0f,

                0.0f, 1.0f,

                1.0f, 1.0f,

                0.0f, 0.0f,

                1.0f, 1.0f,

                1.0f, 0.0f

        };


        mPosition = createFloatBuffer(position);

        mNormal = createFloatBuffer(normal);

        mTexCoord = createFloatBuffer(texCoord);


        // init matrix value

        Matrix.setIdentityM(mModelMatrix, 0);

        Matrix.setIdentityM(mViewMatrix, 0);

        Matrix.translateM(mViewMatrix, 0, 0.0f, 0.0f, -2.5f);

        Matrix.setIdentityM(mProjMatrix, 0);


        // initializing the texture

        Bitmap texImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.mountain02);


        initTexture(texImage);

        texImage.recycle();

    }


Shader 코드는 attribute 로 Texture Coordinate를 추가하고 uniform sampler2D 를 추가하여 Binding 된 Texture 와 연결하도록 합니다

// vertex shader, added texture coordinate attribute 

    "precision mediump float;\n" +

    "attribute vec3 aPosition;\n" +

    "attribute vec3 aNormal;\n" +

    "attribute vec2 aTexCoord;\n" +

    "uniform mat4 uProjMatrix;\n" +

    "uniform mat4 uViewMatrix;\n" +

    "uniform mat4 uModelMatrix;\n" +

    "uniform vec3 uLightColor;\n" +

    "uniform vec3 uLightDir;\n" +

    "uniform vec3 uMaterialDiffuse;\n" +

    "varying vec3 vColor;\n" +

    "varying vec2 vTexCoord;\n" +

    "void main() {\n" +

    "   vTexCoord = aTexCoord;\n" +

    " gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition, 1.0);\n" +

    "   vec3 normal_cameraspace = (uViewMatrix * uModelMatrix * vec4(aNormal, 1.0)).xyz;\n" +

    "   vec3 lightdir_cameraspace = (uViewMatrix * vec4(uLightDir, 1.0)).xyz;" +

    "   vec3 n = normalize(normal_cameraspace);\n" +

    "   vec3 l = normalize(lightdir_cameraspace);\n" +

    "   float cosTheta = clamp( dot(n, l), 0.0, 1.0);" +

    "   vColor = uMaterialDiffuse * uLightColor * cosTheta;" +

    "}\n"


// fragment shader

    "precision mediump float;\n" +

    "uniform sampler2D sTexture0;\n" +

    "varying vec3 vColor;\n" +

    "varying vec2 vTexCoord;\n" +

    "void main() {\n" +

    "   vec4 texColor = texture2D(sTexture0, vTexCoord);\n" +

    "   gl_FragColor = vec4(vColor, 1.0f) * texColor;\n" +

    "}\n"


마지막으로, Shader 코드와 연동하여 Rendering을 수행합니다.

    @Override

    public void draw() {


        GLES20.glUseProgram(mProgram);


        // screen clear color

        GLES20.glClearColor(0.6f, 0.6f, 0.6f, 1.0f);


        // clear screen

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);


        int aPositionLoc = GLES20.glGetAttribLocation(mProgram, "aPosition");

        GLES20.glVertexAttribPointer(aPositionLoc, 3, GLES20.GL_FLOAT, false, 0, mPosition);


        int aNormalLoc = GLES20.glGetAttribLocation(mProgram, "aNormal");

        GLES20.glVertexAttribPointer(aNormalLoc, 3, GLES20.GL_FLOAT, false, 0, mNormal);


        int aTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "aTexCoord");

        GLES20.glVertexAttribPointer(aTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, mTexCoord);


        // light color

        GLES20.glUniform3f(GLES20.glGetUniformLocation(mProgram, "uLightColor"), 0.8f, 0.8f, 0.8f);


        // triangle material color

        GLES20.glUniform3f(GLES20.glGetUniformLocation(mProgram, "uMaterialDiffuse"), 1.0f, 1.0f, 1.0f);


        // light dir

        GLES20.glUniform3f(GLES20.glGetUniformLocation(mProgram, "uLightDir"), 1.0f, -1.0f, -1.0f);


        // triangle model matrix

        // no transform (identity matrix)

        // y-axis, 1 degree rotation every frames

        Matrix.rotateM(mModelMatrix, 0, 1.0f, 0.0f, 1.0f, 0.0f);

        GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgram, "uModelMatrix"), 1, false, mModelMatrix, 0);


        // view matrix

        GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgram, "uViewMatrix"), 1, false, mViewMatrix, 0);


        // projection matrix

        GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgram, "uProjMatrix"), 1, false, mProjMatrix, 0);


        GLES20.glEnableVertexAttribArray(aPositionLoc);

        GLES20.glEnableVertexAttribArray(aNormalLoc);

        GLES20.glEnableVertexAttribArray(aTexCoordLoc);


        // active texture 0

        GLES20.glUniform1i(GLES20.glGetUniformLocation(mProgram, "sTexture0"), 0);


        // binding texture

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureName);


        // rendering

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);


        // binding texture to 0

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);


        GLES20.glDisableVertexAttribArray(aPositionLoc);

        GLES20.glDisableVertexAttribArray(aNormalLoc);

        GLES20.glDisableVertexAttribArray(aTexCoordLoc);


        // starting gl command buffer, non-block

        GLES20.glFlush();

    }


결과 화면 (Nexus 7 2nd, Android 6)

OpenGLES20SimpleTexture.zip