scene.org File Archive

File download

<root>­/­parties­/­2023­/­tdf16ms00­/­glsl/kamoshika_glsl_-3.txt

File size:
7 465 bytes (7.29K)
File date:
2023-10-22 21:17:12
Download count:
all-time: 96

Preview

precision highp float;
uniform vec2 resolution;
uniform vec2 mouse;
uniform float time;
uniform sampler2D backbuffer;
out vec4 outColor;

const int maxDepth = 3; // ƒŒƒC‚ÌŒo˜H‚̐[‚³‚̍őå’li”½ŽË‰ñ”+1‚Ì’lj
const int numSamples = 20; // ƒpƒXƒgƒŒ[ƒVƒ“ƒO‚̃Tƒ“ƒvƒ‹”

const float PI = acos(-1.); // ‰~Žü—¦
const float PI2 = acos(-1.) * 2.;
const float EPS = 0.0001; // ƒŒƒCƒgƒŒ[ƒX‚È‚Ç‚ÉŽg‚¤”÷¬—Ê
const float FOV = 60.; // Ž‹–ìŠpidegreej ”͈́F(0., 180.)
const float fallInterval = 100.; // Voxel‚ª—Ž‚¿‚Ä‚­‚éŠÔŠu
const float fallSpeed = 4.; // Voxel‚ª—Ž‚¿‚鑬‚³
const float heightRange = 5.; // Voxel‚̍‚‚³‚͈̔Í
//const float bumpFactor = 0.7;
const float bumpFactor = 2.;

vec3 camPos; // ƒJƒƒ‰‚̍À•W
vec3 voxelID; // Voxel‚ÌID
vec3 voxelNormal; // Voxel‚Ì–@üƒxƒNƒgƒ‹ ((}1, 0, 0) or (0, }1, 0) or (0, 0, }1))
vec3 voxelPos; // Voxel‚̐®”À•W
float pathSeed = 0.; // ƒpƒXƒgƒŒ[ƒVƒ“ƒO‚ÅŽg‚¤—”‚̃V[ƒh

// 1D‚Ì—”
float hash11(float x) {
  return fract(sin(x) * 43758.5453);
}

// 2D‚Ì—”
float hash12(vec2 p) {
  return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}

// 3D‚Ì—”
float hash13(vec3 p) {
  return fract(sin(dot(p, vec3(12.9898, 78.233, 52.178))) * 43758.5453);
}

// 1D‚Ì—”(ƒV[ƒh‚ðXV)
float random() {
  return hash11(pathSeed++);
}

// 2D‚̉ñ“]s—ñ
mat2 rotate2D(float a) {
  float s = sin(a), c = cos(a);
  return mat2(c, s, -s, c);
}

// HSV‚ðRGB‚É•ÏŠ·
vec3 hsv(float h, float s, float v) {
  vec3 res = fract(h + vec3(0, 2, 1) / 3.);
  res = clamp(abs(res * 6. - 3.) - 1., 0., 1.);
  res = (res - 1.) * s + 1.;
  res *= v;
  return res;
}

// À•Wp‚ÉVoxel‚ª‘¶Ý‚·‚é‚©”Û‚©
float map(vec3 p) {
  float res = 1.;
  vec3 ID = floor(p);
  float a = abs(p.x);
  ID.y -= floor(max(a * a * 0.1, 5.) - hash12(ID.xz) * heightRange);
  float T = time * fallSpeed / fallInterval + hash12(ID.xz * 1.852813);
  if(ID.y > 0.){
    float tmp = ID.y / fallInterval + T;
    if(fract(tmp) * fallInterval > 1.) {
      res = 0.;
    }
    ID.y = floor(tmp);
  } else {
    ID.y += floor(T);
  }
  
  p += 0.5 - camPos;
  if(dot(p, p) < 1.) {
    res = 0.;
  }
  voxelID = ID;
  return res;
}

// ref: "Voxel Edges" by iq
// https://www.shadertoy.com/view/4dfGzs
// ro‚©‚畨‘Ì•\–Ê‚Ü‚Å”ò‚΂µ‚½ƒŒƒC‚Ì’·‚³
float castRay(vec3 ro, vec3 rd, const int itr) {
  //vec3 pos = floor(ro);
  voxelPos = floor(ro);
  vec3 ri = 1.0 / rd;
  vec3 rs = sign(rd);
  vec3 dis = (voxelPos - ro + 0.5 + rs * 0.5) * ri; // ro‚©‚çƒZƒ‹‚Ì‹«ŠE‚܂ł̃ŒƒC‚Ì’·‚³iX,Y,Z•ûŒüj
  
  float res = -1.0;
  vec3 mm = vec3(0);
  vec3 tmp = vec3(0);
  for(int i = 0; i < itr; i++) {
    if(map(voxelPos) > 0.5) {
      res = 1.0;
      break;
    }
    mm = step(dis.xyz, dis.yzx) * step(dis.xyz, dis.zxy); // X,Y,Z‚Ì‚¤‚¿A‚Ç‚Ì•ûŒü‚̗אڃZƒ‹‚ɐi‚Þ‚©
    tmp = mm * rs;
    dis += tmp * ri;
    voxelPos += tmp;
  }
  
  voxelNormal = -tmp;
  vec3 mini = (voxelPos - ro + 0.5 - 0.5 * rs) * ri;
  float t = max(mini.x, max(mini.y, mini.z)); // ro‚©‚çVoxel•\–ʂ܂ŐL‚΂µ‚½ƒŒƒC‚Ì’·‚³
  
  return t * res;
}

// ƒGƒ~ƒbƒVƒ‡ƒ“‚̐F
float emission() {
  return step(hash13(voxelID * 1.552897), 0.08) * 10.;
}

// •¨‘̂̐F
vec3 objColor(){
  return hsv(hash13(voxelID * 1.347385), 0.6, 1.);
}

// Voxel‚̉š“Ê
float bumpFunc(vec3 p, vec3 n) {
  n = abs(n);
  vec2 uv = n.x > 0.5 ? p.yz : n.y > 0.5 ? p.xz : p.xy;
  vec2 ID = floor(uv);
  uv = fract(uv) - 0.5;
  
  if(hash12(ID) < 0.5) {
    uv.y = -uv.y;
  }
  if(uv.y < -uv.x) {
    uv = -uv.yx;
  }
  float d = abs(length(uv - 0.5) - 0.5);
  const float w = 0.15;
  float tmp = w * w - d * d;
  float res = tmp > 0. ? sqrt(tmp) : 0.;
  
  return -res;
}

// ref: "Maze Lattice" by Shane
// https://www.shadertoy.com/view/llGGzh
// Voxel‚̉š“ʃxƒNƒgƒ‹
vec3 bumpMap(vec3 p, vec3 n) {
  const vec2 e = vec2(.002, 0);
  float ref = bumpFunc(p, n);
  vec3 grad = (vec3(bumpFunc(p - e.xyy, n),
                    bumpFunc(p - e.yxy, n),
                    bumpFunc(p - e.yyx, n)) - ref) / e.x;
  grad -= n * dot(n, grad);
  return normalize(n + grad * bumpFactor);
}

// v‚ð“V’¸‚Æ‚µ‚ċɍÀ•Wphi, theta‚¾‚¯‰ñ“]‚³‚¹‚½ƒxƒNƒgƒ‹
// ¦ˆø”v‚Í’·‚³1‚̃xƒNƒgƒ‹‚Å‚ ‚é•K—v‚ ‚è
vec3 jitter(vec3 v, float phi, float sinTheta, float cosTheta) {
  vec3 xAxis = normalize(cross(v.yzx, v));
  vec3 yAxis = cross(v, xAxis);
  vec3 zAxis = v;
  return (xAxis * cos(phi) + yAxis * sin(phi)) * sinTheta + zAxis * cosTheta;
}

// ref: "ƒpƒXƒgƒŒ[ƒVƒ“ƒO - Computer Graphics - memoRANDOM" by Shocker_0x15
// (Japanese article)
// https://rayspace.xyz/CG/contents/path_tracing/

// ref: "GLSL smallpt" by Zavie
// https://www.shadertoy.com/view/4sfGDB

// ref: "[SESSIONS] Syobon's Lobby" by Kamoshika (myself)
// https://www.shadertoy.com/view/ctt3zX

