셰이더로 하프톤(Halftone) 만들어보기

김병찬·2021년 4월 30일
15
post-thumbnail

GLSL을 통해 Halftone 효과를 구현한 이미지 입니다.


개요

위 이미지에 보이는 하프톤 효과를 셰이더를 통해 구현해봅시다.
기본적으로 threejs를 사용합니다.

이번에 배울 내용은

  • 셰이더의 전반적인 이해
  • fract, floor 함수에 대해서

1. Setup

https://github.com/deeean/threejs-playground

해당 레포를 클론 하고

yarn
yarn dev

위 명령어를 입력하여 개발서버를 띄우고 접속합니다.

이런 화면이 나오면 성공입니다.


2. Mosaic

이제 /src/entities/Plane/Plane.frag 파일로 들어가서

varying vec2 vUv;

uniform float time;
uniform sampler2D channel0;

void main() {
  vec2 st = vUv;
  float pixels = 20.0;
  gl_FragColor = texture2D(channel0, floor(st * pixels) / pixels);
}

위와 같이 입력해 줍니다.

과일 사진이 이렇게 모자이크가 들어간 상태로 보입니다.

왜 이렇게 그려지는지 생각해봅시다.

floor(st * pixels) / pixels 이 부분을 설명하겠습니다.

pixels는 일단 10이라고 가정합니다.

st라는 vec2변수는 x, y가 0 ~ 1 소수점으로 된 좌표값입니다.

st * 10 을 한다고 생각해보면

0 ~ 10 까지 소수점을 지나서 도달하게됩니다.

floor 내림 하면 0, 1, 2, 3 ... 10 이렇게 소수점이 사라지고

다시 st / 10.0 을 하면 0, 0.1, 0.2, 0.3 ... 1.0 이런식으로 텍스쳐를 그리기때문에

모자이크가 된것입니다.


3. Circle

모자이크된 색상은 다른 변수에 저장해두고

이제 하프톤을 만들기위해 원을 하나 그려봅시다.

varying vec2 vUv;

uniform float time;
uniform sampler2D channel0;

void main() {
  vec2 st = vUv;
  float pixels = 20.0;
  vec4 mosaicCol = texture2D(channel0, floor(st * pixels) / pixels);

  float dist = distance(st, vec2(0.5));
  dist = step(dist, 0.5);
  gl_FragColor = vec4(vec3(1.0), dist);
}

이전 글과 같은 방법으로 원을 그렸습니다.

이제 모자이크 픽셀수만큼 원을 반복해봅시다.

varying vec2 vUv;

uniform float time;
uniform sampler2D channel0;

void main() {
  vec2 st = vUv;
  float pixels = 20.0;
  vec4 mosaicCol = texture2D(channel0, floor(st * pixels) / pixels);

  float dist = distance(fract(st * pixels), vec2(0.5));
  dist = step(dist, 0.5);
  gl_FragColor = vec4(vec3(1.0), dist);
}

이렇게 입력해줍니다.

원이 20 x 20 배열로 그려졌습니다.

왜 원이 여러 개가 그려졌는지 생각해 봅시다.

fract라는 함수는 소수점만 취하는 함수인데

ex) 10.2 -> 0.2 이런식으로 작동합니다.

위에서 st라는 vec2변수는 x, y가 0 ~ 1 소수점으로 된 좌표값이라고 했습니다.

이를 pixels만큼 곱했습니다.

그러면 0 ~ 20까지 소수점을 포함해서 값이 증가하고

fract를 통해 소수점만 취했습니다.

0 ~ 1, 0 ~ 1, 0 ~ 1 ... 이 20번 반복되기때문에 원이 여러 개가 그려지는 것입니다.

4. Multiply

이제 아까 만들어둔 모자이크를 곱해줍시다.

varying vec2 vUv;

uniform float time;
uniform sampler2D channel0;

void main() {
  vec2 st = vUv;
  float pixels = 20.0;
  vec4 mosaicCol = texture2D(channel0, floor(st * pixels) / pixels);

  float dist = distance(fract(st * pixels), vec2(0.5));
  dist = step(dist, 0.5);
  gl_FragColor = vec4(vec3(1.0), dist) * mosaicCol;
}

이렇게 하프톤 효과를 아주 쉽게 만들수있습니다.

위에 pixels 라는 변수의 값을 100으로 변경하면

간단하게 원의 개수를 늘릴 수 있습니다.

여기까지 하프톤 효과를 만들어보았습니다

셰이더는 색상들을 겹치고 빼서 원하는 결과를 만들어낸다고 생각하면 쉽고 재미있습니다.


현재 WE-AR에서 채용을 진행하고있습니다.

아래 링크를 통해 많은 지원 부탁드립니다.

웹사이트, 채용공고

profile
👀 시각적인 요소를 중요하게 생각합니다.

1개의 댓글

comment-user-thumbnail
2021년 7월 25일

포스팅들 너무 재밌게 보고 있습니다! 아직은 초보 개발자이지만 조만간 이런 멋진 것들을 구현해 낼 수 있겠죠?! 다음 재미나고 멋진 포스팅도 기대하겠습니다! 존버!

답글 달기