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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Depth offset and depth precision comparison test scene.
//!
//! Rectangles are at close distance to each other in the z==0 plane.
//! Rects on the left use "real" depth values, rects on the right use depth offset.
//! You should see the least saturated rects in front of more saturated rects.
//!
//! Press arrow up/down to increase/decrease the distance of the camera to the z==0 plane in tandem with the scale of the rectangles.
//! Press arrow left/right to increase/decrease the near plane distance.

use re_renderer::Hsva;
use re_renderer::{
    renderer::{ColormappedTexture, RectangleDrawData, RectangleOptions, TexturedRect},
    view_builder::{self, Projection, ViewBuilder},
};
use winit::keyboard;

mod framework;

struct Render2D {
    distance_scale: f32,
    near_plane: f32,
}

impl framework::Example for Render2D {
    fn title() -> &'static str {
        "Depth Offset"
    }

    fn new(_re_ctx: &re_renderer::RenderContext) -> Self {
        Self {
            distance_scale: 100.0,
            near_plane: 0.1,
        }
    }

    fn draw(
        &mut self,
        re_ctx: &re_renderer::RenderContext,
        resolution: [u32; 2],
        _time: &framework::Time,
        pixels_per_point: f32,
    ) -> anyhow::Result<Vec<framework::ViewDrawResult>> {
        let mut rectangles = Vec::new();

        let extent_u = glam::vec3(1.0, 0.0, 0.0) * self.distance_scale;
        let extent_v = glam::vec3(0.0, 1.0, 0.0) * self.distance_scale;

        // Rectangles on the left from near to far, using z.
        let base_top_left = glam::vec2(-0.8, -0.5) * self.distance_scale
            - (extent_u.truncate() + extent_v.truncate()) * 0.5;
        let xy_step = glam::vec2(-0.1, 0.1) * self.distance_scale;
        let z_values = [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.0]; // Make sure to go from near to far so that painter's algorithm would fail if depth values are no longer distinct.
        for (i, z) in z_values.into_iter().enumerate() {
            let saturation = 0.1 + i as f32 / z_values.len() as f32 * 0.9;
            rectangles.push(TexturedRect {
                top_left_corner_position: (base_top_left + i as f32 * xy_step).extend(z),
                extent_u,
                extent_v,
                colormapped_texture: ColormappedTexture::from_unorm_rgba(
                    re_ctx
                        .texture_manager_2d
                        .white_texture_unorm_handle()
                        .clone(),
                ),
                options: RectangleOptions {
                    multiplicative_tint: Hsva::new(0.0, saturation, 0.5, 1.0).into(),
                    ..Default::default()
                },
            });
        }

        // Rectangles on the right from near to far, using depth offset.
        let base_top_left = glam::vec2(0.8, -0.5) * self.distance_scale
            - (extent_u.truncate() + extent_v.truncate()) * 0.5;
        let xy_step = glam::vec2(0.1, 0.1) * self.distance_scale;
        let depth_offsets = [1000, 100, 10, 1, 0, -1]; // Make sure to go from near to far so that painter's algorithm would fail if depth values are no longer distinct.
        for (i, depth_offset) in depth_offsets.into_iter().enumerate() {
            let saturation = 0.1 + i as f32 / depth_offsets.len() as f32 * 0.9;
            rectangles.push(TexturedRect {
                top_left_corner_position: (base_top_left + i as f32 * xy_step).extend(0.0),
                extent_u,
                extent_v,
                colormapped_texture: ColormappedTexture::from_unorm_rgba(
                    re_ctx
                        .texture_manager_2d
                        .white_texture_unorm_handle()
                        .clone(),
                ),
                options: RectangleOptions {
                    multiplicative_tint: Hsva::new(0.68, saturation, 0.5, 1.0).into(),
                    depth_offset,
                    ..Default::default()
                },
            });
        }

        let mut view_builder = ViewBuilder::new(
            re_ctx,
            view_builder::TargetConfiguration {
                name: "3D".into(),
                resolution_in_pixel: resolution,
                view_from_world: re_math::IsoTransform::look_at_rh(
                    glam::Vec3::Z * 2.0 * self.distance_scale,
                    glam::Vec3::ZERO,
                    glam::Vec3::Y,
                )
                .ok_or(anyhow::format_err!("invalid camera"))?,
                projection_from_view: Projection::Perspective {
                    vertical_fov: 70.0 * std::f32::consts::TAU / 360.0,
                    near_plane_distance: self.near_plane,
                    aspect_ratio: resolution[0] as f32 / resolution[1] as f32,
                },
                pixels_per_point,
                ..Default::default()
            },
        );
        let command_buffer = view_builder
            .queue_draw(RectangleDrawData::new(re_ctx, &rectangles)?)
            .draw(re_ctx, re_renderer::Rgba::TRANSPARENT)?;

        Ok(vec![{
            framework::ViewDrawResult {
                view_builder,
                command_buffer,
                target_location: glam::Vec2::ZERO,
            }
        }])
    }

    fn on_key_event(&mut self, input: winit::event::KeyEvent) {
        if input.state == winit::event::ElementState::Pressed {
            match input.logical_key {
                keyboard::Key::Named(keyboard::NamedKey::ArrowUp) => {
                    self.distance_scale *= 1.1;
                    re_log::info!(self.distance_scale);
                }
                keyboard::Key::Named(keyboard::NamedKey::ArrowDown) => {
                    self.distance_scale /= 1.1;
                    re_log::info!(self.distance_scale);
                }
                keyboard::Key::Named(keyboard::NamedKey::ArrowRight) => {
                    self.near_plane *= 1.1;
                    re_log::info!(self.near_plane);
                }
                keyboard::Key::Named(keyboard::NamedKey::ArrowLeft) => {
                    self.near_plane /= 1.1;
                    re_log::info!(self.near_plane);
                }
                _ => {}
            }
        }
    }
}

fn main() {
    framework::start::<Render2D>();
}