-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmarchLib.mjs
50 lines (40 loc) · 1.48 KB
/
marchLib.mjs
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
import { add, mul, normalize } from "./shaderLib.mjs";
export const intersectSDF = (a, b) => Math.max(a, b);
export const subtractSDF = (a, b) => Math.max(a, -b);
export const unionSDF = (a, b) => Math.min(a, b);
const STEP = 0.001;
/**
* Get the surface normal at a point.
* @param sceneSDF {(point: [number, number, number]) => number}
* @param point {[number, number, number]}
* @returns {[number, number, number]}
*/
const normal = (sceneSDF, point) => {
const gradient0 = sceneSDF(point);
const gradientX = gradient0 - sceneSDF(add(point, [STEP, 0, 0]));
const gradientY = gradient0 - sceneSDF(add(point, [0, STEP, 0]));
const gradientZ = gradient0 - sceneSDF(add(point, [0, 0, STEP]));
return normalize([gradientX, gradientY, gradientZ]);
};
const MAX_STEPS = 32;
const MAX_DISTANCE = 10;
const HIT_DISTANCE = 0.002;
/**
* Perform ray marching.
* @param source {[number, number, number]}
* @param direction {[number, number, number]}
* @param sceneSDF {(point: [number, number, number]) => number}
* @returns {number}
*/
export const rayMarch = (source, direction, sceneSDF) => {
let distanceTraveled = 0;
for (let i = 0; i < MAX_STEPS; ++i) {
const currentPos = add(source, mul(direction, distanceTraveled));
const distanceToScene = sceneSDF(currentPos);
if (distanceToScene < HIT_DISTANCE)
return normal(sceneSDF, currentPos)[0] * 0.5 + 0.6;
distanceTraveled += distanceToScene;
if (distanceTraveled > MAX_DISTANCE) break;
}
return 0;
};