Mandelbulb con RayMarching
#
Ray casting
#
Es el uso da la intersección de un rayo con una superficie para solucionar diferentes problemas, como determinar el primer elemento interceptado por un rayo, determinar caras ocultas, renderización volumetrica.
Ray tracing
#
Técnica de renderizado aplicando una solución analítica al problema de la intersección del rayo con la superficie.
Ray Marching
#
Algoritmo iterativo que para encontrar la intersección del rayo con la superficie.
- Paso fijo: se define un tamaño para cada paso y se va sumando esta distancia al rayo iterativamente hasta encontrar la interseccion de la superficie con el rayo.
- Sphere tracing: se utiliza SDFs para calcular la distancia recorrida por el rayo en cada iteracion hasta encontrar la interseccion.

Script p5 raymarching.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| let rayMarchingShader;
let easycam;
function preload() {
// Load shader with position2 varying
params = {
precision: Tree.highp,
matrices: Tree.NONE,
varyings: Tree.position2
}
rayMarchingShader = readShader('/showcase/sketches/mandelbulb/shader/rayMarching/static/raymarching.frag', params);
}
function setup() {
let canvas = createCanvas(725, 725, WEBGL);
parent.disableScroll(canvas.canvas);
easycam = createEasyCam({ distance: 500 });
shader(rayMarchingShader);
textureMode(NORMAL);
noStroke();
}
function draw() {
background(0);
quad(-1, -1, 1, -1, 1, 1, -1, 1);
}
|
Fragment shader raymarching.frag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| precision highp float;
varying vec2 position2;
const int MAX_RAY_STEPS = 100;
const float MAX_MARCH_DISTANCE = 100.;
const float MIN_MARCH_DISTANCE = 0.001;
// Get the closest distance from p to world
float world(vec3 p) {
// SDF sphere
float sphere = length(p ) - 1.;
return sphere;
}
// Ray casting with ray march algorithm
float rayMarch(vec3 ro, vec3 rd) {
// Initialize distance
float distanceOrigin = 0.;
for(int i = 0; i < MAX_RAY_STEPS; i++) {
// Calcualte ray position
vec3 rp = ro + distanceOrigin * rd;
// Get the closest distance to ray
float map = world(rp);
// Check if ray intersects
if(map < MIN_MARCH_DISTANCE)
break;
// Advance ray to the next closest point
distanceOrigin += map;
// Break if ray is too far
if(distanceOrigin > MAX_MARCH_DISTANCE) {
distanceOrigin = -1.;
break;
}
}
// return intersection distance
return distanceOrigin;
}
void main() {
// Camera origin, ray origin, ray direction
vec3 co = vec3(0, 0, -2.);
vec3 ro = co;
vec3 rd = normalize(vec3(position2.x, position2.y, 1.));
// Initial color (background)
vec3 col = vec3(0.);
// Spawn ray and get distance
float t = rayMarch(ro, rd);
// Temp color based on distance
col = vec3(clamp(t, 0., 1.));
// Set fragment color
gl_FragColor = vec4(col, 1.);
}
|
Traslaciones y rotaciones
#
Script p5 raymarching.js
33
34
35
36
37
38
39
40
41
42
43
44
45
| function drawShader() {
push();
shader(rayMarchingShader);
rayMarchingShader.setUniform('cameraCenter', easycam.getCenter());
rayMarchingShader.setUniform('cameraDistance', easycam.getDistance());
rayMarchingShader.setUniform('dMatrix', dMatrix().mat3);
quad(-1, -1, 1, -1, 1, 1, -1, 1);
pop();
}
|
Fragment shader raymarching.frag
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| uniform float cameraDistance;
uniform vec3 cameraCenter;
uniform mat3 dMatrix;
// Get the closest distance from p to world
float world(vec3 p) {
// Set point to initial camera distance
p /= 500.;
// transform the point to simulate camera zoom
p /= 1. / cameraDistance;
// apply rotation and translation transformations from object
p *= dMatrix;
// sphere SDF translated on Y axis to see dMatrix effects
float sphere = length(p - vec3(0., 1., 0.)) - .5;
return sphere;
}
|
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
| void main() {
// Camera origin, ray origin, ray direction
vec3 co = vec3(cameraCenter + vec3(0, 0, -2.));
vec3 ro = co;
vec3 rd = normalize(vec3(position2.x, position2.y, 1.));
// Initial color (background)
vec3 col = vec3(0.);
// Spawn ray and get distance
float t = rayMarch(ro, rd);
// Temp color based on distance
col = vec3(clamp(t, 0., 1.));
// Set fragment color
gl_FragColor = vec4(col, 1.);
}
|
Referencias
#