// ƒpƒXƒgƒŒ[ƒVƒ“ƒO‚Å“¾‚ç‚ê‚éF
vec3 pathTrace(vec3 ro, vec3 rd) {
  vec3 acc = vec3(0);
  vec3 mask = vec3(1);
  
  // Å‰‚ɃJƒƒ‰‚©‚烌ƒC‚ð”ò‚΂·
  float t = castRay(ro, rd, 100);
  if(t < 0.) { // ƒŒƒC‚ª•¨‘̂ɏՓ˂µ‚È‚©‚Á‚½
    return vec3(0.);
  }
  ro += t * rd; // ƒŒƒC‚ÌŒ´“_‚𕨑̕\–ʂ܂Ői‚ß‚é
  
  vec3 f = ro - voxelPos - 0.5;
  vec3 n = normalize(f * pow(f, vec3(8.)));
  vec3 bump = bumpMap(ro, voxelNormal);
  n = normalize(n + bump);
  
  // ¦–{—ˆ‚̓Tƒ“ƒvƒ‹”‚Ì•ª‚¾‚¯ƒJƒƒ‰‚©‚烌ƒC‚ð”ò‚΂·‚½‚߁AnumSamples‚ð‚©‚¯‚é
  acc += mask * emission() * float(numSamples);
  mask *= objColor();
  
  // ŽŸ‚ɁA•¨‘Ì•\–Ê‚©‚烉ƒ“ƒ_ƒ€‚ɃŒƒC‚ð”ò‚΂·
  vec3 ro0 = ro + n * EPS;
  vec3 n0 = n;
  vec3 mask0 = mask;
  for(int i = 0; i < numSamples; i++) {
    ro = ro0;
    n = n0;
    mask = mask0;
    for(int depth = 1; depth < maxDepth; depth++) {
      float ur = random(); // ˆê—l—”
      // d“_“IƒTƒ“ƒvƒŠƒ“ƒO‚ðs‚¤‚½‚߁A”¼‹…–Ê“àcos•ª•z‚ðŽg—p‚·‚é
      rd = jitter(n, random() * PI2, sqrt(1. - ur), sqrt(ur)); // ŽŸ‚̃ŒƒC‚Ì•ûŒü
            
      t = castRay(ro, rd, 15);
      if(t < 0.) { // ƒŒƒC‚ª•¨‘̂ɏՓ˂µ‚È‚©‚Á‚½
        break;
      }
      ro += t * rd;
      
      f = ro - voxelPos - 0.5;
      n = normalize(f * pow(f, vec3(8.)));
      bump = bumpMap(ro, voxelNormal);
      n = normalize(n + bump);
      
      acc += mask * emission();
      mask *= objColor();
      ro += n * EPS; // Œ»Ý‚Ì•¨‘Ì•\–Ê‚ð”ð‚¯‚é‚½‚߂ɁA­‚µ•‚‚©‚¹‚é
    }
  }
  
  acc /= float(numSamples);
  acc = clamp(acc, 0., 1.);
  
  return acc;
}

void main() {
  vec2 uv = (gl_FragCoord.xy * 2. - resolution) / min(resolution.x, resolution.y); // À•W‚̐³‹K‰»
  
  camPos = vec3(0.5, 7.5, -time * 2.); // ƒJƒƒ‰‚̈ʒuiƒŒƒC‚ÌŒ´“_j
  vec3 dir = normalize(vec3(0.5, -0.3, -1)); // ƒJƒƒ‰‚ÌŒü‚«
  dir.xy *= rotate2D(time * 0.2);
  vec3 side = normalize(cross(dir, vec3(0, 1, 0)));
  vec3 up = cross(side, dir);
  vec3 rd = normalize(uv.x * side + uv.y * up + dir / tan(FOV / 360. * PI)); // ƒŒƒC‚ÌŒü‚«
  
  // ƒpƒXƒgƒŒ[ƒVƒ“ƒO‚ÅŽg‚¤—”‚̃V[ƒh‚ð‰Šú‰»‚·‚é
  float T = fract(time / 10.) * 500.;
  pathSeed = hash12(gl_FragCoord.xy * PI) * 500.;
  pathSeed += hash12(gl_FragCoord.xy + pathSeed + T) * 500.;
  
  // ƒpƒXƒgƒŒ[ƒVƒ“ƒO‚ð‚·‚é
  vec3 col = vec3(0);
  col += pathTrace(camPos, rd);
  col = pow(col, vec3(1. / 2.2)); // ƒKƒ“ƒ}•â³
  
  // ƒpƒXƒgƒŒ[ƒVƒ“ƒO‚Å“¾‚ç‚ꂽF‚Ì•ªŽU‚ð’ጸ‚·‚邽‚ß‚É‘O‚̃tƒŒ[ƒ€‚̐F‚ð‡¬‚·‚é
  float tex = 0.6;
  col = mix(col, texture(backbuffer, gl_FragCoord.xy / resolution).rgb, tex);
  
  outColor = vec4(col, 1.);
}