ä»æ¥ã¯ãè·é¢ãããïŒç¬Šå·ä»ãè·é¢ãã£ãŒã«ãïŒã䜿çšããç»åã®çæã«çŠç¹ãåœãŠãŸãã ãã®ã¿ã€ãã®ç»åã¯ãå®éã«ã¯ãããªã¢ã¯ã»ã©ã¬ãŒã¿ã§ããã¯ã¿ãŒãã°ã©ãã£ãã¯ãååŸã§ãããšããç¹ã§æ³šç®ã«å€ããŸãã Valveã¯ã2007幎ã«ã¹ã±ãŒã©ãã«ãã«ãŒã«çšã«Team Fortress 2ã§ãã®ã©ã¹ã¿ãŒåæ¹æ³ãæäŸããæåã®1ã€ã§ããã256x256ãã¯ã»ã«ã®ã¿ã®ãã¯ã¹ãã£ã䜿çšããŠåªããå質ã®ãã©ã³ããã¬ã³ããªã³ã°ã§ããŸããããŸã ããŸã人æ°ããããŸããã ãã®æ¹æ³ã¯ãææ°ã®é«è§£å床ç»é¢ã«æé©ã§ãã²ãŒã ã®ãã¯ã¹ãã£ã倧å¹
ã«ç¯çŽã§ããŸããããŒããŠã§ã¢ãå¿
èŠãšãããã¹ããŒããã©ã³ã§æé©ã«åäœããŸãã
ããªãã¯ã¯ãç¹å¥ã«æºåãããè·é¢ããããäœæããŠãæãåçŽãªã·ã§ãŒããŒã䜿çšããå Žåã«çæ³çãªãã¯ãã«å³ãåŸãããããã«ããããšã§ãã ããã«ãã·ã§ãŒããŒã®å©ããåããŠãã·ã£ããŠãã°ããŒãããªã¥ãŒã ãªã©ã®å¹æãåŸãããšãã§ããŸãã
ãã®ãããªç»åãäœæããæ¹æ³ã¯ïŒ
ImageMagickã䜿çšãããšã1ã€ã®ã³ãã³ãã§ãããå®è¡ã§ããŸãã
convert in.png -filter Jinc -resize 400% -threshold 30% \( +clone -negate -morphology Distance Euclidean -level 50%,-50% \) -morphology Distance Euclidean -compose Plus -composite -level 45%,55% -resize 25% out.png
ããã«çµæ¢ç¬Šãæã€ããšã¯ã§ããŸãããæ¬æ Œçãªãããã¯ã¯åŸãããŸããã ããŠãã«ããã®äž-é«éSDFèšç®ã¢ã«ãŽãªãºã ã®èª¬æãC ++ã®äŸãããã³OpenGLã®ããã€ãã®ã·ã§ãŒããŒã
ãã®åªæã¯äœã§ãããïŒ
ãã®æçš¿ã®æåã«ããæåã®ã³ãã³ãã¯ãçœé»ã®ã©ã¹ã¿ãŒã¢ãŠãã©ã€ã³ããSDFãçæããããã®ã¬ã·ãã§ãã ImageMagickã®æ°ããæ©èœã§ãã
Morphologyã«åºã¥ããŠããŸãã 圢æ
å€æã®äžã«ã¯
ãè·é¢ãããã®èšç®ããã
ãŸã ã
è·é¢ãããã®èšç®ã¯ãæãåçŽãªã¢ã«ãŽãªãºã ã§ãã ãã¯ã»ã«ãé»ãŸãã¯çœã®ã¢ãã¯ãç»åã§æ©èœããŸãã è²ã®1ã€ã¯å
éšè²ã§ããã1ã€ã¯å€éšè²ã§ãããšèããŸãïŒã奜ã¿ã§ããã®åçã®ããŒã¿ãŒã®é»ããã¯ã»ã«ã¯å
éšè²ã«ãªããŸãïŒã èæ¯è²ãåæ¯è²ãšåŒã°ããããšããããŸãã ç»åã®ãå
éšããã¯ã»ã«ããšã«ãæãè¿ããå€éšããã¯ã»ã«ãèŠã€ãããã®ãã¯ã»ã«ã®èŒåºŠå€ããæãè¿ããå€éšããã¯ã»ã«ãŸã§ã®
ãŠãŒã¯ãªããè·é¢ãšããŠèšå®ããå¿
èŠããããŸãã ã€ãŸããç»åã®ãã¹ãŠã®ãå€éšããã¯ã»ã«ãŸã§ã®è·é¢ãèšç®ããæå°ã®ãã¯ã»ã«ãéžæããå¿
èŠããããŸãã çµæãšããŠåŸãããè·é¢ãããã¯è·é¢ãã£ãŒã«ãïŒDFïŒãšåŒã°ããŸããããããŸã§ã®ãšããç§ãã¡ã«ã¯é©ããŠããŸããã SDFïŒSigned DFïŒãååŸããã«ã¯ãç»åãå転ããã¢ã«ãŽãªãºã ãç¹°ãè¿ããå床å転ããŠåã®çµæã«è¿œå ããŸãã
匷床å€ãè·é¢å€ã«æ£ç¢ºã«èšå®ããå¿
èŠã¯ãããŸãããå¿
èŠã«å¿ããŠããŒããããç»åãæ¡å€§çž®å°ã§ããŸãã ç¹ã«ãé®®æãªèŒªéã®ã¬ã³ããªã³ã°ã«ã¯ãŒããã®å°ãªããããã䜿çšããããšããå§ãããŸããã·ã£ããŠãã°ããŒãªã©ã®ç¹æ®å¹æã®å Žåã¯ãè·é¢ãããã倧ããããããšããå§ãããŸãã
ImageMagickã¯ãã®ãããªããããäœæããããã®æéãã€æãç°¡åãªæ¹æ³ã§ã¯ãããŸããããImageMagickã¯ã»ãšãã©ãã¹ãŠã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«ååšããéçºè
ãã¹ãã©ã€ãã®ãã€ãã©ã€ã³åŠçã«ãã䜿çšããããããããæè¯ã®ãªãã·ã§ã³ã ãšæããŸãã ã¹ã¯ãªãããå°ãå®æãããç»åçæãã¹ããªãŒã ã«é
眮ããã ãã§ååã§ãã
ä»çµã¿ãèŠãŠã¿ãŸãããã ã¢ã«ãã©ããžãŒæŒç®ãåã«ç»åã«é©çšããŠé©çšããã ãã§ã¯ãæè¯ã®çµæã¯åŸãããŸããã
convert nosdf.png -morphology Distance Euclidean sdf.png
ãã¬ãŽã£ããïŒ ãããã
å€éã«ç³çãçãã ã
ã§ãååãªã³ã³ãã©ã¹ã
ã¯ãããŸããã
-auto-level
ãã©ã¡ãŒã¿ãŒã䜿çšãããšãããã«åŒãåºãããšãã§ããŸãã
convert nosdf.png -morphology Distance Euclidean -auto-level sdf.png
æ¬ é¥ã¯ããã«æããã«ãªããŸããè·é¢ãããã¯å€éšããã®ã¿çæãããŸãã ããã¯ãã¢ã«ãŽãªãºã èªäœã2ãã¹ã§ãããšããäºå®ã®çµæã§ãããã¬ãã£ãã«ã€ããŠãåãããšãç¹°ãè¿ããŸãã
convert nosdf.png -negate -morphology Distance Euclidean -auto-level sdf.png
ä»å察ã®ç¶æ³-å€ã«ååãªã«ãŒãããããŸããã
äžéå±€ã䜿çšããŠãããã®2ã€ã®ã¢ã«ãŽãªãºã ãçµã¿åãããã³ã³ãã©ã¹ãã匷åããæçš¿ã®æåããççãªã¹ã¯ãªãããååŸããããšãæ®ã£ãŠããŸãã
convert in.png -filter Jinc -resize 400% -threshold 30% \( +clone -negate -morphology Distance Euclidean -level 50%,-50% \) -morphology Distance Euclidean -compose Plus -composite -level 45%,55% -resize 25% out.png
ããã€ãã®èª¬æïŒ
-resize 400%
-å
ã®ç»åãå¢ãããŠãããããã®ãšããžãé€å»ããŸãã ãã®ã¢ã«ãŽãªãºã ã¯çœé»ç»åã«å¯ŸããŠã®ã¿æ©èœããå°ãªããšãäœããã®åœ¢ã§ã¢ã³ããšã€ãªã¢ã¹ãæ€èšããããšæããŸãã ãã ãããªãªãžãã«ã4å以äžæå
ã«çœ®ãããšãåžžã«ãå§ãããŸãã ããšãã°ãValveã¯ããã¢çšã«4Kã€ã¡ãŒãžã䜿çšãããããã64x64 SDFãåãåããŸãã ãã¡ãããããã¯ãã§ã«å€ãããŸãã 8ïŒ1ã®æ¯çã蚱容ç¯å²å
ã§ããããšãããããŸããã
-
-level 45%,55%
-è·é¢ãããã®ãŒããã®åºŠåãã調æŽã§ããŸããããã©ã«ãã§ã¯ããã§ã«éåžžã«ãããŸãã§ãã
-filter Jinc
ããã³
-threshold 30%
-å®éšçã«ããã®ãã£ã«ã¿ãŒãšãããå€ã¯å
ã®ç»åã«æé©ã§ãã ãã¿ãã¬ã®äžã§ã確èªããã人ã®ããã®ã¹ã¯ãªãããšãœãŒã¹ã
æé«ã®PSNRã¡ããªãã¯ãèŠã€ããããã®ã¹ã¯ãªããåœç¶ãçã®ãªãã·ã§ã³ã¯ååšããŸããããJincãæãå¹³åçãªãªãã·ã§ã³ãšããŠ30ïŒ
æ®ãã蚱容ã§ããçµæãåŸãŸããã
ç»åïŒ
ã¹ã¯ãªããïŒ
ããŠãããé«ã解å床ã®ãªãªãžãã«ãããå ŽåããºãŒã ã€ã³ããŠããªãã¯ã䜿ããã«ããã§ã«å°ããåŽã«ã®ã¿ã¹ã±ãŒãªã³ã°ããããšãã§ããŸãïŒ
convert in.png -threshold 50% \( +clone -negate -morphology Distance Euclidean -level 50%,-50% \) -morphology Distance Euclidean -compose Plus -composite -level 45%,55% -filter Jinc -resize 10% out.png
Jincãã£ã«ã¿ãŒã¯ããããã®ãµã€ãºãçž®å°ããªãããµã³ããªã³ã°ã®å質ãåäžãããããšãç®çãšããŠããããããã§ãŒã³ã®æåŸã«ã移åãããããšã«æ³šæããŠãã ããã ãŸãã
-threshold 50%
åé€ããªãã§ãã ãã-ãŠãŒã¯ãªããã¯ãéã¢ãã¯ãç»åã§ã¯æ£ããæ©èœããŸããã
è°è«ã®äœå°ã®ããåé¡ ã
ã³ã³ãã©ã¹ããã䌞ã°ããããšã¯çã«ããªã£ãŠããŸããïŒ äžè¬ã«ãçè«çã«ã¯ãã³ã³ãã©ã¹ããå¢å ãããšããµã³ãã«ã®ãã«ã¿ãå¢å ããããããããŒããŠã§ã¢è£éæ³ã䜿çšããŠã¢ã³ããšã€ãªã¢ã¹ãèšç®ãããŸãã èŠããã«ãç¹ã«æ確ã§æ»ãããªèŒªéãšåœ±ã®ãããªå¹æã¯ããã»ã©éèŠã§ã¯ãªãå Žåãã¹ãã¬ããããå¿
èŠããããŸãã å
ã®ã«ãŒãã䌞ã³ãã ãã§ãªãçž®ãå Žåã¯ãããŸãæã¡ãããªãããã«ããŠãã ãããããããªããšãç»åãçž®å°ãããšãSDFã®ãŒããããšããžã®ããã«ã¢ã³ããšã€ãªã¢ã¹ãæªåããŸãã
å質ã¯SDFã«ãŒãã®è§£å床ã«ã©ã®ããã«äŸåããŸããïŒ PSNRããããã®è§£å床ãšã³ã³ãã©ã¹ãã«å¯ŸããŠããããããããšããŸããã äžè¬ã«ãå質ã¯åäžããŸãããããã§ãã«ãŒãã®ã³ã³ãã©ã¹ãã«äŸåããŸãã ãã£ãŒãã®äŸåé¢ä¿ãè©äŸ¡ã§ããŸãã
ããã§ãã¹ã±ãŒã«ã¯ãœãŒã¹ãã¬ãã«ã®ããŒã»ã³ããŒãžãšããŠã®ã¹ã±ãŒã«ã§ã-ã³ã³ãã©ã¹ããã©ãã ããåŒã䌞ã°ãããããã ã¹ã±ãŒã«ãžã®äŸåæ§ã¯ããŸãç·åœ¢ã§ã¯ãªãã30ïŒ
ãéåžžã«åŠ¥åçãªãªãã·ã§ã³ã§ãããã³ã³ãã©ã¹ãã茪éã®å質ã«ããªã匷ã圱é¿ãããšçµè«ä»ããããšãã§ããŸãã
ãŠãŒã¯ãªãããã£ã«ã¿ãŒã®ãµã€ãºã¯å質ã«ã©ã®çšåºŠåœ±é¿ããŸããïŒ ãã£ã«ã¿ãŒãµã€ãºã倧ãããããšã0.1 dB +ã®å¢å ã«ãªããŸããããã¯ãç§ã®æèŠã§ã¯éèŠã§ã¯ãããŸããã
å
ã®ç»åãã©ãã ããçž®å°ãã§ããŸããïŒ åœ¢ç¶ã«å€§ããäŸåããŸãã SDFã¯éãè§ã奜ãã§ã¯ãªãããã®äŸã®ããŒã¿ãŒã®ãããªæ»ãããªçµµã¯ããããã¥ã¢ã¹ã±ãŒã«ã§ãçŽ æŽãããæããããŸãã
C ++ã§ã®é«éã¢ã«ãŽãªãºã ã®å®è£
ã¢ã«ãŽãªãºã ã¯åçŽã§ããããã®ãé¡ãã®å®è£
ã¯æ°æéæ©èœããŸããå®éãåãã¯ã»ã«ã®ç»åå
šäœãã¹ãã£ã³ããå¿
èŠããããŸãã OïŒN ^ 2ïŒã¯ãç§ãã¡ã«ã¯ãŸã£ããé©ããŠããŸããã ããããé ã®ãã人ãã¡ã¯ãOïŒNïŒã§æ©èœããæ£ç¢ºãªïŒïŒïŒDFèšç®ã®ããã®ã¢ã«ãŽãªãºã ããã§ã«èããæãã€ããŠããŸãã ã¿ã¹ã¯ãSDFã«æ¡åŒµããããšã¯ãéåžžã«ç°¡åã§ãïŒåã®äŸãåç
§ïŒã
äžçªäžã®è¡ã åãã¯ã»ã«ã®è·é¢ãã«ãŠã³ããã代ããã«ãç¹å®ã®æ¡ä»¶äžã§åçŽã«è·é¢ãå¢ãããªãããç»åã2åé£ç¶ããŠééããŸãã ããã¯ãé«éã®Box-Blurã¢ã«ãŽãªãºã ãé£æ³ãããŸãã Matanã¯[2]ããåéã§ããŸãããæã§èª¬æããããšããŸãã
ãã¯ã»ã«pããå
ã®ç»åã§æ§æãããé
åN * Mã®èŠçŽ ãšåŒã³ãŸãã ãã¯ã»ã«ã¯æ¬¡ã®æ§é ã§ãã
{ x, y - f - }
ã芧ã®ãšãããæãããªã©ã«ã€ããŠã¯äœããããŸããã -ããã¯å¿
èŠãããŸããã é
åã¯æ¬¡ã®ããã«åœ¢æãããŸãã
å
ã®ç»åã®ãã¯ã»ã«ãæããå Žåã
x = y = 9999 f = 9999 * 9999
å
ã®ç»åã®ãã¯ã»ã«ãæãå Žåã
x = y = f = 0
åãã¯ã»ã«ã«ã¯8ã€ã®è¿åãããã次ã®ããã«çªå·ãä»ããŸãã
2 3 4 1 p 5 8 7 6
次ã«ã2ã€ã®è£å©æ©èœã玹ä»ããŸãã é¢æ°hã¯ããã¯ã»ã«ãšé£æ¥ãã¯ã»ã«éã®ãŠãŒã¯ãªããè·é¢ãèšç®ããããã«å¿
èŠã§ããé¢æ°Gã¯ãã³ã³ããŒãã³ãéã®æ°ããè·é¢å€ãèšç®ããããã«äœ¿çšãããŸãã
h(p, q) { if q - 1 5 {return 2 * qx + 1} if q - 3 7 {return 2 * qy + 1} {return 2 * (qx + qy + 1)} }
G(p, q) { if q - 1 5 {return (1, 0)} if q - 3 7 {return (0, 1)} {return (1, 1)} }
æåã®ãã¹ ã ãã®ããã»ãŒãžã¯ãç»åã®å·Šäžããå³äžã«åãã£ãŠé çªã«å®è¡ãããŸãã æ¬äŒŒã³ãŒãïŒ
p { q 1 4 { if (h(p, q) + qf < pf) { pf = h(p, q) + qf (px, py) = (qx + qy) + G(p, q) } } }
ã»ã«ã³ããã¹ ã ãã®ãã¹ã¯éã®é åºã§å®è¡ãããŸãïŒç»åã®å³äžããå·ŠäžãžïŒã æ¬äŒŒã³ãŒãïŒ
p { q 5 8 { if (h(p, q) + qf < pf) { pf = h(p, q) + qf (px, py) = (qx + qy) + G(p, q) } } }
å
ã®ç»åã®ãã¬ã«å¯ŸããŠã¢ã«ãŽãªãºã ãç¹°ãè¿ãå¿
èŠããããŸãã 次ã«ãåãåã£ã2æã®ã«ãŒãã«ã€ããŠãæçµçãªè·é¢ã®èšç®ãšæžç®ãè¡ã£ãŠã2æã®DFã«ãŒãã1ã€ã®SDFã«çµåããå¿
èŠããããŸãã
d1 = sqrt(p1.f + 1); d2 = sqrt(p2.f + 1); d = d1 - d2;
æåã«ãæ§é å
ã§ãŠãŒã¯ãªããè·é¢ã®æ£æ¹åœ¢ãç¶æãããããã«ãŒããç 磚ããå¿
èŠããããŸãã ãªãè¿œå ããå¿
èŠãããã®ã§ããïŒè³ªåããªãã§ãã ãããçµæã¯çµéšçã§ãæ²ãã£ãŠããªãå ŽåããããŸã:)æçµçãªSDFã«ãŒãã¯ãæåãã2çªç®ãåŒããçµæã§ãããã®åŸãå¿
èŠã«å¿ããŠå€ãã¹ã±ãŒãªã³ã°ããå¿
èŠããããŸãã
ç§ã®æèŠã§ã¯ããããã©ã®ããã«æ©èœããããæã§èª¬æããããšããŠãéåžžã«æ··ä¹±ããŠããããã«èŠããã®ã§ãC ++ã§ãœãŒã¹ã³ãŒããæäŸããŸãã å
¥åç»åãšããŠãããã»ã¹ã®å¯èŠæ§ãæãªããªãããã«ãQtã®QImageã䜿çšããŸããã ãœãŒã¹ã¯ãœãŒã¹[3]ã«åºã¥ããŠããŸããããã°ããããŸãã
ãœãŒã¹ã³ãŒã #include <QPainter> #include <stdio.h> #include <math.h> struct Point { short dx, dy; int f; }; struct Grid { int w, h; Point *grid; }; Point pointInside = { 0, 0, 0 }; Point pointEmpty = { 9999, 9999, 9999*9999 }; Grid grid[2]; static inline Point Get(Grid &g, int x, int y) { return g.grid[y * (gw + 2) + x]; } static inline void Put(Grid &g, int x, int y, const Point &p) { g.grid[y * (gw + 2) + x] = p; } static inline void Compare(Grid &g, Point &p, int x, int y, int offsetx, int offsety) { int add; Point other = Get(g, x + offsetx, y + offsety); if(offsety == 0) { add = 2 * other.dx + 1; } else if(offsetx == 0) { add = 2 * other.dy + 1; } else { add = 2 * (other.dy + other.dx + 1); } other.f += add; if (other.f < pf) { pf = other.f; if(offsety == 0) { p.dx = other.dx + 1; p.dy = other.dy; } else if(offsetx == 0) { p.dy = other.dy + 1; p.dx = other.dx; } else { p.dy = other.dy + 1; p.dx = other.dx + 1; } } } static void GenerateSDF(Grid &g) { for (int y = 1; y <= gh; y++) { for (int x = 1; x <= gw; x++) { Point p = Get(g, x, y); Compare(g, p, x, y, -1, 0); Compare(g, p, x, y, 0, -1); Compare(g, p, x, y, -1, -1); Compare(g, p, x, y, 1, -1); Put(g, x, y, p); } } for(int y = gh; y > 0; y--) { for(int x = gw; x > 0; x--) { Point p = Get(g, x, y); Compare(g, p, x, y, 1, 0); Compare(g, p, x, y, 0, 1); Compare(g, p, x, y, -1, 1); Compare(g, p, x, y, 1, 1); Put(g, x, y, p); } } } static void dfcalculate(QImage *img, int distanceFieldScale) { int x, y; int w = img->width(), h = img->height(); grid[0].w = grid[1].w = w; grid[0].h = grid[1].h = h; grid[0].grid = (Point*)malloc(sizeof(Point) * (w + 2) * (h + 2)); grid[1].grid = (Point*)malloc(sizeof(Point) * (w + 2) * (h + 2)); /* create 1-pixel gap */ for(x = 0; x < w + 2; x++) { Put(grid[0], x, 0, pointInside); Put(grid[1], x, 0, pointEmpty); } for(y = 1; y <= h; y++) { Put(grid[0], 0, y, pointInside); Put(grid[1], 0, y, pointEmpty); for(x = 1; x <= w; x++) { if(qGreen(img->pixel(x - 1, y - 1)) > 128) { Put(grid[0], x, y, pointEmpty); Put(grid[1], x, y, pointInside); } else { Put(grid[0], x, y, pointInside); Put(grid[1], x, y, pointEmpty); } } Put(grid[0], w + 1, y, pointInside); Put(grid[1], w + 1, y, pointEmpty); } for(x = 0; x < w + 2; x++) { Put(grid[0], x, h + 1, pointInside); Put(grid[1], x, h + 1, pointEmpty); } GenerateSDF(grid[0]); GenerateSDF(grid[1]); for(y = 1; y <= h; y++) for(x = 1; x <= w; x++) { double dist1 = sqrt((double)(Get(grid[0], x, y).f + 1)); double dist2 = sqrt((double)(Get(grid[1], x, y).f + 1)); double dist = dist1 - dist2; // Clamp and scale int c = dist * 64 / distanceFieldScale + 128; if(c < 0) c = 0; if(c > 255) c = 255; img->setPixel(x - 1, y - 1, qRgb(c,c,c)); } free(grid[0].grid); free(grid[1].grid); }
ããã§ã¯ãäž¡æ¹ã®ãã¹ã§1ãã¯ã»ã«å¹
ã®ããŠã£ã³ããŠãã䜿çšãããããå
ã®ç»åã®åšå²ã«1ãã¯ã»ã«ã®å¢çç·ãè¿œå ããŠãå¢çç·ããã§ãã¯ããªãããã«ããŸãã è² ã®å Žåãå¢çãå察ã®å€ã«å€æŽããå¿
èŠããããŸãããããã¯[3]ã§èæ
®ãããŠããŸããã§ããã
å®å
šã«æ©èœããã¢ã«ãŽãªãºã ã¯ããªãŒãã³ãœãŒã¹ã®ã©ã¹ã¿ãŒãã©ã³ããžã§ãã¬ãŒã¿ãŒ
UBFGã«ãããŸãã çµæã®äŸïŒ
ã·ã£ããªã
ïŒSDFããã©ã¹ã¿ãŒã³ã³ã¿ãŒãžã®ïŒéå€æã®èãæ¹ã¯ããŒããããšããžãèŠããªããªãçšåºŠã«ã³ã³ãã©ã¹ããäžããããšã«åºã¥ããŠããŸãã SDFã®ã³ã³ãã©ã¹ããå€æŽãããšãããŸããŸãªå¹æãåŸãããšãã§ããç»åã®ã¢ã³ããšã€ãªã¢ã¹ã®å質ã調æŽã§ããŸãã äŸãšããŠããœãŒã¹ãåãäžããŸãã
ãããSDFã§ãããéåžžã«å§çž®ããããµã€ãºãå°ãããªã£ãŠããŸãã 16åã«å¢ãããŸãããã
ããŠãçŸãã茪éãåŸãã«ã¯ãã³ã³ãã©ã¹ããäžããŸãã ãããã®ç®çã§GIMPã䜿çšããŸããã
SDFããªã¢ã«ã¿ã€ã ã§äœ¿çšããçµæã確èªããã«ã¯ãã·ã§ãŒããŒãäžå¯æ¬ ã§ãã æãåçŽãªã¢ã«ãã¡ãã¹ãã䜿çšã§ããŸããããã®ã«ãŒãã§ã¢ã³ããšã€ãªã¢ã¹ãã«ããããŸãã ãã ãã䜿çšãããã·ã§ãŒããŒã¯ã»ãã®2ã3ã®åœä»€ã§ãããå®éã«ã¯ããã©ãŒãã³ã¹ã«ã¯åœ±é¿ããŸããã ããã«ãã·ã§ãŒããŒã¯çŸåšå®äŸ¡ã§ãããã¡ã¢ãª/ãã£ãã·ã¥ã¯é«äŸ¡ã§ããããšãèæ
®ãããšããããªã¡ã¢ãªãç¯çŽããããšã«ãããé«éåãå®çŸã§ããŸãã
次ã«ããã®ããžãã¹ãOpenGLã§äœ¿çšããæ¹æ³ãèŠãŠã¿ãŸãããã ãã¹ãŠã®äŸã¯ãçŽç²ãªGLSLãœãŒã¹ã³ãŒããšããŠæäŸãããŸãã ä»»æã®ã·ã§ãŒããŒãšãã£ã¿ãŒã§è©Šãããšãã§ããŸãã ãã¯ã¹ãã£ãããŒãã§ããå¯äžã®ãšãã£ã¿ãŒã§ããããã
Kick.jsãšãã£ã¿ãŒã§ãã¹ãŠã®äŸããã¹ãããŸããã
æãç°¡åãªã¯ã€ãã¯ãªãã·ã§ã³
precision highp float; uniform sampler2D tex; const float contrast = 40.; void main(void) { vec3 c = texture2D(tex,gl_FragCoord.xy/vec2(256., 128.)*.3).xxx; gl_FragColor = vec4((c-0.5)*contrast,1.0); }
ããã§ã¯ãå¹³åå€ïŒ0.5ïŒã«å¯Ÿããã³ã³ãã©ã¹ããæç»ããŸãã ã³ã³ãã©ã¹ãã®åŒ·ãã¯ããã¯ã¹ãã£ã®ã¹ã±ãŒã«ãšDFãããã®ã¹ãã¢ã«ãã£ãŠç°ãªããŸãããã©ã¡ãŒã¿ã¯å®éšçã«éžæãããã¹ã±ãŒã«ä¿æ°ã䜿çšããŠåäžã«èšå®ãããŸãã
smoothstep
ãã£ã«ã¿ãŒã䜿çšãããšãå質ããããã«æ¹åã§ããŸãã
precision highp float; uniform sampler2D tex; const float threshold = .01; void main(void) { vec3 c = texture2D(tex,gl_FragCoord.xy/vec2(256., 128.)*.3).xxx; vec3 res = smoothstep(.5-threshold, .5+threshold, c); gl_FragColor = vec4(res,1.0); }
ããã§ããããå€ãéžæããå¿
èŠããããŸãã
smoothstep
å€ãã°ã©ãã£ãã¯ã«ãŒããæºåž¯é»è©±ã§
smoothstep
å°ãé
ããªããŸãã
ã¢ãŠãã©ã€ã³å¹æ
ãã®å¹æãåŸãã«ã¯ã2ã€ã®ãããå€ãååŸããè²ãå転ããå¿
èŠããããŸãã
precision highp float; uniform sampler2D tex; const float contrast = 20.; void main(void) { vec3 c = texture2D(tex,gl_FragCoord.xy/vec2(256., 128.)*.35).xxx; vec3 c1 = (c-.45) * contrast; vec3 c2 = 1.-(c-.5) * contrast; vec3 res = mix(c1, c2, (c-.5)*contrast); gl_FragColor = vec4(res,1.0); }
çµæïŒ
ã°ããŒãšã·ã£ããŠå¹æ
åã®äŸãå°ãpohimichit-ç§ãã¡ã¯ã°ããŒå¹æãååŸããŸãïŒ
precision highp float; uniform sampler2D tex; const float contrast = 20.; const float glow = 2.; void main(void) { vec3 c = texture2D(tex,gl_FragCoord.xy/vec2(256., 128.)*.35).xxx; vec3 c1 = clamp((c-.5)*contrast,0.,1.); vec3 c2 = clamp(1.-(c-.5)/glow, 0., 1.); vec3 res = 1.-mix(c1, c2, (c-.5)*contrast); gl_FragColor = vec4(res,1.0); }
圱ãä»ããã«ã¯ããªãã»ããä»ãã®ã°ããŒã®è²ã䜿çšããå¿
èŠããããŸãã
precision highp float; uniform sampler2D tex; const float contrast = 20.; const float glow = 2.; void main(void) { vec3 c = texture2D(tex,gl_FragCoord.xy/vec2(256., 128.)*.35).xxx; vec3 gc = texture2D(tex,gl_FragCoord.xy/vec2(256., 128.)*.35 + vec2(-0.02,0.02)).xxx; vec3 c1 = clamp((c-.5)*contrast,0.,1.); vec3 c2 = clamp(1.-(gc-.5)/glow, 0., 1.); vec3 res = 1.-mix(c1, c2, (c-.5)*contrast); gl_FragColor = vec4(res,1.0); }
çµæïŒ
çµæã¯ããã»ã©æãèŠããªããããããŸããããããã¯å°ãããããããã䜿çšããããã§ãã
åç
§è³æ
[1]
ãã¯ãã«ãã¯ã¹ãã£ãšç¹æ®å¹æã®ã¢ã«ãã¡ãã¹ãæ¡å€§ã®æ¹åã¯ãValveã®èšäºãšåãã§ãã
[2]
ãã©ã³ã¯ã»Yã»ã·ãŒãã€ãŒã»ã¿ã»ãŠãŒã 3x3è¿åã䜿çšãã2åã®ã¹ãã£ã³ã§ã®ãŠãŒã¯ãªããè·é¢ã®é«éå€æ -äžåœèªïŒ ãããããã ã®ãã¥ãŒãžã£ãŒãžãŒå€§åŠã§ãã
[3]
www.codersnotes.com/notes/signed-distance-fields-ãããããªãé«éãªã¢ã«ãŽãªãºã ã§ãããæ®å¿µãªãããã®äœæè
ã¯ããã€ãã®ãšã©ãŒãèµ·ãããä¹ç®ãååšããŸããããã¯ããã®èšäºã§ç€ºããã¢ã«ãŽãªãºã ãããããã«é
ãã§ãã
[4]
contourtextures.wikidot.comã¯SDFèšç®ã®å¥ã®å®è£
ã§ããããã®å©ç¹ã¯ãšããžã®ã¹ã ãŒãžã³ã°ãèæ
®ããŠæãè¿ããã€ã³ãã決å®ã§ããããšã§ãã ããã©ãŒãã³ã¹ã«ã€ããŠã¯äœãèšãããŠããŸããããé«è§£å床ã®ãªãªãžãã«ãå
¥æããæ¹æ³ããªãå Žåã¯è¯ãããšã§ãïŒäžæ¹ã§ãé«çŽãªããªãã¯ãè¡ãããšãã§ããŸãïŒã ããªããããã䜿çšããçµéšãããå Žåã¯ãã³ã¡ã³ãã§éäŒããŸãã
[5]
gpuhacks.wordpress.com/2013/07/08/signed-distance-field-rendering-of-color-bit-planes-ã«ã©ãŒãã¯ãã«ç»åãã¬ã³ããªã³ã°ããæ¹æ³ïŒå°æ°ã®è²ã«é©ããŠããŸãïŒã
[6]
distance.sourceforge.netã¯ãããŸããŸãªSDFèšç®ã¢ã«ãŽãªãºã ãæ¯èŒãããèå³æ·±ããªãœãŒã¹ã§ãã
upd ã Bas1lã«ããçºèšã®ãããã§ãã¢ã«ãŽãªãºã ã¯ãŸã å®å
šã«æ£ç¢ºã§ã¯ãªãã蚌æã®ãšã©ãŒã«ãããæè¿åãŸã§ã®è·é¢ã®èšç®ã«ãšã©ãŒãäžããå¯èœæ§ããããŸãã
ãã®èšäºã§ã¯ãã¢ã«ãŽãªãºã ã®æ¹è¯çã玹ä»ããŸãã
upd2 ãŠãŒã¶ãŒachkasovããã·ã§ãŒããŒã«é¢ããã³ã¡ã³ãã çªç¶ã®ç§»è¡ãçºçããå ŽåãSDFã«ãŒãã«èåãšäžåäžãªã¢ã³ããšã€ãªã¢ã·ã³ã°ãçŸããããšããããŸãã å¹æãšãã®å¯ŸåŠæ¹æ³ã®è©³çŽ°ïŒ
iquilezles.org/www/articles/distance/distance.htmã·ã§ãŒããŒãå€æŽãããšããšãªã¢ããã ãããŒã«ã倧å¹
ã«æ¹åãããŸãã
GLSLã³ãŒã precision highp float; uniform sampler2D tex; const float contrast = 2.; float f(vec2 p) { return texture2D(tex,p).x - 0.5; } vec2 grad(vec2 p) { vec2 h = vec2( 4./256.0, 0.0 ); return vec2( f(p+h.xy) - f(ph.xy), f(p+h.yx) - f(ph.yx) )/(2.0*hx); } void main(void) { vec2 p = gl_FragCoord.xy/vec2(256., 128.)*.35; //float c = texture2D(tex,p).x; float v = f(p); vec2 g = grad(p); float c = (v)/length(g); float res = c * 300.; gl_FragColor = vec4(res,res,res, 1.0); }