
Three.js를 써봤습니다.

Three.js의 Fragment Shader로 이런 것을 할 수 있다?
https://zzz664.github.io/text-hover/
위 링크로 접속 시 예제 확인이 가능합니다.
Fragment Shader는 화면의 픽셀을 조작하는 프로그램입니다.
예를 들면 픽셀의 밝기, 투명도, 색상을 조작하는 것이죠.
텍스쳐 맵핑 시 텍스쳐가 맵핑 될 좌표도 정할 수 있습니다.
위 예제는 텍스쳐 좌표와 마우스 좌표와 방향으로 왜곡효과를 준 것 입니다.
Fragment Shader 전문
const distortionFragment = ` varying vec2 vUv; uniform sampler2D uTexture; uniform vec2 uMouse; uniform vec2 uPrevMouse; void main() { vec2 gridUv = floor(vUv * vec2(40.0, 40.0)) / vec2(40.0, 40.0); vec2 centerOfPixel = gridUv + vec2(1.0/80.0, 1.0/80.0); vec2 mouseDirection = uMouse - uPrevMouse; vec2 pixelToMouseDirection = centerOfPixel - uMouse; float pixelDistanceToMouse = length(pixelToMouseDirection); float strength = smoothstep(0.1, 0.0, pixelDistanceToMouse); vec2 uvOffset = strength * -mouseDirection * 0.3; vec2 uv = vUv - uvOffset; gl_FragColor = texture2D(uTexture, uv); } `;
vUv: 텍스쳐 좌표(0~1사이의 실수 값을 가짐)를 나타내는 2차원 벡터 변수 (vertexShader에서 전달받는다)
uTexture: 여기서는 2D 평면에 대응되는 2D 이미지를 메모리에서 읽어와 색상을 결정하기 위한 샘플러 변수
uMouse: 마우스 좌표를 나타내는 2차원 벡터 변수
uPrevMouse: 마우스의 이전 좌표를 나타내는 2차원 벡터 변수
gridUv: 0~1사이 실수 값을 40배 확대한 후 소수점 자리를 모두 버린 후 다시 0~1사이 실수 값으로 변환하여 화면을 40개의 격자로 나눔
centerOfPixel: 블록을 40개로 나누었으므로 블록 하나 당 크기는 1/40.0이다. 여기에 중심을 의미하므로 2로 나누어주면 1/80.0이라는 값이 나오게 됨. 블록의 정중앙 좌표를 나타내는 2차원 벡터 변수
mouseDirection: 마우스가 움직인 방향을 나타내는 2차원 벡터 변수. 현재좌표 - 이전좌표를 통해 구한다.
pixelToMouseDirection: 블록의 중앙에서 마우스가 움직인 방향을 나타내는 2차원 벡터 변수. 중앙좌표 - 현재마우스좌표를 통해 구한다.
pixelDistanceToMouse: pixelToMouseDirection 방향 벡터의 크기를 구해 마우스가 어느정도 거리를 움직였는지 저장하는 float변수
strength: smoothstep함수는 [0.1, 0.0] 범위에 pixelDistanceToMouse값이 포함되면 sigmoid(S자 모양)형태로 보간하여 0~1사이 값을 반환하는 함수다. 여기서 입력값이 pixelDistanceToMouse이므로 마우스와 가까우면 strength의 값은 1에 가깝고 멀면 0에 가깝다.
uvOffset: strength로 텍스쳐 좌표의 시작점을 비트는 강도를 조절하고 마우스가 움직인 반대 방향으로 30%만큼 시작위치를 옮긴 좌표를 계산함
uv: 실제 텍스쳐가 입혀질 좌표로 vertexShader에서 계산된 vUv좌표에 위에서 계산한 uvOffset으로 왜곡효과를 준다. 여기서 -를 해주었는데 uvOffset이 마우스 반대방향으로 계산됐기 때문에 최종적으로 마우스 방향으로 왜곡이 진행된다. +로 바꾸면 마우스 반대방향으로 왜곡이 진행된다.
gl_FragColor: 최종적인 픽셀의 색상값. uTexture의 2D이미지 색상을 uv좌표에 매핑하여 최종적인 픽셀의 색상을 결정한다.
설명이 복잡한데 간단히 요약하면 화면을 40x40 격자로 분할하여 마우스가 움직이는 방향으로 격자 셀들을 조작하는 프로그램이다. 마우스와 가까운 블록은 많이 움직이고, 마우스와 먼 블록은 적게 움직인다.
requestAnimationFrame함수를 이용하여 계속 업데이트 되는 마우스 좌표를 shader에 전달하고 렌더링을 진행했다.
마우스 좌표는 마우스에 eventListener를 추가하여 핸들러를 통해 구하고 마우스 좌표를 업데이트 했다. enter, leave, move 3개의 이벤트 핸들러를 작성했다.
이 예제에서는 text를 canvas에 렌더링하여 텍스쳐를 만드는데, 이 부분 대신에 다른 이미지를 넣으면 해당 이미지에 이 효과를 사용할 수 있다.
자세한 코드는 아래 주소에 올라가 있다.
https://github.com/zzz664/zzz664.github.io/tree/main/text-hover
나중에 프로젝트 진행 시 히어로 이미지같은 부분에 해당 기능을 최적화해서 넣는다면 색다른 경험이 될 것 같다.

댓글
댓글을 작성하려면 이 필요합니다.