νμ μ μΈ WebGL λ©μ μ °μ΄λ νμ΄νλΌμΈμ μ΄ν΄λ³΄μΈμ. νμ€ν¬ μ¦νμ΄ μ΄λ»κ² λκ·λͺ¨ μ€μκ° μ§μ€λ©νΈλ¦¬ μμ±κ³Ό μ°¨μΈλ μΉ κ·Έλν½μ μν κ³ κΈ μ»¬λ§μ κ°λ₯νκ² νλμ§ μμ보μΈμ.
μ§μ€λ©νΈλ¦¬μ ν΄λ°©: WebGLμ λ©μ μ °μ΄λ νμ€ν¬ μ¦ν νμ΄νλΌμΈ μ¬μΈ΅ λΆμ
μΉμ λ μ΄μ μ μ μΈ 2μ°¨μ λ§€μ²΄κ° μλλλ€. μ¨ λ§νλ μ ν 컨νΌκ·λ μ΄ν°μ κ±΄μΆ μκ°νλΆν° 볡μ‘ν λ°μ΄ν° λͺ¨λΈκ³Ό 본격μ μΈ κ²μμ μ΄λ₯΄κΈ°κΉμ§, νλΆνκ³ λͺ°μ κ° μλ 3D κ²½νμ μν νκΈ°μ°¬ νλ«νΌμΌλ‘ μ§ννμ΅λλ€. κ·Έλ¬λ μ΄λ¬ν μ§νλ κ·Έλν½ μ²λ¦¬ μ₯μΉ(GPU)μ μ λ‘ μλ λΆλ΄μ μ€λλ€. μλ λμ νμ€ μ€μκ° κ·Έλν½ νμ΄νλΌμΈμ κ°λ ₯νμ§λ§, κ·Έ νκ³λ₯Ό λλ¬λ΄λ©° νλ μ ν리μΌμ΄μ μ΄ μꡬνλ κΈ°ννμ 볡μ‘μ±μ λν λ³λͺ© νμμ μΌμΌν€λ κ²½μ°κ° λ§μμ΅λλ€.
μ΄μ WEBGL_mesh_shader νμ₯μ ν΅ν΄ μΉμμ μ κ·Όν μ μλ ν¨λ¬λ€μ μ ν κΈ°λ₯μΈ λ©μ μ
°μ΄λ νμ΄νλΌμΈμ΄ λ±μ₯νμ΅λλ€. μ΄ μλ‘μ΄ λͺ¨λΈμ GPUμμ μ§μ€λ©νΈλ¦¬λ₯Ό μκ°νκ³ μ²λ¦¬νλ λ°©μμ κ·Όλ³Έμ μΌλ‘ λ°κΏλλ€. κ·Έ μ€μ¬μλ νμ€ν¬ μ¦ν(Task Amplification)μ΄λΌλ κ°λ ₯ν κ°λ
μ΄ μμ΅λλ€. μ΄κ²μ λ¨μν μ μ§μ μΈ μ
λ°μ΄νΈκ° μλλλ€. μ€μΌμ€λ§ λ° μ§μ€λ©νΈλ¦¬ μμ± λ‘μ§μ CPUμμ GPUμ κ³ λλ‘ λ³λ ¬μ μΈ μν€ν
μ²λ‘ μ§μ μ΄λμμΌ, μ΄μ μλ μΉ λΈλΌμ°μ μμ λΉμ€μ©μ μ΄κ±°λ λΆκ°λ₯νλ κ°λ₯μ±μ μ΄μ΄μ£Όλ νλͺ
μ μΈ λμ½μ
λλ€.
μ΄ μ’ ν© κ°μ΄λλ λ©μ μ °μ΄λ μ§μ€λ©νΈλ¦¬ νμ΄νλΌμΈμ μ¬μΈ΅μ μΌλ‘ νꡬν©λλ€. μ°λ¦¬λ κ·Έ μν€ν μ²λ₯Ό μ΄ν΄λ³΄κ³ , νμ€ν¬ μ °μ΄λμ λ©μ μ °μ΄λμ λͺ νν μν μ μ΄ν΄νλ©°, νμ€ν¬ μ¦νμ νμ©νμ¬ μ°¨μΈλ μκ°μ μΌλ‘ λλκ³ μ±λ₯μ΄ λ°μ΄λ μΉ μ ν리μΌμ΄μ μ ꡬμΆνλ λ°©λ²μ μμλ³Ό κ²μ λλ€.
κ³Όκ±°λ‘μ νκ·: μ ν΅μ μΈ μ§μ€λ©νΈλ¦¬ νμ΄νλΌμΈμ νκ³
λ©μ μ °μ΄λμ νμ μ μ§μ μΌλ‘ μ΄ν΄νλ €λ©΄, κ·Έκ²μ΄ λ체νλ νμ΄νλΌμΈμ λ¨Όμ μ΄ν΄ν΄μΌ ν©λλ€. μμ λ λμ μ€μκ° κ·Έλν½μ λΉκ΅μ κ³ μ λ κΈ°λ₯μ νμ΄νλΌμΈμ μν΄ μ§λ°°λμμ΅λλ€:
- μ μ μ °μ΄λ(Vertex Shader): κ°λ³ μ μ μ μ²λ¦¬νμ¬ νλ©΄ 곡κ°μΌλ‘ λ³νν©λλ€.
- (μ ν μ¬ν) ν μ λ μ΄μ μ °μ΄λ(Tessellation Shaders): μ§μ€λ©νΈλ¦¬ ν¨μΉλ₯Ό μΈλΆννμ¬ λ λ―ΈμΈν λν μΌμ λ§λλλ€.
- (μ ν μ¬ν) μ§μ€λ©νΈλ¦¬ μ °μ΄λ(Geometry Shader): ν리미ν°λΈ(μ , μ , μΌκ°ν)λ₯Ό μ€μκ°μΌλ‘ μμ±νκ±°λ νκ΄΄ν μ μμ΅λλ€.
- λμ€ν°λΌμ΄μ (Rasterizer): ν리미ν°λΈλ₯Ό ν½μ λ‘ λ³νν©λλ€.
- νλκ·Έλ¨ΌνΈ μ °μ΄λ(Fragment Shader): κ° ν½μ μ μ΅μ’ μμμ κ³μ°ν©λλ€.
μ΄ λͺ¨λΈμ μ°λ¦¬μκ² λ§μ λμμ μ£Όμμ§λ§, νΉν μ₯λ©΄μ΄ λ³΅μ‘ν΄μ§μ λ°λΌ λ΄μ¬λ νκ³λ₯Ό κ°μ§κ³ μμ΅λλ€:
- CPUμ μ’ μλ λλ‘μ° μ½(Draw Calls): CPUλ μ νν 무μμ κ·Έλ €μΌ νλμ§ νμ νλ μμ²λ μμ μ λ΄λΉν©λλ€. μ¬κΈ°μλ μ λ체 컬λ§(μΉ΄λ©λΌ μμΌ λ°μ κ°μ²΄ μ κ±°), νμ 컬λ§(λ€λ₯Έ κ°μ²΄μ κ°λ €μ§ κ°μ²΄ μ κ±°), κ·Έλ¦¬κ³ μΈλΆ μμ€(LOD) μμ€ν κ΄λ¦¬κ° ν¬ν¨λ©λλ€. μλ°±λ§ κ°μ κ°μ²΄κ° μλ μ₯λ©΄μ κ²½μ°, μ΄λ‘ μΈν΄ CPUκ° μ£Όλ λ³λͺ© νμμ΄ λμ΄ κ΅Άμ£Όλ¦° GPUμ λ°μ΄ν°λ₯Ό μΆ©λΆν 빨리 곡κΈνμ§ λͺ»ν μ μμ΅λλ€.
- κ²½μ§λ μ λ ₯ ꡬ쑰: νμ΄νλΌμΈμ κ²½μ§λ μ λ ₯-μ²λ¦¬ λͺ¨λΈμ κΈ°λ°μΌλ‘ ꡬμΆλμμ΅λλ€. μ λ ₯ μ΄μ λΈλ¬λ μ μ μ νλμ© κ³΅κΈνκ³ , μ °μ΄λλ λΉκ΅μ μ νλ λ°©μμΌλ‘ μ΄λ₯Ό μ²λ¦¬ν©λλ€. μ΄λ μΌκ΄μ± μκ³ λ³λ ¬μ μΈ λ°μ΄ν° μ²λ¦¬μ λ°μ΄λ νλ GPU μν€ν μ²μ μ΄μμ μ΄μ§ μμ΅λλ€.
- λΉν¨μ¨μ μΈ μ¦ν: μ§μ€λ©νΈλ¦¬ μ °μ΄λκ° μ§μ€λ©νΈλ¦¬ μ¦ν(μ λ ₯ ν리미ν°λΈμμ μ μΌκ°ν μμ±)μ νμ©νμ§λ§, μ λͺ λμ μ λλ‘ λΉν¨μ¨μ μ΄μμ΅λλ€. κ·Έ μΆλ ₯ λμμ νλμ¨μ΄μ μμΈ‘ λΆκ°λ₯ν κ²½μ°κ° λ§μ, λ§μ λκ·λͺ¨ μ ν리μΌμ΄μ μμ μ¬μ©μ κΊΌλ¦¬κ² λ§λλ μ±λ₯ λ¬Έμ λ₯Ό μΌκΈ°νμ΅λλ€.
- λλΉλλ μμ : μ ν΅μ μΈ νμ΄νλΌμΈμμλ λ λλ§ν μΌκ°νμ 보λ΄λ©΄, κ·Έ μΌκ°νμ΄ κΆκ·Ήμ μΌλ‘ 컬λ§λκ±°λ λ·λ©΄μ ν₯ν ν½μ λκ»μ μ‘°κ°μΌμ§λΌλ μ μ μ °μ΄λκ° μΈ λ² μ€νλ©λλ€. μ΅μ’ μ΄λ―Έμ§μ μλ¬΄λ° κΈ°μ¬λ νμ§ μλ μ§μ€λ©νΈλ¦¬μ λ§μ μ²λ¦¬ λ₯λ ₯μ΄ μλͺ¨λ©λλ€.
ν¨λ¬λ€μμ μ ν: λ©μ μ °μ΄λ νμ΄νλΌμΈ μκ°
λ©μ μ °μ΄λ νμ΄νλΌμΈμ μ μ , ν μ λ μ΄μ , μ§μ€λ©νΈλ¦¬ μ °μ΄λ λ¨κ³λ₯Ό μλ‘κ³ λ μ μ°ν 2λ¨κ³ λͺ¨λΈλ‘ λ체ν©λλ€:
- νμ€ν¬ μ °μ΄λ(Task Shader) (μ ν μ¬ν): μΌλ§λ λ§μ μμ μ΄ νμνμ§λ₯Ό κ²°μ νλ κ³ μμ€ μ μ΄ λ¨κ³μ λλ€. μ¦ν μ °μ΄λ(Amplification Shader)λΌκ³ λ μλ €μ Έ μμ΅λλ€.
- λ©μ μ °μ΄λ(Mesh Shader): λ°μ΄ν° λ°°μΉλ₯Ό μ²λ¦¬νμ¬ "λ©μλ¦Ώ(meshlets)"μ΄λΌλ μκ³ λ 립μ μΈ μ§μ€λ©νΈλ¦¬ ν¨ν·μ μμ±νλ μ£Όλ ₯ λ¨κ³μ λλ€.
μ΄ μλ‘μ΄ μ κ·Ό λ°©μμ λ λλ§ μ² νμ κ·Όλ³Έμ μΌλ‘ λ°κΏλλ€. CPUκ° λͺ¨λ κ°μ²΄μ λν λͺ¨λ λ¨μΌ λλ‘μ° μ½μ λ―ΈμΈ κ΄λ¦¬νλ λμ , μ΄μ λ³Έμ§μ μΌλ‘ GPUμ "μ¬κΈ° 볡μ‘ν μ₯λ©΄μ λν κ³ μμ€ μ€λͺ μ΄ μμΌλ, μΈλΆ μ¬νμ λ€κ° μμμ μ²λ¦¬ν΄λΌ"λΌκ³ λ§νλ κ°λ ₯ν λ¨μΌ λλ‘μ° λͺ λ Ήμ λ΄λ¦΄ μ μμ΅λλ€.
κ·Έλ¬λ©΄ GPUλ νμ€ν¬ λ° λ©μ μ °μ΄λλ₯Ό μ¬μ©νμ¬ μ»¬λ§, LOD μ ν, μ μ°¨μ μμ±μ κ³ λλ‘ λ³λ ¬μ μΈ λ°©μμΌλ‘ μννμ¬ μ€μ λ‘ λ³΄μ΄λ μ§μ€λ©νΈλ¦¬λ₯Ό μμ±νλ λ° νμν μμ λ§ μμν©λλ€. μ΄κ²μ΄ GPU μ£Όλ λ λλ§ νμ΄νλΌμΈμ λ³Έμ§μ΄λ©°, μ±λ₯κ³Ό νμ₯μ± λ©΄μμ κ²μ 체μΈμ μ λλ€.
μ§νμ: νμ€ν¬(μ¦ν) μ °μ΄λ μ΄ν΄νκΈ°
νμ€ν¬ μ °μ΄λλ μλ‘μ΄ νμ΄νλΌμΈμ λλμ΄λ©° κ·Έ λλΌμ΄ νμ ν΅μ¬μ λλ€. μ νμ μΈ λ¨κ³μ΄μ§λ§, "μ¦ν"μ΄ μΌμ΄λλ κ³³μ λλ€. μ£Όμ μν μ μ μ μ΄λ μΌκ°νμ μμ±νλ κ²μ΄ μλλΌ, μμ λμ€ν¨μ² μν μ νλ κ²μ λλ€.
νμ€ν¬ μ °μ΄λλ 무μμΈκ°?
νμ€ν¬ μ °μ΄λλ₯Ό κ±°λν κ±΄μ€ νλ‘μ νΈμ νλ‘μ νΈ κ΄λ¦¬μλΌκ³ μκ°ν΄λ³΄μΈμ. CPUλ κ΄λ¦¬μμκ² "λμ ꡬμ 건μ€"κ³Ό κ°μ κ³ μμ€ λͺ©νλ₯Ό μ€λλ€. νλ‘μ νΈ κ΄λ¦¬μ(νμ€ν¬ μ °μ΄λ)λ μ§μ λ²½λμ μμ§ μμ΅λλ€. λμ , μ 체 μμ μ νκ°νκ³ , μ²μ¬μ§μ νμΈνλ©°, μ΄λ€ 건μ€ν(λ©μ μ °μ΄λ μμ κ·Έλ£Ή)μ΄ μΌλ§λ νμνμ§ κ²°μ ν©λλ€. νΉμ κ±΄λ¬Όμ΄ νμ μλ€κ³ κ²°μ (컬λ§)νκ±°λ νΉμ μ§μμλ 10κ° νμ΄ νμνκ³ λ€λ₯Έ μ§μμλ 2κ° νλ§ νμνλ€κ³ κ²°μ ν μ μμ΅λλ€.
κΈ°μ μ μΈ μ©μ΄λ‘, νμ€ν¬ μ °μ΄λλ μ»΄ν¨νΈμ μ μ¬ν μμ κ·Έλ£ΉμΌλ‘ μ€νλ©λλ€. λ©λͺ¨λ¦¬μ μ κ·Όνκ³ , 볡μ‘ν κ³μ°μ μννλ©°, κ°μ₯ μ€μνκ²λ μΌλ§λ λ§μ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμν μ§ κ²°μ ν μ μμ΅λλ€. μ΄ κ²°μ μ΄ κ·Έ νμ ν΅μ¬μ λλ€.
μ¦νμ ν
"μ¦ν"μ΄λΌλ μ©μ΄λ νμ€ν¬ μ °μ΄λκ° μμ μ λ¨μΌ μμ κ·Έλ£Ήμ κ°μ§κ³ 0, 1 λλ λ€μμ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμν μ μλ λ₯λ ₯μμ λΉλ‘―λ©λλ€. μ΄ λ₯λ ₯μ νμ μ μ λλ€:
- 0κ° μ€ν(Launch Zero): νμ€ν¬ μ °μ΄λκ° κ°μ²΄λ μ₯λ©΄μ μΌλΆκ° 보μ΄μ§ μλλ€κ³ νλ¨νλ©΄(μ: μΉ΄λ©λΌ μ λ체 μΈλΆ), λ¨μν 0κ°μ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμνλλ‘ μ νν μ μμ΅λλ€. ν΄λΉ κ°μ²΄μ κ΄λ ¨λ λͺ¨λ μ μ¬μ μμ μ λ μ΄μ μ²λ¦¬λμ§ μκ³ μ¬λΌμ§λλ€. μ΄κ²μ μ μ μΌλ‘ GPUμμ μνλλ λ§€μ° ν¨μ¨μ μΈ μ»¬λ§μ λλ€.
- 1κ° μ€ν(Launch One): μ΄κ²μ μ§μ μ μΈ ν΅κ³Όμ λλ€. νμ€ν¬ μ °μ΄λ μμ κ·Έλ£Ήμ νλμ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ΄ νμνλ€κ³ κ²°μ ν©λλ€.
- λ€μ μ€ν(Launch Many): μ΄κ²μ΄ μ μ°¨μ μμ±μμ λ§λ²μ΄ μΌμ΄λλ λΆλΆμ λλ€. λ¨μΌ νμ€ν¬ μ °μ΄λ μμ κ·Έλ£Ήμ μΌλΆ μ λ ₯ λ§€κ°λ³μλ₯Ό λΆμνκ³ μμ² κ°μ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμνκΈ°λ‘ κ²°μ ν μ μμ΅λλ€. μλ₯Ό λ€μ΄, λ€νμ λͺ¨λ νμμ΄λ λΉ½λΉ½ν μ±λ¨μ λͺ¨λ μνμ±μ λν΄ μμ κ·Έλ£Ήμ μμν μ μμΌλ©°, μ΄ λͺ¨λ κ²μ΄ CPUμ λ¨μΌ λμ€ν¨μΉ λͺ λ Ήμμ λΉλ‘―λ©λλ€.
νμ€ν¬ μ °μ΄λ GLSL κ°λ μ΄ν΄λ³΄κΈ°
ꡬ체μ μΈ λ΄μ©μ 볡μ‘ν μ μμ§λ§, GLSL(WebGL νμ₯μ©)μ ν΅μ¬ μ¦ν λ©μ»€λμ¦μ λλΌμΈ μ λλ‘ κ°λ¨ν©λλ€. μ΄λ `EmitMeshTasksEXT()` ν¨μλ₯Ό μ€μ¬μΌλ‘ μ΄λ£¨μ΄μ§λλ€.
μ°Έκ³ : μ΄κ²μ λ¨μνλ κ°λ μ μμ μ λλ€.
#version 310 es
#extension GL_EXT_mesh_shader : require
layout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;
// CPUμμ μ λ¬λ μ λνΌ
uniform mat4 u_viewProjectionMatrix;
uniform uint u_totalObjectCount;
// λ§μ κ°μ²΄μ λν κ²½κ³ κ΅¬λ₯Ό ν¬ν¨νλ λ²νΌ
struct BoundingSphere {
vec4 centerAndRadius;
};
layout(std430, binding = 0) readonly buffer ObjectBounds {
BoundingSphere bounds[];
} objectBounds;
void main() {
// μμ
κ·Έλ£Ήμ κ° μ€λ λλ λ€λ₯Έ κ°μ²΄λ₯Ό νμΈν μ μμ΅λλ€.
uint objectIndex = gl_GlobalInvocationID.x;
if (objectIndex >= u_totalObjectCount) {
return;
}
// μ΄ κ°μ²΄μ κ²½κ³ κ΅¬μ λν΄ GPUμμ μ λ체 컬λ§μ μνν©λλ€.
BoundingSphere sphere = objectBounds.bounds[objectIndex];
bool isVisible = isSphereInFrustum(sphere.centerAndRadius, u_viewProjectionMatrix);
// 보μ΄λ κ²½μ°, μ΄λ₯Ό 그리기 μν΄ νλμ λ©μ μ
°μ΄λ μμ
κ·Έλ£Ήμ μμν©λλ€.
// μ°Έκ³ : μ΄ λ‘μ§μ 보μ΄λ κ°μ²΄λ₯Ό μΈκΈ° μν΄ atomicμ μ¬μ©νκ³
// νλμ μ€λ λκ° λͺ¨λ κ°μ²΄μ λν΄ λμ€ν¨μΉνλ λ± λ 볡μ‘ν μ μμ΅λλ€.
if (isVisible) {
// μ΄κ²μ GPUμ λ©μ νμ€ν¬λ₯Ό μμνλΌκ³ μ§μν©λλ€. λ§€κ°λ³μλ
// λ©μ μ
°μ΄λ μμ
κ·Έλ£Ήμ μ 보λ₯Ό μ λ¬νλ λ° μ¬μ©λ μ μμ΅λλ€.
// κ°λ¨ν νκΈ° μν΄, κ° νμ€ν¬ μ
°μ΄λ νΈμΆμ΄ μ§μ λ©μ νμ€ν¬μ λ§€νλ μ μλ€κ³ κ°μ ν©λλ€.
// λ νμ€μ μΈ μλ리μ€λ λ¨μΌ μ€λ λμμ κ·Έλ£Ήννκ³ λμ€ν¨μΉνλ κ²μ ν¬ν¨ν©λλ€.
// λ¨μνλ κ°λ
μ λμ€ν¨μΉ:
// μ€μ λ‘λ νλμ νμ€ν¬ μ
°μ΄λ νΈμΆμ΄ μ¬λ¬ λ©μ μ
°μ΄λμ λμ€ν¨μΉλ₯Ό κ΄λ¦¬νμ§λ§,
// μ¬κΈ°μλ 보μ΄λ κ° κ°μ²΄κ° μ체 νμ€ν¬λ₯Ό μ»λλ€κ³ κ°μ ν©λλ€.
EmitMeshTasksEXT(1u, 0u, 0u); // μ΄κ²μ΄ ν΅μ¬ μ¦ν ν¨μμ
λλ€
}
// 보μ΄μ§ μλλ€λ©΄, μ무κ²λ νμ§ μμ΅λλ€! κ°μ²΄λ μ΄ νμΈ μΈμ μ λ‘ GPU λΉμ©μΌλ‘ 컬λ§λ©λλ€.
}
μ€μ μλ리μ€μμλ μμ κ·Έλ£Ήμ ν μ€λ λκ° κ²°κ³Όλ₯Ό μ§κ³νκ³ μμ κ·Έλ£Ήμ΄ μ± μμ§λ λͺ¨λ 보μ΄λ κ°μ²΄μ λν΄ λ¨μΌ `EmitMeshTasksEXT` νΈμΆμ ν μ μμ΅λλ€.
μμ μ: μ§μ€λ©νΈλ¦¬ μμ±μμμ λ©μ μ °μ΄λμ μν
νμ€ν¬ μ °μ΄λκ° νλ μ΄μμ μμ κ·Έλ£Ήμ λμ€ν¨μΉνλ©΄, λ©μ μ °μ΄λκ° κ·Έ μν μ μ΄μ΄λ°μ΅λλ€. νμ€ν¬ μ °μ΄λκ° νλ‘μ νΈ κ΄λ¦¬μλΌλ©΄, λ©μ μ °μ΄λλ μ€μ λ‘ μ§μ€λ©νΈλ¦¬λ₯Ό ꡬμΆνλ μλ ¨λ 건μ€νμ λλ€.
μμ κ·Έλ£Ήμμ λ©μλ¦ΏμΌλ‘
νμ€ν¬ μ °μ΄λμ λ§μ°¬κ°μ§λ‘, λ©μ μ °μ΄λλ νλ ₯μ μΈ μ€λ λ μμ κ·Έλ£ΉμΌλ‘ μ€νλ©λλ€. μ΄ μ 체 μμ κ·Έλ£Ήμ 곡λ λͺ©νλ λ©μλ¦Ώ(meshlet)μ΄λΌλ λ¨μΌμ μμ μ§μ€λ©νΈλ¦¬ λ°°μΉλ₯Ό μμ±νλ κ²μ λλ€. λ©μλ¦Ώμ λ¨μν μ μ λͺ¨μκ³Ό κ·Έλ€μ μ°κ²°νλ ν리미ν°λΈ(μΌκ°ν)μ λλ€. μΌλ°μ μΌλ‘ λ©μλ¦Ώμ μ μ μμ μ μ (μ: μ΅λ 128κ°)κ³Ό μΌκ°ν(μ: μ΅λ 256κ°)μ ν¬ν¨νλ©°, μ΄λ νλ GPU μΊμ λ° μ²λ¦¬ λͺ¨λΈμ λ§€μ° μΉνμ μΈ ν¬κΈ°μ λλ€.
μ΄κ²μ μ΄μμ κ°λ μ΄ μμλ μ μ μ °μ΄λμλ κ·Όλ³Έμ μΌλ‘ λ€λ₯Έ μ μ λλ€. λ©μ μ °μ΄λμμλ μμ κ·Έλ£Ήμ λͺ¨λ μ€λ λκ° λ©λͺ¨λ¦¬λ₯Ό 곡μ νκ³ νλ ₯νμ¬ λ©μλ¦Ώμ ν¨μ¨μ μΌλ‘ ꡬμΆν μ μμ΅λλ€.
μ μ κ³Ό ν리미ν°λΈ μμ±νκΈ°
λ¨μΌ `gl_Position`μ λ°ννλ λμ , λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ λ©μλ¦Ώμ λν μμ ν λ°μ΄ν°λ‘ μΆλ ₯ λ°°μ΄μ μ±μλλ€. μ€λ λλ€μ ν¨κ» μμ νμ¬ μ μ μμΉ, λ²μ , UV μ’ν λ° κΈ°ν μμ±μ μ΄ λ°°μ΄μ μλλ€. λν κ° μΌκ°νμ ꡬμ±νλ μ μ μ μ§μ νμ¬ ν리미ν°λΈλ₯Ό μ μν©λλ€.
λ©μ μ °μ΄λμ λ§μ§λ§ λ¨κ³λ `SetMeshOutputsEXT()`μ κ°μ ν¨μλ₯Ό νΈμΆνμ¬ μ νν μΌλ§λ λ§μ μ μ κ³Ό ν리미ν°λΈλ₯Ό μμ±νλμ§ μ μΈνλ κ²μ λλ€. κ·Έλ¬λ©΄ νλμ¨μ΄λ μ΄ λ©μλ¦Ώμ κ°μ Έμ λμ€ν°λΌμ΄μ μ μ§μ μ λ¬ν©λλ€.
λ©μ μ °μ΄λ GLSL κ°λ μ΄ν΄λ³΄κΈ°
λ€μμ κ°λ¨ν μ¬κ°νμ μμ±νλ λ©μ μ °μ΄λμ κ°λ μ μμ μ λλ€. μ€λ λλ€μ΄ `gl_LocalInvocationID`μ κΈ°λ°νμ¬ μ΄λ»κ² νλ ₯νλμ§ μ£Όλͺ©νμΈμ.
#version 310 es
#extension GL_EXT_mesh_shader : require
// μ°λ¦¬ λ©μλ¦Ώμ μ΅λ μΆλ ₯μ μ μν©λλ€.
layout(max_vertices = 4, max_primitives = 2) out;
layout(triangles) out;
layout(local_size_x = 4, local_size_y = 1, local_size_z = 1) in;
// μ΄ λ΄μ₯ μΆλ ₯ λ°°μ΄μ μ μ λ°μ΄ν°λ₯Ό μλλ€.
out gl_MeshVerticesEXT {
vec4 position;
vec2 uv;
} vertices[];
// μ΄ λ°°μ΄μ μΌκ°ν μΈλ±μ€λ₯Ό μλλ€.
out uint gl_MeshPrimitivesEXT[];
uniform mat4 u_modelViewProjectionMatrix;
void main() {
// μ΄ λ©μλ¦Ώμ λν΄ μμ±ν μ΄ μ μ λ° ν리미ν°λΈ μ
const uint vertexCount = 4;
const uint primitiveCount = 2;
// μ€μ λ‘ μΆλ ₯νλ μ μ κ³Ό ν리미ν°λΈ μλ₯Ό νλμ¨μ΄μ μ립λλ€.
SetMeshOutputsEXT(vertexCount, primitiveCount);
// μ¬κ°νμ μ μ μμΉμ UVλ₯Ό μ μν©λλ€.
vec4 positions[4] = vec4[4](
vec4(-0.5, 0.5, 0.0, 1.0),
vec4(-0.5, -0.5, 0.0, 1.0),
vec4(0.5, 0.5, 0.0, 1.0),
vec4(0.5, -0.5, 0.0, 1.0)
);
vec2 uvs[4] = vec2[4](
vec2(0.0, 1.0),
vec2(0.0, 0.0),
vec2(1.0, 1.0),
vec2(1.0, 0.0)
);
// μμ
κ·Έλ£Ήμ κ° μ€λ λκ° νλμ μ μ μ μμ±νλλ‘ ν©λλ€.
uint id = gl_LocalInvocationID.x;
if (id < vertexCount) {
vertices[id].position = u_modelViewProjectionMatrix * positions[id];
vertices[id].uv = uvs[id];
}
// μ²μ λ μ€λ λκ° μ¬κ°νμ λ μΌκ°νμ μμ±νλλ‘ ν©λλ€.
if (id == 0) {
// 첫 λ²μ§Έ μΌκ°ν: 0, 1, 2
gl_MeshPrimitivesEXT[0] = 0u;
gl_MeshPrimitivesEXT[1] = 1u;
gl_MeshPrimitivesEXT[2] = 2u;
}
if (id == 1) {
// λ λ²μ§Έ μΌκ°ν: 1, 3, 2
gl_MeshPrimitivesEXT[3] = 1u;
gl_MeshPrimitivesEXT[4] = 3u;
gl_MeshPrimitivesEXT[5] = 2u;
}
}
μ€μ©μ μΈ λ§λ²: νμ€ν¬ μ¦νμ νμ© μ¬λ‘
μ΄ νμ΄νλΌμΈμ μ§μ ν νμ 볡μ‘νκ³ μ€μ μ μΈ λ λλ§ λ¬Έμ μ μ μ©ν λ λλ¬λ©λλ€.
νμ© μ¬λ‘ 1: λκ·λͺ¨ μ μ°¨μ μ§μ€λ©νΈλ¦¬ μμ±
μμλ§ κ°μ κ³ μ ν μνμ±μ΄ μλ λΉ½λΉ½ν μνμ± μ§λλ₯Ό λ λλ§νλ€κ³ μμν΄λ³΄μΈμ. κΈ°μ‘΄ νμ΄νλΌμΈμμλ CPUκ° κ° μνμ±μ μ μ λ°μ΄ν°λ₯Ό μμ±νκ³ κ°κ°μ λν΄ λ³λμ λλ‘μ° μ½μ λ°νν΄μΌ νλ―λ‘, μ΄λ μμ ν λΆκ°λ₯ν μ κ·Ό λ°©μμ λλ€.
λ©μ μ °μ΄λ μν¬νλ‘μ°:
- CPUλ λ¨μΌ λλ‘μ° μ½μ λ°νν©λλ€: `drawMeshTasksEXT(1, 1)`. λν μ λνΌ λ²νΌμ νλμ λ°κ²½ λ° μνμ± λ°λμ κ°μ μΌλΆ κ³ μμ€ λ§€κ°λ³μλ₯Ό μ λ¬ν©λλ€.
- λ¨μΌ νμ€ν¬ μ °μ΄λ μμ κ·Έλ£Ήμ΄ μ€νλ©λλ€. λ§€κ°λ³μλ₯Ό μ½κ³ , μλ₯Ό λ€μ΄ 50,000κ°μ μνμ±μ΄ νμνλ€κ³ κ³μ°ν©λλ€. κ·Έλ° λ€μ `EmitMeshTasksEXT(50000, 0, 0)`λ₯Ό νΈμΆν©λλ€.
- GPUλ λ³λ ¬λ‘ 50,000κ°μ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμν©λλ€.
- κ° λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ κ³ μ ID(`gl_WorkGroupID`)λ₯Ό μλλ‘ μ¬μ©νμ¬ νλμ κ³ μ ν μνμ±μ λν μ μ κ³Ό μΌκ°νμ μ μ°¨μ μΌλ‘ μμ±ν©λλ€.
κ·Έ κ²°κ³Ό, κ±°μ μ μ μΌλ‘ GPUμμ μμ±λ κ±°λνκ³ λ³΅μ‘ν μ₯λ©΄μ΄ λ§λ€μ΄μ Έ CPUκ° λ¬Όλ¦¬ λ° AIμ κ°μ λ€λ₯Έ μμ μ μ²λ¦¬ν μ μκ² ν΄μ€λλ€.
νμ© μ¬λ‘ 2: λκ·λͺ¨ GPU μ£Όλ 컬λ§
μλ°±λ§ κ°μ κ°λ³ κ°μ²΄κ° μλ μμΈν λμ μ₯λ©΄μ μκ°ν΄λ³΄μΈμ. CPUλ λ§€ νλ μλ§λ€ λͺ¨λ κ°μ²΄μ κ°μμ±μ νμΈν μ μμ΅λλ€.
λ©μ μ °μ΄λ μν¬νλ‘μ°:
- CPUλ μ₯λ©΄μ μλ λͺ¨λ λ¨μΌ κ°μ²΄μ λν κ²½κ³ λ³Όλ₯¨(μ: ꡬ λλ μμ)μ ν¬ν¨νλ ν° λ²νΌλ₯Ό μ λ‘λν©λλ€. μ΄κ²μ ν λ²λ§ λ°μνκ±°λ κ°μ²΄κ° μμ§μΌ λλ§ λ°μν©λλ€.
- CPUλ μ 체 κ²½κ³ λ³Όλ₯¨ λͺ©λ‘μ λ³λ ¬λ‘ μ²λ¦¬νκΈ°μ μΆ©λΆν νμ€ν¬ μ °μ΄λ μμ κ·Έλ£Ήμ μμνλ λ¨μΌ λλ‘μ° μ½μ λ°νν©λλ€.
- κ° νμ€ν¬ μ °μ΄λ μμ κ·Έλ£Ήμλ κ²½κ³ λ³Όλ₯¨ λͺ©λ‘μ μΌλΆκ° ν λΉλ©λλ€. ν λΉλ κ°μ²΄λ₯Ό μννλ©° κ° κ°μ²΄μ λν΄ μ λ체 컬λ§(κ·Έλ¦¬κ³ μ μ¬μ μΌλ‘ νμ 컬λ§)μ μννκ³ , 보μ΄λ κ°μ²΄μ μλ₯Ό μ λλ€.
- λ§μ§λ§μΌλ‘, 보μ΄λ κ°μ²΄μ IDλ₯Ό μ λ¬νλ©΄μ μ νν κ·Έ μλ§νΌμ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμν©λλ€.
- κ° λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ κ°μ²΄ IDλ₯Ό λ°μ λ²νΌμμ λ©μ λ°μ΄ν°λ₯Ό μ‘°ννκ³ λ λλ§μ μν ν΄λΉ λ©μλ¦Ώμ μμ±ν©λλ€.
μ΄κ²μ μ 체 μ»¬λ§ νλ‘μΈμ€λ₯Ό GPUλ‘ μ΄λμμΌ CPU κΈ°λ° μ κ·Ό λ°©μμΌλ‘λ μ¦μ λ§λΉλ 볡μ‘μ±μ μ₯λ©΄μ κ°λ₯νκ² ν©λλ€.
νμ© μ¬λ‘ 3: λμ μ΄κ³ ν¨μ¨μ μΈ LOD(Level of Detail)
LOD μμ€ν μ λ©λ¦¬ μλ κ°μ²΄μ λν΄ λ κ°λ¨ν λͺ¨λΈλ‘ μ ννμ¬ μ±λ₯μ λ§€μ° μ€μν©λλ€. λ©μ μ °μ΄λλ μ΄ νλ‘μΈμ€λ₯Ό λ μΈλΆννκ³ ν¨μ¨μ μΌλ‘ λ§λλλ€.
λ©μ μ °μ΄λ μν¬νλ‘μ°:
- κ°μ²΄μ λ°μ΄ν°λ λ©μλ¦Ώμ κ³μΈ΅ κ΅¬μ‘°λ‘ μ¬μ μ²λ¦¬λ©λλ€. λ κ±°μΉ LODλ λ μ κ³ ν° λ©μλ¦Ώμ μ¬μ©ν©λλ€.
- μ΄ κ°μ²΄μ λν νμ€ν¬ μ °μ΄λλ μΉ΄λ©λΌλ‘λΆν°μ 거리λ₯Ό κ³μ°ν©λλ€.
- 거리μ λ°λΌ μ΄λ€ LOD μμ€μ΄ μ μ νμ§ κ²°μ ν©λλ€. κ·Έλ° λ€μ ν΄λΉ LODμ λν΄ λ©μλ¦Ώ λ¨μλ‘ μ»¬λ§μ μνν μ μμ΅λλ€. μλ₯Ό λ€μ΄, ν° κ°μ²΄μ κ²½μ° λ³΄μ΄μ§ μλ κ°μ²΄ λ·λ©΄μ λ©μλ¦Ώμ 컬λ§ν μ μμ΅λλ€.
- μ νλ LODμ 보μ΄λ λ©μλ¦Ώμ λν΄μλ§ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμν©λλ€.
μ΄κ²μ CPUκ° μ 체 λͺ¨λΈμ κ΅μ²΄νλ κ²λ³΄λ€ ν¨μ¬ ν¨μ¨μ μΈ, μΈλΆνλ μ€μκ° LOD μ ν λ° μ»¬λ§μ κ°λ₯νκ² ν©λλ€.
μμνκΈ°: `WEBGL_mesh_shader` νμ₯ νλ‘κ·Έλ¨ μ¬μ©νκΈ°
μ€νν μ€λΉκ° λμ ¨λμ? λ€μμ WebGLμμ λ©μ μ °μ΄λλ₯Ό μμνκΈ° μν μ€μ©μ μΈ λ¨κ³μ λλ€.
μ§μ μ¬λΆ νμΈνκΈ°
무μ보λ€λ μ΄κ²μ μ΅μ²¨λ¨ κΈ°λ₯μ λλ€. μ¬μ©μμ λΈλΌμ°μ μ νλμ¨μ΄κ° μ΄λ₯Ό μ§μνλμ§ νμΈν΄μΌ ν©λλ€.
const gl = canvas.getContext('webgl2');
const meshShaderExtension = gl.getExtension('WEBGL_mesh_shader');
if (!meshShaderExtension) {
console.error("μ¬μ© μ€μΈ λΈλΌμ°μ λλ GPUκ° WEBGL_mesh_shaderλ₯Ό μ§μνμ§ μμ΅λλ€.");
// μ ν΅μ μΈ λ λλ§ κ²½λ‘λ‘ λ체
}
μλ‘μ΄ λλ‘μ° μ½
`drawArrays`μ `drawElements`λ μμ΄λ²λ¦¬μΈμ. μλ‘μ΄ νμ΄νλΌμΈμ μλ‘μ΄ λͺ λ ΉμΌλ‘ νΈμΆλ©λλ€. `getExtension`μμ μ»λ νμ₯ κ°μ²΄μ μλ‘μ΄ ν¨μλ€μ΄ ν¬ν¨λ κ²μ λλ€.
// 10κ°μ νμ€ν¬ μ
°μ΄λ μμ
κ·Έλ£Ήμ μμν©λλ€.
// κ° μμ
κ·Έλ£Ήμ μ
°μ΄λμ μ μλ local_sizeλ₯Ό κ°μ§λλ€.
meshShaderExtension.drawMeshTasksEXT(0, 10);
`count` μΈμλ μμν νμ€ν¬ μ °μ΄λμ λ‘컬 μμ κ·Έλ£Ή μλ₯Ό μ§μ ν©λλ€. νμ€ν¬ μ °μ΄λλ₯Ό μ¬μ©νμ§ μλ κ²½μ°, μ΄λ μ§μ λ©μ μ °μ΄λ μμ κ·Έλ£Ήμ μμν©λλ€.
μ °μ΄λ μ»΄νμΌ λ° λ§ν¬
κ³Όμ μ μ ν΅μ μΈ GLSLκ³Ό μ μ¬νμ§λ§, `meshShaderExtension.MESH_SHADER_EXT` λ° `meshShaderExtension.TASK_SHADER_EXT` μ νμ μ °μ΄λλ₯Ό μμ±νκ² λ©λλ€. μ μ λ° νλκ·Έλ¨ΌνΈ μ °μ΄λλ₯Ό λ§ν¬νλ―μ΄ μ΄λ€μ νλ‘κ·Έλ¨μ ν¨κ» λ§ν¬ν©λλ€.
κ²°μ μ μΌλ‘, λ μ °μ΄λμ GLSL μμ€ μ½λλ νμ₯μ νμ±ννλ μ§μλ¬ΈμΌλ‘ μμν΄μΌ ν©λλ€:
#extension GL_EXT_mesh_shader : require
μ±λ₯ κ³ λ € μ¬ν λ° λͺ¨λ² μ¬λ‘
- μ¬λ°λ₯Έ μμ κ·Έλ£Ή ν¬κΈ° μ ν: μ °μ΄λμ `layout(local_size_x = N)`μ λ§€μ° μ€μν©λλ€. 32 λλ 64 ν¬κΈ°λ κΈ°λ³Έ νλμ¨μ΄ μν€ν μ²μ μ λ§κΈ° λλ¬Έμ μ’ μ’ μ’μ μΆλ°μ μ΄μ§λ§, νΉμ μν¬λ‘λμ λν μ΅μ μ ν¬κΈ°λ₯Ό μ°ΎκΈ° μν΄ νμ νλ‘νμΌλ§μ ν΄μΌ ν©λλ€.
- νμ€ν¬ μ °μ΄λλ₯Ό κ°κ²°νκ² μ μ§: νμ€ν¬ μ °μ΄λλ κ°λ ₯ν λꡬμ΄μ§λ§ μ μ¬μ μΈ λ³λͺ© νμμ΄ λ μλ μμ΅λλ€. μ¬κΈ°μ μννλ μ»¬λ§ λ° λ‘μ§μ κ°λ₯ν ν ν¨μ¨μ μ΄μ΄μΌ ν©λλ€. 미리 κ³μ°ν μ μλ€λ©΄ λλ¦¬κ³ λ³΅μ‘ν κ³μ°μ νΌνμΈμ.
- λ©μλ¦Ώ ν¬κΈ° μ΅μ ν: λ©μλ¦ΏλΉ μ μ λ° ν리미ν°λΈ μμλ νλμ¨μ΄μ λ°λΌ μ΅μ μ μ§μ μ΄ μμ΅λλ€. μ μΈνλ `max_vertices` λ° `max_primitives`λ μ μ€νκ² μ νν΄μΌ ν©λλ€. λ무 μμΌλ©΄ μμ κ·Έλ£Ή μμ μ€λ²ν€λκ° μ§λ°°μ μ λλ€. λ무 ν¬λ©΄ λ³λ ¬μ±κ³Ό μΊμ ν¨μ¨μ±μ μκ² λ©λλ€.
- λ°μ΄ν° μΌκ΄μ±μ΄ μ€μ: νμ€ν¬ μ °μ΄λμμ 컬λ§μ μνν λ, μΌκ΄λ μ κ·Ό ν¨ν΄μ μ΄μ§νλλ‘ λ©λͺ¨λ¦¬μ κ²½κ³ λ³Όλ₯¨ λ°μ΄ν°λ₯Ό λ°°μ΄νμΈμ. μ΄λ GPU μΊμκ° ν¨κ³Όμ μΌλ‘ μλνλ λ° λμμ΄ λ©λλ€.
- μΈμ μ¬μ©νμ§ λ§μμΌ ν μ§ μκΈ°: λ©μ μ °μ΄λκ° λ§λ₯ ν΄κ²°μ± μ μλλλ€. μμμ κ°λ¨ν κ°μ²΄λ₯Ό λ λλ§νλ κ²½μ°, λ©μ νμ΄νλΌμΈμ μ€λ²ν€λκ° μ ν΅μ μΈ μ μ νμ΄νλΌμΈλ³΄λ€ λ릴 μ μμ΅λλ€. λκ·λͺ¨ κ°μ²΄ μ, 볡μ‘ν μ μ°¨μ μμ±, GPU μ£Όλ μν¬λ‘λμ κ°μ΄ κ·Έλ€μ κ°μ μ΄ λΉλλ κ³³μμ μ¬μ©νμΈμ.
κ²°λ‘ : μΉ μ€μκ° κ·Έλν½μ λ―Έλλ λ°λ‘ μ§κΈμ λλ€
νμ€ν¬ μ¦νμ κ°μΆ λ©μ μ °μ΄λ νμ΄νλΌμΈμ μ§λ 10λ κ° μ€μκ° κ·Έλν½μμ κ°μ₯ μ€μν λ°μ μ€ νλλ₯Ό λνν©λλ€. ν¨λ¬λ€μμ κ²½μ§λ CPU κ΄λ¦¬ νλ‘μΈμ€μμ μ μ°ν GPU μ£Όλ νλ‘μΈμ€λ‘ μ νν¨μΌλ‘μ¨, κΈ°ννμ 볡μ‘μ±κ³Ό μ₯λ©΄ κ·λͺ¨μ λν μ΄μ μ μ₯λ²½μ νλ¬Όμμ΅λλ€.
μ΄ κΈ°μ μ Vulkan, DirectX 12 Ultimate, Metalκ³Ό κ°μ νλ κ·Έλν½ APIμ λ°©ν₯κ³Ό μΌμΉνλ©°, λ μ΄μ κ³ κΈ λ€μ΄ν°λΈ μ ν리μΌμ΄μ μ κ΅νλμ§ μμ΅λλ€. WebGLμμμ λ±μ₯μ μ΄μ λ³΄λ€ λ μμΈνκ³ , λμ μ΄λ©°, λͺ°μ κ° μλ μΉ κΈ°λ° κ²½νμ μλ‘μ΄ μλλ₯Ό μ΄μ΄μ€λλ€. μ΄ μλ‘μ΄ λͺ¨λΈμ κΈ°κΊΌμ΄ λ°μλ€μ΄λ €λ κ°λ°μμκ² μ°½μμ μΈ κ°λ₯μ±μ μ¬μ€μ 무νν©λλ€. μ 체 μΈκ³λ₯Ό μ€μκ°μΌλ‘ μμ±ν μ μλ νμ΄, μ²μμΌλ‘, λ§ κ·Έλλ‘ μΉ λΈλΌμ°μ λ΄μμ μ¬λ¬λΆμ μλμ μμ΅λλ€.