glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
블랜딩 수식
glBlendFunc
으로 F
값을 설정할 수 있음glBlendEquation
으로 가운데 연산자 설정 가능glBlendFunc
으로 설정예시
glBlendFunc
에서 사용 가능한 인자
- GL_ZERO
, GL_ONE
- GL_SRC_COLOR
, GL_SRC_ALPHA
- GL_ONE_MINUS_SRC_COLOR
, GL_ONE_MINUS_SRC_ALPHA
- GL_DST_COLOR
, GL_DST_ALPHA
- GL_ONE_MINUS_DST_COLOR
, GL_ONE_MINUS_DST_ALPHA
- GL_CONSTANT_COLOR
, GL_CONSTANT_ALPHA
- GL_ONE_MINUS_CONSTANT_COLOR
, GL_ONE_MINUS_CONSTANT_ALPHA
glBlendFuncSeparate
함수를 이용하여 color / alpha 별로 별도의 수식 적용 가능
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
glBlendEquation
에서 사용 가능한 인자GL_FUNC_ADD
: src + dst
GL_FUNC_SUBTRACT
: src - dst
GL_FUNC_REVERSE_SUBTRACT
: dst - src
GL_MIN
: min(src, dst)
GL_MAX
: max(src, dst)
shader/texture.fs
수정#version 330 core
in vec4 vertexColor;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D tex;
void main() {
fragColor = texture(tex, texCoord);
}
Context
에 m_textureProgram
멤버 추가 bool Init();
ProgramUPtr m_program;
ProgramUPtr m_simpleProgram;
ProgramUPtr m_textureProgram;
Context::Init()
에서 m_textureProgram
초기화 m_textureProgram = Program::Create("./shader/texture.vs", "./shader/texture.fs");
if (!m_textureProgram)
return false;
Mesh::CreatePlane()
함수 추가CLASS_PTR(Mesh);
class Mesh {
public:
static MeshUPtr Create(
const std::vector<Vertex>& vertices,
const std::vector<uint32_t>& indices,
uint32_t primitiveType);
static MeshUPtr CreateBox();
static MeshUPtr CreatePlane();
Mesh::CreatePlane()
함수 구현MeshUPtr Mesh::CreatePlane() {
std::vector<Vertex> vertices = {
Vertex { glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec2(0.0f, 0.0f) },
Vertex { glm::vec3( 0.5f, -0.5f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec2(1.0f, 0.0f) },
Vertex { glm::vec3( 0.5f, 0.5f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec2(1.0f, 1.0f) },
Vertex { glm::vec3(-0.5f, 0.5f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec2(0.0f, 1.0f) },
};
std::vector<uint32_t> indices = {
0, 1, 2, 2, 3, 0,
};
return Create(vertices, indices, GL_TRIANGLES);
}
CreatePlane()
과 m_textureProgram
, texture.fs
를 사용
Context
에 m_plane
멤버 및 m_windowTexture
추가
MeshUPtr m_box;
MeshUPtr m_plane;
MaterialPtr m_planeMaterial;
MaterialPtr m_box1Material;
MaterialPtr m_box2Material;
TexturePtr m_windowTexture;
m_windowTexture
는 굳이Material
일 필요가 없음, 단일 텍스처만사용하면 된다.
Context::Init()
에서 m_plane
, m_windowTexture
초기화m_plane = Mesh::CreatePlane();
m_windowTexture = Texture::CreateFromImage(
Image::Load("./image/blending_transparent_window.png").get());
Context::Render()
에서 m_plane
, m_windowTexture
, m_textureProgram
으로 드로잉 glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_textureProgram->Use();
m_windowTexture->Bind();
m_textureProgram->SetUniform("tex", 0);
modelTransform =
glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.5f, 4.0f));
transform = projection * view * modelTransform;
m_textureProgram->SetUniform("transform", transform);
m_plane->Draw(m_textureProgram.get());
상세 설명:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_SRC_ALPHA
= 알파 값 곱하기GL_ONE_MINUS_SRC_ALPHA
= 1-소스 컬러의 알파값를 곱한다.m_textureProgram->Use();
m_windowTexture->Bind();
m_textureProgram->SetUniform("tex", 0);
modelTransform =
glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.5f, 4.0f));
transform = projection * view * modelTransform;
m_textureProgram->SetUniform("transform", transform);
m_plane->Draw(m_textureProgram.get());
modelTransform =
glm::translate(glm::mat4(1.0f), glm::vec3(0.2f, 0.5f, 5.0f));
transform = projection * view * modelTransform;
m_textureProgram->SetUniform("transform", transform);
m_plane->Draw(m_textureProgram.get());
modelTransform =
glm::translate(glm::mat4(1.0f), glm::vec3(0.4f, 0.5f, 6.0f));
transform = projection * view * modelTransform;
m_textureProgram->SetUniform("transform", transform);
m_plane->Draw(m_textureProgram.get());
빌드 및 결과
- 정면에서 보면 정확한 결과물
- 뒤에서 보면 잘못된 결과 발생
잘못된 결과가 발생하는 원인
- 카메라 앞의 유리창을 먼저 그리는 경우
- 카메라와 가까운 유리창이 depth buffer 값을 갱신
- 뒤의 유리창은 depth test를 통과하지 못하고 그려지지 않음
투명한 부분을 그리는 문제 (창틀 구석)
fragment discard
- fragment shader에서 discard를 호출하면 해당 픽셀을 그리지 않을 수 있음
- 해당 픽셀을 그리지 않으므로 해당 픽셀의 depth test도 하지 않게 된다.
shader/texture.fs
를 다음과 같이 수정
#version 330 core
in vec4 vertexColor;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D tex;
void main() {
vec4 pixel = texture(tex, texCoord);
if (pixel.a < 0.01)
discard;
fragColor = pixel;
}
카메라와 가까운 부분을 먼저 그려 뒤의 블랜딩 plane이 안보이는 경우 (반투명한 유리)
오브젝트를 그릴때 보이는 부분만 그리자! 안보이는 부분은 뭐하러 그리냐
glEnable(GL_CULL_FACE); // face culling 활성화
glDisable(GL_CULL_FACE); // face culling 비활성화
glFrontFace(GL_CCW); // CCW 방향의 면을 앞면으로 설정
glCullFace(GL_BACK); // 뒷면을 그리지 않기
glCullFace(GL_FRONT); // 앞면을 그리지 않기
glDisable(GL_CULL_FACE)
glFrontFace(GL_CCW)
glCullFace(GL_BACK)
OpenGL course 10-02: 스텐실, 블랜딩, 컬링
https://heinleinsgame.tistory.com/26