tangled
alpha
login
or
join now
j0.lol
/
bl0ck
0
fork
atom
WebGPU Voxel Game
0
fork
atom
overview
issues
4
pulls
pipelines
Tutorial 4: Buffers
j0.lol
1 year ago
b76cc6ab
9e4295b2
+178
-65
4 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
src
lib.rs
shader.wgsl
+15
Cargo.lock
···
152
152
name = "bl0ck"
153
153
version = "0.1.0"
154
154
dependencies = [
155
155
+
"bytemuck",
155
156
"cfg-if",
156
157
"console_error_panic_hook",
157
158
"console_log",
···
201
202
version = "1.18.0"
202
203
source = "registry+https://github.com/rust-lang/crates.io-index"
203
204
checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
205
205
+
dependencies = [
206
206
+
"bytemuck_derive",
207
207
+
]
208
208
+
209
209
+
[[package]]
210
210
+
name = "bytemuck_derive"
211
211
+
version = "1.7.1"
212
212
+
source = "registry+https://github.com/rust-lang/crates.io-index"
213
213
+
checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26"
214
214
+
dependencies = [
215
215
+
"proc-macro2",
216
216
+
"quote",
217
217
+
"syn 2.0.77",
218
218
+
]
204
219
205
220
[[package]]
206
221
name = "bytes"
+1
Cargo.toml
···
12
12
wasm-bindgen = "0.2.93"
13
13
web-sys = "0.3.70"
14
14
pollster = "0.3.0"
15
15
+
bytemuck = { version = "1.18.0", features = ["derive"] }
15
16
16
17
17
18
[lib]
+151
-59
src/lib.rs
···
1
1
+
use wgpu::util::DeviceExt;
1
2
use winit::{
2
3
event::*,
3
4
event_loop::EventLoop,
···
8
9
#[cfg(target_arch = "wasm32")]
9
10
use wasm_bindgen::prelude::*;
10
11
12
12
+
#[repr(C)]
13
13
+
#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)]
14
14
+
struct Vertex {
15
15
+
position: [f32; 3],
16
16
+
color: [f32; 3],
17
17
+
}
18
18
+
19
19
+
impl Vertex {
20
20
+
fn desc() -> wgpu::VertexBufferLayout<'static> {
21
21
+
wgpu::VertexBufferLayout {
22
22
+
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
23
23
+
step_mode: wgpu::VertexStepMode::Vertex,
24
24
+
attributes: &[
25
25
+
wgpu::VertexAttribute {
26
26
+
offset: 0,
27
27
+
shader_location: 0,
28
28
+
format: wgpu::VertexFormat::Float32x3,
29
29
+
},
30
30
+
wgpu::VertexAttribute {
31
31
+
offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
32
32
+
shader_location: 1,
33
33
+
format: wgpu::VertexFormat::Float32x3,
34
34
+
},
35
35
+
],
36
36
+
}
37
37
+
}
38
38
+
}
39
39
+
40
40
+
const TRI_VERTICES: &[Vertex] = &[
41
41
+
// CCW order
42
42
+
Vertex {
43
43
+
position: [0.0, 0.5, 0.0],
44
44
+
color: [1.0, 0.0, 0.0],
45
45
+
},
46
46
+
Vertex {
47
47
+
position: [-0.5, -0.5, 0.0],
48
48
+
color: [0.0, 1.0, 0.0],
49
49
+
},
50
50
+
Vertex {
51
51
+
position: [0.5, -0.5, 0.0],
52
52
+
color: [0.0, 0.0, 1.0],
53
53
+
},
54
54
+
];
55
55
+
56
56
+
const VERTICES: &[Vertex] = &[
57
57
+
Vertex { position: [-0.0868241, 0.49240386, 0.0], color: [0.5, 0.0, 0.5] }, // A
58
58
+
Vertex { position: [-0.49513406, 0.06958647, 0.0], color: [0.5, 0.0, 0.5] }, // B
59
59
+
Vertex { position: [-0.21918549, -0.44939706, 0.0], color: [0.5, 0.0, 0.5] }, // C
60
60
+
Vertex { position: [0.35966998, -0.3473291, 0.0], color: [0.5, 0.0, 0.5] }, // D
61
61
+
Vertex { position: [0.44147372, 0.2347359, 0.0], color: [0.5, 0.0, 0.5] }, // E
62
62
+
];
63
63
+
64
64
+
const INDICES: &[u16] = &[
65
65
+
0, 1, 4,
66
66
+
1, 2, 4,
67
67
+
2, 3, 4,
68
68
+
];
69
69
+
11
70
struct State<'srfc> {
12
71
surface: wgpu::Surface<'srfc>,
13
72
device: wgpu::Device,
···
15
74
config: wgpu::SurfaceConfiguration,
16
75
size: winit::dpi::PhysicalSize<u32>,
17
76
render_pipeline: wgpu::RenderPipeline,
77
77
+
vertex_buffer: wgpu::Buffer,
78
78
+
index_buffer: wgpu::Buffer,
79
79
+
num_indices: u32,
18
80
19
81
// Window must be declared after surface
20
82
// so it gets dropped after it
···
23
85
// src: learn wgpu
24
86
window: &'srfc Window,
25
87
26
26
-
clear_color: wgpu::Color
88
88
+
clear_color: wgpu::Color,
27
89
}
28
90
29
91
impl<'a> State<'a> {
···
100
162
101
163
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
102
164
label: Some("Shader"),
103
103
-
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into())
165
165
+
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
104
166
});
105
167
106
168
let render_pipeline_layout =
107
169
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
108
170
label: Some("Render Pipeline Layout"),
109
171
bind_group_layouts: &[],
110
110
-
push_constant_ranges: &[]
172
172
+
push_constant_ranges: &[],
111
173
});
112
112
-
174
174
+
113
175
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
114
176
label: Some("Render Pipeline"),
115
177
layout: Some(&render_pipeline_layout),
116
178
vertex: wgpu::VertexState {
117
179
module: &shader,
118
180
entry_point: "vs_main",
119
119
-
buffers: &[],
181
181
+
buffers: &[Vertex::desc()],
120
182
compilation_options: wgpu::PipelineCompilationOptions::default(),
121
183
},
122
184
fragment: Some(wgpu::FragmentState {
···
142
204
multisample: wgpu::MultisampleState {
143
205
count: 1,
144
206
mask: !0,
145
145
-
alpha_to_coverage_enabled: false
207
207
+
alpha_to_coverage_enabled: false,
146
208
},
147
209
multiview: None,
148
210
cache: None,
149
211
});
150
212
213
213
+
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
214
214
+
label: Some("Vertex Buffer"),
215
215
+
contents: bytemuck::cast_slice(VERTICES),
216
216
+
usage: wgpu::BufferUsages::VERTEX,
217
217
+
});
218
218
+
219
219
+
let index_buffer = device.create_buffer_init(
220
220
+
&wgpu::util::BufferInitDescriptor {
221
221
+
label: Some("Index Buffer"),
222
222
+
contents: bytemuck::cast_slice(INDICES),
223
223
+
usage: wgpu::BufferUsages::INDEX,
224
224
+
}
225
225
+
);
226
226
+
227
227
+
let num_indices = INDICES.len() as u32;
228
228
+
151
229
Self {
152
230
window,
153
231
surface,
···
156
234
config,
157
235
size,
158
236
render_pipeline,
237
237
+
vertex_buffer,
238
238
+
index_buffer,
239
239
+
num_indices,
159
240
clear_color: wgpu::Color {
160
241
r: 0.1,
161
242
g: 0.2,
162
243
b: 0.3,
163
163
-
a: 1.0
164
164
-
}
244
244
+
a: 1.0,
245
245
+
},
165
246
}
166
247
}
167
248
···
182
263
183
264
fn input(&mut self, event: &WindowEvent) -> bool {
184
265
match event {
185
185
-
WindowEvent::CursorMoved { device_id, position } => {
266
266
+
WindowEvent::CursorMoved {
267
267
+
device_id,
268
268
+
position,
269
269
+
} => {
186
270
dbg!(position);
187
271
self.clear_color = wgpu::Color {
188
188
-
r: position.x / (self.window.inner_size().width as f64),
189
189
-
g: 0.2,
190
190
-
b: position.y / (self.window.inner_size().height as f64),
191
191
-
a: 0.1
272
272
+
r: position.x / (self.window.inner_size().width as f64),
273
273
+
g: 0.2,
274
274
+
b: position.y / (self.window.inner_size().height as f64),
275
275
+
a: 0.1,
192
276
};
193
277
return true;
194
194
-
},
278
278
+
}
195
279
_ => {}
196
280
}
197
281
198
282
false
199
283
}
200
284
201
201
-
fn update(&mut self) {
202
202
-
}
285
285
+
fn update(&mut self) {}
203
286
204
287
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
205
288
let output = self.surface.get_current_texture()?;
206
289
207
207
-
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
290
290
+
let view = output
291
291
+
.texture
292
292
+
.create_view(&wgpu::TextureViewDescriptor::default());
208
293
209
209
-
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
210
210
-
label: Some("Render Encoder")
211
211
-
});
294
294
+
let mut encoder = self
295
295
+
.device
296
296
+
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
297
297
+
label: Some("Render Encoder"),
298
298
+
});
212
299
213
300
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
214
301
label: Some("Render Pass"),
···
218
305
ops: wgpu::Operations {
219
306
load: wgpu::LoadOp::Clear(self.clear_color),
220
307
store: wgpu::StoreOp::Store,
221
221
-
}
308
308
+
},
222
309
})],
223
310
depth_stencil_attachment: None,
224
311
occlusion_query_set: None,
225
312
timestamp_writes: None,
226
313
});
227
227
-
314
314
+
228
315
render_pass.set_pipeline(&self.render_pipeline);
229
229
-
render_pass.draw(0..3, 0..1);
316
316
+
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
317
317
+
render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
318
318
+
render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
230
319
231
320
// drop render pass before we submit to drop the mut borrow on encoder
232
321
drop(render_pass);
···
277
366
let mut state = State::new(&window).await;
278
367
let mut surface_configured = false;
279
368
280
280
-
event_loop.run(move |event, control_flow| {
281
281
-
match event {
369
369
+
event_loop
370
370
+
.run(move |event, control_flow| match event {
282
371
Event::WindowEvent {
283
372
ref event,
284
373
window_id,
285
285
-
} if window_id == state.window().id() => if !state.input(event) {
286
286
-
match event {
287
287
-
WindowEvent::CloseRequested | WindowEvent::KeyboardInput {
288
288
-
event:
289
289
-
KeyEvent {
290
290
-
state: ElementState::Pressed,
291
291
-
physical_key: PhysicalKey::Code(KeyCode::Escape),
292
292
-
..
293
293
-
},
294
294
-
..
295
295
-
} => control_flow.exit(),
296
296
-
WindowEvent::Resized(physical_size) => {
297
297
-
surface_configured = true;
298
298
-
state.resize(*physical_size);
299
299
-
}
300
300
-
WindowEvent::RedrawRequested => {
301
301
-
state.window().request_redraw();
302
302
-
303
303
-
if !surface_configured {
304
304
-
return;
374
374
+
} if window_id == state.window().id() => {
375
375
+
if !state.input(event) {
376
376
+
match event {
377
377
+
WindowEvent::CloseRequested
378
378
+
| WindowEvent::KeyboardInput {
379
379
+
event:
380
380
+
KeyEvent {
381
381
+
state: ElementState::Pressed,
382
382
+
physical_key: PhysicalKey::Code(KeyCode::Escape),
383
383
+
..
384
384
+
},
385
385
+
..
386
386
+
} => control_flow.exit(),
387
387
+
WindowEvent::Resized(physical_size) => {
388
388
+
surface_configured = true;
389
389
+
state.resize(*physical_size);
305
390
}
391
391
+
WindowEvent::RedrawRequested => {
392
392
+
state.window().request_redraw();
306
393
307
307
-
state.update();
308
308
-
match state.render() {
309
309
-
Ok(_) => {}
310
310
-
Err(
311
311
-
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated
312
312
-
) => state.resize(state.size),
313
313
-
Err(wgpu::SurfaceError::OutOfMemory) => {
314
314
-
log::error!("Out of memory!");
315
315
-
control_flow.exit();
394
394
+
if !surface_configured {
395
395
+
return;
316
396
}
317
317
-
Err(wgpu::SurfaceError::Timeout) => {
318
318
-
log::warn!("Surface timeout!");
397
397
+
398
398
+
state.update();
399
399
+
match state.render() {
400
400
+
Ok(_) => {}
401
401
+
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
402
402
+
state.resize(state.size)
403
403
+
}
404
404
+
Err(wgpu::SurfaceError::OutOfMemory) => {
405
405
+
log::error!("Out of memory!");
406
406
+
control_flow.exit();
407
407
+
}
408
408
+
Err(wgpu::SurfaceError::Timeout) => {
409
409
+
log::warn!("Surface timeout!");
410
410
+
}
319
411
}
320
412
}
413
413
+
_ => {}
321
414
}
322
322
-
_ => {}
323
415
}
324
324
-
},
416
416
+
}
325
417
Event::AboutToWait => {
326
418
state.window().request_redraw();
327
419
}
328
420
_ => {}
329
329
-
}})
421
421
+
})
330
422
.unwrap();
331
423
}
+11
-6
src/shader.wgsl
···
1
1
// Vertex shader
2
2
3
3
+
struct VertexInput {
4
4
+
@location(0) position: vec3<f32>,
5
5
+
@location(1) color: vec3<f32>,
6
6
+
}
7
7
+
3
8
struct VertexOutput {
4
9
@builtin(position) clip_position: vec4<f32>,
10
10
+
@location(0) color: vec3<f32>,
5
11
};
6
12
7
13
@vertex
8
14
fn vs_main(
9
9
-
@builtin(vertex_index) in_vertex_index: u32,
15
15
+
model: VertexInput,
10
16
) -> VertexOutput {
11
17
var out: VertexOutput;
12
12
-
let x = f32(1 - i32(in_vertex_index)) * 0.5;
13
13
-
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
14
14
-
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
18
18
+
out.color = model.color;
19
19
+
out.clip_position = vec4<f32>(model.position, 1.0);
15
20
return out;
16
21
}
17
22
···
20
25
21
26
@fragment
22
27
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
23
23
-
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
24
24
-
}
28
28
+
return vec4<f32>(in.color, 1.0);
29
29
+
}