驿°çãªWebGLã¡ãã·ã¥ã·ã§ãŒããŒãã€ãã©ã€ã³ã解説ãã¿ã¹ã¯å¢å¹ ã«ãããå€§èŠæš¡ãªãªã³ã¶ãã©ã€ãžãªã¡ããªçæãšé«åºŠãªã«ãªã³ã°ãå®çŸããæ¬¡äžä»£ã®Webã°ã©ãã£ãã¯ã¹ãå¯èœã«ããŸãã
ãžãªã¡ããªã®è§£æŸïŒWebGLã®ã¡ãã·ã¥ã·ã§ãŒããŒã¿ã¹ã¯å¢å¹ ãã€ãã©ã€ã³ã®åŸ¹åºè§£èª¬
Webã¯ãã¯ãéçãªäºæ¬¡å ã¡ãã£ã¢ã§ã¯ãããŸãããæ¯ãåããããªè£œåã³ã³ãã£ã®ã¥ã¬ãŒã¿ãŒã建ç¯ããžã¥ã¢ã©ã€ãŒãŒã·ã§ã³ãããè€éãªããŒã¿ã¢ãã«ãæ¬æ Œçãªã²ãŒã ãŸã§ãè±ãã§æ²¡å ¥æã®ãã3Däœéšã®ããã®æŽ»æ°ãããã©ãããã©ãŒã ãžãšé²åããŸããããããããã®é²åã¯ãã°ã©ãã£ãã¯ã¹ããã»ãã·ã³ã°ãŠãããïŒGPUïŒã«åäŸã®ãªãèŠæ±ãçªãä»ããŠããŸããé·å¹Žã«ããããæšæºçãªãªã¢ã«ã¿ã€ã ã°ã©ãã£ãã¯ã¹ãã€ãã©ã€ã³ã¯ã匷åã§ããäžæ¹ã§ãæä»£é ãã§ããããšã瀺ãããŠãããææ°ã®ã¢ããªã±ãŒã·ã§ã³ãå¿ èŠãšãã幟äœåŠçè€éãã®ããã«ããã¯ãšããŠäœçšããããšããããããŸãã
ããã§ç»å Žããã®ããWEBGL_mesh_shaderæ¡åŒµæ©èœãéããŠWebã§å©çšã§ããããã«ãªã£ãããã©ãã€ã ã·ãããšãªãã¡ãã·ã¥ã·ã§ãŒããŒãã€ãã©ã€ã³ã§ãããã®æ°ããã¢ãã«ã¯ãGPUäžã§ã®ãžãªã¡ããªã®èãæ¹ãšåŠçæ¹æ³ãæ ¹æ¬çã«å€ããŸãããã®äžå¿ã«ããã®ã¯ãã¿ã¹ã¯å¢å¹
ãšãã匷åãªã³ã³ã»ããã§ããããã¯åãªã挞é²çãªã¢ããããŒãã§ã¯ãããŸãããCPUããGPUã®é«åºŠã«äžŠååãããã¢ãŒããã¯ãã£ã«çŽæ¥ã¹ã±ãžã¥ãŒãªã³ã°ãšãžãªã¡ããªçæããžãã¯ãç§»åããã驿°çãªé£èºã§ããã以åã¯Webãã©ãŠã¶ã§ã¯éçŸå®çãŸãã¯äžå¯èœã ã£ãå¯èœæ§ãè§£ãæŸã¡ãŸãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãã¡ãã·ã¥ã·ã§ãŒããŒãžãªã¡ããªãã€ãã©ã€ã³ãæ·±ãæãäžããŠãããŸãããã®ã¢ãŒããã¯ãã£ã調ã¹ãã¿ã¹ã¯ã·ã§ãŒããŒãšã¡ãã·ã¥ã·ã§ãŒããŒã®æç¢ºãªåœ¹å²ãçè§£ããã¿ã¹ã¯å¢å¹ ãã©ã®ããã«æŽ»çšããŠãèŠèŠçã«èŠäºã§é«æ§èœãªæ¬¡äžä»£ã®Webã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããããè§£ãæãããŸãã
ã¡ãã£ãšå·»ãæ»ãïŒåŸæ¥ã®ãžãªã¡ããªãã€ãã©ã€ã³ã®å¶é
ã¡ãã·ã¥ã·ã§ãŒããŒã®é©æ°æ§ãçã«çè§£ããã«ã¯ããŸãããããã眮ãæãããã€ãã©ã€ã³ãçè§£ããå¿ èŠããããŸããæ°å幎ã«ãããããªã¢ã«ã¿ã€ã ã°ã©ãã£ãã¯ã¹ã¯æ¯èŒçåºå®ãããæ©èœãã€ãã©ã€ã³ã«ãã£ãŠæ¯é ãããŠããŸããã
- é ç¹ã·ã§ãŒããŒïŒåã ã®é ç¹ãåŠçããããããã¹ã¯ãªãŒã³ã¹ããŒã¹ã«å€æããŸãã
- ïŒãªãã·ã§ã³ïŒããã»ã¬ãŒã·ã§ã³ã·ã§ãŒããŒïŒãžãªã¡ããªã®ãããã现åå²ããŠããã现ãããã£ããŒã«ãäœæããŸãã
- ïŒãªãã·ã§ã³ïŒãžãªã¡ããªã·ã§ãŒããŒïŒããªããã£ãïŒç¹ãç·ãäžè§åœ¢ïŒããªã³ã¶ãã©ã€ã§äœæãŸãã¯ç Žæ£ã§ããŸãã
- ã©ã¹ã¿ã©ã€ã¶ãŒïŒããªããã£ãããã¯ã»ã«ã«å€æããŸãã
- ãã©ã°ã¡ã³ãã·ã§ãŒããŒïŒåãã¯ã»ã«ã®æçµçãªè²ãèšç®ããŸãã
ãã®ã¢ãã«ã¯ååã«åœ¹ç«ã¡ãŸããããç¹ã«ã·ãŒã³ãè€éã«ãªãã«ã€ããŠãåºæã®å¶éããããŸãã
- CPUããŠã³ãã®ãããŒã³ãŒã«ïŒCPUã¯ãæ£ç¢ºã«äœãæç»ããå¿ èŠãããããææ¡ãããšããèšå€§ãªã¿ã¹ã¯ãæ±ããŠããŸããããã«ã¯ããã©ã¹ã¿ã ã«ãªã³ã°ïŒã«ã¡ã©ã®èŠéå€ã«ãããªããžã§ã¯ãã®åé€ïŒããªã¯ã«ãŒãžã§ã³ã«ãªã³ã°ïŒä»ã®ãªããžã§ã¯ãã«ãã£ãŠé ãããŠãããªããžã§ã¯ãã®åé€ïŒãããã³ã¬ãã«ãªããã£ããŒã«ïŒLODïŒã·ã¹ãã ã®ç®¡çãå«ãŸããŸããæ°çŸäžã®ãªããžã§ã¯ããå«ãã·ãŒã³ã®å Žåãããã«ãããCPUãäž»èŠãªããã«ããã¯ã«ãªãã貪欲ãªGPUã«ååã«éãäŸçµŠã§ããªããªãå¯èœæ§ããããŸãã
- 硬çŽããå ¥åæ§é ïŒãã€ãã©ã€ã³ã¯ã硬çŽããå ¥ååŠçã¢ãã«ãäžå¿ã«æ§ç¯ãããŠããŸããå ¥åã¢ã»ã³ãã©ãŒã¯é ç¹ã1ã€ãã€äŸçµŠããã·ã§ãŒããŒã¯æ¯èŒçå¶çŽãããæ¹æ³ã§ããããåŠçããŸããããã¯ãã³ããŒã¬ã³ããªäžŠåããŒã¿åŠçã«åªããŠããææ°ã®GPUã¢ãŒããã¯ãã£ã«ã¯çæ³çã§ã¯ãããŸããã
- éå¹ççãªå¢å¹ ïŒãžãªã¡ããªã·ã§ãŒããŒã¯ãžãªã¡ããªã®å¢å¹ ïŒå ¥åããªããã£ãããæ°ããäžè§åœ¢ãäœæããïŒãå¯èœã«ããŸããããæªåé«ãéå¹ççã§ããããããã®åºååäœã¯ããŒããŠã§ã¢ã«ãšã£ãŠäºæž¬äžå¯èœã§ããããšãå€ããå€ãã®å€§èŠæš¡ã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠéã¹ã¿ãŒã¿ãŒãšãªãããã©ãŒãã³ã¹ã®åé¡ã«ã€ãªãããŸããã
- ç¡é§ãªäœæ¥ïŒåŸæ¥ã®ãã€ãã©ã€ã³ã§ã¯ãã¬ã³ããªã³ã°ããããã«äžè§åœ¢ãéä¿¡ãããšããã®äžè§åœ¢ãæçµçã«ã«ãªã³ã°ãããããèé¢ãåããŠãããã¯ã»ã«å¹ ã®èãã¹ã©ã€ããŒã§ãã£ãŠããé ç¹ã·ã§ãŒããŒã3åå®è¡ãããŸããæçµçãªç»åã«äœãè²¢ç®ããªããžãªã¡ããªã«å€ãã®åŠçèœåãè²»ããããŠããŸãã
ãã©ãã€ã ã·ããïŒã¡ãã·ã¥ã·ã§ãŒããŒãã€ãã©ã€ã³ã®å°å ¥
ã¡ãã·ã¥ã·ã§ãŒããŒãã€ãã©ã€ã³ã¯ãé ç¹ãããã»ã¬ãŒã·ã§ã³ããžãªã¡ããªã·ã§ãŒããŒã¹ããŒãžããæ°ãããããæè»ãª2段éã¢ãã«ã«çœ®ãæããŸãã
- ã¿ã¹ã¯ã·ã§ãŒããŒïŒãªãã·ã§ã³ïŒïŒã©ãã ãã®äœæ¥ãå¿ èŠããæ±ºå®ããé«ã¬ãã«ã®å¶åŸ¡ã¹ããŒãžãå¢å¹ ã·ã§ãŒããŒãšãåŒã°ããŸãã
- ã¡ãã·ã¥ã·ã§ãŒããŒïŒããŒã¿ã®ããããæäœããŠããã¡ãã·ã¥ã¬ããããšåŒã°ããå°ããèªå·±å®çµåã®ãžãªã¡ããªãã±ãããçæããäž»åã¹ããŒãžã
ãã®æ°ããã¢ãããŒãã¯ãã¬ã³ããªã³ã°ã®å²åŠãæ ¹æ¬çã«å€ããŸããCPUããã¹ãŠã®ãªããžã§ã¯ãã®ãã¹ãŠã®ãããŒã³ãŒã«ã现ãã管çãã代ããã«ãGPUã«æ¬¡ã®ããã«æç€ºãã匷åãªãããŒã³ãã³ãã1ã€çºè¡ã§ããããã«ãªããŸããããè€éãªã·ãŒã³ã®é«ã¬ãã«ã®èª¬æãããã«ç€ºããŸãã詳现ãçè§£ããŠãã ãããã
GPUã¯ãã¿ã¹ã¯ã·ã§ãŒããŒãšã¡ãã·ã¥ã·ã§ãŒããŒã䜿çšããŠãé«åºŠã«äžŠåãªæ¹æ³ã§ã«ãªã³ã°ãLODéžæãããã³ããã·ãŒãžã£ã«çæãå®è¡ããå®éã«è¡šç€ºããããžãªã¡ããªãçæããããã«å¿ èŠãªäœæ¥ã®ã¿ãéå§ã§ããŸãããããGPUé§åã®ã¬ã³ããªã³ã°ãã€ãã©ã€ã³ã®æ¬è³ªã§ãããããã©ãŒãã³ã¹ãšã¹ã±ãŒã©ããªãã£ã®ã²ãŒã ãã§ã³ãžã£ãŒã§ãã
ææ®è ïŒã¿ã¹ã¯ïŒå¢å¹ ïŒã·ã§ãŒããŒã®çè§£
ã¿ã¹ã¯ã·ã§ãŒããŒã¯ãæ°ãããã€ãã©ã€ã³ã®é è³ã§ããããã®é©ãã¹ãåã®éµã§ãããªãã·ã§ã³ã®ã¹ããŒãžã§ããããå¢å¹ ããçºçããå Žæã§ãããã®äž»ãªåœ¹å²ã¯ãé ç¹ãäžè§åœ¢ãçæããããšã§ã¯ãªããã¯ãŒã¯ãã£ã¹ãããã£ãŒãšããŠæ©èœããããšã§ãã
ã¿ã¹ã¯ã·ã§ãŒããŒãšã¯äœã§ããïŒ
ã¿ã¹ã¯ã·ã§ãŒããŒãå€§èŠæš¡ãªå»ºèšãããžã§ã¯ãã®ãããžã§ã¯ããããŒãžã£ãŒãšèããŠãã ãããCPUã¯ãããŒãžã£ãŒã«ãéœåžå°åºã建èšãããã®ãããªé«ã¬ãã«ã®ç®æšãäžããŸãããããžã§ã¯ããããŒãžã£ãŒïŒã¿ã¹ã¯ã·ã§ãŒããŒïŒã¯ãã¬ã³ã¬ãèªåã§ç©ã¿ãŸããã代ããã«ãã¿ã¹ã¯å šäœãè©äŸ¡ããéåçã確èªããã©ã®å»ºèšã¯ã«ãŒïŒã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒãïŒãå¿ èŠããããã³ããã€å¿ èŠããæ±ºå®ããŸããç¹å®ã®å»ºç©ãå¿ èŠãªãïŒã«ãªã³ã°ïŒããšããŸãã¯ç¹å®ã®ãšãªã¢ã«ã¯10ã®ã¯ã«ãŒãå¿ èŠã§ããããå¥ã®ãšãªã¢ã«ã¯2ã€ããå¿ èŠãªãããšã決å®ã§ããŸãã
æè¡çã«ã¯ãã¿ã¹ã¯ã·ã§ãŒããŒã¯ã³ã³ãã¥ãŒãã®ãããªã¯ãŒã¯ã°ã«ãŒããšããŠå®è¡ãããŸããã¡ã¢ãªã«ã¢ã¯ã»ã¹ããè€éãªèšç®ãå®è¡ããæãéèŠãªããšã«ãèµ·åããã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒãã®æ°ã決å®ã§ããŸãããã®æ±ºå®ã¯ãã®åã®æ žå¿ã§ãã
å¢å¹ ã®å
ãå¢å¹ ããšããçšèªã¯ãã¿ã¹ã¯ã·ã§ãŒããŒãç¬èªã®1ã€ã®ã¯ãŒã¯ã°ã«ãŒããååŸãããŒãã1ã€ããŸãã¯å€æ°ã®ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããèµ·åã§ããããšã«ç±æ¥ããŸãããã®æ©èœã¯å€é©çã§ãã
- ãŒãã®èµ·åïŒã¿ã¹ã¯ã·ã§ãŒããŒããªããžã§ã¯ããŸãã¯ã·ãŒã³ã®ãã£ã³ã¯ã衚瀺ãããªãïŒäŸïŒã«ã¡ã©ã®ãã©ã¹ã¿ã ã®å€åŽïŒãšå€æããå ŽåããŒãã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããèµ·åããããšãéžæã§ããŸãããã®ãªããžã§ã¯ãã«é¢é£ä»ããããŠããå¯èœæ§ã®ãããã¹ãŠã®äœæ¥ã¯ããã以äžåŠçãããããšãªãæ¶ããŸããããã¯ãGPUã§å®å šã«å®è¡ãããä¿¡ããããªãã»ã©å¹ççãªã«ãªã³ã°ã§ãã
- 1ã€ã®èµ·åïŒããã¯ã¹ãã¬ãŒããã¹ã¹ã«ãŒã§ããã¿ã¹ã¯ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒãã¯ã1ã€ã®ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããå¿ èŠã§ãããšå€æããŸãã
- 倿°ã®èµ·åïŒããã¯ãããã·ãŒãžã£ã«çæã®ããã«éæ³ãèµ·ããå Žæã§ããåäžã®ã¿ã¹ã¯ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããããã€ãã®å ¥åãã©ã¡ãŒã¿ãŒãåæããæ°åã®ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããèµ·åããããšã決å®ã§ããŸããããšãã°ã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);
// 衚瀺ãããŠããå Žåã¯ã1ã€ã®ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããèµ·åããŠæç»ããŸãã
// 泚ïŒãã®ããžãã¯ã¯ããè€éã«ãªãå¯èœæ§ããããã¢ãããã¯ã䜿çšããŠå¯èŠã®
// ãªããžã§ã¯ããã«ãŠã³ããã1ã€ã®ã¹ã¬ãããããããã¹ãŠããã£ã¹ãããããŸãã
if (isVisible) {
// ããã¯ãGPUã«ã¡ãã·ã¥ã¿ã¹ã¯ãèµ·åããããã«æç€ºããŸãããã©ã¡ãŒã¿ãŒã¯ã
// ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒãã«æ
å ±ãæž¡ãããã«äœ¿çšã§ããŸãã
// ç°¡åã«ããããã«ãåã¿ã¹ã¯ã·ã§ãŒããŒåŒã³åºããã¡ãã·ã¥ã¿ã¹ã¯ã«çŽæ¥ãããã³ã°ã§ãããšæ³å®ããŸãã
// ããçŸå®çãªã·ããªãªã§ã¯ãåäžã®ã¹ã¬ããããã®ã°ã«ãŒãåãšãã£ã¹ããããå«ãŸããŸãã
// ç°¡ç¥åãããæŠå¿µçãªãã£ã¹ãããïŒ
// åå¯èŠãªããžã§ã¯ããç¬èªã®ã¿ã¹ã¯ãååŸãããšæ³å®ããŸãããå®éã«ã¯
// 1ã€ã®ã¿ã¹ã¯ã·ã§ãŒããŒåŒã³åºããè€æ°ã®ã¡ãã·ã¥ã·ã§ãŒããŒã®ãã£ã¹ãããã管çããŸãã
EmitMeshTasksEXT(1u, 0u, 0u); // ããã¯éèŠãªå¢å¹
颿°ã§ã
}
// 衚瀺ãããŠããªãå Žåã¯ãäœãããŸããïŒãã®ãªããžã§ã¯ãã¯ããã®ãã§ãã¯ãè¶
ããŠãŒãGPUã³ã¹ãã§ã«ãªã³ã°ãããŸãã
}
å®éã®ã·ããªãªã§ã¯ãã¯ãŒã¯ã°ã«ãŒãå ã®1ã€ã®ã¹ã¬ãããçµæãéçŽããã¯ãŒã¯ã°ã«ãŒããæ åœãããã¹ãŠã®å¯èŠãªããžã§ã¯ãã«å¯ŸããŠåäžã®`EmitMeshTasksEXT`åŒã³åºããè¡ãå ŽåããããŸãã
åŽååïŒãžãªã¡ããªçæã«ãããã¡ãã·ã¥ã·ã§ãŒããŒã®åœ¹å²
ã¿ã¹ã¯ã·ã§ãŒããŒã1ã€ä»¥äžã®ã¯ãŒã¯ã°ã«ãŒãããã£ã¹ããããããšãã¡ãã·ã¥ã·ã§ãŒããŒãåŒãç¶ããŸããã¿ã¹ã¯ã·ã§ãŒããŒããããžã§ã¯ããããŒãžã£ãŒã§ããå Žåãã¡ãã·ã¥ã·ã§ãŒããŒã¯å®éã«ãžãªã¡ããªãæ§ç¯ããçç·Žãã建èšã¯ã«ãŒã§ãã
ã¯ãŒã¯ã°ã«ãŒãããã¡ãã·ã¥ã¬ãããž
ã¿ã¹ã¯ã·ã§ãŒããŒãšåæ§ã«ãã¡ãã·ã¥ã·ã§ãŒããŒã¯ã¹ã¬ããã®å調ã¯ãŒã¯ã°ã«ãŒããšããŠå®è¡ãããŸãããã®ã¯ãŒã¯ã°ã«ãŒãå šäœã®å ±éã®ç®æšã¯ãã¡ãã·ã¥ã¬ãããšåŒã°ããåäžã®å°ããªãžãªã¡ããªããããçæããããšã§ããã¡ãã·ã¥ã¬ããã¯ãåã«é ç¹ã®ã³ã¬ã¯ã·ã§ã³ãšããããæ¥ç¶ããããªããã£ãïŒäžè§åœ¢ïŒã§ããéåžžãã¡ãã·ã¥ã¬ããã«ã¯ãå°æ°ã®é ç¹ïŒäŸïŒæå€§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)
);
// ã¯ãŒã¯ã°ã«ãŒãå
ã®åã¹ã¬ããã«1ã€ã®é ç¹ãçæãããŸã
uint id = gl_LocalInvocationID.x;
if (id < vertexCount) {
vertices[id].position = u_modelViewProjectionMatrix * positions[id];
vertices[id].uv = uvs[id];
}
// æåã®2ã€ã®ã¹ã¬ããã«ãåè§åœ¢ã®2ã€ã®äžè§åœ¢ãçæãããŸã
if (id == 0) {
// æåã®äžè§åœ¢ïŒ0ã1ã2
gl_MeshPrimitivesEXT[0] = 0u;
gl_MeshPrimitivesEXT[1] = 1u;
gl_MeshPrimitivesEXT[2] = 2u;
}
if (id == 1) {
// 2çªç®ã®äžè§åœ¢ïŒ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`ïŒãã·ãŒããšããŠäœ¿çšããŠã1ã€ã®äžæã®å°ææã®é ç¹ãšäžè§åœ¢ãããã·ãŒãžã£ã«ã«çæããŸãã
ãã®çµæãå€§èŠæš¡ã§è€éãªã·ãŒã³ãã»ãŒå®å šã«GPUã§çæãããCPUã¯ç©çãAIãªã©ã®ä»ã®ã¿ã¹ã¯ãåŠçã§ããããã«ãªããŸãã
ãŠãŒã¹ã±ãŒã¹2ïŒå€§èŠæš¡ãªGPUé§åã®ã«ãªã³ã°
æ°çŸäžã®åã ã®ãªããžã§ã¯ããå«ã詳现ãªéœåžã®ã·ãŒã³ãæ€èšããŠãã ãããCPUã¯åãã¬ãŒã ã§ãã¹ãŠã®ãªããžã§ã¯ãã®å¯èŠæ§ããã§ãã¯ããããšã¯ã§ããŸããã
ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ãããŒïŒ
- CPUã¯ãã·ãŒã³å ã®ãã¹ãŠã®åäžãªããžã§ã¯ãã®å¢çããªã¥ãŒã ïŒäŸïŒçãŸãã¯ããã¯ã¹ïŒãå«ã倧ããªãããã¡ãŒãã¢ããããŒãããŸããããã¯1åã ãããŸãã¯ãªããžã§ã¯ããç§»åããå Žåã«ã®ã¿çºçããŸãã
- CPUã¯åäžã®ãããŒã³ãŒã«ãçºè¡ããå¢çããªã¥ãŒã ã®ãªã¹ãå šäœã䞊è¡ããŠåŠçããã®ã«ååãªæ°ã®ã¿ã¹ã¯ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããèµ·åããŸãã
- åã¿ã¹ã¯ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒãã«ã¯ãå¢çããªã¥ãŒã ãªã¹ãã®ãã£ã³ã¯ãå²ãåœãŠãããŸããå²ãåœãŠããããªããžã§ã¯ããå埩åŠçããããããã«å¯ŸããŠãã©ã¹ã¿ã ã«ãªã³ã°ïŒããã³æœåšçãªãªã¯ã«ãŒãžã§ã³ã«ãªã³ã°ïŒãå®è¡ãã衚瀺ãããŠãããªããžã§ã¯ãã®æ°ãã«ãŠã³ãããŸãã
- æåŸã«ããã®æ°ã®ã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒããæ£ç¢ºã«èµ·åããå¯èŠãªããžã§ã¯ãã®IDãæž¡ããŸãã
- åã¡ãã·ã¥ã·ã§ãŒããŒã¯ãŒã¯ã°ã«ãŒãã¯ãªããžã§ã¯ãIDãåä¿¡ãããããã¡ãŒããã¡ãã·ã¥ããŒã¿ãã«ãã¯ã¢ããããã¬ã³ããªã³ã°ã«å¯Ÿå¿ããã¡ãã·ã¥ã¬ãããçæããŸãã
ããã«ãããã«ãªã³ã°ããã»ã¹å šäœãGPUã«ç§»åããCPUããŒã¹ã®ã¢ãããŒããããã«éº»çºãããè€éãã®ã·ãŒã³ãå¯èœã«ãªããŸãã
ãŠãŒã¹ã±ãŒã¹3ïŒåçã§å¹ççãªã¬ãã«ãªããã£ããŒã«ïŒLODïŒ
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("Your browser or GPU does not support 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é§åã®ã¯ãŒã¯ããŒãã
çµè«ïŒWebäžã®ãªã¢ã«ã¿ã€ã ã°ã©ãã£ãã¯ã¹ã®æªæ¥ã¯ä»
ã¿ã¹ã¯å¢å¹ ãåããã¡ãã·ã¥ã·ã§ãŒããŒãã€ãã©ã€ã³ã¯ãéå»10幎éã§ãªã¢ã«ã¿ã€ã ã°ã©ãã£ãã¯ã¹ã«ãããæãéèŠãªé²æ©ã®1ã€ã衚ããŠããŸãã硬çŽããCPU管çã®ããã»ã¹ããæè»ãªGPUé§åã®ããã»ã¹ã«ãã©ãã€ã ãç§»è¡ããããšã«ããã幟äœåŠçè€éããšã·ãŒã³ã¹ã±ãŒã«ã«å¯Ÿãã以åã®éå£ãæã¡ç ŽããŸãã
ãã®ãã¯ãããžãŒã¯ãVulkanãDirectX 12 UltimateãMetalãªã©ã®ææ°ã®ã°ã©ãã£ãã¯ã¹APIã®æ¹åæ§ãšäžèŽããŠããããã¯ããã€ãšã³ããã€ãã£ãã¢ããªã±ãŒã·ã§ã³ã«éå®ãããŸãããWebGLãžã®ãã®ç»å Žã¯ããããŸã§ä»¥äžã«è©³çްã§ãã€ãããã¯ã§æ²¡å ¥åã®WebããŒã¹ã®äœéšã®æ°ããæä»£ã®æãéããŸãããã®æ°ããã¢ãã«ãåãå ¥ããææã®ããéçºè ã«ãšã£ãŠãåµé çãªå¯èœæ§ã¯äºå®äžç¡éã§ãããªã³ã¶ãã©ã€ã§å šäžçãçæããåã¯ãåããŠãæåéãWebãã©ãŠã¶å ã§ããªãã®æå ã«ãããŸãã