Shaping functions
쉐이더 로직은 특별합니다. 이는 자바스크립트나 다른 프로그래밍 언어에서 사용하는 것과는 다릅니다. 문법은 비슷하지만, 로직을 구현하는 방법은 다릅니다. 이는 일종의 블랙 박스와 같아서 데이터를 넣으면 프래그먼트 쉐이더에 대한 색상이나 버텍스 쉐이더에 대한 위치를 얻게 됩니다.
그런데 출력을 어떻게 제어할까요? 어떻게 원하는 모양으로 보이게 만들까요? 이때 shaping functions가 필요합니다.
이번 레슨에서는 프래그먼트 쉐이더에 중점을 둘 것이지만, 동일한 원리가 버텍스 쉐이더에도 적용됩니다.
연습 구역
shaping의 예술을 익히려면 연습과 실험이 필요합니다. 쉐이더가 작동하는 방식에 익숙해지는 데 시간이 걸리지만, 일단 익숙해지면 놀라운 효과를 만들어낼 수 있습니다.
여러분이 가장 성공하기 좋은 위치에 있도록 하기 위해, 실시간으로 쉐이더를 시각화할 수 있는 멋진 환경의 3D 아트 갤러리 장면을 준비했습니다.
창의력이 흐르는 걸 느끼셨나요? 모든 빈 액자들이 여러분의 걸작을 기다리고 있습니다!
사용된 3D 모델은 Maxim Mavrichev의 VR Gallery이며, Creative Commons Attribution 라이선스가 적용되었습니다.
갤러리 내부를 네비게이트하기 위해 1인칭 카메라인 <CameraControls />
를 사용하였으며, Squoosh를 사용하여 텍스처 크기를 줄였습니다.
SimpleShaderMaterial
갤러리의 모든 액자는 SimpleShaderMaterial
의 복사본입니다. 이는 여러분을 위해 내가 준비한 기본 사용자 정의 쉐이더로, 다음을 포함합니다:
uColor
: 색상uTime
: 애플리케이션 시작 이후 경과된 시간vUv
: 프래그먼트의 UV 좌표 (두 축에서 각각 0에서 1 사이)
이들은 <App.jsx />
에서 확장되어 장면에서 선언적으로 사용할 수 있습니다.
갤러리 내 위치에 따라 이름이 지정되어 있지만, 그것들을 사용하여 걸작을 만들고 나면 더 의미 있는 이름으로 자유롭게 변경하세요!
Functions
우리의 셰이더의 각 fragment에 대해, 같은 코드가 다른 입력값으로 실행될 것입니다.
선을 그리기 위해서는 if 문을 사용하여 픽셀이 선 안에 있는지 확인할 것입니다. 그러나 더 복잡한 형태를 만드는 것은 매우 어렵고 비효율적입니다.
대신, 우리는 함수를 사용하여 출력을 형성합니다. 수학의 전문가일 필요는 없으니 걱정하지 마세요. 사용할 수 있는 함수가 무엇인지, 그 함수가 무엇을 하는지 이해하기만 하면 됩니다.
함수를 일부 입력값을 받으면 어떤 출력을 주는 기계로 생각하세요. 예를 들어, 함수
f(x) = x * 2
는 숫자x
를 받아서x * 2
를 결과로 돌려줍니다.
다양한 함수의 효과를 시각화하기 위해, 우리는 Graphtoy를 사용할 것입니다. 이 도구는 함수를 입력하고 그 결과를 볼 수 있는 간단한 툴입니다. 우리가 셰이더에서 함수를 실험할 때 그 함수에 대한 이해를 검증하는 데 도움을 줍니다.
Graphtoy에서 f(x) = x * 2
함수를 시각화해봅시다:
셰이더를 실험할 때, Graphtoy는 곧 당신의 최고의 친구가 될 것입니다.
우리의 이용 가능한 다양한 함수를 실험해봅시다.
Step
step 함수는 간단한 함수로, 입력값이 임계값보다 작으면 0
을 반환하고, 입력값이 임계값보다 크면 1
을 반환합니다.
이 함수는 두 개의 매개변수를 받습니다:
edge
: 임계값x
: 입력값
앞 프레임 ArtFront02Material.jsx
fragment 셰이더에서 사용할 수 있습니다:
void main() { float pct = 1.0; pct = step(0.5, vUv.x); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
우리는 표현하려는 색상의 비율을 결정하기 위해 pct
변수를 선언합니다. 기본값으로 1.0
으로 설정하고, step
함수를 사용해서 vUv.x
가 0.5
보다 작으면 0.0
으로 설정합니다.
프레임의 왼쪽 절반은 검정색이고, 오른쪽 절반은 uColor
유니폼에 설정된 색상입니다.
의 수직축에 다른 임계값 적용해봅시다:
void main() { float pct = 1.0; pct = step(0.2, vUv.y); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
프레임의 하단 20%는 검정색이고, 나머지는 보라색으로 되어있습니다.
UV 좌표는 프레임의 왼쪽 하단 모서리에 원점이 있으므로,
[0, 0]
은 왼쪽 하단 모서리이고[1, 1]
은 오른쪽 상단 모서리입니다.
효과를 반전시키고 싶다면 step
함수의 매개변수를 단순히 교환하면 됩니다:
void main() { float pct = 1.0; pct = step(vUv.y, 0.2); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
이제 반대의 효과를 얻었습니다.
Mix
mix 함수는 두 값 사이의 선형 보간을 반환하는 간단한 함수입니다.
이 함수는 세 개의 매개변수를 받습니다:
x
: 첫 번째 값y
: 두 번째 값a
:x
와y
사이를 보간할 값
사용해봅시다:
void main() { float pct = 1.0; pct = mix(0.0, 1.0, vUv.x); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
검은색에서 보라색으로의 멋진 그라데이션을 볼 수 있습니다.
다른 많은 함수들처럼, 벡터 구성 요소와 같은 다른 데이터 유형에서도 사용할 수 있습니다. 세로축에 흰색에서 보라색으로의 그라데이션을 생성해봅시다:
void main() { vec3 whiteColor = vec3(1.0); vec3 finalColor = mix(whiteColor, uColor, vUv.y); gl_FragColor = vec4(finalColor, 1.0); }
흰색에서 보라색으로의 멋진 그라데이션을 볼 수 있습니다.
mix
함수를 처음 호출하여 pct
값을 얻은 후, 이 값을 사용하여 whiteColor
와 uColor
사이를 보간해보겠습니다:
void main() { vec3 whiteColor = vec3(1.0); float pct = mix(0.0, 0.3, vUv.y); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
보라색이 아주 연하며, pct
의 최대 값이 0.3
입니다.
mix 함수를 사용하여 mix
함수와 작동 방식을 실험해보세요.
mix
함수를 사용한 3가지 다른 보간은 완전히 다른 결과를 줍니다.
Smoothstep
smoothstep 함수는 두 값 사이를 부드럽게 보간하는 간단한 함수입니다.
이것은 세 가지 매개변수를 받습니다:
edge0
: 하한edge1
: 상한x
:edge0
와edge1
사이를 보간할 값
세 가지 다른 결과를 제공합니다:
x
가edge0
보다 작을 때는0.0
x
가edge1
보다 클 때는1.0
x
가edge0
와edge1
사이에 있을 때는0.0
과1.0
사이의 부드러운 보간
이것을 사용하여 pct
값을 변경해 봅시다:
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
이제 전환은 0.4
와 0.6
사이에서만 이루어집니다. 그 아래는 모두 흰색이고, 그 위는 모두 보라색입니다.
Min & Max
min
과 max
는 두 입력값 간의 최소값 또는 최대값을 반환하는 간단한 함수입니다. 이 함수들은 JavaScript의 Math.min
및 Math.max
함수와 정확히 동일한 방식으로 작동합니다.
우리의 pct
값을 세밀히 조정하기 위해 이 함수들을 사용해 보겠습니다. 먼저 pct
값이 0.4
보다 낮아지는 일이 없도록 설정합시다 (완전히 하얗게 되는 것을 방지하기 위해):
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); pct = max(pct, 0.4); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
그리고 0.6
을 넘지 않도록 설정합니다 (완전히 보라색이 되는 것을 방지하기 위해):
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); pct = max(pct, 0.4); pct = min(pct, 0.6); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
색상이 희미해졌고, 전환이 매우 부드럽습니다.
이제 Graphtoy에서 시각화해 봅시다:
max(x, 0.4)
의 표현
min(x, 0.6)
의 표현
그리고 이 둘을 결합하면:
우리의 값들이 결코 0.4
아래로 내려가지 않으며 0.6
을 넘지 않는 걸 볼 수 있습니다.
우리의
min
및max
함수 결합은 clamp 함수로 대체될 수 있습니다. 이는min(max(x, min), max)
의 축약형입니다.
연산 및 패턴
다양한 유용한 함수를 알아보기 전에, 연산을 사용하여 패턴을 만드는 방법을 살펴보겠습니다.
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.