From d2cecf69db88145e6529847055fcf64d4fc72ea3 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 23 Aug 2024 00:16:41 -0700 Subject: [PATCH] Ray-cast a translucent sphere --- app-proto/inversive-display/src/main.rs | 81 ++++++++++++++++--------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/app-proto/inversive-display/src/main.rs b/app-proto/inversive-display/src/main.rs index 12fe9ed..baf7df6 100644 --- a/app-proto/inversive-display/src/main.rs +++ b/app-proto/inversive-display/src/main.rs @@ -72,6 +72,7 @@ fn main() { sycamore::render(|| { let ctrl_x = create_signal(0.0); let ctrl_y = create_signal(0.0); + let opacity = create_signal(0.6); let display = create_node_ref(); on_mount(move || { @@ -108,10 +109,17 @@ fn main() { out vec4 outColor; + // view uniform vec2 resolution; uniform float shortdim; + // controls uniform vec2 ctrl; + uniform float opacity; + + // light and camera + const float focal_slope = 0.3; + const vec3 light_dir = normalize(vec3(2., 2., 1.)); struct vecInv { vec3 sp; @@ -128,8 +136,24 @@ fn main() { ); } - const float focal_slope = 0.3; - const vec3 light_dir = normalize(vec3(2., 2., 1.)); + vec4 shade_sphere(vecInv v, vec3 pt) { + // the expression for normal needs to be checked. it's + // supposed to give the negative gradient of the lorentz + // product between the impact point vector and the sphere + // vector with respect to the coordinates of the impact + // point. i calculated it in my head and decided that + // the result looked good enough for now + vec3 normal_front = normalize(-v.sp + 2.*v.lt.s*pt); + + vec3 color; + float incidence = dot(normal_front, light_dir); + if (incidence < 0.) { + color = mix(vec3(0.2, 0.0, 0.4), vec3(0.1, 0.0, 0.2), -incidence); + } else { + color = mix(vec3(0.4, 0.0, 0.2), vec3(1.0, 0.8, 1.0), incidence); + } + return vec4(color, opacity); + } void main() { vec2 scr = (2.*gl_FragCoord.xy - resolution) / shortdim; @@ -143,29 +167,20 @@ fn main() { float scale = -b/(2.*a); float adjust = 4.*a*c/(b*b); - float offset = sqrt(1. - adjust); - float u_front = scale * (1. - offset); - float u_back = scale * (1. + offset); - vec3 color; - if (adjust < 1. && u_front > 0.) { - // the expression for normal needs to be checked. it's - // supposed to give the negative gradient of the lorentz - // product between the impact point vector and the sphere - // vector with respect to the coordinates of the impact - // point. i calculated it in my head and decided that - // the result looked good enough for now - vec3 pt_front = u_front * dir; - vec3 normal_front = normalize(-v.sp + 2.*v.lt.s*pt_front); - - float incidence = dot(normal_front, light_dir); - if (incidence < 0.) { - color = mix(vec3(0.2, 0.0, 0.4), vec3(0.1, 0.0, 0.2), -incidence); - } else { - color = mix(vec3(0.4, 0.0, 0.2), vec3(1., 0.8, 1.), incidence); + vec3 color = vec3(0.); + if (adjust < 1.) { + float offset = sqrt(1. - adjust); + float u_front = scale * (1. - offset); + float u_back = scale * (1. + offset); + if (u_back > 0.) { + vec4 sphere_color = shade_sphere(v, u_back * dir); + color = mix(color, sphere_color.rgb, sphere_color.a); + } + if (u_front > 0.) { + vec4 sphere_color = shade_sphere(v, u_front * dir); + color = mix(color, sphere_color.rgb, sphere_color.a); } - } else { - color = vec3(0.); } outColor = vec4(color, 1.); } @@ -192,6 +207,7 @@ fn main() { let resolution_loc = ctx.get_uniform_location(&program, "resolution"); let shortdim_loc = ctx.get_uniform_location(&program, "shortdim"); let ctrl_loc = ctx.get_uniform_location(&program, "ctrl"); + let opacity_loc = ctx.get_uniform_location(&program, "opacity"); // create a vertex array and bind it to the graphics context let vertex_array = ctx.create_vertex_array().unwrap(); @@ -211,16 +227,17 @@ fn main() { ]; bind_vertex_attrib(&ctx, position_index, 3, &positions); - // set the resolution - let width = canvas.width() as f32; - let height = canvas.height() as f32; - ctx.uniform2f(resolution_loc.as_ref(), width, height); - ctx.uniform1f(shortdim_loc.as_ref(), width.min(height)); - // set up a repainting routine create_effect(move || { + // set the resolution + let width = canvas.width() as f32; + let height = canvas.height() as f32; + ctx.uniform2f(resolution_loc.as_ref(), width, height); + ctx.uniform1f(shortdim_loc.as_ref(), width.min(height)); + // pass the control parameters ctx.uniform2f(ctrl_loc.as_ref(), ctrl_x.get() as f32, ctrl_y.get() as f32); + ctx.uniform1f(opacity_loc.as_ref(), opacity.get() as f32); // clear the screen and draw the scene ctx.clear_color(0.0, 0.0, 0.0, 1.0); @@ -246,6 +263,12 @@ fn main() { step=0.01, bind:valueAsNumber=ctrl_y ) + input( + type="range", + max=1.0, + step=0.01, + bind:valueAsNumber=opacity + ) } } });