the timeless (mercury / Revision 2014 / 64k)
on (mercury / Revision 2015 / 64k)
Catacombs (Íñigo Quílez / Shadertoy)
Bridge (Íñigo Quílez / Shadertoy)
Fractal Land (Kali / Shadertoy)
Solstice (Otavio Good / Shadertoy)
Skyline (Otavio Good / Shadertoy)
Technique de synthèse d'images:
Historique:
Rastérisation:
Raycasting:
Raymarching à pas constant:
Raymarching à pas constant:
Idée: Utiliser la distance à la surface pour ajuster dynamiquement le pas de marche
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Raymarching à pas adaptif:
Code GLSL
float intersect(vec3 O /* origin */, vec3 d /* direction */) {
float t = 0;
for (int i = 0; i < MaxNumSteps; ++i) {
vec3 P = O + t * d;
float r = f(P);
if (r < Epsilon)
return t;
t += r;
}
return MaxT;
}
f(P)
?
Un ensemble `ccS` est représenté par une fonction `f`: `bbbR^3 -> bbbR` telle que pour `P in bbbR^3`:
avec `d(P, del ccS) = min_(Q in del ccS) |vec(PQ)|`
(cas particulier de surface implicite)
Code GLSL
float sdfSphere(vec3 P, float R) {
return length(P) - R;
}
Code GLSL
float sdfPlane(vec3 P, vec3 n, float d) {
return dot(n, P) + d;
}
Code GLSL
float sdfCylinder(vec3 P, float R) {
return length(P.xy) - R;
}
Code GLSL
float sdfTorus(vec3 P, float R, float r) {
vec2 Q = vec2(length(P.xy) - R, P.z);
return length(Q) - r;
}
Code GLSL
float sdfCone(vec3 P, vec2 u) {
vec2 Q = vec2(length(P.xy), P.z);
return dot(Q, u);
}
Code GLSL
float sdfBox(vec3 P, vec3 s) {
vec3 Q = abs(P) - s;
return max(Q.x, max(Q.y, Q.z));
}
Code GLSL
float sdfRoundBox(vec3 P, vec3 s, float r) {
vec3 Q = abs(P) - s;
return length(max(Q, 0.0)) - r;
}
Code GLSL
float sdfCapsule(vec3 P, vec3 P1, vec3 P2, float r) {
vec3 u = P - P1;
vec3 v = P2 - P1;
float d = clamp(dot(u, v) / dot(v, v), 0.0, 1.0);
return length(u - d * v) - r;
}
Code GLSL
float sdfAffine(vec3 P) {
mat3 Rz = makeRotation(Pi / 6.0, vec3(0.0, 0.0, 1.0));
mat3 Ry = makeRotation(-Pi / 6.0, vec3(0.0, 1.0, 0.0));
float s = 1.5;
P = s * Ry * Rz * P + vec3(1.0, 0.5, 0.25);
return sdfRoundBox(P, vec3(0.375, 0.5, 0.75), 0.125) / s;
}
Code GLSL
float sdfRepeat(vec3 P) {
P.xy = abs(P.xy);
P.xy -= vec2(0.75, 1.0);
return sdfRoundBox(P, vec3(0.375, 0.5, 0.75), 0.125);
}
Code GLSL
float sdfRepeat(vec3 P) {
vec2 size = vec2(2.0, 3.0);
P.xy = mod(P.xy + 0.5 * size, size) - 0.5 * size;
return sdfRoundBox(P, vec3(0.375, 0.5, 0.75), 0.125);
}
Code GLSL
float sdfTwist(vec3 P) {
float c = cos(P.z);
float s = sin(P.z);
mat2 R = mat2(c, s, -s, c);
P = vec3(R * P.xy, P.z);
return sdfRoundBox(P, vec3(0.375, 0.5, 0.75), 0.125);
}
Code GLSL
float sdfDisplacement(vec3 P) {
float d1 = sdfSphere(P, 1.0);
float d2 = 0.05 * sin(12.0 * P.x) * sin(12.0 * P.y) * sin(12.0 * P.z);
return d1 + d2;
}
Code GLSL
float sdfDisplacement(vec3 P) {
float d1 = sdfSphere(P, 1.0);
float d2 = sdfRoundBox(P, vec3(0.375, 0.5, 0.75), 0.125);
float a = 0.75;
return mix(d1, d2, a);
}
Code GLSL
float sdfStar(vec3 P) {
float theta = atan(P.x, P.z);
float r = length(P.xz);
theta = mod(theta + Pi / 5.0, Pi / 2.5) - Pi / 5.0;
P.zx = r * vec2(cos(theta), sin(theta));
P.xy = abs(P.xy);
return sdfPlane(P, normalize(vec3(3.0, 5.0, 1.0)), 0.2);
}
Code GLSL
float sdfBoxWithHoles(vec3 P) {
float d1 = sdfRoundBox(P, vec3(2.25, 0.75, 0.5), 0.125);
float d2 = sdfCylinder(P - vec3(1.5, 0.0, 0.0), 0.5);
float d3 = sdfBoxCylinder(P, vec2(0.5));
float d4 = sdfHexagonalCylinder(P + vec3(1.5, 0.0, 0.0), 0.5);
float d234 = min(d2, min(d3, d4));
vec2 u = max(vec2(0.0625 + d1, 0.0625 - d234), vec2(0.0));
return min(-0.0625, max(d1, -d234)) + length(u);
}
Formules usuelles d'illumination applicables:
`C_(p ixel) = C_(ambient) + C_(di f fuse) + C_(specu lar)`
`C_(ambient) = L_(ambient) M_(ambient)`
`C_(di f fuse) = L_(di f fuse) M_(di f fuse) max(< vec n . vec l >, 0)`
`C_(specu lar) = L_(specu lar) M_(specu lar) max(< vec r . vec l >, 0)^(shi ni n ess)`
Comment calculer la normale `vec n` à la surface `del ccS`?
La normale (sortante) `vec n` à `del ccS` est:
`vec n = vec grad f = ((del f) / (del x), (del f) / (del y), (del f) / (del z))`
Évaluation par différences finies (centrées):
`(del f) / (del x)(P) ~~ (f(P + h) - f(P - h)) / (2 h)` avec `h = epsilon vec e_x`
vec3 sdfNormal(vec3 P) {
vec3 h = Epsilon * vec3(1.0, 0.0, 0.0);
return normalize(vec3(sdf(P + h.xyz) - sdf(P - h.xyz),
sdf(P + h.zxy) - sdf(P - h.zxy),
sdf(P + h.yzx) - sdf(P - h.yzx)));
}
attribute vec3 aPosition;
void main() {
gl_Position = vec4(aPosition, 1.0);
}
gl_FragCoord
/ fragCoord
),gl_FragColor
/ fragColor
.Sketch:
PShader raymarching;
void setup() {
size(WIDTH, HEIGHT, P3D);
noStroke();
// Load fragment shader from data/raymarching.glsl
raymarching = loadShader("raymarching.glsl");
raymarching.set("iResolution", float(WIDTH), float(HEIGHT));
}
void draw() {
shader(raymarching);
rect(0, 0, WIDTH, HEIGHT);
}