Advertisement
fisharmy100

gltf + wgpu integration

Apr 12th, 2024
1,342
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 14.34 KB | Source Code | 0 0
  1. // PLEASE NOTE: Not all files are included, spisifically alot of the wgpu helper functions
  2.  
  3. // ===================================================================================================
  4. // Model.rs
  5. // ===================================================================================================
  6.  
  7. pub struct Model
  8. {
  9.     pub meshes: Vec<Mesh>,
  10.     pub materials: HashMap<u64, Material>
  11. }
  12.  
  13. impl Model
  14. {
  15.     pub fn vertex_layout() -> wgpu::VertexBufferLayout<'static>
  16.    {
  17.        Vertex::layout()
  18.    }
  19.  
  20.    pub fn from_glb(bytes: &[u8], device: &wgpu::Device, queue: &wgpu::Queue) -> Result<Self, String>
  21.    {
  22.        let data = match gltf::Gltf::from_slice(bytes)
  23.        {
  24.            Ok(ok) => ok,
  25.            Err(e) => return Err(e.to_string())
  26.        };
  27.  
  28.        let mut buffer_data: Vec<Vec<u8>> = Vec::new();
  29.        for buffer in data.buffers()
  30.        {
  31.            match buffer.source()
  32.            {
  33.                gltf::buffer::Source::Bin =>
  34.                {
  35.                    if let Some(blob) = data.blob.as_deref()
  36.                    {
  37.                        buffer_data.push(blob.into());
  38.                    };
  39.                }
  40.                gltf::buffer::Source::Uri(_uri) =>
  41.                {
  42.                    return Err("URI's are not implemented yet".into())
  43.                }
  44.            }
  45.        }
  46.  
  47.        let Some(mesh) = data.meshes().next() else { return Err("glb file must have a mesh".into()); };
  48.        let meshes: Result<_, String> = mesh.primitives().map(|p| Mesh::from_primitive(p, &buffer_data, device)).collect();
  49.  
  50.        let mut materials = HashMap::new();
  51.        for m in mesh.primitives().map(|p| p.material())
  52.        {
  53.            let id = get_gltf_material_id(m.clone());
  54.            if materials.get(&id).is_none()
  55.            {
  56.                let material = match Material::from_glb(m, &buffer_data, device, queue)
  57.                {
  58.                    Ok(ok) => ok,
  59.                    Err(e) => return Err(e)
  60.                };
  61.                materials.insert(id, material);
  62.            }
  63.        }
  64.  
  65.        match meshes
  66.        {
  67.            Ok(ok) => Ok(Self {
  68.                meshes: ok,
  69.                materials,
  70.            }),
  71.            Err(err) => Err(err)
  72.        }
  73.    }
  74. }
  75.  
  76. pub struct Mesh
  77. {
  78.    pub vertex_buffer: wgpu::Buffer,
  79.    pub index_buffer: wgpu::Buffer,
  80.    pub index_count: u32,
  81.    pub material_id: u64,
  82. }
  83.  
  84. impl Mesh
  85. {
  86.    pub fn from_primitive<'a>(primitive: gltf::Primitive<'a>, buffer_data: &Vec<Vec<u8>>, device: &wgpu::Device) -> Result<Self, String>
  87.    {
  88.        let reader = primitive.reader(|buffer| Some(&buffer_data[buffer.index()]));
  89.  
  90.        let mut vertices: Vec<Vertex> = match reader.read_positions()
  91.        {
  92.            Some(p) => p.map(|p| Vertex::new(p, Vec2::ZERO, Vec3::ZERO)),
  93.            None => return Err("Mesh needs vertex positions".into())
  94.        }.collect();
  95.  
  96.        println!("{:?}", vertices);
  97.  
  98.        match reader.read_colors(0)
  99.        {
  100.            Some(cs) =>
  101.            {
  102.                cs.into_rgb_f32().enumerate().for_each(|(i, c)| vertices[i].color = c);
  103.            },
  104.            None => {}
  105.        };
  106.  
  107.        match reader.read_tex_coords(0)
  108.        {
  109.            Some(uvs) =>
  110.            {
  111.                uvs.into_f32().enumerate().for_each(|(i, uv)| { vertices[i].uv = uv});
  112.            },
  113.            None => {}
  114.        }
  115.  
  116.        let indices: Vec<u32> = match reader.read_indices()
  117.        {
  118.            Some(i) => i.into_u32(),
  119.            None => return Err("Mesh does not have an index buffer".into())
  120.        }.collect();
  121.  
  122.        let vertex_buffer = make_vertex_buffer(VertexBufferDescriptor {
  123.            data: &vertices,
  124.            device,
  125.            additional_usages: None,
  126.            label: None
  127.        });
  128.  
  129.        let index_buffer = make_index_buffer(IndexBufferDescriptor {
  130.            data: IndexType::U32(&indices),
  131.            device,
  132.            additional_usages: None,
  133.            label: None
  134.        });
  135.  
  136.        let material_id = get_gltf_material_id(primitive.material());
  137.  
  138.        Ok(Self {
  139.            vertex_buffer,
  140.            index_buffer,
  141.            index_count: indices.len() as u32,
  142.            material_id,
  143.        })
  144.    }
  145. }
  146.  
  147. pub struct MaterialTexture
  148. {
  149.    pub texture: wgpu::Texture,
  150.    pub view: wgpu::TextureView,
  151.    pub sampler: wgpu::Sampler,
  152.    pub bind_group: wgpu::BindGroup,
  153. }
  154.  
  155. impl MaterialTexture
  156. {
  157.    pub fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout
  158.    {
  159.        make_bind_group_layout(device, None, &[
  160.            EntryType::Texture {
  161.                visibility: wgpu::ShaderStages::FRAGMENT,
  162.                view_dim: wgpu::TextureViewDimension::D2,
  163.                sample_type: wgpu::TextureSampleType::Float { filterable: true }
  164.            },
  165.            EntryType::Sampler {
  166.                visibility: wgpu::ShaderStages::FRAGMENT,
  167.                binding_type: wgpu::SamplerBindingType::Filtering
  168.            }
  169.        ])
  170.    }
  171.  
  172.    pub fn new(texture: wgpu::Texture, device: &wgpu::Device) -> Self
  173.    {
  174.        let view = make_default_texture_view(&texture);
  175.        let sampler = make_pixel_sampler(device);
  176.        let layout = Self::layout(device);
  177.        let bind_group = make_bind_group(device, &layout, None, [
  178.            wgpu::BindingResource::TextureView(&view),
  179.            wgpu::BindingResource::Sampler(&sampler)
  180.        ]);
  181.  
  182.        Self
  183.        {
  184.            texture,
  185.            view,
  186.            sampler,
  187.            bind_group
  188.        }
  189.    }
  190. }
  191.  
  192. pub struct Material
  193. {
  194.    pub color: Color,
  195.    pub texture: Option<MaterialTexture>
  196. }
  197.  
  198. impl Material
  199. {
  200.    pub fn from_glb(mat: gltf::Material, buffer_data: &Vec<Vec<u8>>, device: &wgpu::Device, queue: &wgpu::Queue) -> Result<Self, String>
  201.    {
  202.        let color = mat.pbr_metallic_roughness().base_color_factor();
  203.        let texture = match mat.pbr_metallic_roughness().base_color_texture()
  204.        {
  205.            Some(texture) =>
  206.            {
  207.                let source = texture.texture().source().source();
  208.                match source
  209.                {
  210.                    Source::View { view, mime_type } =>
  211.                    {
  212.                        let parent_buffer_data = &buffer_data[view.buffer().index()];
  213.                        let data = &parent_buffer_data[view.offset()..view.offset() + view.length()];
  214.                        let mime_type = mime_type.replace('/', ".");
  215.                        let image = image::load_from_memory_with_format(
  216.                                data,
  217.                                image::ImageFormat::from_path(mime_type).unwrap(),
  218.                            ).unwrap();
  219.                        
  220.                        let rgba = image.to_rgba8();
  221.                        let texture = make_rgba_texture(MakeRgbaTextureDescriptor {
  222.                            rgba: &rgba,
  223.                            device,
  224.                            queue,
  225.                            label: None,
  226.                            additional_usages: None
  227.                        });
  228.  
  229.                        Some(MaterialTexture::new(texture, device))
  230.                    },
  231.                    Source::Uri { uri: _, mime_type: _ } => return Err("Texture URI's not supported".into()),
  232.                }
  233.            }
  234.            None => None,
  235.        };
  236.  
  237.        Ok(Self
  238.        {
  239.            color: Color::from_vec4(color.into()),
  240.            texture,
  241.        })
  242.    }
  243. }
  244.  
  245. fn get_gltf_material_id(mat: gltf::Material) -> u64
  246. {
  247.    let mut hasher = DefaultHasher::new();
  248.    mat.index().hash(&mut hasher);
  249.    hasher.finish()
  250. }
  251.  
  252. #[derive(ecs::Resource)]
  253. pub struct ModelRenderer
  254. {
  255.    color_pipeline: wgpu::RenderPipeline,
  256.    texture_pipeline: wgpu::RenderPipeline,
  257.  
  258.    camera_uniform: wgpu::Buffer,
  259.    camera_bind_group: wgpu::BindGroup,
  260.    
  261.    color_uniform: wgpu::Buffer,
  262.    color_bind_group: wgpu::BindGroup,
  263.  
  264.    // TEMP
  265.    model: Model,
  266. }
  267.  
  268. impl ModelRenderer
  269. {
  270.    pub fn new(state: &WgpuState) -> Self
  271.    {
  272.        let device = &state.device();
  273.  
  274.        let camera_uniform = make_uniform_buffer(UniformBufferDescriptor {
  275.            label: None,
  276.            device,
  277.            data: Mat4::ZERO,
  278.            additional_usages: Some(BufferUsages::COPY_DST)
  279.        });
  280.  
  281.        let camera_layout = make_bind_group_layout(&state.device(), None, &[
  282.            EntryType::Uniform(ShaderStages::VERTEX),
  283.        ]);
  284.  
  285.        let camera_bind_group = make_bind_group(&state.device, &camera_layout, None, [
  286.            camera_uniform.as_entire_binding(),
  287.        ]);
  288.  
  289.        let color_uniform = make_uniform_buffer(UniformBufferDescriptor {
  290.            label: None,
  291.            device,
  292.            data: Vec4::ZERO,
  293.            additional_usages: Some(BufferUsages::COPY_DST)
  294.        });
  295.  
  296.        let color_layout = make_bind_group_layout(&state.device(), None, &[
  297.            EntryType::Uniform(ShaderStages::VERTEX),
  298.        ]);
  299.  
  300.        let color_bind_group = make_bind_group(&state.device, &color_layout, None, [
  301.            color_uniform.as_entire_binding(),
  302.        ]);
  303.  
  304.        let color_pipeline = make_color_render_pipeline(state, &camera_layout, &color_layout);
  305.        let texture_pipeline = make_texture_render_pipeline(state, &camera_layout, &color_layout);
  306.  
  307.        let model = Model::from_glb(include_bytes!("../../assets/models/test_slab.glb"), &device, &state.queue()).unwrap();
  308.  
  309.        Self
  310.        {
  311.            color_pipeline,
  312.            texture_pipeline,
  313.            camera_uniform,
  314.            camera_bind_group,
  315.            color_uniform,
  316.            color_bind_group,
  317.            model
  318.        }
  319.    }
  320.  
  321.    pub fn draw(&self, state: &WgpuState, view_proj: &Mat4, depth_texture: &DepthTexture, view: &wgpu::TextureView)
  322.    {
  323.        state.queue().write_buffer(&self.camera_uniform, 0, bytemuck::bytes_of(view_proj));
  324.  
  325.        for mesh in &self.model.meshes
  326.        {
  327.            let mut encoder = make_command_encoder(&state.device());
  328.        
  329.            let material = self.model.materials.get(&mesh.material_id).unwrap();
  330.            state.queue().write_buffer(&self.color_uniform, 0, bytemuck::bytes_of(&material.color.as_vec4()));
  331.  
  332.            let mut render_pass = make_render_pass(&mut encoder, view, Some(depth_texture));
  333.  
  334.            if let Some(texture) = &material.texture
  335.            {
  336.                render_pass.set_pipeline(&self.texture_pipeline);
  337.                render_pass.set_bind_group(2, &texture.bind_group, &[]);
  338.            }
  339.            else
  340.            {
  341.                render_pass.set_pipeline(&self.color_pipeline);
  342.            }
  343.  
  344.            render_pass.set_bind_group(0, &self.camera_bind_group, &[]);
  345.            render_pass.set_bind_group(1, &self.color_bind_group, &[]);
  346.  
  347.            render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
  348.            render_pass.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
  349.            render_pass.draw_indexed(0..mesh.index_count, 0, 0..1);
  350.            
  351.            drop(render_pass);
  352.            state.queue().submit(std::iter::once(encoder.finish()));
  353.        }
  354.    }
  355. }
  356.  
  357. pub fn make_color_render_pipeline(state: &WgpuState, camera_layout: &wgpu::BindGroupLayout, color_layout: &wgpu::BindGroupLayout) -> wgpu::RenderPipeline
  358. {
  359.    let shader = &state.device().create_shader_module(include_spirv!(env!("color_mesh_shader.spv")));
  360.    make_render_pipeline(&state.device(), state.surface_config(), &RenderPipelineInfo {
  361.        shader,
  362.        vs_main: "vs_main",
  363.        fs_main: "fs_main",
  364.        opacity: Opacity::Opaque,
  365.        vertex_buffers: &[&Model::vertex_layout()],
  366.        bind_groups: &[&camera_layout, &color_layout],
  367.        label: None,
  368.        has_depth_texture: true
  369.    })
  370. }
  371.  
  372. pub fn make_texture_render_pipeline(state: &WgpuState, camera_layout: &wgpu::BindGroupLayout, color_layout: &wgpu::BindGroupLayout) -> wgpu::RenderPipeline
  373. {
  374.    let shader = &state.device().create_shader_module(include_spirv!(env!("texture_mesh_shader.spv")));
  375.    let model_texture_layout = MaterialTexture::layout(&state.device());
  376.  
  377.    make_render_pipeline(&state.device(), state.surface_config(), &RenderPipelineInfo {
  378.        shader,
  379.        vs_main: "vs_main",
  380.        fs_main: "fs_main",
  381.        opacity: Opacity::Opaque,
  382.        vertex_buffers: &[&Model::vertex_layout()],
  383.        bind_groups: &[&camera_layout, &color_layout, &model_texture_layout],
  384.        label: None,
  385.        has_depth_texture: true
  386.    })
  387. }
  388.  
  389. // ===================================================================================================
  390. // Texture.rs
  391. // ===================================================================================================
  392. #[derive(Debug, Clone, Copy)]
  393. pub struct MakeRgbaTextureDescriptor<'a>
  394. {
  395.     pub rgba: &'a ImageBuffer<Rgba<u8>, Vec<u8>>,
  396.    pub device: &'a wgpu::Device,
  397.     pub queue: &'a wgpu::Queue,
  398.    pub label: Option<&'a str>,
  399.     pub additional_usages: Option<wgpu::TextureUsages>,
  400. }
  401.  
  402. pub fn make_rgba_texture(desc: MakeRgbaTextureDescriptor) -> wgpu::Texture
  403. {
  404.     let MakeRgbaTextureDescriptor {
  405.         rgba,
  406.         device,
  407.         queue,
  408.         label,
  409.         additional_usages
  410.     } = desc;
  411.  
  412.     let dim = rgba.dimensions();
  413.  
  414.     let usage = wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST | match additional_usages {
  415.         Some(u) => u,
  416.         None => wgpu::TextureUsages::empty()
  417.     };
  418.  
  419.     let texture_size = wgpu::Extent3d {
  420.         width: dim.0,
  421.         height: dim.1,
  422.         depth_or_array_layers: 1,
  423.     };
  424.  
  425.     let texture = device.create_texture(&wgpu::TextureDescriptor {
  426.         size: texture_size,
  427.         mip_level_count: 1,
  428.         sample_count: 1,
  429.         dimension: wgpu::TextureDimension::D2,
  430.         format: wgpu::TextureFormat::Rgba8UnormSrgb,
  431.         usage,
  432.         label,
  433.         view_formats: &[],
  434.     });
  435.  
  436.     let copy_texture = wgpu::ImageCopyTexture {
  437.         texture: &texture,
  438.         mip_level: 0,
  439.         origin: wgpu::Origin3d::ZERO,
  440.         aspect: wgpu::TextureAspect::All
  441.     };
  442.  
  443.     let data_layout = wgpu::ImageDataLayout {
  444.         offset: 0,
  445.         bytes_per_row: Some(4 * dim.0),
  446.         rows_per_image: Some(dim.1),
  447.     };
  448.  
  449.     queue.write_texture(copy_texture, &rgba, data_layout, texture_size);
  450.  
  451.     texture
  452. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement