

이런 오브젝트를 띄워볼거임
이미지 중에는 png형식의 이미지가 있음
그리고 png는 alpha값을 담을 수 있는 이미지 형식임
alpha값이 높으면 완전 불투명, alpha값이 낮으면 완전 투명
이렇게 되는거임ㅇㅇ
그럼 어떻게 이런 알파값을 사용할 수 있을까??
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
LearnOpenGL(4) - texture, image pixel data to gpu
이 부분을 보면
glTexImage메서드에 대한 설명이 나옴
저기서 색상 포맷을 RGBA로 바꿔주면 이제 alpha값을 사용할 수 있게 됨
그리고 이제 fragment shader로 가서...
uniform sampler2D texture1;
void main()
{
vec4 texColor = texture(texture1, TexCoords);
FragColor = texColor;
}
이렇게 사용하면 되지비
float grassVertices[] =
{
// positions // texture Coords (swapped y coordinates because texture is flipped upside down)
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 1.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
1.0f, 0.5f, 0.0f, 1.0f, 0.0f
};
이렇게 VBO, VAO용 풀때기 정점 속성 매핑해주고..
std::vector<glm::vec3> vegetation
{
glm::vec3(-1.5f, 0.0f, -0.48f),
glm::vec3( 1.5f, 0.0f, 0.51f),
glm::vec3( 0.0f, 0.0f, 0.7f),
glm::vec3(-0.3f, 0.0f, -2.3f),
glm::vec3 (0.5f, 0.0f, -0.6f)
};
//render
while()
{
//...
// draw objects
shader.use();
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 model = glm::mat4(1.0f);
shader.setMat4("projection", projection);
shader.setMat4("view", view);
// vegetation
glBindVertexArray(transparentVAO);
glBindTexture(GL_TEXTURE_2D, transparentTexture);
for (unsigned int i = 0; i < vegetation.size(); i++)
{
model = glm::mat4(1.0f);
model = glm::translate(model, vegetation[i]);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
//...
}
이렇게 월드좌표로 변환해주면...

이런 텍스쳐가 나옴...
이유가 뭘까?
바로 GL은 스스로 어떤 alpha값을 가진 fragment를 없애야하는지 모르는거임
그럼 그걸 어떻게 판단하도록 할 수 있을까?
discard라는 glsl명령어을 쓰면 됨
fragment shader에
if(texColor.a < 0.1) discard;
이 한줄만 추가해주면 됨
따라서 전체 fragment shader코드는
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D texture1;
void main()
{
vec4 texColor = texture(texture1, TexCoords);
if(texColor.a < 0.1) discard;
FragColor = texColor;
}
이렇게 되는거임
그냥 재미로 alpha임계값을 >로 해볼까?

제대로 표시되어야할 풀때기만 사라진 모습적인 모습
그럼 제대로 하면?

ㅇㅇㅇㅇ
색유리 뒤의 오브젝트는 어떻게 색상이 결정되는걸까?
- = 색상 결과
- = 영향을 주는 물체의 색상
- = 영향을 주는 물체의 색상의 지수(강하기)
- = 영향을 받는 물체의 색상
- = 영향을 받는 물체의 색상의 지수(강하기)
그럼 factor(지수)는 어떻게 구할까?
영향을 주는 물체의 색상지수는
해당 텍스쳐의 alpha값을 그대로 사용함
영향을 받는 물체의 색상지수는
1 - (영향을 주는 물체의 색상지수)를 사용함
예를들어
:
:
:
:
가 되는거임
따라서 식에 대입해보면
요로코롬 되어버리는겨~
그럼 이걸 어떻게 GL에 적용?
먼저
glEnabled(GL_BLEND);
로 BLEND옵션을 켜주자
그리고 사용할것이
glBlendFunc임
glBlendFunc(GLenum sfactor, GLenum dfactor);
여기서 GLenum으로 사용할 수 있는 값들이 있음
| 옵션 | 가치 / 중요성 |
|---|---|
GL_ZERO | 인수는 0과 같습니다. |
GL_ONE | 인수는 1과 같습니다. |
GL_SRC_COLOR | 팩터는 소스 색상 벡터 와 같습니다. |
GL_ONE_MINUS_SRC_COLOR | 팩터는 1에서 소스 색상 벡터를 뺀 값()과 같습니다. |
GL_DST_COLOR | 팩터는 목적지 색상 벡터 과 같습니다. |
GL_ONE_MINUS_DST_COLOR | 팩터는 1에서 목적지 색상 벡터를 뺀 값()과 같습니다. |
GL_SRC_ALPHA | 팩터는 소스 색상 벡터 의 알파(alpha) 성분과 같습니다. |
GL_ONE_MINUS_SRC_ALPHA | 팩터는 소스 색상 벡터 의 1 - 알파(1 - alpha) 성분과 같습니다. |
GL_DST_ALPHA | 팩터는 목적지 색상 벡터 의 알파(alpha) 성분과 같습니다. |
GL_ONE_MINUS_DST_ALPHA | 팩터는 목적지 색상 벡터 의 1 - 알파(1 - alpha) 성분과 같습니다. |
GL_CONSTANT_COLOR | 팩터는 상수 색상 벡터 와 같습니다. |
GL_ONE_MINUS_CONSTANT_COLOR | 팩터는 1에서 상수 색상 벡터를 뺀 값()과 같습니다. |
GL_CONSTANT_ALPHA | 팩터는 상수 색상 벡터 의 알파(alpha) 성분과 같습니다. |
GL_ONE_MINUS_CONSTANT_ALPHA | 팩터는 상수 색상 벡터 의 1 - 알파(1 - alpha) 성분과 같습니다. |
즉, 위 옵션에서 살펴보면
우리가 사용할 두 옵션은
GL_SRC_ALPHA와 GL_ONE_MINUS_SRC_COLOR가 되겠음~~
glBlendFunc는 색상의 RGB와 A 모두에 동시적으로 적용되는 blending옵션을 주는 메서드라면,,,
glBlendFuncSeparate는 RGB와 A에 따로따로 적용되는 blending옵션을 줄 수 있음
glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
이렇게!
이 식이 색상 결정하는 식이란걸 위에서 알려줘씀
그럼 glBlendEquation는 뭐하는걸까
OPERATOR
저 OPERATOR를 결정짓는거임
| 상수 | 설명 | 연산 공식 |
|---|---|---|
| GL_FUNC_ADD | 소스와 대상의 결과를 더함 (기본값) | |
| GL_FUNC_SUBTRACT | 소스 결과에서 대상 결과를 뺌 | |
| GL_FUNC_REVERSE_SUBTRACT | 대상 결과에서 소스 결과를 뺌 | |
| GL_MIN | 소스와 대상 중 더 작은 값을 선택 | |
| GL_MAX | 소스와 대상 중 더 큰 값을 선택 |

이런 창문을 그릴거임
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
unsigned int windowTex = loadTexture("D:/01_Develope/CPP/learn_opengl/learn_opengl/Resources/blend/blending_transparent_window.png");
while()
{
//...
// grassTex
glBindVertexArray(transparentVAO);
glBindTexture(GL_TEXTURE_2D, grassTex);
for (unsigned int i = 0; i < vegetation.size(); i++)
{
model = glm::mat4(1.0f);
model = glm::translate(model, vegetation[i]);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
//windowTex
glBindVertexArray(transparentVAO);
glBindTexture(GL_TEXTURE_2D, windowTex);
for (unsigned int i = 0; i < vegetation.size(); i++)
{
model = glm::mat4(1.0f);
glm::vec3 newVec(vegetation[i].x, vegetation[i].y, vegetation[i].z + 1);
model = glm::translate(model, newVec);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
//...
}
이렇게 BlendFunc와 grass보다 z축으로 약간 앞쪽에 창문을 그림
그럼..

이런 텍스쳐가 렌더링 되는데,
잘보면 창문쪽이 이상함
이렇게 depth가 제대로 계산되고 있지 않은 모습을 볼 수 있음
depth test는 기본적으로 텍스쳐의 alpha를 고려하지 않음
따라서 alpha로 인해 투명하게 적용되어야 하는 부분이 고려되지 않아
저렇게 창문이 서로 block이 된것처럼 렌더링 되는거임
그럼 이걸 어떻게 해결하나...?
먼저 순서가 중요함
정렬함이때 정렬이 중요함
카메라 위치에서부터 먼곳에 있는 오브젝트 -> 가까운곳에 있는 오브젝트 순서로 정렬이 되어야함
아이디어는 간단함
cpp의 map을 이용하는거임
map은 기본적으로 sorted map이라서, key값을 기준으로 오름차순 정렬이 되며 값이 추가됨
std::vector<glm::vec3> windows
{
glm::vec3(-1.5f, 0.0f, 0.52f),
glm::vec3( 1.5f, 0.0f, 1.51f),
glm::vec3( 0.0f, 0.0f, 1.7f),
glm::vec3(-0.3f, 0.0f, -1.3f),
glm::vec3 (0.5f, 0.0f, 0.4f)
};
std::map<float, glm::vec3> sorted;
for (unsigned int i = 0; i < windows.size(); i++)
{
float distance = glm::length(camera.Position - windows[i]);
sorted[distance] = windows[i];
}
먼저 windows위치변환을 위한 배열을 만들어주고
map을 이용해 오름차순으로 정렬해줌
문제가 있음
위에서 분명히 먼 거리에 있는 오브젝트부터 렌더링한다고 했는데?
지금 오름차순이면 가까운거리->먼거리 순서로 정렬되어 있자나?
그거 그냥 cpp의 rbegin, rend를 사용하면
역순으로 iteration가능해짐
for(std::map<float,glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
{
model = glm::mat4(1.0f);
model = glm::translate(model, it->second);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
그래서 이렇게 하면됨
그럼 대충 코드는
//...
int main()
{
//...
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// build and compile shaders
// -------------------------
Shader shader("VertexShaders/BlendShader.vsh", "FragmentShaders/BlendShader.fsh");
float grassVertices[] =
{
// positions // texture Coords (swapped y coordinates because texture is flipped upside down)
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 1.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
1.0f, -0.5f, 0.0f, 1.0f, 1.0f,
1.0f, 0.5f, 0.0f, 1.0f, 0.0f
};
// transparent VAO
unsigned int transparentVAO, transparentVBO;
glGenVertexArrays(1, &transparentVAO);
glGenBuffers(1, &transparentVBO);
glBindVertexArray(transparentVAO);
glBindBuffer(GL_ARRAY_BUFFER, transparentVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(grassVertices), grassVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0);
// load textures
unsigned int grassTex = loadTexture("D:/01_Develope/CPP/learn_opengl/learn_opengl/Resources/blend/grass.png");
unsigned int windowTex = loadTexture("D:/01_Develope/CPP/learn_opengl/learn_opengl/Resources/blend/blending_transparent_window.png");
std::vector<glm::vec3> vegetation
{
glm::vec3(-1.5f, 0.0f, -0.48f),
glm::vec3( 1.5f, 0.0f, 0.51f),
glm::vec3( 0.0f, 0.0f, 0.7f),
glm::vec3(-0.3f, 0.0f, -2.3f),
glm::vec3 (0.5f, 0.0f, -0.6f)
};
std::vector<glm::vec3> windows
{
glm::vec3(-1.5f, 0.0f, 0.52f),
glm::vec3( 1.5f, 0.0f, 1.51f),
glm::vec3( 0.0f, 0.0f, 1.7f),
glm::vec3(-0.3f, 0.0f, -1.3f),
glm::vec3 (0.5f, 0.0f, 0.4f)
};
shader.use();
shader.setInt("texture1", 0);
// render loop
while (!glfwWindowShouldClose(window))
{
//...
// draw objects
shader.use();
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 model = glm::mat4(1.0f);
shader.setMat4("projection", projection);
shader.setMat4("view", view);
// grassTex
glBindVertexArray(transparentVAO);
glBindTexture(GL_TEXTURE_2D, grassTex);
for (unsigned int i = 0; i < vegetation.size(); i++)
{
model = glm::mat4(1.0f);
model = glm::translate(model, vegetation[i]);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
//sort window Pos
std::map<float, glm::vec3> sorted;
for (unsigned int i = 0; i < windows.size(); i++)
{
float distance = glm::length2(camera.Position - windows[i]);
sorted[distance] = windows[i];
}
//windowTex
glBindVertexArray(transparentVAO);
glBindTexture(GL_TEXTURE_2D, windowTex);
for(std::map<float,glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
{
model = glm::mat4(1.0f);
model = glm::translate(model, it->second);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
//...
요로코롬 되고...

이렇게 잘 되어버림~~
order independent transparency라는 기법이 있음
지금은 정렬을 하고 있는데,
이게 계속 위치가 변경되는 오브젝트라면
map에 추가하는 연산으로 인해 코드가 길어지고 성능이 안좋아짐
그래서 사용되는게 order independent transparency임
순서에 구애받지 않는 투명성이라고 직역가능한데,
이건 나중에 리얼타임렌더링 공부할때 depth buffer를 더 자세하게 공부하면
그때 다루도록 하겠음!!