Bozeå ¥é
ãã®è¨äºã¯Boze Advent Calendar 2020ã®ï¼æ¥ç®ã®è¨äºã§ãï¼é ããªã£ã¦ç³ã訳ããã¾ããï¼
https://qiita.com/advent-calendar/2020/boze2020
åæ¥ã¯ããªãªã¸ãã«ã®ä¸æ¥å主ããã®ãBozeã£ã¦ä½ï¼ãã§ããã
ã¨ã¦ãå²å¦çã§è¯ãè¨äºã§ãããã
åæ¥ã®è¨äºã§"Boze"ãä½ãããã£ãã¨æãã¾ãã®ã§ãä»åã¯ããå®è·µçãª"Boze"ã«ã¤ãã¦æ¸ãã¦ã¿ããã¨æãã¾ãã
unity é²æ©tiktok ã§ãããã§ããâ¨â¨â¨
— ä¸æ¥å主⨠(@mikkabouzu777) 2018å¹´7æ5æ¥
ã¢ãã¡ã¼ã·ã§ã³ã®ãã¼æä½ã§ããã§ãããã§ããâ¨â¨
ãã¨ãã¹ã¯ãªãããåãã¦å¼ã£ãã§ãâ¦â¨â¨é£ããã§ãâ¦â¨â¨
ããã¿ã¼ãã¼ãã£ã¼ãã¼ããâ¨â¨â¨(å¤ã£ã½ãð) pic.twitter.com/Tycjm3aXoC
Bozeå ¥é
ç§ã®"Boze"ã¯ãã¬ã¤ãã¼ãã³ã°ãç¨ãã"Boze"ã§ãã
æ©éã§ãããæä½éã®ã¬ã¤ãã¼ãã³ã°ã«ãã"Boze"ã®ãµã³ãã«ã§ãã
neort.io
æä½éã§ãããçµæ§ãªé·ããããã®ã§ãè¦ç¹é¨åã ãæç²ãã¦è§£èª¬ãã¾ãã
ã¬ã¤ãã¼ãã³ã°ã¨ã¯
ã¬ã¤ãã¼ãã³ã°ã¨ã¯ããã®åã®éããã¬ã¤ï¼å ï¼ããã¼ãã³ã°ï¼è¡é²ï¼ããã¦ã¬ã³ããªã³ã°ããææ³ã§ãã
â親ã®é¡ããè¦ãã¬ã¤ãã¼ãã³ã°ã®å³
ã¬ã¤ã¯ãåå³å½¢ã®è·é¢é¢æ°ããã¬ã¤ã¨ã®è·é¢ãè¨ç®ãããã®è·é¢ã®é·ãã ãã¬ã¤ãé²ãã¦ãå度è·é¢ãæ±ãã¦â¦ã¨ããã®ãç¹°ãè¿ãã¦ããæãã§ãã
è·é¢ããã®ãããå°ãããªã£ããå³å½¢ã«æ¥è§¦ãã¦ããã¨å¤æãã¾ãã
ã½ã¼ã¹ä¸ã§ã¯ãtraceRayãããã«ãããã¾ãã
// è·é¢é¢æ°ããããã³ã°ããå¦çï¼ç©ºéã®ä¸å¿ã«Bozeãããã ãï¼ surface map(vec3 p) { surface result = SURF_NOHIT(1e5); float ms = sin(iTime) * 0.5 + 0.5; // boze surface boze = sdBoze(p, vec3(1), ms); result = opU(result, boze); return result; } // ã¬ã¤ãé²ã¾ããå¦ç surface traceRay(in vec3 origin, in vec3 direction, float dist, out vec3 pos) { float t = 0.0; pos = origin; int count = 0; surface hit; float d; for (int i = 0; i < MAX_MARCH; i++) { hit = map(pos); d = hit.dist; if (d <= EPS || d >= MAX_DIST) { break; } t += d; pos = origin + direction * t; count++; } hit.dist = t; hit.count = count; pos = origin + direction * t; if(hit.isHit) { // Lighting vec3 normal = norm(pos); vec3 lightDir = normalize(vec3(cos(iTime), 1, sin(iTime))); vec3 lightColor = vec3(1.5); float NoL = saturate(dot(normal, lightDir)); vec3 ambientColor = vec3(0.1); hit.albedo.rgb *= NoL * lightColor + ambientColor; } if(d <= EPS){ hit.isHit = true; return hit; }else{ hit.isHit = false; return hit; } } // ã¬ã¤ãé²ã¾ãã¦ãå³å½¢ã¨è¡çªãã¦ãªãã£ããèæ¯è²ã«ããå¦ç vec3 render(vec3 p, vec3 ray, vec2 uv) { vec3 pos; surface mat = traceRay(p, ray, 0., pos); vec3 col = vec3(0,0,0); vec3 sky = vec3(0.3); col = mat.isHit ? mat.albedo.rgb : sky; return col; }
ã¬ã¤ãå³å½¢ã«æ¥è§¦ããããå³å½¢ã®è¡¨é¢ã®è²ãåå¾ããå¿
è¦ãããã¾ããã"Boze"ã®å ´åãèãç®ãå£ã¨ããããè²ãéãã¾ãã
ãã®ãããåå³å½¢ããè·é¢ãåå¾ããã¨ãã«ãä¸ç·ã«è²ãè¿ãããã«æ»ãå¤ãæ§é ä½ã«ãã¦ãã¾ãã
// è·é¢é¢æ°ããã®æ å ±ãæ ¼ç´ããæ§é ä½ struct surface { float dist; // è·é¢ vec4 albedo; // è² int count; // é²ãã åæ° bool isHit; // è¡çªãã©ã° };
Bozeã®æ§æè¦ç´
"Boze"ã¯ãåºæ¬çãªè·é¢é¢æ°ã®çµã¿åããã§ã§ãã¦ãã¾ãã
ä¸è¨ã«"Boze"ã§ä½¿ã£ã¦ããåºæ¬çãªè·é¢é¢æ°ä¸è¦§ãç´¹ä»ãã¾ãã
sdCappedTorusï¼æ¬ ãããã¼ã©ã¹ï¼ãªã³ã°ï¼
float sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb) { p.x = abs(p.x); float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy); return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb; }
sdEllipsoidï¼æ¥åç
float sdEllipsoid( vec3 p, vec3 r ) { float k0 = length(p/r); float k1 = length(p/(r*r)); return k0*(k0-1.0)/k1; }
sdCapsuleï¼ã«ãã»ã«
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) { vec3 pa = p - a, ba = b - a; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); return length(pa - ba*h) - r; }
sdRoundBoxï¼è§ä¸¸ç«æ¹ä½
float sdRoundBox(vec3 p, vec3 size, float r) { return length(max(abs(p) - size * 0.5, 0.0)) - r; }
sdRoundedCylinderï¼è§ä¸¸åæ±
float sdRoundedCylinder( vec3 p, float ra, float rb, float h ) { vec2 d = vec2( length(p.xz)-2.0*ra+rb, abs(p.y) - h ); return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rb; }
ç»ååºå ¸ï¼ distance functions by iq www.iquilezles.org
"Boze"ã®åãã¼ã
é é¨
ãªããããªå¸åã®é é¨ã¯ãã«ãã»ã«ã¨è§ä¸¸åæ±ãèåããã¦ä½ã£ã¦ãã¾ãã ä¸é¨ãã«ãã»ã«ã§ãä¸é¨ãè§ä¸¸åæ±ã§ãã
// head float d = sdCapsule(p, vec3(0,0.05,0), vec3(0, 0.11, 0), 0.125); float d1 = sdRoundedCylinder(p + vec3(0,0.025,0), 0.095, 0.05, 0.0); d = smin(d, d1, 0.1);
ï¼ã¤ã®å³å½¢ãSmooth minã¨ãããªãããã«è£å®ããé¢æ°ã使ã£ã¦èåããã¦ãã¾ãã
float smin( float d1, float d2, float k ) { float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 ); return mix( d2, d1, h ) - k*h*(1.0-h); }
è³
è³ã¯ãæ¬ ãããã¼ã©ã¹ãï¼ï¼åº¦ã»ã©å¾ãã¦ä½ã£ã¦ãã¾ãã
float sdEar(vec3 p) { p = rotate(p, RAD90+0.25, vec3(0,0,1)); return sdCappedTorus(p + vec3(0.05, 0.175, 0), vec2(sin(0.7),cos(0.7)), 0.03, 0.01); }
ã¾ããé¡ã®ãã¼ãã¯å£ä»¥å¤ã¯å·¦å³å¯¾ç§°ãªã®ã§ãã¬ã¤ã®åº§æ¨ãX座æ¨ã絶対å¤ã«ãããã¨ã§ã空éãå·¦å³å¯¾ç§°ã«ãªã£ã¦è·é¢é¢æ°ãåæ¸ãã¦ãã¾ãã
vec3 mxp = vec3(-abs(p.x), p.yz); // ear float d2 = sdEar(mxp); d = opU(d, d2);
å£
å£ã¯æ¥åçã使ã£ã¦ãã¾ãããå£è§ãè¥å¹²ä¸ããããã«æ¥åçã®ä¸å¿ããXæ¹åã«é¢ããã»ã©å転ããã¦æªãã¦ãã¾ãã
float sdMouse(vec3 p, float ms) { vec3 q = opBendXY(p, 2.0); ms += 0.00001; return sdEllipsoid(q - vec3(0,0,0.2), vec3(0.035, 0.01 * ms,0.05 * ms)); } vec3 opBendXY(vec3 p, float k) { float c = cos(k*p.x); float s = sin(k*p.x); mat2 m = mat2(c,-s,s,c); return vec3(m*p.xy,p.z); }
ç®ã¨çæ¯
ç®ã¯è¦ãã¾ãã¾ã§ããã«ãã»ã«ãçæ¯ã¯è§ä¸¸ããããç´°ããã¦ä½ã£ã¦ãã¾ãã
float sdEyeBrow(vec3 p) { const float x = 0.05; p = opBendXZ(p + vec3(0.02,0,-0.02), -6.5); return sdRoundBox(p + vec3(0.005, -0.14,-0.11), vec3(0.003,0.0025,0.05), 0.001); }
// eye float d4 = sdCapsule(mxp, vec3(-EYE_SPACE, 0.06, 0.13), vec3(-EYE_SPACE, 0.08, 0.125), 0.0175); surface eye = SURF_BLACK(d4); // eyebrows float d9 = sdEyeBrow(mxp); eye.dist = opU(eye.dist, d9);
é ¬
ãã¼ãåä½ã§ä¸çªè¤éãªã®ããé ¬ã®ããããã®ç·ã§ãã
å
ã®ãã¶ã¤ã³ã§ã¯ææ¸ãã§ããããããã¦ããç·ã§ãããã¬ã¤ãã¼ãã³ã°ã§ã¯3æ¬ã®ã«ãã»ã«ãæªããªããé£çµãã¦åç¾ãã¦ãã¾ãã
float sdCheep(vec3 p) { const float x = 0.05; const float z = -0.175; const float r = 0.0045; const float rb1 = 100.; p = rotate(p, M_PI * -0.6 * (p.x - x), vec3(-0.2,0.8,0)); float d = sdCapsule(opBendXY(p + vec3(x, -0.01, z), rb1), vec3(-0.005,0.0,0.0), vec3(0.005, 0., 0.001), r); float d1 = sdCapsule(opBendXY(p + vec3(x+0.01, -0.01, z), 200.0), vec3(-0.0026,0.0,0), vec3(0.0026, 0., 0), r); float d2 = sdCapsule(opBendXY(p + vec3(x+0.019, -0.015, z), -rb1), vec3(-0.01,0.0,-0.01), vec3(0.0045, 0., 0.0), r); return opU(opU(d, d1), d2); }
ãã¼ãã®åæ
åè¿°ã®é¡ã®ãã¼ããåæãã¾ãã
è·é¢é¢æ°ã§ã®å³å½¢ã®åæã¯ã以ä¸ã®ã¨ããã§ãã
// å float opUnion( float d1, float d2 ) { min(d1,d2); } // é¤ float opSubtraction( float d1, float d2 ) { return max(-d1,d2); } // 交差ï¼è«çç©ï¼ float opIntersection( float d1, float d2 ) { return max(d1,d2); }
ã¾ããé¡ã¨è³ã¨é ¬ãopUnionã§åæãã¾ãã
ç®ãå£ãçæ¯ã¯ãå¹ãã§ããã®ã§opSubtractionã§åé¤ãã¾ãã
ããã§å®æï¼
åã ãã®"Boze"ãä½ããï¼