텍스쳐 있는 사각형 만들기

OpenGL로 사각형을 그리는것까지 성공했다면, 텍스쳐를 입히는것은 어렵지 않습니다. 
이미 만들어둔 사각형에서 쉐이더를 포함한 몇가지 코드를 수정하여 텍스쳐를 출력하도록 하겠습니다.
사각형 만들기는 링크를 참조해주세요

UV 좌표계

OpenGL에서 사각형을 그릴때는 삼각형 두개를 이어 붙인다는것을 이제 알것입니다. 사각형으로 된 이미지를 삼각형 두개로 만들어진 사각형에 표현하기위해서는 마찬가지로 이미지를 삼각형 모양으로 잘라 전달하는 방법이 필요합니다. 이 때 필요한것이 UV 좌표계입니다.

Android의 OpenGL ES UV좌표계는 다음과 같습니다.

DirectX와 같으며 일반적인 OpenGL과는 반대입니다.

UV 좌표는 2개의 float형으로 처리하며, 두개의 모든 값을 백분율 ( 0~ 1) 로 처리합니다. 그러므로 0.0f이상 1.0f이하의 값으로 표현됩니다.

하나의 도형에 다음과 같이 이미지를 잘라 매핑할 수 있습니다.

 

사각형에 대해서 하나의 이미지(텍스쳐)를 매핑하기 위한 uv좌표계는 위의 그림과 같습니다. 삼각형 두개가 나오도록 사선으로 자른 형태입니다. 사진의 일부만 적용하고 싶다면 uv좌표계를 수정할 수도 있습니다.

위의 그림을 코드로 표현한다면 다음과 같습니다.

float[] vertices = new float[]{
    -0.5f, -0.5f,  0f,  //bottom left
    0.5f, -0.5f,  0f,  //bottom right
    0.5f,  0.5f,  0f,  // top right
    -0.5f,  0.5f,  0f, // top left
};

float[] uvs = new float[]{
    0f,1f,
    1f,1f,
    1f,0f,
    0f,0f
};
Warning : 메쉬를 만들때 동차좌표상의 정점과, uv좌표상의 정점의 순서는 일치해야합니다.

텍스쳐 입히는 과정

텍스처를 입히는 과정을 간단히 요약하자면 다음과 같습니다.

텍스쳐 생성 > 텍스처 바인딩 > Bitmap 로드 > 그리기

이제 실제로 구현하는 코드를 살펴보도록 하겠습니다.
쉐이더코드는 다음과 같습니다.

//버텍스 쉐이더
String vertexShader = "uniform mat4 uMVPMatrix;" +
 "attribute vec4 vPosition;" +
 "attribute vec2 a_texCoord;" +
 "varying vec2 v_texCoord;" +
 "void main() {" +
 "  gl_Position = uMVPMatrix * vPosition;" +
 "  v_texCoord = a_texCoord;"+
 "}";

//프레그먼트 쉐이더
String fragmentShader = "precision mediump float;" +
 "varying vec2 v_texCoord;"+
 "uniform sampler2D s_texture;"+
 "void main() {" +
 "  gl_FragColor = texture2D(s_texture, v_texCoord);" +
 "}";

기존의 단색 배경을 갖는 사각형을 그릴때와 달라진점이 보이시나요?
gl_FragColor에 대입되는 값이 컬러값이 아닌 텍스쳐이고, texture2D함수의 인자로 텍스쳐와 uv 좌표값을 받고 있습니다.

Notice : uv핸들러(a_texCoord)를 얻는방식은 정점핸들러 얻는방식과 유사하므로 내용에서 제외 했습니다.

텍스쳐 생성 및 바인딩

int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);

텍스쳐를 1개 생성합니다.

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

첫번째 텍스쳐를 활성화 합니다. 텍스쳐를 한개만 사용할 경우 생략 가능합니다.

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

텍스쳐를 바인딩합니다. textures[0]의 텍스쳐를 사용하겠다는 뜻입니다. 아직까지는 해당텍스쳐에 이미지가 로드되지 않은 상태입니다.

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

텍스쳐의 크기가 매핑되는 삼각형과의 크기가 맞지 않을 경우 축소하거나 확대할 때 어떤식으로 필터링 할것인지 결정하는 코드입니다. 더 자세한 내용은 문서를 참조해주세요.

Bitmap bitmap = BitmapFactory.decodeResource(context, R.drawable.리소스아이디);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

drawable 리소스로부터 이미지 하나를 불러와 Bitmap으로 만든뒤 GLUtils.texImage2D 메소드를 이용하여 현재 바인딩된 텍스쳐에 연동시키는 과정입니다.

이제 텍스쳐준비가 끝났습니다. 나머지 설정을 마치고 그리기를 수행해보세요. 이미지가 출력될것입니다.

본 프로젝트는 github에서 확인 가능합니다.

카테고리: Graphics

2개의 댓글

corat · 2020년 4월 29일 1:52 오후

정말 감사합니다ㅠㅠㅠ 어제 오늘 끙끙대던거 드디어 풀렸네요 너무 감사합니다 잘 보고 갑니다!:)

    Charlezz · 2020년 4월 29일 4:25 오후

    풀리셨다니 다행입니다 !

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.