Post Lists

2018년 6월 24일 일요일

Lighting - Colors (1)

https://learnopengl.com/Lighting/Colors

---------------------------------------------------------------------------

Colors
우리는 간단히 이전 튜토리얼에서 OpenGL이 color들을 가지고 어떻게 작동하는지를 언급했었다. 그러나 지금까지 colors들의 겉부분만 다루었다. 여기에서 우리는 광범위하게 color가 무엇인지 그리고 다가오는 lighting 튜토리얼을 위한 scene을 구성하는 것을 시작할 것이다.

실제 세계에서, 색은 실제적으로 자신의 색을 가진 각각의 오브젝트와 함께 어떤 알려진 color value값을 취할 수 있다. 디지털 세계에서, 우리는 그 (무하한) 실제 color들을 (제한된) digital 값으로 연결시킬 필요가 있고, 그러므로 모든 실제 세계의 색들이 디지털적으로 표현될 수 있는 것은 아니다. 그러나 우리는 너가 어쨋든 차이점을 눈치채지 못할 만큼의 많은 색들을 표현할 수 있다. 색들은 디지털적으로 RGB로 흔히 축약되는 red, green과 blue 요소를 사용하여 나타내어진다. 그러한 3가지 값들의 다른 조합을 사용하여, 우리는 거의 어떤 색이든지 나타낼 수 있다. 예를들어, coral color를 얻기 위해, 우리는 color vector를 이렇게 정의한다.

  glm::vec3 coral(1.0f, 0.5f, 0.31f);

우리가 실 세계에서 보는 색들은 그 객체들이 실제로 가지고 있는 색이 아니다. 그러나 그 색들은 객체로부터 반사되어진다. 객체에 의해 흡수되지 않은(거절된) 색들이 우리가 그것들을 인지하는 색이다. 예를들어, 태양의 빛은 하얀색으로 인지되는데, 그것은 많은 다른 색들의 조합된 합이다. (너가 이미지에서도 볼 수 있듯이) 그래서 만약 너가 하얀 빛을 파란색 장난감에 비추면, 그것은 파란색을 제외한 모든 하얀색의 sub-colors들을 흡수한다. 장난감은 blue value를 흡수하지 않기 때문에, 그것이 반사되고 그리고 이 반사된 빛은 우리의 눈에 들어온다. 이것은 장난감이 파란색을 가진 것 처럼 보이게 만든다. 다음의 이미지는 color색의 장난감에 대한 이것을 보여준다. 여기에서 그것은 다양한 강도로 몇 가지 색을 반사시킨다.

너는 하얀 태양광이 실제로 모든 가능한 색들의 조합이고 객체는 그러한 색들의 많은 부분을 흡수한다는 것을 알 수 있다. 그것은 오직 그 객체의 색을 나타내는 색만을 반사시킨다. 그러한 조합은 우리가 인지하는 것이다. (이 경우에 colar color)

이러한 색의 반사 규칙들은 직접적으로 그래픽스 영역에 적용된다. 우리가 OpenGL에서 light source를 정의할 때, 우리는 이 빛의 source에 color를 주길 원한다. 이전의 문단에서 우리는 하얀색 컬러를 가졌었다. 그래서 우리는 light source에게 white color를 또한 줄 것이다. 만약 우리가 그러고나서 그 light source의 color를 object의 color value와 곱한다면, 그 결과 color는 그 객체의 반사된 color이다. (그러므로 그것의 인지된 색) 우리의 장난감을 다시봐보자 (이번엔 colar 값을 가진 것으로) 그리고 어떻게 우리가 그것의 인지가능한 색을 그래픽스 영역에서 계산하는지 봐보자. 우리는 결과 color vector를 두 color vector에 component 방향으로 곱셈을 하여 얻어낸다.

glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);

우리는 toy의 색이 흰 빛의 많은 부분을 흡수한다는 것을 알 수 있지만, 그것 자신의 컬러 값을 기반으로 하여, 몇 가지 red, green 그리고 blue 값을 반사시킨다는 것을 알 수 있다. 이것은 어떻게 색이 실제 세계에서 작동하는지에 대한 표현이다. 우리는 따라서 객체의 색을 광원(light source)로 부터 반사시키는 각 color component의 양으로 정의할 수 있다. 이제 만약 우리가 green light를 쓰면 어떤 일이 일어날까?

glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (0.0f, 0.5f, 0.0f);

우리가 볼 수 있듯이, 장난감은 흡수하거나 반사시킬 red나 blue light가 없다. 그 장난감은 또한 빛의 green value의 절반을 흡수할 뿐만 아니라, 여전히 light의 green value의 절반을 반사시킨다. 우리가 인지하는 장난감의 색을 dark-greenish 색이 될 것이다. 우리는 만약 green light를 사용한다면, 오직 green color components만이 반사될 수 있고 따라서 그것만이 인지될 수 있다는 것을 알 수 있다. 어떠한 빨간색과 파란색이 인지되지 않는다. 결과는 color object는 갑자기 dark-greenish 객체가 된다. dark olive-green light로 한 가지 더 해보자:

glm::vec3 lightColor(0.33f, 0.42f, 0.18f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (0.33f, 0.21f, 0.06f);

너가 볼 수 있듯이, 우리는 다른 빛의 색을 사용하여 객체로부터 예상치 못한 색들을 얻을 수 있다. 색들을 가지고 창의적이게 되는 것은 어렵지 않다.

그러나 색에 대해 충분했으니, 우리가 실험할 수 있는 scene을 구성해보자.

A lighting scene
다가오는 튜토리얼에서 우리는 광범위한 컬러들을 사용하여 실제 세계의 조명을 재현함으로써 흥미로운 비쥬얼을 만들 것이다. 이제 우리는 광원을 사용할 것이기 때문에, 우리는 그것들을 scene에 있는 시각적 객체로서 보이고 싶어한다. 그리고 빛을 재현하기위해 한 객체를 적어도 추가해야 한다.

우리가 필요한 첫 번째 것은 빛을 cast(던지는, 뿌리는)하는 한 객체이고, 그리고 우리는 이전 튜토리얼의 그 악명높은 container cube를 사용할 것이다. 우리는 또한 그 광원이 3D scene에서 어디에 위치해있는지를 보여주는 light object를 필요할 것이다. 간단히 말해서, 우리는 또한 광원을 cube로 나타낼 것이다. (우리는 이미 vertex data를 가지고 있지 않은가?)

그래서, vertex buffer object를 채우고, vertex attribute pointer들을 설정하고 모든 그러한 이상한 일들은 너에게 이제는 쉬울 것이다. 그래서 우리는 그러한 단계들을 거치도록 안할 것이다. 만약 너가 그러한 것에 어려움을 가진다면, 너가 이전 튜토리얼들을 다시 보고 계속하기정네 가능하면 exercise들을 하기를 제안한다.

그래서, 우리가 실제로 필요한 첫 번째 것은 vertex shader가 container를 그리도록 하는 것이다. 컨테이너의 vertex positions들을 같다. (비록 우리가 이번에 텍스쳐 좌표를 필요하지 않을 지라도) 그래서 그 코드는 새로울 것은 없을 것이다. 우리는 이전 튜토리얼에서 vertex shader의 stripped down version을 사용할 것이다.

#version 330 core
layout (location = 0) in vec3 aPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}

너의 vertex data와 attribute pointer가 새로운 vertex shadeㄱ에 일치하도록 업데이트 해라. (만약 너가 원한다면, 너는 텍스쳐 데이터와 attribute pointer들을 활성화 해놓을 수 있다; 우리는 그것들을 지금 당장 사용하지 않을 것이지만, 새로운 시작으로 출발하는 것이 나쁜 생각은 아니다.)

우리는 또한 lamp cube를 만들 것이기 때문에, 우리는 특히 lamp를 위한 새로운 VAO를 만들고 싶다. 우리는 또한 같은 VAO를 사용하여 lamp를 나타낼 수 있고 그러고나서 간단히 model matrix에 변환을할 수 있지만, 앞으로의 튜토리얼에서 우리는 container object의 vertex data와 attribute pointer들을 꽤 종종 바꿀 것이다. 그래서 우리는 이러한 변화가 lamp object에 전달되기를 원하지 않는다. (우리는 오직 lamp의 vertex position만을 신경쓴다.) 그래서 우리는 새로운 VAO를 만들 것이다.

unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

코드는 상대적으로 간단하다. 우리는 container와 lamp cube 둘 다 만들 었으니, 정의할 한 가지 것이 남았다. 그것은 fragment shader이다 :

#version 330 core

out vec4 FragColor;

uniform vec3 objectColor;
uniform vec3 lightColor;

void main()
{
    FragColor = vec4(lightColor * objectColor, 1.0);
}

fragment shader는 uniform 변수로부터 object color와 light color 둘 다 받아들인다. 여기에서 우리는 이 튜토리얼의 처음에 이야기 했듯이 광원의 색을 오브젝트의 (반사된) 색과 곱한다. 또 다시, 이 쉐이더는 이해하기에 쉬울 것이다. 오브젝트의 색을 마지막 섹션의 coral color값으로 정하자. 흰색 빛고 함께:

shader1.use();
shader1.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
shader1.setVec3("lightColor", 1.0f, 1.0f, 1.0f);

주목해야할 남은 한 가지 것은 우리가 vertex와 fragment shader들을 바꾸기 시작할 때, lamp cube는 또한 바뀔 것이고 이것은 우리가 원하는게 아니라는 것이다. 우리는 lamp object의 색이 앞으로의 튜토리얼에서 lighting calculation에 의해 영향받기를 원하지 않지만, 오히려 lamp가 나머지로부터 고립되도록 하기를 원한다. (이것은 lamp가 정말 광원처럼 보이게 만든다.)

이것을 하기위해서, 우리는 실제로 lamp를 그리기 위해 사용할 두 번째 쉐이더를 만들필요가 있다. 따라서 lighting shader에 대한 어떠한 변화로부터 안전할 것이다. vertex shader는 현재의 vertex shader와 같다. 그래서 너는 간단히 lamp의 vertex shader의 소스 코드를 복사할 수 있다. lamp의 fragment shader는 lamp'의 color가 밝도록 유지해야 한다. lamp에 상수 white color 값을 정의하여:

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0);
}

우리가 우리의 오브젝트들을 그리기 원할 때, 우리는 정의한 lighting shader를 사용하여 container object를 (또는 가능하게 많은 다른 오브젝트들을) 그리길 원한다.  그리고 lamp를 그리고 싶을 때, 우리는 lamp의 shader를 사용하길 원한다. 튜토리얼 동안에 우리는 점차적으로 천천히 좀 더 현실적인 결과를 갖도록 lighting shader를 수정할 것이다.

lamp cube의 주된 목적은 light가 어디로 부터 오는지를 보여주는 것이다. 우리는 보통 light source의 위치를 scene의 어딘가로 정의한다, 그러나 이것은 시작적 의미를 가지지 않는 간단한 위치이다. 실제 lamp를 보여주기 위해서, 우리는 광원의 같은 위치에 lamp cube를 그릴 것이다. 이것은 lamp shader를 가진 lamp object를 그려서 이루어진다. 그리고 이것은 lamp cube가 항상 하얗게 유지된다. scene의 빛의 상태와 상관없이.

world-space 좌표에서 광원의 위치를 나타내는 전역 변수 vec3 변수를 선언해보자

 glm::vec3 lightPos(1.2f, 1.0f, 2.0f);

우리는 그러고나서  lamp의 cube를 그리기전에 광원의 위치로 옮기길 원한다.  그리고 우리는 또한 lamp가 너무 dominant하지 않기 위해 그것을 조금 크기를 줄일 것이다.

glm::mat4 lmodel(1);
lmodel = glm::translate(lmodel, lightPos);
lmodel = glm::scale(lmodel, glm::vec3(0.2f));

lamp를 그리는 결과 코드는 그런 후에 이것과 같을 것이다:

lighting_Source.use();
lighting_Source.setMat4("view", view);
lighting_Source.setMat4("projection", projection);
glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);

적절한 위치에 모든 code fragments들을 넣는 것은 조명을 실험하는데 적절힌 환경 설정된 깔끔한 OpenGL 프로그램을 만들어낼 것이다. 만약 모든 것이 컴파일 된다면, 그것은 이것처럼 보일 것이다:


지금 당장은 볼게 많이 없지만, 나는 앞으로의 튜토리얼에서 좀 더 멋지게 될 것이라는 것을 약속할 것이다.

만약 너가 전반적으로 프로그램에 많은 모든 코드 모음을 발견하는데 어려움이 있다면 source code를 여기에서 확인하고 조심스럽게 code와 주석을 통해 너만의 방식으로 해나가라

color에 대한 조금의 지식을 가졌고 섹시한 lighting stuff를 위한 기본 scene을 만들었으니, 우리는 진짜 마법이 시작되는 다음 튜토리얼로 점프해갈 수 있다.

댓글 없음:

댓글 쓰기