Render multiple cubes

Description

In our game we're going to render many cubes to make up a world. Most of what we've built can be reused, but we'll want to put the cubes in different positions.

We've already built a transformation that can move the model cube at the origin to an arbitrary position in the world. The position is supplied to the vertex shader via a uniform which we had given a default value.

The more common use for a uniform is for the application to pass in values to the shader each time the pipeline is invoked (i.e. when we call glDrawTriangles). In this case we want to specify a new position each time we draw a cube.

Screenshot

Commands

git clone git@github.com:atsheehan/iridium
cd iridium
git checkout 0e78981dfa2fe7106f72762adc9d3132483dac62
cargo run --release

Code Changes

Modified shaders/cube.vertGitHub

@@ -3,7 +3,7 @@
33 const float NEAR = 0.1;
44 const float FAR = 10000.0;
55
6- uniform vec3 position = vec3(2.0, 3.0, 6.0);
6+ uniform vec3 position;
77
88 out vec3 vertex_color;
99
@@ -3,7 +3,7 @@
3 const float NEAR = 0.1;
4 const float FAR = 10000.0;
5
6- uniform vec3 position = vec3(2.0, 3.0, 6.0);
7
8 out vec3 vertex_color;
9
@@ -3,7 +3,7 @@
3 const float NEAR = 0.1;
4 const float FAR = 10000.0;
5
6+ uniform vec3 position;
7
8 out vec3 vertex_color;
9

Modified src/main.rsGitHub

@@ -1,5 +1,7 @@
1+ mod math;
12 mod render;
23
4+ use math::Vec3;
35 use render::Renderer;
46 use winit::{
57 event::{Event, WindowEvent},
@@ -23,7 +25,10 @@
2325 window_id,
2426 } if window_id == renderer.window_id() => {
2527 renderer.clear();
26- renderer.draw_cube();
28+ renderer.draw_cube(&Vec3(2.0, 3.0, 6.0));
29+ renderer.draw_cube(&Vec3(-4.0, 0.0, 6.0));
30+ renderer.draw_cube(&Vec3(5.0, 10.0, 30.0));
31+ renderer.draw_cube(&Vec3(20.0, -23.0, 30.0));
2732 renderer.present();
2833 }
2934 _ => (),
@@ -1,5 +1,7 @@
 
1 mod render;
2
 
3 use render::Renderer;
4 use winit::{
5 event::{Event, WindowEvent},
@@ -23,7 +25,10 @@
23 window_id,
24 } if window_id == renderer.window_id() => {
25 renderer.clear();
26- renderer.draw_cube();
 
 
 
27 renderer.present();
28 }
29 _ => (),
@@ -1,5 +1,7 @@
1+ mod math;
2 mod render;
3
4+ use math::Vec3;
5 use render::Renderer;
6 use winit::{
7 event::{Event, WindowEvent},
@@ -23,7 +25,10 @@
25 window_id,
26 } if window_id == renderer.window_id() => {
27 renderer.clear();
28+ renderer.draw_cube(&Vec3(2.0, 3.0, 6.0));
29+ renderer.draw_cube(&Vec3(-4.0, 0.0, 6.0));
30+ renderer.draw_cube(&Vec3(5.0, 10.0, 30.0));
31+ renderer.draw_cube(&Vec3(20.0, -23.0, 30.0));
32 renderer.present();
33 }
34 _ => (),

Added src/math.rsGitHub

1+ pub(crate) struct Vec3(pub(crate) f32, pub(crate) f32, pub(crate) f32);
1+ pub(crate) struct Vec3(pub(crate) f32, pub(crate) f32, pub(crate) f32);

Modified src/render.rsGitHub

@@ -15,6 +15,8 @@
1515 window::{Window, WindowBuilder, WindowId},
1616 };
1717
18+ use crate::math::Vec3;
19+
1820 const CUBE_VERTEX_SHADER_SRC: &str = include_str!("../shaders/cube.vert");
1921 const CUBE_FRAGMENT_SHADER_SRC: &str = include_str!("../shaders/cube.frag");
2022
@@ -100,7 +102,9 @@
100102 }
101103 }
102104
103- pub(crate) fn draw_cube(&mut self) {
105+ pub(crate) fn draw_cube(&mut self, position: &Vec3) {
106+ self.cube_program.set_uniform_vec3("position", position);
107+
104108 unsafe {
105109 gl::UseProgram(self.cube_program.gl_id());
106110 gl::BindVertexArray(self.cube_vertex_array_id);
@@ -172,6 +176,16 @@
172176 fn gl_id(&self) -> GLuint {
173177 self.id.0
174178 }
179+
180+ fn set_uniform_vec3(&mut self, name: &str, value: &Vec3) {
181+ let Vec3(x, y, z) = *value;
182+
183+ let cstr_name = CString::new(name).unwrap();
184+ let location = unsafe { gl::GetUniformLocation(self.gl_id(), cstr_name.as_ptr()) };
185+ unsafe {
186+ gl::Uniform3f(location, x, y, z);
187+ }
188+ }
175189 }
176190
177191 struct ShaderId(GLuint);
@@ -15,6 +15,8 @@
15 window::{Window, WindowBuilder, WindowId},
16 };
17
 
 
18 const CUBE_VERTEX_SHADER_SRC: &str = include_str!("../shaders/cube.vert");
19 const CUBE_FRAGMENT_SHADER_SRC: &str = include_str!("../shaders/cube.frag");
20
@@ -100,7 +102,9 @@
100 }
101 }
102
103- pub(crate) fn draw_cube(&mut self) {
 
 
104 unsafe {
105 gl::UseProgram(self.cube_program.gl_id());
106 gl::BindVertexArray(self.cube_vertex_array_id);
@@ -172,6 +176,16 @@
172 fn gl_id(&self) -> GLuint {
173 self.id.0
174 }
 
 
 
 
 
 
 
 
 
 
175 }
176
177 struct ShaderId(GLuint);
@@ -15,6 +15,8 @@
15 window::{Window, WindowBuilder, WindowId},
16 };
17
18+ use crate::math::Vec3;
19+
20 const CUBE_VERTEX_SHADER_SRC: &str = include_str!("../shaders/cube.vert");
21 const CUBE_FRAGMENT_SHADER_SRC: &str = include_str!("../shaders/cube.frag");
22
@@ -100,7 +102,9 @@
102 }
103 }
104
105+ pub(crate) fn draw_cube(&mut self, position: &Vec3) {
106+ self.cube_program.set_uniform_vec3("position", position);
107+
108 unsafe {
109 gl::UseProgram(self.cube_program.gl_id());
110 gl::BindVertexArray(self.cube_vertex_array_id);
@@ -172,6 +176,16 @@
176 fn gl_id(&self) -> GLuint {
177 self.id.0
178 }
179+
180+ fn set_uniform_vec3(&mut self, name: &str, value: &Vec3) {
181+ let Vec3(x, y, z) = *value;
182+
183+ let cstr_name = CString::new(name).unwrap();
184+ let location = unsafe { gl::GetUniformLocation(self.gl_id(), cstr_name.as_ptr()) };
185+ unsafe {
186+ gl::Uniform3f(location, x, y, z);
187+ }
188+ }
189 }
190
191 struct ShaderId(GLuint);