module = wgsl`
struct Vertex {
@builtin(vertex_index)
vertex_index : u32,
};
struct Point {
@builtin(position)
position: vec4f,
};
struct Uniforms {
time: f32,
frame: u32,
resolution: vec4f,
view: mat4x4f,
};
struct Pointers {
count: u32,
positions: array<vec4f, 10>,
}
struct Ray {
origin: vec3f,
// assume direction is normalized
direction: vec3f,
};
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
@group(1) @binding(0) var<uniform> pointers: Pointers;
const bin = vec4f(-1,3,0,1);
const points = array(
Point(
bin.xxzw,
),
Point(
bin.xyzw,
),
Point(
bin.yxzw,
),
);
const spheres = array(
// cube
bin.xxxw,
bin.xxww,
bin.xwxw,
bin.xwww,
bin.wxxw,
bin.wxww,
bin.wwxw,
bin.wwww,
// octahedron
bin.zzww,
bin.zzxw,
bin.zwzw,
bin.zxzw,
bin.wzzw,
bin.xzzw,
);
fn set_xyz(point: ptr<function, vec4f>, value: vec3f) {
*point = vec4(value, (*point).w);
}
fn ray_point(ray: Ray, t: f32) -> vec3f {
return ray.origin + t * ray.direction;
}
// apply projective transform
// in affine space
fn rotate(point: vec3f, transform: mat4x4f) -> vec3f {
let q = transform * vec4(point, 1);
return q.xyz / q.w;
}
// apply projective function
// in tangent space
fn rotate_direction(direction: vec3f, transform: mat4x4f) -> vec3f {
let q = transform * vec4(direction, 0);
return q.xyz;
}
fn rotate_ray(ray: Ray, transform: mat4x4f) -> Ray {
return Ray(
rotate(ray.origin, transform),
rotate_direction(ray.direction, transform)
);
}
fn rotate_ray_ref(ray: ptr<function, Ray>, transform: mat4x4f) {
(*ray).origin = rotate((*ray).origin, transform);
(*ray).direction = rotate((*ray).direction, transform);
}
fn sphere(color: ptr<function, vec4f>, ray: Ray, center: vec3f, r: f32) {
let offset = center - ray.origin;
let t_closest = dot(offset, ray.direction);
let closest = ray_point(ray, t_closest);
let d = distance(closest, center);
if (d > r) {
return;
}
let dt = sqrt(r*r - d*d);
var t = t_closest - dt;
if (t < 0.01) {
t = t_closest + dt;
if (t < 0.01) {
return;
}
}
var z = (*color).w - 1;
if (z == 0) {
z = 100.0;
}
if (t > z) {
return;
}
(*color).w = t + 1;
let intersection = ray_point(ray, t);
let normal = (intersection - center) / r;
set_xyz(color, .8*(.5 + .5*normal));
*color += vec4(
vec3(.2 * fract(1.5*intersection)),
0);
var fresnel = length(cross(normal, ray.direction));
fresnel=saturate(exp(fresnel - 3.));
//set_xyz(color, mix(color.xyz, vec3(1), fresnel);
}
fn rescale(pixels: vec2f) -> vec2f {
return 2
* (pixels - uniforms.resolution.xy / 2)
/ uniforms.resolution.z;
}
@vertex fn vertex(
vert: Vertex,
) -> Point {
return points[vert.vertex_index];
}
@fragment fn fragment(point: Point) -> @location(0) vec4f {
_ = uniforms;
_ = pointers;
var pos = rescale(point.position.xy);
pos *= 1.25;
var d = length(pos);
d = smoothstep(1.1, 1.2, d) *exp(-d);
var color: vec4f = vec2(d, 1.0).xxxy;
let origin = vec3(pos, -5);
var ray = Ray(
origin,
// ortographic
//vec3(0,0,1),
normalize(origin + vec3(0,0,10))
);
rotate_ray_ref(&ray, uniforms.view);
sphere(&color, ray, vec3(0.0), 1.0);
for (var i = 0u; i < 8u + 6u; i++) {
let s = spheres[i];
sphere(&color, ray, s.xyz, s.w / 10);
}
for (var i = 0u; i < pointers.count; i++) {
let pointer = pointers.positions[i];
var d = 0.03 * length(
(point.position.xy
- pointer.xy)
/ vec2(pointer.zw)
);
color = mix(
color,
vec4(1.0),
exp(-d)
);
}
return color;
}
`.value