使用wgpu结合lyon时三角形无法渲染的问题排查
使用wgpu + lyon绘制图形无显示问题排查
问题描述
我用wgpu结合lyon开发画线系统,调用draw_indexed()加载lyon生成的VertexBuffers时,画面完全没有内容显示。
相关实现代码
impl LineDrawer { fn build(self, device: &Device) -> Vec<Buffer> { let mut buffers = Vec::new(); for i in self.lines { let buffer = i.build(); let vertex = device.create_buffer_init(&BufferInitDescriptor { label: None, contents: bytemuck::cast_slice(&buffer.vertices), usage: wgpu::BufferUsages::VERTEX, }); let index_len = buffer.indices.len(); let index = device.create_buffer_init(&BufferInitDescriptor { label: None, contents: bytemuck::cast_slice(&buffer.indices), usage: wgpu::BufferUsages::INDEX, }); buffers.push(Buffer { index, vertex, index_len }); } buffers } pub fn render( self, device: &Device, encoder: &mut wgpu::CommandEncoder, view: &wgpu::TextureView, camera_bind_group: &wgpu::BindGroup, ) { let shader = device.create_shader_module(wgpu::include_wgsl!("line_drawer.wgsl")); let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Line Drawer Pipeline Layout"), bind_group_layouts: &[camera_bind_group_layout], push_constant_ranges: &[], }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("Line Drawer Pipeline"), layout: Some(&render_pipeline_layout), vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", buffers: &[ColorVertex::desc()], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: config.format, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, })], }), primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, polygon_mode: wgpu::PolygonMode::Fill, front_face: wgpu::FrontFace::Ccw, strip_index_format: None, cull_mode: Some(wgpu::Face::Back), conservative: false, unclipped_depth: false, }, depth_stencil: None, multisample: wgpu::MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false, }, multiview: None, }); let buffers = self.build(device); { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Load, store: true, }, })], depth_stencil_attachment: None, }); render_pass.set_pipeline(pipeline); render_pass.set_bind_group(0, camera_bind_group, &[]); for i in 0..buffers.len() { render_pass.set_index_buffer(buffers[i].index.slice(..), wgpu::IndexFormat::Uint16); render_pass.set_vertex_buffer(0, buffers[i].vertex.slice(..)); render_pass.draw_indexed(0..buffers[i].index_len as u32, 0, 0..1) } } } pub struct Line { buffer: VertexBuffers<ColorVertex, u32>, } struct Buffer { index: wgpu::Buffer, vertex: wgpu::Buffer, index_len: usize, } impl Line { pub fn rectangle(mut self, bounds: Rect, color: Color) -> Self { { let buffers = &mut self.buffer; let rect = lyon::math::Box2D::from_origin_and_size( lyon::math::point(bounds.x, bounds.y), lyon::math::size(bounds.width, bounds.height), ); let vb = VertexBuilder { color: LinearColor::from(color), }; let builder = &mut lyon::tessellation::BuffersBuilder::new(buffers, vb); let mut tessellator = lyon::tessellation::FillTessellator::new(); tessellator.tessellate_rectangle( &rect, &lyon::lyon_tessellation::FillOptions::default(), builder ) .expect("could not create rectangle"); } self } pub fn build(self) -> VertexBuffers<ColorVertex, u32> { dbg!(&self.buffer); self.buffer }
调试输出
&self.buffer = VertexBuffers { vertices: [ ColorVertex { position: [ 0.0, 0.0, 0.0, ], color: [ 1.0, 1.0, 1.0, 1.0, ], }, ColorVertex { position: [ 0.0, 100.0, 0.0, ], color: [ 1.0, 1.0, 1.0, 1.0, ], }, ColorVertex { position: [ 100.0, 100.0, 0.0, ], color: [ 1.0, 1.0, 1.0, 1.0, ], }, ColorVertex { position: [ 100.0, 0.0, 0.0, ], color: [ 1.0, 1.0, 1.0, 1.0, ], }, ], indices: [ 0, 1, 2, 0, 2, 3, ], }
问题定位与修复
1. 索引格式不匹配(核心问题)
lyon生成的索引是u32类型,但渲染时设置的索引格式是Uint16,导致索引数据解析错误,无法正确绘制三角形。
修复:修改render方法中的索引格式设置:
render_pass.set_index_buffer(buffers[i].index.slice(..), wgpu::IndexFormat::Uint32);
2. 渲染管线重复创建
每次调用render都重新创建shader和渲染管线,不仅效率低下,还可能引发状态不一致问题。
修复:将shader和渲染管线的创建逻辑移到LineDrawer的初始化阶段,复用已有资源。
3. 顶点坐标空间转换缺失
如果顶点着色器没有将本地坐标转换到裁剪空间,图形会被视锥体裁剪,无法显示在屏幕上。
修复:确保顶点着色器包含视图-投影矩阵转换逻辑,示例如下:
struct CameraUniform { view_proj: mat4x4<f32>, }; @group(0) @binding(0) var<uniform> camera: CameraUniform; struct VertexInput { @location(0) position: vec3<f32>, @location(1) color: vec4<f32>, }; struct VertexOutput { @location(0) color: vec4<f32>, @builtin(position) clip_position: vec4<f32>, }; @vertex fn vs_main(input: VertexInput) -> VertexOutput { var out: VertexOutput; out.color = input.color; out.clip_position = camera.view_proj * vec4(input.position, 1.0); return out; }
4. 相机视锥体范围验证
检查相机投影矩阵是否覆盖了图形的坐标范围(示例中矩形坐标为0-100),如果视锥体不包含该区域,图形会被裁剪。例如使用正交投影时:
let proj = glam::Mat4::orthographic_rh_gl(0.0, screen_width, screen_height, 0.0, 0.0, 1000.0);
5. 渲染通道初始状态检查
当前渲染通道使用LoadOp::Load,如果帧缓冲未正确初始化,可能导致显示异常。可以尝试改为清空初始状态:
ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), store: true, },
内容的提问来源于stack exchange,提问作者Jove
相关产品推荐
相关产品推荐

