macOS에서 OpenGL 프로그래밍 (2-5. 다중 텍스처 결합)

macOS에서 OpenGL 프로그래밍의 목차로 돌아가기

소개



지난번은 단일 텍스처를 읽고 표시하는 프로그램을 작성했습니다.

이번에는 두 장의 텍스처를 동시에 사용하여 시간에 따라 어느 텍스처를 크게 표시할지를 전환하면서 애니메이션을 만들고 싶습니다.

1. ShaderProgram 클래스 개선



우선은 ShaderProgram 클래스에, float 형의 uniform 변수의 값을 세트 할 수 있도록 SetUniform() 함수의 오버로드 함수를 추가합니다. 또한 이전에 작성한 SetUniform() 함수와 동일한 작업을 수행하는 부분이 최소화되도록 uniform 변수의 위치를 ​​얻기 위해 GetUniformLocation() 함수를 별도로 추가합니다.

Shader.hpp(일부)
class ShaderProgram
{
    /* 一部省略 */

public:
    GLint   GetUniformLocation(const std::string& name);
    void    SetUniform(const std::string& name, float value);
    void    SetUniform(const std::string& name, int value);
    void    Use();
};

이러한 함수를 구현하는 코드를 ShaderProgram.cpp에 씁니다. 대부분의 행 수는 uniform 변수의 위치를 ​​쿼리하기 위한 코드이므로, GetUniformLocation() 함수를 준비한 것으로, 2개의 SetUniform() 함수의 구현은 2행씩으로 끝나게 되었습니다.

Shader.cpp(일부)
GLint ShaderProgram::GetUniformLocation(const std::string& name)
{
    GLint location;
    if (uniformLocationMap.find(name) == uniformLocationMap.end()) {
        location = glGetUniformLocation(program, name.c_str());
        if (location < 0) {
            throw GameError("ShaderProgram::SetUniform() Cannot locate a uniform value: %s", name.c_str());
        }
        uniformLocationMap[name] = location;
    } else {
        location = uniformLocationMap[name];
    }
    return location;
}

void ShaderProgram::SetUniform(const std::string& name, float value)
{
    GLint location = GetUniformLocation(name);
    glUniform1f(location, value);
}

void ShaderProgram::SetUniform(const std::string& name, int value)
{
    GLint location = GetUniformLocation(name);
    glUniform1i(location, value);
}

2. Game 클래스에 변수 추가



Game.hpp를 편집하여 새 텍스처 변수tex2와 시간이 지남에 따라 값을 변경하는 변수t를 추가합니다.

Game.hpp(일부)
class Game
{
    /* ここまで省略 */
    Texture     *tex;
    Texture     *tex2;
    float       t;

    /* 以下、省略 */
};

Game.cpp를 편집하여 생성자에서 새 텍스처를 새로 만드는 코드와 첫 번째 텍스처를 바인딩하는 코드를 추가합니다 (이전에는 0 번째 텍스처를 바인딩하고 사용했습니다). 또한 변수t를 0.0f로 초기화합니다.

Game.cpp(생성자)
Game::Game()
{
    /* 前半省略 */

    tex = new Texture("photo.jpg");
    tex2 = new Texture("photo2.jpg");
    glActiveTexture(GL_TEXTURE0);
    tex->Bind();
    glActiveTexture(GL_TEXTURE1);
    tex2->Bind();
    program->Use();
    program->SetUniform("tex", 0);
    program->SetUniform("tex2", 1);

    t = 0.5f;

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}

이용할 수 있는 텍스처의 수는, 2개 뿐만이 아니라, GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, ...라고 정수가 준비되어 있으므로, 3개에서도 4개에서도 동시에 이용할 수 있습니다.

Game 클래스의 소멸자에는 추가한 텍스처를 삭제하기 위한 코드를 잊지 않고 써 둡니다.

Game 클래스의 소멸자
Game::~Game()
{
    delete program;
    delete tex;
    delete tex2;
    ...
}

그런 다음 Game::Render() 함수 구현입니다. 키보드의 왼쪽 및 오른쪽 화살표 키를 사용하여 변수t의 값을 0.0에서 1.0으로 변경합니다.

Game.cpp(Render() 함수)
void Game::Render()
{
    if (Input::GetKey(KeyCode::LeftArrow)) {
        t -= 0.5f * Time::deltaTime;
    }
    if (Input::GetKey(KeyCode::RightArrow)) {
        t += 0.5f * Time::deltaTime;
    }
    if (t < 0.0f) {
        t = 0.0f;
    } else if (t > 1.0f) {
        t = 1.0f;
    }

    program->Use();
    program->SetUniform("t", t);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(vao);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void *)0);
}

텍스처의 번호를 나타내는 sampler2D형의 변수 2개와 달리, 변수 t 의 값은 계속 변화하기 때문에, Render() 함수의 선두로 매 프레임 세트 재차 합니다.

3. 프래그먼트 셰이더 재작성



이번에는 정점 쉐이더의 변경은 필요 없기 때문에, 단편 쉐이더만을, 다음과 같이 재기록합니다.

myshader.fsh
#version 410

in vec4 color;
in vec2 uv;
uniform sampler2D tex;
uniform sampler2D tex2;
uniform float t;
layout (location=0) out vec4 frag_color;

void main()
{
    vec4 c1 = texture(tex, uv);
    vec4 c2 = texture(tex2, uv);
    frag_color = (uv.x < t? c1: c2);
}

sampler2D 형의 uniform 변수 tex를 1 개 늘려, float 형의 값을 받기위한 uniform 변수 t도 추가했습니다.

그런 다음 tex 변수를 사용하여 0 번째 텍스처 이미지에서 tex2 변수를 사용하여 첫 번째 텍스처 이미지에서 UV 좌표에 해당하는 색상 값을 가져옵니다 c1c2 에 저장합니다. 마지막으로 3항 연산자를 사용해, UV 좌표의 X 좌표가 0.0~1.0의 t의 값보다 작으면 c1의 값을, 그렇지 않으면 c2의 값을 사용하도록(듯이) frag_color 변수에 할당 명령을 씁니다.

4. 텍스처 이미지 추가



마지막으로 이전과 마찬가지로 새 이미지를 프로젝트에 추가합니다. "photo2.jpg"라는 이미지 파일을 추가했습니다.

 

 

5. 정리



어플리케이션을 실행하면, 좌우의 화살표 키의 조작에 따라서, X축 방향으로 2매의 텍스처 화상이 크기를 바꾸면서 표시되게 된 것을 알 수 있습니다.

 

지금까지 프로젝트: MyGL은 _s로 p2-5. 지 p

다음 문서: macOS에서 OpenGL 프로그래밍 (2-6. 정점 데이터에 GLKit 구조체 사용)

좋은 웹페이지 즐겨찾기