개발/OpenGL / / 2022. 3. 11. 15:51

OpenGL 공부일지 - OpenGL Super Bible 텍스처 - 1

반응형

Textures

텍스처는 쉐이더가 읽기도 쓰기도 하는 구조화된 스토리지이다. 주로 이미지 데이터를 저장 시 사용된다. 

텍스터는 생성하여 텍스처 유닛에 바인딩되고, 관리할 수 있는 객체 형태로 표현된다. 

glGenTextures로 텍스처 객체를 생성하고, 텍스처 타깃에 바인딩되어야 비로소 텍스처라고 부를 수 있다.

버퍼 객체를 바인딩하는 것과 유사하지만 테긋처는 소멸할 때까지 해당 타깃의 타입이 유지된다.

Creating and Initialzing Textures

텍스처 생성을 위해 이름을 생성하고, 타깃에 바인딩하고 opengl에 저장할 이미지 사이즈를 알려주어야 한다. 

// The type used for names in OpenGL is GLuint
GLuint texture;

// Create a new 2D texture object
glCreateTextures(GL_TEXTURE_2D, 1, &texture);

// Specify the amount of storage we want to use for the texture
glTextureStorage2D(texture, // Texture object
    1, // 1 mipmap level
    GL_RGBA32F, // 32-bit floating-point RGBA data
    256, 256); // 256 x 256 texels

// Now bind it to the context using the GL_TEXTURE_2D binding point
glBindTexture(GL_TEXTURE_2D, texture);

위 코드를 보자. glCreateTexture(6판의 경우 glGenTextures)로 객체이름 생성, glBindTextrue로 바인딩, glTexStorage로 스토리지를 할당한다.

glTexStorage2D함수는 텍스처를 바인딩하기 위해 사용되는 동작을 설정하고, 밉맵에서 사용할 레벨의 수 설정, 텍스처의 내부 포맷, 텍스처의 넓이와 높이를 설정한다. opengl은 이 텍스처를 저장할 충분한 메모리를 할당한다. 

// Define some data to upload into the texture
float * data = new float[256 * 256 * 4];

// generate_texture() is a function that fills memory with image data
generate_texture(data, 256, 256);

// Assume that "texture" is a 2D texture that we created earlier
glTextureSubImage2D(texture, // Texture object
    0, // Level 0
    0, 0, // Offset 0, 0
    256, 256, // 256 x 256 texels, replace entire
    image
    GL_RGBA, // Four-channel data
    GL_FLOAT, // Floating-point data
    data); // Pointer to data

// Free the memory we allocated before - OpenGL now has our data
delete [] data;

glTextSubImage2D를 사용하면 텍스처의 일부 데이터를 지정할 수 있다.

Texture Targets and Types

바로 위 코드는 2D 텍스처 타깃에 새 이름을 바인딩하고, 2D 텍스처를 만드는 방법을 설명한다. 

텍스처 객체는 바인된 타깃에 따라 타입이 다르다.

여러가지 텍스처 타깃이 있는데, 3D 텍스처는 볼륨을 표현할 수 있고 3차원 텍스처 좌표를 가질 수 있다. 

 버퍼 텍스처라는 것이 있는 모양인데, 이는 1D 텍스처와 유사하지만 스토리지가 실제 버퍼 객체로 표현하는 특별한 텍스처 타입이라고 한다. 최대크기가 1D 텍스처보다 훨씬 크지만 필터링 및 밉맵과 같은 1D 텍스처의 기능 중 일부가 지원되지 않는다.

 멀티 샘플 텍스처 타입은 멀티 샘플 안티에일리어싱을 위해 사용된다. 이는 이미지 퀄리티를 향상시키기 위한 기법이고, 특히 라인과 폴리곤의 경계선에서 효과가 두드러진다.

Reading from Textures in Shaders

텍스처 객체를 생성하고, 데이터를 넣으면 쉐이더에서 그 데이터를 읽어 컬러 프래그먼트에 적용할 수 있다. 

텍스처는 쉐이더에서 sampler variable로 사용되고, 샘플러 타입으로 유니폼을 선언하면 외부에서도 접근 가능하다. 

텍스처를 여러 차원 생성하고 사용가능한 것처럼 GLSL에서 사용할 수 있는 샘플러 변수도 여러 종류이다. 

#version 450 core

uniform sampler2D s;

out vec4 color;

void main(void)
{
	color = texelFetch(s, ivec2(gl_FragCoord.xy), 0);
}

위 코드의 GLSL을 보자. 텍스처를 읽고 있다. 코드에서는 2차원 텍스처 타입인 sampler2D를 사용하고 있고, uniform타입으로 변수를 생성하고 texelFetch라는 함수로 유니폼과 텍스처를 읽을 위치는 텍스처 좌표를 사용해서 호출하고 있다.

