컴퓨터 그래픽스/OpenGL

#12 Tinylender 개발일지 : LightLayer 추가 (1)

san10 2024. 9. 25. 21:28

이제 만든 모델링의 쉐이더를 조정해서 여러 표현을 할 수 있도록 만들 생각이였다.

그런데 기본적으로.. 빛을 컨트롤 할 수 있어야 쉐이더가 유의미할것이다.

그래서 Light를 생성하고 조작할 수 있는 기능을 만들었다.

(이전까지는 빛이 특정위치에 하드코딩 되어있었다.)

 

텍스트박스 기능 추가

이번 글의 주제와 직접적인 연관이 있는 것은 아니지만

textbox에 새로운 기능을 추가했다!

원래는 키보드 입력으로만 텍스트의 내용을 조정할 수 있었는데

이젠 드래그로도 변경할 수 있다.

 

 

LightLayer

class LightLayer : public Layer
{
public:
    LightLayer() {};
    LightLayer(std::string name, glm::vec3 lightColor, glm::vec3 pos);
    void SetPosition(glm::vec3 pos);
    void SetRotation(glm::vec3 rot);
    void SetScale(glm::vec3 scale);
    void SetColor(glm::vec3 color);
    void SetIndex(unsigned int i);
    void Draw();

private:
    glm::vec3 mLightColor;
    unsigned int mLayerIndex;
};

LightLayer는 이름에서 알 수 있듯이

빛의 정보를 가지고 있는 Layer다.

일단 쉐이더를 제일 기본적인 쉐이더인 blinn-phong 으로 구현해놓았기에

현재는 위치와 색상 정보만 가지고있도록 구성했다.

 

 

LightLayer는 만들었는데..

그런데..

생각을 해보니

빛이라는 것은 전역적인 것이라서

모든 쉐이더가 빛 정보를 알고 있어야 할 것이다.

 

그래서 구현을 어떻게 할지 고민했는데,

glsl의 uniform을 전역적으로 쓸 수 있게 해주는 

uniform buffer object라는 것이 있다는 것을 알았다.

 

https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object

 

Uniform Buffer Object - OpenGL Wiki

A Buffer Object that is used to store uniform data for a shader program is called a Uniform Buffer Object. They can be used to share uniforms between different programs, as well as quickly change between sets of uniforms for the same program object. The te

www.khronos.org

https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL

 

LearnOpenGL - Advanced GLSL

Advanced GLSL Advanced-OpenGL/Advanced-GLSL This chapter won't really show you super advanced cool new features that give an enormous boost to your scene's visual quality. This chapter goes more or less into some interesting aspects of GLSL and some nice t

learnopengl.com

uniform buffer object는 실제로 쉐이더들이 공유하는 행렬이나 빛과 같은 데이터에 많이 쓰이는 것 같았다.

이번에도 learnOpenGL 따라서 만들었다.

struct BlinnPhongLight
{
   vec3 lightColor;
   vec3 lightPos;
};

layout (std140) uniform Lights
{
    BlinnPhongLight lights[32];
   
};

glsl에 uniform block을 선언해주고..

 

glGenBuffers(1, &lightsUBO);
glBindBuffer(GL_UNIFORM_BUFFER, lightsUBO);
glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4 * 2 * 32, NULL, GL_STATIC_DRAW);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, lightsUBO, 0, sizeof(float) * 4 * 2 * 32);

VBO, VAO 생성하는 것처럼 glGenBuffers로 생성해주고

필요한만큼 메모리를 할당해준다.

 

여기서...

vec3는 float가 3개로 이루어진 자료구조니깐

4(float 사이즈) * 3 이 아닌가 싶은데

std140의 규칙이 있어서

4*3 + 4(offset) 으로 이루어진다.

 

mUniformBlockIndex = glGetUniformBlockIndex(mShader.ID, "Lights");
glUniformBlockBinding(mShader.ID, mUniformBlockIndex, 0);

그리고 uniform block을 사용할 쉐이더를 바인딩한다.

 

이렇게 하면 uniform block을 사용할 준비 끝이다.

 

Collection

void Collection::Rendering(Layer *layer)
{
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    if (layer->GetVisible() && layer->layerType == eLayerType::SHAPE)
    {
        static_cast<ShapeLayer *>(layer)->Draw();
    }

    if (layer->GetVisible() && layer->layerType == eLayerType::LIGHT)
    {
        glBindBuffer(GL_UNIFORM_BUFFER, lightsUBO);
        static_cast<LightLayer *>(layer)->Draw();
    }

    if (layer->children.size() == 0)
        return;

    for (Layer *child : mRootLayer->children)
    {
        Rendering(child);
    }
}

Collection의 Rendering()도 lightlayer의 Draw()를 호출하도록 수정했다.

lightLayer의 Draw()는...

void LightLayer::Draw()
{
    unsigned int uniformOffset = mLayerIndex * LIGHT_SIZE;
    glBufferSubData(GL_UNIFORM_BUFFER, uniformOffset + 16, sizeof(float) * 3, glm::value_ptr(GetPosition()));
    glBufferSubData(GL_UNIFORM_BUFFER, uniformOffset, sizeof(float) * 3, glm::value_ptr(mLightColor));
}

uniform block의 내용물을 바꿔준다.

 

 

실행 결과

light도 상단에 버튼을 추가하여 빛을 추가할 수 있게 했다!

 

(당연히) ShapeLayer처럼 빛을 이동시키거나 빛의 색을 변경할 수도 있다.

 

 

빛은 (당연히) 중첩이 되므로 빛을 조정하여 여러 색을 연출할 수도 있다.

 

 

위에서도 언급했듯이 지금은 blinn-phong으로 쉐이더를 구현했고..

아마 다음에는 pointlight나 spotlight 구현하지 않을까?

이게 아니더라도 최소한 shininess나.. meterial 조절할 수 있도록 만들것 같다.