Skip to content

Commit a84c089

Browse files
committed
Simplify normal estimation
1 parent 26b5fe7 commit a84c089

File tree

6 files changed

+61
-84
lines changed

6 files changed

+61
-84
lines changed
Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,28 @@
11
import tgpu from 'typegpu';
2-
import { vec3f } from 'typegpu/data';
3-
import { mul, normalize } from 'typegpu/std';
2+
import { vec2f, vec3f } from 'typegpu/data';
3+
import { normalize } from 'typegpu/std';
44

55
import { MarchParams } from './marchSdf.ts';
6-
import { ShapeContext } from './types.ts';
6+
7+
// Doing it in a derived until WGSL generation can properly decide when to `let` and when to `var`
8+
const epsilon = tgpu['~unstable'].derived(() =>
9+
// Arbitrary - should be smaller than any surface detail in your distance function, but not so small as to get lost in float precision
10+
vec2f(MarchParams.surfaceThreshold.$ * 0.5, 0),
11+
);
712

813
/**
914
* Estimates the normal vector at a point in space, based on the SDF given by `MarchParams.sampleSdf`.
1015
*/
11-
export const estimateNormal = tgpu['~unstable'].fn(
12-
[vec3f, ShapeContext],
16+
export const estimateNormal = tgpu.fn(
17+
[vec3f],
1318
vec3f,
14-
)((point, ctx) => {
15-
/** Arbitrary - should be smaller than any surface detail in your distance function, but not so small as to get lost in float precision */
16-
const epsilon = MarchParams.getSurfaceThreshold.value(ctx) * 0.5;
17-
const offX = vec3f(point.x + epsilon, point.y, point.z);
18-
const offY = vec3f(point.x, point.y + epsilon, point.z);
19-
const offZ = vec3f(point.x, point.y, point.z + epsilon);
20-
21-
const centerDistance = MarchParams.sampleSdf.value(point);
22-
const xDistance = MarchParams.sampleSdf.value(offX);
23-
const yDistance = MarchParams.sampleSdf.value(offY);
24-
const zDistance = MarchParams.sampleSdf.value(offZ);
25-
26-
return normalize(
27-
mul(
28-
1 / epsilon,
29-
vec3f(
30-
xDistance - centerDistance,
31-
yDistance - centerDistance,
32-
zDistance - centerDistance,
33-
),
34-
),
19+
)((point) => {
20+
const centerDistance = MarchParams.sampleSdf.$(point);
21+
const distance = vec3f(
22+
MarchParams.sampleSdf.$(point.add(epsilon.$.xyy)),
23+
MarchParams.sampleSdf.$(point.add(epsilon.$.yxy)),
24+
MarchParams.sampleSdf.$(point.add(epsilon.$.yyx)),
3525
);
26+
27+
return normalize(distance.sub(centerDistance));
3628
});

apps/phoure-www/src/lib-ray-marching/marchSdf.ts

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,48 @@ import * as d from 'typegpu/data';
33
import * as std from 'typegpu/std';
44
import { ShapeContext } from './types.ts';
55

6-
type SampleSdf = TgpuFn<[d.Vec3f], d.F32>;
7-
8-
const defaultGetSurfaceThreshold = tgpu['~unstable'].fn([ShapeContext], d.f32)(
9-
(_ctx) => 0.001,
10-
);
6+
type SampleSdf = TgpuFn<(pos: d.Vec3f) => d.F32>;
117

128
export const MarchParams = {
13-
maxSteps: tgpu['~unstable'].slot(500),
9+
maxSteps: tgpu.slot(500),
1410

1511
/**
1612
* The distance from the camera at which the sky should be drawn instead of the world.
1713
*/
18-
farPlane: tgpu['~unstable'].slot(100),
14+
farPlane: tgpu.slot(100),
1915

20-
getSurfaceThreshold: tgpu['~unstable'].slot(defaultGetSurfaceThreshold),
21-
sampleSdf: tgpu['~unstable'].slot<SampleSdf>(),
16+
surfaceThreshold: tgpu.slot<number>(0.001),
17+
sampleSdf: tgpu.slot<SampleSdf>(),
2218
};
2319

2420
export const MarchResult = d.struct({
2521
steps: d.u32,
2622
position: d.vec3f,
2723
});
2824

29-
export const march = tgpu['~unstable'].fn([
25+
export const march = tgpu.fn([
3026
d.ptrFn(ShapeContext),
3127
d.u32,
3228
d.ptrFn(MarchResult),
3329
])((ctx, limit, out) => {
3430
let pos = d.vec3f(ctx.rayPos);
3531
let prev_dist = d.f32(-1);
36-
let min_dist = d.f32(MarchParams.farPlane.value);
32+
let min_dist = d.f32(MarchParams.farPlane.$);
3733

3834
let step = d.u32(0);
3935
let progress = d.f32(0);
4036

4137
for (; step <= limit; step++) {
4238
pos = std.add(ctx.rayPos, std.mul(ctx.rayDir, progress));
43-
min_dist = MarchParams.sampleSdf.value(pos);
39+
min_dist = MarchParams.sampleSdf.$(pos);
4440

4541
// Inside volume?
46-
if (min_dist <= 0.) {
42+
if (min_dist <= 0) {
4743
// No need to check more objects.
4844
break;
4945
}
5046

51-
if (
52-
min_dist < MarchParams.getSurfaceThreshold.value(ctx) &&
53-
min_dist < prev_dist
54-
) {
47+
if (min_dist < MarchParams.surfaceThreshold.$ && min_dist < prev_dist) {
5548
// No need to check more objects.
5649
break;
5750
}
@@ -60,7 +53,7 @@ export const march = tgpu['~unstable'].fn([
6053
progress += min_dist;
6154
ctx.rayDistance += min_dist;
6255

63-
if (progress > MarchParams.farPlane.value) {
56+
if (progress > MarchParams.farPlane.$) {
6457
// Stop checking.
6558
break;
6659
}
@@ -71,12 +64,9 @@ export const march = tgpu['~unstable'].fn([
7164
out.position = pos;
7265

7366
// Not near surface or distance rising?
74-
if (
75-
min_dist > MarchParams.getSurfaceThreshold.value(ctx) * 2. ||
76-
min_dist > prev_dist
77-
) {
67+
if (min_dist > MarchParams.surfaceThreshold.$ * 2 || min_dist > prev_dist) {
7868
// Sky
79-
out.steps = MarchParams.maxSteps.value + 1;
69+
out.steps = MarchParams.maxSteps.$ + 1;
8070
return;
8171
}
8272

apps/phoure-www/src/lib/GameEngine/sdfRenderer/sdfRenderer.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,7 @@ const renderSubPixel = tgpu.fn(
8686
return std.min(skyColor(init_shape_ctx.rayDir), d.vec3f(1));
8787
}
8888

89-
const init_normal = estimateNormal(
90-
init_march_result.position,
91-
init_shape_ctx,
92-
);
89+
const init_normal = estimateNormal(init_march_result.position);
9390
const init_material = Material();
9491

9592
worldMat(init_march_result.position, init_shape_ctx, init_material);
@@ -135,7 +132,7 @@ const renderSubPixel = tgpu.fn(
135132
break;
136133
}
137134

138-
normal = estimateNormal(shape_ctx.rayPos, shape_ctx);
135+
normal = estimateNormal(shape_ctx.rayPos);
139136

140137
worldMat(shape_ctx.rayPos, shape_ctx, material);
141138

@@ -236,7 +233,7 @@ const auxComputeFn = tgpu['~unstable'].computeFn({
236233
if (marchResult.steps >= MarchParams.maxSteps.$) {
237234
worldNormal = std.neg(shapeCtx.rayDir);
238235
} else {
239-
worldNormal = estimateNormal(marchResult.position, shapeCtx);
236+
worldNormal = estimateNormal(marchResult.position);
240237
}
241238

242239
const material = Material();

apps/phoure-www/src/lib/GameEngine/sdfRenderer/worldSdf.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ export const worldMat = tgpu.fn([d.vec3f, ShapeContext, d.ptrFn(Material)])((
7777
ctx,
7878
out,
7979
) => {
80-
const sd = MarchParams.getSurfaceThreshold.value(ctx);
8180
const d_left_blob = objLeftBlob(pos);
8281
const d_center_blob = objCenterBlob(pos);
8382
const d_right_blob = objRightBlob(pos);
@@ -87,21 +86,20 @@ export const worldMat = tgpu.fn([d.vec3f, ShapeContext, d.ptrFn(Material)])((
8786
out.emissive = false;
8887
out.roughness = 1;
8988

90-
if (d_left_blob <= sd) {
89+
if (d_left_blob <= MarchParams.surfaceThreshold.$) {
9190
// left blob
9291
out.albedo = d.vec3f(1, 0.5, 0.2);
9392
out.roughness = 0.95;
94-
} else if (d_center_blob <= sd) {
93+
} else if (d_center_blob <= MarchParams.surfaceThreshold.$) {
9594
// test light
9695
out.albedo = mul(20, d.vec3f(1, 1, 0.5));
9796
out.emissive = true;
98-
} else if (d_right_blob <= sd) {
97+
} else if (d_right_blob <= MarchParams.surfaceThreshold.$) {
9998
out.albedo = mul(0.9, d.vec3f(0.5, 0.5, 0.6));
10099
out.roughness = 0.1;
101-
} else if (d_floor_blob <= sd) {
100+
} else if (d_floor_blob <= MarchParams.surfaceThreshold.$) {
102101
matFloor(pos, out);
103102
} else {
104-
// out.albedo = vec3f(0.5, 0.5, 0.2);
105103
out.albedo = skyColor(ctx.rayDir);
106104
}
107105
});

pnpm-lock.yaml

Lines changed: 22 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ packages:
44

55
# Define a catalog of version ranges.
66
catalog:
7-
typegpu: https://pkg.pr.new/software-mansion/TypeGPU/typegpu@c81e38bfa323506e5933b26e7e5965450c68217b
7+
typegpu: https://pkg.pr.new/software-mansion/TypeGPU/typegpu@e598b31a3d03476d47bd66002e80dfacb54d8203
88
unplugin-typegpu: ^0.2.2

0 commit comments

Comments
 (0)