위 코드는 gl_FragCoord로 구한 텍스처 좌표를 사용해서 유니폼 샘플러로부터 읽는다. gl_FragCoord 변수는 프로그래먼트 쉐이더의 입력으로 전달되는 변수로 윈도우 좌표로 계산된 프래그먼트의 부동소수점 좌표를 담는다. 

texelFetch는 텍스처의 넓이, 높이를 받으므로 2요소 정수벡터 ivec2를 생성해서 전달하였다.

 

#include <sb6.h>
#include <vmath.h>

#include <string>
static void print_shader_log(GLuint shader)
{
    std::string str;
    GLint len;

    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
    if (len != 0)
    {
        str.resize(len);
        glGetShaderInfoLog(shader, len, NULL, &str[0]);
    }

#ifdef _WIN32
    OutputDebugStringA(str.c_str());
#endif
}

static const char * vs_source[] =
{
    "#version 420 core                                                              \n"
    "                                                                               \n"
    "void main(void)                                                                \n"
    "{                                                                              \n"
    "    const vec4 vertices[] = vec4[](vec4( 0.75, -0.75, 0.5, 1.0),               \n"
    "                                   vec4(-0.75, -0.75, 0.5, 1.0),               \n"
    "                                   vec4( 0.75,  0.75, 0.5, 1.0));              \n"
    "                                                                               \n"
    "    gl_Position = vertices[gl_VertexID];                                       \n"
    "}                                                                              \n"
};

static const char * fs_source[] =
{
    "#version 430 core                                                              \n"
    "                                                                               \n"
    "uniform sampler2D s;                                                           \n"
    "                                                                               \n"
    "out vec4 color;                                                                \n"
    "                                                                               \n"
    "void main(void)                                                                \n"
    "{                                                                              \n"
    "    color = texture(s, gl_FragCoord.xy / textureSize(s, 0));                   \n"
    "}                                                                              \n"
};

class simpletexture_app : public sb6::application
{
public:
    void init()
    {
        static const char title[] = "OpenGL SuperBible - Simple Texturing";

        sb6::application::init();

        memcpy(info.title, title, sizeof(title));
    }

    void startup(void)
    {
        // Generate a name for the texture
        glGenTextures(1, &texture);

        // Now bind it to the context using the GL_TEXTURE_2D binding point
        glBindTexture(GL_TEXTURE_2D, texture);

        // Specify the amount of storage we want to use for the texture
        glTexStorage2D(GL_TEXTURE_2D,   // 2D texture
                       8,               // 8 mipmap levels
                       GL_RGBA32F,      // 32-bit floating-point RGBA data
                       256, 256);       // 256 x 256 texels

        // Define some data to upload into the texture
        float * data = new float[256 * 256 * 4];

        // generate_texture() is a function that fills memory with image data
        generate_texture(data, 256, 256);

        // Assume the texture is already bound to the GL_TEXTURE_2D target
        glTexSubImage2D(GL_TEXTURE_2D,  // 2D texture
                        0,              // Level 0
                        0, 0,           // Offset 0, 0
                        256, 256,       // 256 x 256 texels, replace entire image
                        GL_RGBA,        // Four channel data
                        GL_FLOAT,       // Floating point data
                        data);          // Pointer to data

        // Free the memory we allocated before - \GL now has our data
        delete [] data;

        program = glCreateProgram();
        GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fs, 1, fs_source, NULL);
        glCompileShader(fs);

        print_shader_log(fs);

        GLuint vs = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vs, 1, vs_source, NULL);
        glCompileShader(vs);

        print_shader_log(vs);

        glAttachShader(program, vs);
        glAttachShader(program, fs);

        glLinkProgram(program);

        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
    }

    void shutdown(void)
    {
        glDeleteProgram(program);
        glDeleteVertexArrays(1, &vao);
        glDeleteTextures(1, &texture);
    }

    void render(double t)
    {
        static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
        glClearBufferfv(GL_COLOR, 0, green);

        glUseProgram(program);
        glDrawArrays(GL_TRIANGLES, 0, 3);
    }

private:
    void generate_texture(float * data, int width, int height)
    {
        int x, y;

        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                data[(y * width + x) * 4 + 0] = (float)((x & y) & 0xFF) / 255.0f;
                data[(y * width + x) * 4 + 1] = (float)((x | y) & 0xFF) / 255.0f;
                data[(y * width + x) * 4 + 2] = (float)((x ^ y) & 0xFF) / 255.0f;
                data[(y * width + x) * 4 + 3] = 1.0f;
            }
        }
    }

private:
    GLuint      texture;
    GLuint      program;
    GLuint      vao;
};

DECLARE_MAIN(simpletexture_app);

(github 소스코드에서 해당 예제는 simpletexture project이다)

 

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유