|
| 1 | +# Rectangle Elements |
| 2 | + |
| 3 | +Naturally we don't want just one triangle. When you're playing The Witcher 3, |
| 4 | +there's at least two triangles on the screen (maybe more!). |
| 5 | + |
| 6 | +Let's move on to drawing a rectangle. For this we need a second triangle. |
| 7 | + |
| 8 | +We could just add three more vertex entries and call it a day. If we wanted two |
| 9 | +triangles that were each on their own that's what we might do. However, since |
| 10 | +these two triangles making up our rectangle are going to be directly touching, |
| 11 | +that means we'd have six vertexes making up only four "real" points. That's 50% |
| 12 | +more space used than we want! It may seem small now, but a complete model for a |
| 13 | +tree or a person or something like that can easily end up being thousands of |
| 14 | +triangles. Making that be 50% more space used is a bad time. |
| 15 | + |
| 16 | +Of course this problem of duplicate vertices is a fairly easy problem to solve, |
| 17 | +and GL has it covered. What we do is specify an [Index |
| 18 | +Buffer](https://www.khronos.org/opengl/wiki/Vertex_Specification#Index_buffers). |
| 19 | +It holds the indexes of the vertex buffer entries we want to use to form each |
| 20 | +geometry element (in this case triangles). Then the vertex buffer doesn't need |
| 21 | +to have any duplicates, we just have more than one triangle index the same |
| 22 | +vertex. |
| 23 | + |
| 24 | +Note: What we'll be drawing is usually called a "quad", because the important |
| 25 | +part is that it has four outside edges. It's not really important that the edges |
| 26 | +are in two pairs of parallel lines at right angles with each other like a true |
| 27 | +rectangle has. |
| 28 | + |
| 29 | +## Data |
| 30 | + |
| 31 | +So we've got some new data. We're going to have 4 vertex entries that describes |
| 32 | +the points we want to use, and an index buffer with 2 entries where each entry |
| 33 | +describes a triangle using the points. |
| 34 | + |
| 35 | +```rust |
| 36 | +type Vertex = [f32; 3]; |
| 37 | +type TriIndexes = [u32; 3]; |
| 38 | + |
| 39 | +const VERTICES: [Vertex; 4] = |
| 40 | + [[0.5, 0.5, 0.0], [0.5, -0.5, 0.0], [-0.5, -0.5, 0.0], [-0.5, 0.5, 0.0]]; |
| 41 | + |
| 42 | +const INDICES: [TriIndexes; 2] = [[0, 1, 3], [1, 2, 3]]; |
| 43 | +``` |
| 44 | + |
| 45 | +## Element Buffer Object |
| 46 | + |
| 47 | +Our indexes go into a separate kind of buffer. This is that `ElementArray` |
| 48 | +buffer type that I snuck into the cleanup lesson. |
| 49 | + |
| 50 | +After we make and bind our vertex data we also bind a buffer for the element |
| 51 | +data and upload it, the code looks nearly identical: |
| 52 | + |
| 53 | +```rust |
| 54 | +let ebo = Buffer::new().expect("Couldn't make the element buffer."); |
| 55 | +ebo.bind(BufferType::ElementArray); |
| 56 | +learn::buffer_data( |
| 57 | + BufferType::ElementArray, |
| 58 | + bytemuck::cast_slice(&INDICES), |
| 59 | + GL_STATIC_DRAW, |
| 60 | +); |
| 61 | +``` |
| 62 | + |
| 63 | +## Draw It! |
| 64 | + |
| 65 | +Finally, instead of calling `glDrawArrays`, we use a separate function called [`glDrawElements`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDrawElements.xhtml). |
| 66 | + |
| 67 | +* `mode`: The style of drawing. We're still drawing triangles so we keep that |
| 68 | + from before. |
| 69 | +* `count`: The number of index elements to draw. We want two triangles to form |
| 70 | + our quad, and there's three indexes per triangle, so we put 6. |
| 71 | +* `type`: This is the type of the index data. The `u32` type is specified with |
| 72 | + `GL_UNSIGNED_INT`. I used `u32` out of habit, we could have made our indexes |
| 73 | + be `u16` or `u8` as well. |
| 74 | +* `indices`: is a pointer to the position within the index buffer to start the |
| 75 | + drawing with. Similar to the attribute specification, you pretend the index |
| 76 | + buffer starts at address 0 and then you decide the offset you want, and then |
| 77 | + cast that to a `*const` pointer. |
| 78 | + |
| 79 | +So the usage looks like this: |
| 80 | + |
| 81 | +```rust |
| 82 | +// and then draw! |
| 83 | +unsafe { |
| 84 | + glClear(GL_COLOR_BUFFER_BIT); |
| 85 | + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 as *const _); |
| 86 | +} |
| 87 | +win.swap_window(); |
| 88 | +``` |
| 89 | + |
| 90 | +## Bonus: Wireframe Mode |
| 91 | + |
| 92 | +Since this lesson is really short let's look at one extra ability we can use. |
| 93 | + |
| 94 | +You often see 3d models with just the outlines of each triangle. "Wireframe |
| 95 | +mode" it's sometimes called. We can easily do that with |
| 96 | +[`glPolygonMode`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml). |
| 97 | + |
| 98 | +* We can specify the `face`, but in the Core profile the only valid value is |
| 99 | + `GL_FRONT_AND_BACK` (in Compatibility profile you can also use `GL_FRONT` or |
| 100 | + `GL_BACK`). |
| 101 | +* We also specify the `mode`. The default is `GL_FILL`, but With `GL_LINE` we |
| 102 | + get the wireframe effect. `GL_POINT` is also allowed, but makes it pretty hard |
| 103 | + to see what's going on. |
| 104 | + |
| 105 | +All this can go in our `lib.rs` file: |
| 106 | + |
| 107 | +```rust |
| 108 | +/// The polygon display modes you can set. |
| 109 | +#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 110 | +pub enum PolygonMode { |
| 111 | + /// Just show the points. |
| 112 | + Point = GL_POINT as isize, |
| 113 | + /// Just show the lines. |
| 114 | + Line = GL_LINE as isize, |
| 115 | + /// Fill in the polygons. |
| 116 | + Fill = GL_FILL as isize, |
| 117 | +} |
| 118 | + |
| 119 | +/// Sets the font and back polygon mode to the mode given. |
| 120 | +pub fn polygon_mode(mode: PolygonMode) { |
| 121 | + unsafe { glPolygonMode(GL_FRONT_AND_BACK, mode as GLenum) }; |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +And then before our main loop we can turn it on: |
| 126 | + |
| 127 | +```rust |
| 128 | +learn::polygon_mode(PolygonMode::Line); |
| 129 | +``` |
| 130 | + |
| 131 | +Now we get a wireframe quad! and it looks like two triangles just like it should! |
| 132 | + |
| 133 | +## Done! |
| 134 | + |
| 135 | +* Code [003-rectangle-elements](https://github.com/rust-tutorials/learn-opengl/blob/master/examples/003-rectangle-elements.rs) |
0 commit comments