Skip to content

Instantly share code, notes, and snippets.

@edom18
Created September 27, 2018 05:04
Show Gist options
  • Save edom18/b60166c6137953bc0aa778869f99dd31 to your computer and use it in GitHub Desktop.
Save edom18/b60166c6137953bc0aa778869f99dd31 to your computer and use it in GitHub Desktop.
レイマーチングでAmbient Occlusion ref: https://qiita.com/edo_m18/items/63dbacb57db3b7734483
// なんちゃってAOを計算する
//
// +-----------------+--------------------+
// | ro = Ray Origin | rd = Ray Direction |
// +-----------------+--------------------+
vec4 genAmbientOcclusion(vec3 ro, vec3 rd)
{
vec4 totao = vec4(0.0);
float sca = 1.0;
for (int aoi = 0; aoi < 5; aoi++)
{
float hr = 0.01 + 0.02 * float(aoi * aoi);
vec3 aopos = ro + rd * hr;
float dd = distFunc(aopos);
float ao = clamp(-(dd - hr), 0.0, 1.0);
totao += ao * sca * vec4(1.0, 1.0, 1.0, 1.0);
sca *= 0.75;
}
const float aoCoef = 0.5;
totao.w = 1.0 - clamp(aoCoef * totao.w, 0.0, 1.0);
return totao;
}
float distFunc(vec3 pos)
{
float d1 = distSphere(pos, size);
float d2 = distPlane(pos, vec4(0.0, 1.0, 0.0, 2.0));
float d3 = distTorus(pos, vec2(0.5, 0.2));
return min(d3, min(d1, d2));
}
vec3 aopos = ro + rd * hr;
float hr = 0.01 + 0.02 * float(aoi * aoi); // aoiはイテレーション回数を表すint型。for (int aoi...
vec3 aopos = ro + rd * hr;
float dd = distFunc(aopos);
float ao = clamp(-(dd - hr), 0.0, 1.0);
totao += ao * sca * vec4(1.0, 1.0, 1.0, 1.0);
sca *= 0.75;
float hr = 0.01 + 0.02 * float(aoi * aoi); // aoiはイテレーション回数を表すint型。for (int aoi...
vec3 aopos = ro + rd * hr;
float dd = distFunc(aopos);
float ao = clamp(-(dd - hr), 0.0, 1.0);
totao += ao * sca * vec4(1.0, 1.0, 1.0, 1.0);
sca *= 0.75;
vec3 cameraPos = vec3(0.0, -0.5, 1.5);
vec3 cameraDir = normalize(vec3(0.0, -0.3, -1.0));
vec3 lightDir = vec3(1.0, 1.0, 1.0);
float softShadow = 16.0;
float size = 0.5;
// sphereの距離関数
float distSphere(vec3 pos, float size)
{
vec3 spPos = vec3(1.0, -1.8, -1.0);
return length(pos - spPos) - size;
}
// Planeの距離関数
float distPlane(vec3 pos, vec4 n)
{
return dot(pos, n.xyz) + n.w;
}
// トーラスの距離関数
float distTorus(vec3 p, vec2 t)
{
vec2 tPos = vec2(0.0, -2.0);
vec2 q = vec2(length(p.xy - tPos) - t.x, p.z);
return length(q - tPos) - t.y;
}
float distFunc(vec3 pos)
{
float d1 = distSphere(pos, size);
float d2 = distPlane(pos, vec4(0.0, 1.0, 0.0, 2.0));
float d3 = distTorus(pos, vec2(0.5, 0.2));
return min(d3, min(d1, d2));
}
vec3 getNormal(vec3 pos)
{
const float e = 0.0001;
const vec3 dx = vec3(e, 0, 0);
const vec3 dy = vec3(0, e, 0);
const vec3 dz = vec3(0, 0, e);
float d = distFunc(pos);
return normalize(vec3(
d - distFunc(vec3(pos - dx)),
d - distFunc(vec3(pos - dy)),
d - distFunc(vec3(pos - dz))
));
}
// 影を計算する
// オブジェクトの衝突位置からライト方向にレイを飛ばし、
// 遮蔽があったら影とする。
// また、ライトに向かうレイがなにかのオブジェクトに接近した場合は
// 最接近情報を保持し、影の影響度として利用する(ソフトシャドウ)
// +-----------------+--------------------+
// | ro = Ray Origin | rd = Ray Direction |
// +-----------------+--------------------+
float genShadow(vec3 ro, vec3 rd)
{
// 距離関数の結果 = 距離
float h = 0.0;
// 現在のレイの位置
float c = 0.001;
// レイの最接近距離
float r = 1.0;
// シャドウ係数(濃さ)
float shadowCoef = 0.5;
// レイマーチにより影を計算する
for (float t = 0.0; t < 50.0; t++)
{
h = distFunc(ro + rd * c);
if (h < 0.001)
{
return shadowCoef;
}
// 現時点の距離関数の結果と係数を掛けたものを
// レイの現時点での位置で割ったものを利用する
// 計算結果のうち、もっとも小さいものを採用する
r = min(r, h * softShadow / c);
c += h;
}
return 1.0 - shadowCoef + (r * shadowCoef);
}
// なんちゃってAOを計算する
//
// +-----------------+--------------------+
// | ro = Ray Origin | rd = Ray Direction |
// +-----------------+--------------------+
vec4 genAmbientOcclusion(vec3 ro, vec3 rd)
{
vec4 totao = vec4(0.0);
float sca = 1.0;
for (int aoi = 0; aoi < 5; aoi++)
{
float hr = 0.01 + 0.02 * float(aoi * aoi);
vec3 aopos = ro + rd * hr;
float dd = distFunc(aopos);
float ao = clamp(-(dd - hr), 0.0, 1.0);
totao += ao * sca * vec4(1.0, 1.0, 1.0, 1.0);
sca *= 0.75;
}
const float aoCoef = 0.5;
totao.w = 1.0 - clamp(aoCoef * totao.w, 0.0, 1.0);
return totao;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 p = (fragCoord.xy * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
vec4 m = iMouse / iResolution.xxxx;
vec3 col = vec3(0.0);
vec3 cPos = cameraPos;
vec3 cDir = normalize(vec3(m.x, -m.y, -1.0));
vec3 cSide = normalize(cross(cDir, vec3(0, 1, 0)));
vec3 cUp = normalize(cross(cSide, cDir));
float targetDepth = 1.3;
vec3 ray = normalize(cSide * p.x + cUp * p.y + cDir * targetDepth);
float dist, depth;
depth = 0.0;
vec3 pos;
const int maxsteps = 128;
const float eps = 0.001;
for (int i = 0; i < maxsteps; i++)
{
pos = cPos + ray * depth;
dist = distFunc(pos);
if (dist < eps)
{
break;
}
depth += dist;
}
float shadow = 1.0;
if (dist < eps)
{
vec3 n = getNormal(pos);
float diff = dot(n, lightDir);
shadow = genShadow(pos + n + 0.001, lightDir);
vec4 totao = genAmbientOcclusion(pos, n);
float u = 1.0 - floor(mod(pos.x, 2.0));
float v = 1.0 - floor(mod(pos.z, 2.0));
if ((u == 1.0 && v < 1.0) || (v == 1.0 && u < 1.0))
{
diff *= 0.7;
}
col = vec3(diff) + vec3(0.1);
col -= totao.xyz * totao.w;
}
fragColor = vec4(col, 1.0) * exp(-depth * 0.12);
}
// ... 省略
vec4 ao = genAmbientOcclusion(pos, n);
// ... 省略(なにがしかの色計算)
col -= ao.xyz * ao.w;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment