I simply want to make it add triangles at the spot clicked on the screen. Im new to rust and wgpu so I have been following this tutorial. I have used OpenGL a few times so I thought this was pretty similar and stopped at buffers and indices. (Possibly mistake)
I think the issue has to do with the vertex buffer
use crate::tri::Traingle;
pub struct Renderer {
pub window: Window, // using winit
surface: wgpu::Surface,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
pub size: winit::dpi::PhysicalSize<u32>,
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
buffer_size: usize,
}
impl Renderer {
pub async fn new(window: Window) -> Self {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default());
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance.request_adapter(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: Some(&surface),
force_fallback_adapter: false,
},
).await.unwrap();
let (device, queue) = adapter.request_device(
&wgpu::DeviceDescriptor {
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
label: None,
},
None,
).await.unwrap();
let surface_caps = surface.get_capabilities(&adapter);
let surface_format = surface_caps.formats.iter()
.copied()
.filter(|f| f.is_srgb())
.next()
.unwrap_or(surface_caps.formats[0]);
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface_format,
width: size.width,
height: size.height,
present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![],
};
surface.configure(&device, &config);
let shader = device.create_shader_module(wgpu::include_wgsl!("shader.wgsl"));
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor::default());
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[
Vertex::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
cull_mode: Some(wgpu::Face::Back),
..wgpu::PrimitiveState::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
});
let vertex_buffer = device.create_buffer(
&wgpu::BufferDescriptor {
label: Some("Vertex Buffer"),
size: 0u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
}
);
let buffer_size = 0usize;
Self {
window,
surface,
device,
queue,
config,
size,
render_pipeline,
vertex_buffer,
buffer_size,
}
}
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.config.width = new_size.width;
self.config.height = new_size.height;
self.surface.configure(&self.device, &self.config);
}
}
pub fn input(&mut self) -> bool {
false
}
pub fn update(&mut self) {}
pub fn render(&mut self, triangles: &Vec<Triangle>) -> Result<(), wgpu::SurfaceError> {
let output = self.surface.get_current_texture()?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[
Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
})
],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
// creates a vector that will be filled with the vertex positions
let mut vertices: Vec<Vertex> = vec![Vertex { position: [0., 0., 0.] }; triangles.len() * 3];
// loops through the triangles and adds their vertices to the list
for (i, tri) in triangles.iter().enumerate() {
vertices[i * 3] = Vertex {
position: [tri.x, tri.y - tri::RADIUS / 800., 0.]
};
vertices[i * 3 + 1] = Vertex {
position: [tri.x - tri::RADIUS / 1200., tri.y + tri::RADIUS / 800., 0.]
};
vertices[i * 3 + 2] = Vertex {
position: [tri.x + tri::RADIUS / 1200., tri.y + tri::RADIUS / 800., 0.]
};
}
// create a new buffer with the right size if its different
if vertices.len() != self.buffer_size {
self.vertex_buffer = self.device.create_buffer(
&wgpu::BufferDescriptor {
label: Some("Vertex Buffer"),
size: (vertices.len() * std::mem::size_of::<[f32; 3]>()) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
}
);
self.buffer_size = vertices.len();
}
self.queue.write_buffer(&self.vertex_buffer, 0u64, bytemuck::cast_slice(vertices.as_slice()));
let num_vertices = vertices.len() as u32;
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.draw(0..num_vertices, 0..1);
drop(render_pass);
self.queue.submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
}
and heres the part of main.rs
where the click function actually adds a triangle.. although this part im 99% sure is functioning correctly
// there is a 'triangles' vec which is passed to Renderer.render()
WindowEvent::MouseInput { button, state, .. } => {
if button == &MouseButton::Left && state == &ElementState::Pressed {
triangles.push(Triangle {
x: mouse_position.x as f32 / WIDTH as f32,
y: mouse_position.y as f32 / HEIGHT as f32,
});
}
}
and finally the wgsl code
struct VertexInput {
@location(0) position: vec3<f32>,
};
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
};
@vertex
fn vs_main(
model: VertexInput,
) -> VertexOutput {
var out: VertexOutput;
out.clip_position = vec4<f32>(model.position, 1.0);
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.8, 0.1, 1.0);
}
Maybe I should be using a swapchain? I dont know why that would be the reason it isnt working but again im days into this
all help appreciated
You wrote:
This is a clockwise-wound triangle, which by your pipeline's
PrimitiveState
is considered a back-face and culled.You should:
cull_mode
toNone
, so that any further winding / mirroring bugs don't cause your triangles to disappear.If you still don't get any visible triangles, I suggest modifying your code to print out the contents of
vertices: Vec<Vertex>
so that you can see whether the coordinates of the triangles are reasonable. “Everything is accidentally positioned offscreen” is one of the classic ways to get a blank screen.