IT/Android

[OpenGL ES] Android NDK 환경에서 glm 라이브러리 사용하기

버건디 팩토리 2021. 9. 1. 02:47
반응형

NDK 환경에서 glm 사용하기

OpenGL ES 2.0에는 1.0과는 다르게 고정 파이프라인을 삭제하고 shader를 이용해 rotate, translate perspective 등의 계산을 진행해야한다.

따라서 glRotatef, glTranslatef, glutPerspective 등의 쉽게 사용하던 OpenGL의 함수를 2.0에서는 사용할 수 없게 되었다.

이런 불편함을 해결하기 위해 행렬 단위에서 shader를 조금 더 쉽게 이용할 수 있도록 도와주는게 glm 라이브러리이다.

이번 포스트는 glm과 OpenGL ES에 대해 기본적으로 이해하는 독자를 대상으로 하기 때문에, shader, NDK 환경에 대한 내용은 거의 다루지 않는다.

Android에 glm 설치하기

1. glm 다운로드

https://github.com/g-truc/glm

 

GitHub - g-truc/glm: OpenGL Mathematics (GLM)

OpenGL Mathematics (GLM). Contribute to g-truc/glm development by creating an account on GitHub.

github.com

위 깃허브에서 모든 파일을 다운로드한다.

2. glm 다운로드

다운 받은 폴더 중 glm 폴더만을 안드로이드 프로젝트 내 "src/main/cpp"로 복사한다.

이때 위 path는 NDK 환경 초기 설정 위치로, 자신의 프로젝트에서 CMakeLists의 위치를 변경했다면

build.gradle(module: app) 에서 CMake path에 glm 폴더를 복사한다.

android {
    ```
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"		// path에 glm 폴더 복사
        }
    }
}

3. CMakeList 작성

glm 폴더를 add_subdirectory하여 include 폴더로 지정한다.

이때 CMakeList.txt 파일의 위치에 따라 glm 폴더를 다르게 작성해야 할 수도 있다. 하지만 2번에서와 같이 cmake path에 glm을 저장했다면 간단하게 아래 문장만 추가해도 된다.

add_subdirectory(glm)

이후 기존에 존재하는 target_link_libraries에 glm 종속성을 더한다.

# add lib dependencies
target_link_libraries(
# Specifies the target library.
native-lib
# Links the target library to the log library included in the NDK.
GLESv2
glm)

아래는 전체 cmake code이다. 이를 CMakeList.txt의 적절한 위치에 추가해준다.

# Import the CMakeLists.txt for the glm library
add_subdirectory(glm) # if your CMakeLists is at '../cpp'
# add_subdirectory(src/main/cpp/glm) # if your CMakeLists is at '../app'

# add lib dependencies
target_link_libraries(
# Specifies the target library.
native-lib
# Links the target library to the log library included in the NDK.
GLESv2
glm)

4. NDK include

glm을 사용할 모든 준비가 끝났으므로, 아래 헤더파일을 추가하여 glm을 사용한다.

// glm libs
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/closest_point.hpp>

GLM result

glm에 대한 사용 설명은 아래 opengl-tutorial에 매우 잘 나와있다.

나는 단순히 NDK 환경에서 glm을 사용하는 것을 보여주도록 하겠다.

http://www.opengl-tutorial.org/kr/beginners-tutorials/tutorial-3-matrices/

 

Tutorial 3 : 행렬(매트릭스)

엔진이 배를 움직이는 것이 아니다. 배는 그 자리에 가만이 있으나 엔진이 이 세상을 회전해 움직이는 것이다. Futurama 이부분은 모든 것에 있어 가장 중요한 단 하나의 튜토리얼입니다. 그러니

www.opengl-tutorial.org

OpenGL draw

projection view, model view를 모두 identity 행렬로 선언한다.

이후 원하는 위치에 따라 배치하고 아래 방향으로 회전하는 정육면체를 만든다.

shader 환경에서도 glm을 활용하여 쉽게 view를 변환할 수 있다.

 

포스트를 마치며

이번 글에서는 단순히 glm을 Android에서 사용하는 방법만 주로 작성했다.

앞으로의 포스트에서는 model을 그리는 OpenGL ES 2.0 shader에 대해서는 설명과 함께 추후 업로드하려고 한다!

따라서 이번에는 model을 그려  onDrawFrame에서 실행될 NDK 함수만 첨부하도록 하겠다.

이때 NDK에서 glm에 빨간 줄이 뜨며 "No matching function"이라고 에러가 발생하지만 무시하고 컴파일하면 작동한다!

void draw_model() {

   // draw마다 모델 회전을 위한 변수 초기화
    if(a == 360.f) a = 0.f;
    a += 1.f;

   /*-----glm-----*/

    mPMatrix = glm::mat4(1.0f);         // ProjectionView
    mMMatrix = glm::mat4(1.0f);         // ModelView

    // ProjectionView의 perspective 선언
    mPMatrix = glm::perspective(45.0f, (float)w /(float)h, 1.0f, 500.0f);

    // ModelView -10만큼 z 방향으로 이동
    mMMatrix = glm::translate(mMMatrix, glm::vec3(0.f, 0.f, -10.f));
    // ModelView -45도 회전
    mMMatrix = glm::rotate(mMMatrix, glm::radians(-45.f), glm::vec3(0.0f, 1.0f, 0.f));
    // ModelView a도 만큼 회전
    mMMatrix = glm::rotate(mMMatrix, glm::radians(a), glm::vec3(1.0f, 0.0f, -1.f));

   /*-----shader-----*/

    glUseProgram(mProgram);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mTextureID);   // Fragment Shader로 텍스쳐를 전달한다(sample2D)

    // projection, modelview 행렬 shader 연결
    glUniformMatrix4fv(muPMatrixHandle, 1, GL_FALSE, glm::value_ptr(mPMatrix));
    glUniformMatrix4fv(muMMatrixHandle, 1, GL_FALSE, glm::value_ptr(mMMatrix));

    // vertex buffer 연결
    glVertexAttribPointer(maPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, 12, vertices);
    glEnableVertexAttribArray(maPositionHandle);

    // texture 지정
    glVertexAttribPointer(maTextureHandle, 2, GL_FLOAT, GL_FALSE, 8, texture);
    glEnableVertexAttribArray(maTextureHandle);

    for(int i = 0; i < 6; i++) {
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indexes + 2 * 3 * i);
    }
}
반응형