pub const fn vec3(x: f32, y: f32, z: f32) -> Vec3Expand description
Shorthand Vec3 constructor.
Examples found in repository?
examples/chat/welcome.rs (line 553)
540fn axis_hit(origin: Vec3, direction: Vec3) -> (f32, bool, Vec3) {
541 let quadratic = direction.x * direction.x + direction.z * direction.z;
542 let linear = 2.0 * (origin.x * direction.x + origin.z * direction.z);
543 let constant = origin.x * origin.x + origin.z * origin.z - AXIS_RADIUS * AXIS_RADIUS;
544 let discriminant = linear * linear - 4.0 * quadratic * constant;
545 let root = (-linear - discriminant.max(0.0).sqrt()) / (2.0 * quadratic).max(1e-8);
546 let hit_y = origin.y + direction.y * root;
547 let cylinder = if discriminant >= 0.0 && root > 0.0 && (AXIS_BOTTOM..=AXIS_TOP).contains(&hit_y)
548 {
549 root
550 } else {
551 f32::INFINITY
552 };
553 let cap_center = vec3(0.0, AXIS_TOP, 0.0);
554 let cap = sphere_depth(origin, direction, cap_center, AXIS_RADIUS * 1.75);
555 let depth = cylinder.min(cap);
556 if !depth.is_finite() {
557 return (f32::INFINITY, false, vec3(0.0, 1.0, 0.0));
558 }
559 let point = origin + direction * depth;
560 let normal = if cap < cylinder {
561 (point - cap_center).normalize()
562 } else {
563 vec3(point.x, 0.0, point.z).normalize()
564 };
565 (depth, true, normal)
566}
567
568/// Terminal display lift in linear light so braille remains legible on the
569/// dark card.
570fn tone(color: Vec3) -> Vec3 {
571 color * 1.28 + Vec3::rgb(4, 4, 4)
572}
573
574/// Per-frame scene state shared by every ray: sun direction, disk spin,
575/// glass transition, and the pointer camera offsets.
576struct Platter {
577 sun: Vec3,
578 angle: f32,
579 transition: f32,
580 /// Smoothed pointer camera from [`Welcome`]: (lift, yaw).
581 pointer: (f32, f32),
582}
583
584impl Platter {
585 fn new(pointer: (f32, f32)) -> Self {
586 Self { sun: vec3(-0.55, 1.0, 0.38).normalize(), angle: 0.0, transition: 0.0, pointer }
587 }
588
589 /// Floor glow: light shafts, the disk's shadow, tinted transmission
590 /// through the glass, and a soft rim reflection.
591 fn ground(&self, origin: Vec3, direction: Vec3) -> (Vec3, f32) {
592 if direction.y >= 0.0 {
593 return (BACKGROUND, 0.0);
594 }
595 let depth = (FLOOR_Y - origin.y) / direction.y;
596 if depth <= 0.0 {
597 return (BACKGROUND, 0.0);
598 }
599 let floor = origin + direction * depth;
600 let stage =
601 (-0.42 * ((floor.x.abs() / 2.30).powi(4) + ((floor.z + 0.15).abs() / 1.70).powi(4))).exp();
602
603 let sun_depth = (DISK_Y - DISK_HALF_THICKNESS - FLOOR_Y) / self.sun.y;
604 let sunlit = floor + self.sun * sun_depth;
605 let shadow_radius = sunlit.x.hypot(sunlit.z);
606 let occlusion = smooth(((DISK_RADIUS + 0.08 - shadow_radius) / 0.16).clamp(0.0, 1.0));
607 let rays = sun_rays(floor.x, floor.z);
608
609 let neutral_alpha = stage * rays * (1.0 - occlusion) * 0.36;
610 let neutral = (BACKGROUND + vec3(0.36, 0.33, 0.27) * (stage * rays)).clamp01();
611 let mut color = neutral * neutral_alpha + BACKGROUND * (1.0 - neutral_alpha);
612 let mut alpha = neutral_alpha;
613
614 let transmission_alpha =
615 stage * sun_rays(sunlit.x, sunlit.z) * occlusion * self.transition * 0.64;
616 let transmission =
617 (BACKGROUND + gradient(sunlit.z.atan2(sunlit.x) - self.angle) * 0.86).clamp01();
618 color = transmission * transmission_alpha + color * (1.0 - transmission_alpha);
619 alpha = transmission_alpha + alpha * (1.0 - transmission_alpha);
620
621 let mirrored = vec3(direction.x, -direction.y, direction.z);
622 let reflected_depth = (DISK_Y - DISK_HALF_THICKNESS - FLOOR_Y) / mirrored.y.max(1e-6);
623 let reflected = floor + mirrored * reflected_depth;
624 let reflected_radius = reflected.x.hypot(reflected.z);
625 if reflected_radius <= DISK_RADIUS {
626 let edge = smooth(((DISK_RADIUS - reflected_radius) / 0.13).clamp(0.0, 1.0));
627 let grazing = (1.0 + direction.y).clamp(0.0, 1.0);
628 let reflection_alpha = self.transition * edge * (0.22 + 0.28 * grazing);
629 let reflection = gradient(reflected.z.atan2(reflected.x) - self.angle);
630 color = reflection * reflection_alpha + color * (1.0 - reflection_alpha);
631 alpha = reflection_alpha + alpha * (1.0 - reflection_alpha);
632 }
633 (color, alpha)
634 }
635}
636
637impl Trace for Platter {
638 fn advance(&mut self, now: Duration) -> Camera {
639 let elapsed = now.as_secs_f32();
640 self.angle = disk_rotation(elapsed);
641 self.transition = color_mix(elapsed);
642 Camera {
643 target: vec3(0.0, 0.08, 0.0),
644 yaw: self.pointer.1 + reveal_orbit(elapsed) + (elapsed * 0.31).sin() * 0.018,
645 pitch: CAMERA_PITCH,
646 distance: CAMERA_DISTANCE,
647 lift: self.pointer.0.clamp(-0.42, 0.42) + (elapsed * 0.55).sin() * 0.014,
648 focal: CAMERA_FOCAL,
649 }
650 }