three_d/renderer/geometry/
sprites.rs

1use crate::core::*;
2use crate::renderer::*;
3
4///
5/// A set of sprites, ie. a set of quads that orients itself towards the camera.
6///
7/// The sprites will always orient themselves towards the camera, but if a direction is specified, the sprite normals will also always be orthogonal to that direction.
8/// For example, if the up direction is specified, the sprites will rotate around the up direction trying to face the camera.
9/// Sprites are also known as billboards in the case where no direction is specified.
10///
11pub struct Sprites {
12    context: Context,
13    position_buffer: VertexBuffer<Vec3>,
14    uv_buffer: VertexBuffer<Vec2>,
15    center_buffer: InstanceBuffer<Vec3>,
16    transformation: Mat4,
17    direction: Option<Vec3>,
18}
19
20impl Sprites {
21    ///
22    /// Create a new set of [Sprites] with the given centers. The centers also determines the number of sprites.
23    /// The sprites will always orient themselves towards the camera, but if a direction is specified, the sprite normals will always be orthogonal to that direction.
24    ///
25    pub fn new(context: &Context, centers: &[Vec3], direction: Option<Vec3>) -> Self {
26        let position_buffer = VertexBuffer::new_with_data(
27            context,
28            &[
29                vec3(-1.0, -1.0, 0.0),
30                vec3(1.0, -1.0, 0.0),
31                vec3(1.0, 1.0, 0.0),
32                vec3(1.0, 1.0, 0.0),
33                vec3(-1.0, 1.0, 0.0),
34                vec3(-1.0, -1.0, 0.0),
35            ],
36        );
37        let uv_buffer = VertexBuffer::new_with_data(
38            context,
39            &[
40                vec2(0.0, 0.0),
41                vec2(1.0, 0.0),
42                vec2(1.0, 1.0),
43                vec2(1.0, 1.0),
44                vec2(0.0, 1.0),
45                vec2(0.0, 0.0),
46            ],
47        );
48        Self {
49            context: context.clone(),
50            position_buffer,
51            uv_buffer,
52            center_buffer: InstanceBuffer::new_with_data(context, centers),
53            transformation: Mat4::identity(),
54            direction,
55        }
56    }
57
58    ///
59    /// Returns the local to world transformation applied to all sprites.
60    ///
61    pub fn transformation(&self) -> Mat4 {
62        self.transformation
63    }
64
65    ///
66    /// Set the local to world transformation applied to all sprites.
67    ///
68    pub fn set_transformation(&mut self, transformation: Mat4) {
69        self.transformation = transformation;
70    }
71
72    ///
73    /// Set a direction the sprite normals are always orthogonal to.
74    ///
75    pub fn set_direction(&mut self, direction: Option<Vec3>) {
76        self.direction = direction;
77    }
78
79    ///
80    /// Set the centers of the sprites. The centers also determines the number of sprites.
81    ///
82    pub fn set_centers(&mut self, centers: &[Vec3]) {
83        self.center_buffer.fill(centers);
84    }
85
86    fn draw(&self, program: &Program, render_states: RenderStates, viewer: &dyn Viewer) {
87        program.use_uniform("eye", viewer.position());
88        program.use_uniform("viewProjection", viewer.projection() * viewer.view());
89        program.use_uniform("transformation", self.transformation);
90        program.use_vertex_attribute("position", &self.position_buffer);
91        if program.requires_attribute("uv_coordinate") {
92            program.use_vertex_attribute("uv_coordinate", &self.uv_buffer);
93        }
94        program.use_instance_attribute("center", &self.center_buffer);
95        program.use_uniform("direction", self.direction.unwrap_or(vec3(0.0, 0.0, 0.0)));
96        program.draw_arrays_instanced(
97            render_states,
98            viewer.viewport(),
99            6,
100            self.center_buffer.instance_count(),
101        )
102    }
103}
104
105impl<'a> IntoIterator for &'a Sprites {
106    type Item = &'a dyn Geometry;
107    type IntoIter = std::iter::Once<&'a dyn Geometry>;
108
109    fn into_iter(self) -> Self::IntoIter {
110        std::iter::once(self)
111    }
112}
113
114impl Geometry for Sprites {
115    fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
116        self.draw(program, render_states, viewer);
117    }
118
119    fn vertex_shader_source(&self) -> String {
120        include_str!("shaders/sprites.vert").to_owned()
121    }
122
123    fn id(&self) -> GeometryId {
124        GeometryId::Sprites
125    }
126
127    fn render_with_material(
128        &self,
129        material: &dyn Material,
130        viewer: &dyn Viewer,
131        lights: &[&dyn Light],
132    ) {
133        render_with_material(&self.context, viewer, &self, material, lights);
134    }
135
136    fn render_with_effect(
137        &self,
138        material: &dyn Effect,
139        viewer: &dyn Viewer,
140        lights: &[&dyn Light],
141        color_texture: Option<ColorTexture>,
142        depth_texture: Option<DepthTexture>,
143    ) {
144        render_with_effect(
145            &self.context,
146            viewer,
147            self,
148            material,
149            lights,
150            color_texture,
151            depth_texture,
152        )
153    }
154
155    fn aabb(&self) -> AxisAlignedBoundingBox {
156        AxisAlignedBoundingBox::INFINITE
157    }
158}