Skip to main content

ranim_render/primitives/
viewport.rs

1use glam::{Mat4, Vec2};
2
3use crate::utils::{WgpuBuffer, WgpuContext};
4
5/// Total normalized-depth span reserved for scene-order biasing.
6///
7/// Fragments whose true depth differs by less than this span may be reordered
8/// by scene insertion order (later items on top); anything farther apart keeps
9/// true depth ordering. The per-order epsilon divides this span by the frame's
10/// full scene-order span (at least one). This keeps offsets bounded even when
11/// omitted render plugins leave gaps in the prepared items' scene orders.
12pub const DEPTH_ORDER_SPAN: f32 = 1e-4;
13
14/// Uniforms for the camera
15#[repr(C, align(16))]
16#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
17pub struct ViewportUniform {
18    proj_mat: Mat4,
19    view_mat: Mat4,
20    half_frame_size: Vec2,
21    /// Per-order depth bias epsilon, see [`DEPTH_ORDER_SPAN`].
22    bias_epsilon: f32,
23    _padding: u32,
24}
25
26impl ViewportUniform {
27    /// Build a view packet from projection, view and frame-size data.
28    pub fn new(proj_mat: Mat4, view_mat: Mat4, half_frame_size: Vec2, bias_epsilon: f32) -> Self {
29        Self {
30            proj_mat,
31            view_mat,
32            half_frame_size,
33            bias_epsilon,
34            _padding: 0,
35        }
36    }
37    pub(crate) fn as_bind_group_layout_entry(binding: u32) -> wgpu::BindGroupLayoutEntry {
38        wgpu::BindGroupLayoutEntry {
39            binding,
40            visibility: wgpu::ShaderStages::COMPUTE | wgpu::ShaderStages::VERTEX_FRAGMENT,
41            ty: wgpu::BindingType::Buffer {
42                ty: wgpu::BufferBindingType::Uniform,
43                has_dynamic_offset: false,
44                min_binding_size: None,
45            },
46            count: None,
47        }
48    }
49}
50
51impl Default for ViewportUniform {
52    fn default() -> Self {
53        Self::new(Mat4::IDENTITY, Mat4::IDENTITY, Vec2::ONE, 0.0)
54    }
55}
56
57pub struct ViewportBindGroup {
58    pub bind_group: wgpu::BindGroup,
59}
60
61impl AsRef<wgpu::BindGroup> for ViewportBindGroup {
62    fn as_ref(&self) -> &wgpu::BindGroup {
63        &self.bind_group
64    }
65}
66
67impl ViewportBindGroup {
68    pub fn bind_group_layout(ctx: &WgpuContext) -> wgpu::BindGroupLayout {
69        ctx.device
70            .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
71                label: Some("Viewport Bind Group Layout"),
72                entries: &[ViewportUniform::as_bind_group_layout_entry(0)],
73            })
74    }
75
76    pub(crate) fn new(ctx: &WgpuContext, uniforms_buffer: &WgpuBuffer<ViewportUniform>) -> Self {
77        let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
78            label: Some("Camera Uniforms"),
79            layout: &Self::bind_group_layout(ctx),
80            entries: &[wgpu::BindGroupEntry {
81                binding: 0,
82                resource: wgpu::BindingResource::Buffer(
83                    uniforms_buffer.as_ref().as_entire_buffer_binding(),
84                ),
85            }],
86        });
87        Self { bind_group }
88    }
89}
90
91#[derive(bevy_ecs::prelude::Resource)]
92pub struct ViewportGpuPacket {
93    pub(crate) uniforms_buffer: WgpuBuffer<ViewportUniform>,
94    pub(crate) uniforms_bind_group: ViewportBindGroup,
95}
96
97impl ViewportGpuPacket {
98    /// Bind the current view data in an item rendering pipeline.
99    pub fn bind_group(&self) -> &wgpu::BindGroup {
100        &self.uniforms_bind_group.bind_group
101    }
102
103    pub(crate) fn new(ctx: &WgpuContext, data: &ViewportUniform) -> Self {
104        let uniforms_buffer = WgpuBuffer::new_init(
105            ctx,
106            Some("Uniforms Buffer"),
107            wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
108            *data,
109        );
110        let uniforms_bind_group = ViewportBindGroup::new(ctx, &uniforms_buffer);
111
112        Self {
113            uniforms_buffer,
114            uniforms_bind_group,
115        }
116    }
117
118    pub fn update(&mut self, ctx: &WgpuContext, data: &ViewportUniform) {
119        self.uniforms_buffer.set(ctx, *data);
120    }
121}