Add simple shading
This commit is contained in:
@@ -10,3 +10,4 @@ I will try to keep this list up to date with all resources, which
|
|||||||
I use for learning.
|
I use for learning.
|
||||||
- https://sotrh.github.io/learn-wgpu/#what-is-wgpu (Starting point for this project)
|
- https://sotrh.github.io/learn-wgpu/#what-is-wgpu (Starting point for this project)
|
||||||
- https://github.com/sotrh/learn-wgpu (Matching GitHub Repo)
|
- https://github.com/sotrh/learn-wgpu (Matching GitHub Repo)
|
||||||
|
- https://www.youtube.com/watch?v=vV8mwo65kR8 (Building WebGPU with Rust Talk by FOSDEM)
|
||||||
|
|||||||
27
src/challenge_shader.wgsl
Normal file
27
src/challenge_shader.wgsl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Vertex shader
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
[[builtin(position)]] clip_coordinates: vec4<f32>;
|
||||||
|
[[location(0)]] position: vec2<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn main(
|
||||||
|
[[builtin(vertex_index)]] in_vertex_index: u32,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
let x = f32(1 - i32(in_vertex_index)) * 0.5;
|
||||||
|
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
|
||||||
|
out.clip_coordinates = vec4<f32>(x, y, 0.0, 1.0);
|
||||||
|
out.position = vec2<f32>(x, y);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fragment shader
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
||||||
|
let r = in.position.x;
|
||||||
|
let g = in.position.y;
|
||||||
|
return vec4<f32>(r, g, 0.1, 1.0);
|
||||||
|
}
|
||||||
23
src/shader.wgsl
Normal file
23
src/shader.wgsl
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Vertex shader
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
[[builtin(position)]] clip_position: vec4<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn main(
|
||||||
|
[[builtin(vertex_index)]] in_vertex_index: u32,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
let x = f32(1 - i32(in_vertex_index)) * 0.5;
|
||||||
|
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
|
||||||
|
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fragment shader
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
||||||
|
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
|
||||||
|
}
|
||||||
175
src/state.rs
175
src/state.rs
@@ -1,3 +1,4 @@
|
|||||||
|
use wgpu::PrimitiveTopology;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::*,
|
event::*,
|
||||||
window::Window,
|
window::Window,
|
||||||
@@ -12,24 +13,32 @@ pub struct State {
|
|||||||
swap_chain: wgpu::SwapChain,
|
swap_chain: wgpu::SwapChain,
|
||||||
pub size: winit::dpi::PhysicalSize<u32>,
|
pub size: winit::dpi::PhysicalSize<u32>,
|
||||||
clear_color: wgpu::Color,
|
clear_color: wgpu::Color,
|
||||||
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
|
challenge_render_pipeline: wgpu::RenderPipeline,
|
||||||
|
use_challenge_render_pipeline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub async fn new(window: &Window) -> Self {
|
pub async fn new(window: &Window) -> Self {
|
||||||
// actual screen size
|
// actual screen size
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
|
|
||||||
// handle to gpu
|
// handle to gpu
|
||||||
|
// PRIMARY, VULKAN, DX12, METAL, BROWSER_WEBGPU
|
||||||
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
|
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
|
||||||
|
|
||||||
// a surface to draw to
|
// a surface to draw to
|
||||||
let surface = unsafe { instance.create_surface(window) };
|
let surface = unsafe { instance.create_surface(window) };
|
||||||
// get a working adapter for the current system
|
|
||||||
|
// get a physical adapter for the current system
|
||||||
let adapter = instance.request_adapter(
|
let adapter = instance.request_adapter(
|
||||||
&wgpu::RequestAdapterOptions {
|
&wgpu::RequestAdapterOptions {
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
},
|
},
|
||||||
).await.unwrap();
|
).await.unwrap();
|
||||||
// adapter device and queue
|
|
||||||
|
// logical device and command queue to work with
|
||||||
let (device, queue) = adapter.request_device(
|
let (device, queue) = adapter.request_device(
|
||||||
&wgpu::DeviceDescriptor {
|
&wgpu::DeviceDescriptor {
|
||||||
// no special features required
|
// no special features required
|
||||||
@@ -40,6 +49,7 @@ impl State {
|
|||||||
},
|
},
|
||||||
None, // Trace path
|
None, // Trace path
|
||||||
).await.unwrap();
|
).await.unwrap();
|
||||||
|
|
||||||
// description of the swap_chain
|
// description of the swap_chain
|
||||||
let sc_desc = wgpu::SwapChainDescriptor {
|
let sc_desc = wgpu::SwapChainDescriptor {
|
||||||
// how textures will be used
|
// how textures will be used
|
||||||
@@ -52,9 +62,139 @@ impl State {
|
|||||||
// how to sync with the display
|
// how to sync with the display
|
||||||
present_mode: wgpu::PresentMode::Fifo,
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
};
|
};
|
||||||
|
|
||||||
// actually create a swap_chain
|
// actually create a swap_chain
|
||||||
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||||
|
|
||||||
|
// load shader file
|
||||||
|
let shader = device.create_shader_module(
|
||||||
|
&wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Shader"),
|
||||||
|
flags: wgpu::ShaderFlags::all(),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
let render_pipeline_layout = device.create_pipeline_layout(
|
||||||
|
&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Render Pipeline Layput"),
|
||||||
|
bind_group_layouts: &[],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// add everything to the render_pipeline
|
||||||
|
let render_pipeline = device.create_render_pipeline(
|
||||||
|
&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Render Pipeline"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
// function name in shader.wgsl for [[stage(vertex)]]
|
||||||
|
entry_point: "main",
|
||||||
|
// already specified in the shader
|
||||||
|
buffers: &[],
|
||||||
|
|
||||||
|
},
|
||||||
|
// needed to sotre color data to swap_chain
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "main",
|
||||||
|
// setup of color outputs
|
||||||
|
targets: &[wgpu::ColorTargetState {
|
||||||
|
format: sc_desc.format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrite::ALL,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: PrimitiveTopology::TriangleList,
|
||||||
|
strip_index_format: None,
|
||||||
|
// triangle facing forward when Counter Clock Wise
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: Some(wgpu::Face::Back),
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
clamp_depth: false,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
// only use 1 sample => no extra sampling
|
||||||
|
count: 1,
|
||||||
|
// use all
|
||||||
|
mask: !0,
|
||||||
|
// not using anti aliasing
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// overwrite challenge shader file to shader
|
||||||
|
let shader = device.create_shader_module(
|
||||||
|
&wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Shader"),
|
||||||
|
flags: wgpu::ShaderFlags::all(),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(
|
||||||
|
include_str!("challenge_shader.wgsl").into()),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
let render_pipeline_layout = device.create_pipeline_layout(
|
||||||
|
&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Render Pipeline Layput"),
|
||||||
|
bind_group_layouts: &[],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// add everything to the challnge_render_pipeline
|
||||||
|
let challenge_render_pipeline = device.create_render_pipeline(
|
||||||
|
&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Render Pipeline"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
// function name in shader.wgsl for [[stage(vertex)]]
|
||||||
|
entry_point: "main",
|
||||||
|
// already specified in the shader
|
||||||
|
buffers: &[],
|
||||||
|
|
||||||
|
},
|
||||||
|
// needed to sotre color data to swap_chain
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "main",
|
||||||
|
// setup of color outputs
|
||||||
|
targets: &[wgpu::ColorTargetState {
|
||||||
|
format: sc_desc.format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrite::ALL,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: PrimitiveTopology::TriangleList,
|
||||||
|
strip_index_format: None,
|
||||||
|
// triangle facing forward when Counter Clock Wise
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: Some(wgpu::Face::Back),
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
clamp_depth: false,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
// only use 1 sample => no extra sampling
|
||||||
|
count: 1,
|
||||||
|
// use all
|
||||||
|
mask: !0,
|
||||||
|
// not using anti aliasing
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
surface,
|
surface,
|
||||||
device,
|
device,
|
||||||
@@ -63,6 +203,9 @@ impl State {
|
|||||||
swap_chain,
|
swap_chain,
|
||||||
size,
|
size,
|
||||||
clear_color: wgpu::Color { r: 0.6, g: 0.6, b: 0.1, a: 1.0 },
|
clear_color: wgpu::Color { r: 0.6, g: 0.6, b: 0.1, a: 1.0 },
|
||||||
|
render_pipeline,
|
||||||
|
challenge_render_pipeline,
|
||||||
|
use_challenge_render_pipeline: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,10 +223,21 @@ impl State {
|
|||||||
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
let x = (position.x as f64) / 1000 as f64;
|
let x = (position.x as f64) / self.size.width as f64;
|
||||||
let y = (position.y as f64) / 1000 as f64;
|
let y = (position.y as f64) / self.size.height as f64;
|
||||||
self.clear_color = wgpu::Color { r: x, g: x, b: y, a: 1.0};
|
self.clear_color = wgpu::Color { r: x, g: x, b: y, a: 1.0};
|
||||||
true
|
true
|
||||||
|
},
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input: KeyboardInput {
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
virtual_keycode: Some(VirtualKeyCode::Space),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
self.use_challenge_render_pipeline = !self.use_challenge_render_pipeline;
|
||||||
|
true
|
||||||
}
|
}
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
@@ -106,7 +260,7 @@ impl State {
|
|||||||
label: Some("Render Encoder"),
|
label: Some("Render Encoder"),
|
||||||
});
|
});
|
||||||
// create a render_pass
|
// create a render_pass
|
||||||
let _render_pass = encoder.begin_render_pass(
|
let mut render_pass = encoder.begin_render_pass(
|
||||||
&wgpu::RenderPassDescriptor {
|
&wgpu::RenderPassDescriptor {
|
||||||
label: Some("Render Pass"),
|
label: Some("Render Pass"),
|
||||||
color_attachments: &[
|
color_attachments: &[
|
||||||
@@ -122,8 +276,17 @@ impl State {
|
|||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// set pipeline
|
||||||
|
if self.use_challenge_render_pipeline {
|
||||||
|
render_pass.set_pipeline(&self.challenge_render_pipeline);
|
||||||
|
} else {
|
||||||
|
render_pass.set_pipeline(&self.render_pipeline);
|
||||||
|
}
|
||||||
|
// draw triangle
|
||||||
|
render_pass.draw(0..3, 0..1);
|
||||||
|
|
||||||
// drop so encoder isn't borrowed mutually anymore
|
// drop so encoder isn't borrowed mutually anymore
|
||||||
drop(_render_pass);
|
drop(render_pass);
|
||||||
|
|
||||||
// submit finished command buffers
|
// submit finished command buffers
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
|||||||
Reference in New Issue
Block a user