본문 바로가기

ComputerGraphics [고려대학교_한정현]

Android + OpenGLES로 사각형 그리기

[OpenGLES 의 도형그리기 기본]

OpenGLES 는 다음과 같은 방법으로 점, 선, 도형을 그려나간다.

 

 

[사각형 그리기]

보통 삼각형 두개를 합쳐서 그린다.

 

아래는 사각형을 그릴때 필요한 두개의 삼각형을 반시계 방향으로그려보고, 좌표를 생각해 본 것이다.

사각형 그리기의 좌표

 

 

[소스코드] 는 이전의 Trangle 소스코드에서 Triangle.java 의 다음 파란색 부분만 수정하면 된다.

package com.samman.myapplication;

import android.opengl.GLES20;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class Triangle {
    //각형 정점 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

            0.5f, 0.5f, 0.0f   // top right
    };
    private float color[] = {0.5f, 0.5f,0.5f, 0.5f};

    //Vertex Shader ( Shader: 정점에 처리할 연산을 정의하는 메소드 )
    private final String mVertexShaderCode = // Vertex로 포현할 position 프로그램 코드
            "attribute vec4 vPosition;"+ // 객체의 위치를 저장하기 위한 vec4 자료형(4개의 int로 이루어진 벡터)
                    "void main(){"+ // 셰이더함수
                    "gl_Position = vPosition;"+ // 현재 vertex의 좌표 값을 저장함
                    "}";


    //Fragment Shader ( 픽셀에 색상을 넣음 )
    private final String mFragmenetShaderCode  =
            "precision mediump float;\n" +
                    "uniform vec4 vColor;\n" +
                    "void main() {\n" +
                    "   gl_FragColor = vColor;\n" +
                    "}\n";

 

 // vertex를 그리는 순서를 입력한 소스코드
   private short mDrawOrder[] = { 0, 1, 2, 0, 2, 3};
   ByteBuffer dlb = ByteBuffer.allocateDirect(mDrawOrder.length *2);
   dlb.order(ByteOrder.nativeOrder());   
   mDrawListBuffer = dlb.asShortBuffer();
   mDrawListBuffer.put(mDrawOrder);
   mDrawListBuffer.position(0);


    //정점을 이루는 좌표의 갯수
    static final int COORDS_PER_VERTEX = 3;
    //정점(꼭지점) 갯수
    private final int vertextCount = triangleCoords.length /COORDS_PER_VERTEX;
    //정점을 이루는 크기(Bytes)( 정점의 좌표값들은 보통 Float 으로 표현됨 )
    private final int vertexStride = COORDS_PER_VERTEX * 4;

    private final int mProgram;

    private FloatBuffer mVertexBuffer;
    private int mPositionHandle;
    private int mColorHandle;

    public Triangle() {
        //버퍼 셋팅
        ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4); //바이트버퍼 할당: 정점 3개 * 각 정점의 좌표 3개 * 4Bytes
        bb.order(ByteOrder.nativeOrder()); //리틀엔디언,빅엔디언 셋팅
        mVertexBuffer = bb.asFloatBuffer(); //FloatBuffer로 변환
        mVertexBuffer.put(triangleCoords);  //Float으로 이루어진 삼각형좌표 배열을 삽입
        mVertexBuffer.position(0); //첫번째 좌표부터 읽도록 positioning

        //Shader 셋팅
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, mVertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, mFragmenetShaderCode);

        //프로그램 생성 -> 쉐이더 붙이기 -> 프로그램 링크 ( 쉐이더간의 인터페이스를 생성해주고, 최종 결과물까지 나오도록 내부 파이프라인을 연결해준다. )
        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);
        GLES20.glLinkProgram(mProgram); // 링크된 프로그램은 GLES20.glUseProgram()을 이용해서 사용된다. (아래참고)
    }

    public void draw(){
        GLES20.glUseProgram(mProgram); // VertexShader, FragmentShader가 셋팅되고 링크된 프로그램을 사용한다.

        //쉐이더내에서 Handler 로 좌표값 셋팅//
        mPositionHandle = GLES20.glGetAttribLocation(mProgram,  "vPosition");// VertexShader를 통해 셋팅된 정점을 읽어들일수 있는 positionHandle을 가져옴
        GLES20.glEnableVertexAttribArray(mPositionHandle); //좌표들을 쓸수 있도록 핸들을 기동시킴
        GLES20.glVertexAttribPointer( //움직이는 PositionHandle이 float형의 VertexBuffer를 타고다니면서 좌표를 얻어냄
                mPositionHandle,
                COORDS_PER_VERTEX,
                GLES20.GL_FLOAT,
                false,
                vertexStride,
                mVertexBuffer);
        //쉐이더내에서 Handler 로 색상 셋팅//
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); // Fragment Shader 를 통해 셋팅된 컬러 값을 읽어들일수 있는 positionHandle을 가져옴
        GLES20.glUniform4fv(mColorHandle, 1, color, 0 ); // 색상을 설정함

        //그리기 및 종료
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertextCount); // 그리기

        GLES20.glDrawElement(GLES20.GL_TRIANGLES, mDrawOrder.length, GLES20.GL_UNSINGED_SHORT, mDrawListBuffer);
        GLES20.glDisableVertexAttribArray(mPositionHandle); //PositionHandle 중지함
    }

    //쉐이더들을 처리할(컴파일)할 메소드
    public static int loadShader(int type, String shaderCode){
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }
}