Materials
This commit is contained in:
parent
306a983d14
commit
f3fff03aff
|
@ -5,7 +5,7 @@ use std::ops::Range;
|
|||
#[derive(Clone)]
|
||||
struct DrawState {
|
||||
group_id: usize,
|
||||
texture_id: usize,
|
||||
material_id: usize,
|
||||
sub_id: usize,
|
||||
instance_range: Range<u32>,
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ pub enum Command {
|
|||
BindMeshGroup {
|
||||
group_id: usize,
|
||||
},
|
||||
BindTexture {
|
||||
texture_id: usize,
|
||||
BindMaterial {
|
||||
material_id: usize,
|
||||
},
|
||||
Draw {
|
||||
sub_id: usize,
|
||||
|
@ -27,7 +27,7 @@ pub struct CommandIterator<'a> {
|
|||
command_set: &'a CommandSet,
|
||||
command_idx: usize, // TODO use iterator instead lol
|
||||
last_group_id: usize,
|
||||
last_texture_id: usize,
|
||||
last_material_id: usize,
|
||||
}
|
||||
|
||||
impl<'a> CommandIterator<'a> {
|
||||
|
@ -36,7 +36,7 @@ impl<'a> CommandIterator<'a> {
|
|||
command_set,
|
||||
command_idx: 0,
|
||||
last_group_id: usize::MAX,
|
||||
last_texture_id: usize::MAX,
|
||||
last_material_id: usize::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,16 +48,16 @@ impl<'a> Iterator for CommandIterator<'a> {
|
|||
let DrawState {
|
||||
group_id,
|
||||
sub_id,
|
||||
texture_id,
|
||||
material_id,
|
||||
instance_range,
|
||||
} = self.command_set.draws.get(self.command_idx)?.clone();
|
||||
|
||||
if group_id != self.last_group_id {
|
||||
self.last_group_id = group_id;
|
||||
Some(Command::BindMeshGroup { group_id })
|
||||
} else if texture_id != self.last_texture_id {
|
||||
self.last_texture_id = texture_id;
|
||||
Some(Command::BindTexture { texture_id })
|
||||
} else if material_id != self.last_material_id {
|
||||
self.last_material_id = material_id;
|
||||
Some(Command::BindMaterial { material_id })
|
||||
} else {
|
||||
self.command_idx += 1;
|
||||
Some(Command::Draw {
|
||||
|
@ -78,8 +78,8 @@ impl CommandSet {
|
|||
let mut sorted_meshes = HashMap::<(usize, usize), Vec<MeshInstance>>::new();
|
||||
for instance in instances.iter() {
|
||||
let group_id = instance.mesh.group_id;
|
||||
let texture_id = instance.albedo.id;
|
||||
let key = (group_id, texture_id);
|
||||
let material_id = instance.material.id;
|
||||
let key = (group_id, material_id);
|
||||
if let Some(by_state) = sorted_meshes.get_mut(&key) {
|
||||
by_state.push(*instance);
|
||||
} else {
|
||||
|
@ -90,7 +90,7 @@ impl CommandSet {
|
|||
let mut transforms = Vec::new();
|
||||
let mut draws = Vec::new();
|
||||
|
||||
for ((group_id, texture_id), mut meshes) in sorted_meshes.drain() {
|
||||
for ((group_id, material_id), mut meshes) in sorted_meshes.drain() {
|
||||
let mut sorted_subs = HashMap::<usize, Vec<MeshInstance>>::new();
|
||||
for mesh in meshes.drain(..) {
|
||||
let sub_id = mesh.mesh.sub_id;
|
||||
|
@ -109,7 +109,7 @@ impl CommandSet {
|
|||
let instance_range = start_idx..end_idx;
|
||||
draws.push(DrawState {
|
||||
group_id,
|
||||
texture_id,
|
||||
material_id,
|
||||
sub_id,
|
||||
instance_range,
|
||||
});
|
||||
|
|
|
@ -10,3 +10,9 @@ pub struct MeshHandle {
|
|||
pub struct TextureHandle {
|
||||
pub id: usize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
|
||||
pub struct MaterialHandle {
|
||||
pub id: usize,
|
||||
}
|
||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -19,7 +19,7 @@ use pool::*;
|
|||
use renderer::*;
|
||||
use scene::*;
|
||||
|
||||
fn load_model() -> (MeshData, TextureData) {
|
||||
fn load_model(ren: &mut Renderer) -> (MeshHandle, MaterialHandle) {
|
||||
use tobj::*;
|
||||
|
||||
let model_data = include_bytes!("viking_room.obj").to_vec();
|
||||
|
@ -57,6 +57,9 @@ fn load_model() -> (MeshData, TextureData) {
|
|||
|
||||
indices.extend(m.mesh.indices.iter().map(|i| i + index_base));
|
||||
|
||||
let mesh_data = MeshData { vertices, indices };
|
||||
let mesh_handle = ren.mesh_pool.allocate(&ren.device, &mesh_data);
|
||||
|
||||
let albedo_data = include_bytes!("viking_room.png");
|
||||
let albedo = image::load_from_memory(albedo_data).unwrap();
|
||||
|
||||
|
@ -70,14 +73,22 @@ fn load_model() -> (MeshData, TextureData) {
|
|||
albedo_rgba.push(0xff);
|
||||
}
|
||||
|
||||
(
|
||||
MeshData { vertices, indices },
|
||||
TextureData {
|
||||
width: dimensions.0,
|
||||
height: dimensions.1,
|
||||
data: albedo_rgba,
|
||||
},
|
||||
)
|
||||
let albedo_data = TextureData {
|
||||
width: dimensions.0,
|
||||
height: dimensions.1,
|
||||
data: albedo_rgba,
|
||||
};
|
||||
|
||||
let albedo = ren
|
||||
.texture_pool
|
||||
.allocate(&ren.device, &ren.queue, &albedo_data);
|
||||
|
||||
let material_data = MaterialData { albedo };
|
||||
let material_handle =
|
||||
ren.material_pool
|
||||
.allocate(&ren.device, &ren.texture_pool, &material_data);
|
||||
|
||||
(mesh_handle, material_handle)
|
||||
}
|
||||
|
||||
trait WorldState {
|
||||
|
@ -91,11 +102,7 @@ struct Grid {
|
|||
|
||||
impl Grid {
|
||||
fn new(ren: &mut Renderer) -> Self {
|
||||
let (mesh_data, albedo_data) = load_model();
|
||||
let mesh = ren.mesh_pool.allocate(&ren.device, &mesh_data);
|
||||
let albedo = ren
|
||||
.texture_pool
|
||||
.allocate(&ren.device, &ren.queue, &albedo_data);
|
||||
let (mesh, material) = load_model(ren);
|
||||
let mut meshes = Vec::new();
|
||||
for x in -5..5 {
|
||||
for y in -5..5 {
|
||||
|
@ -103,7 +110,7 @@ impl Grid {
|
|||
let transform = glam::Mat4::from_translation(translation);
|
||||
meshes.push(MeshInstance {
|
||||
mesh,
|
||||
albedo,
|
||||
material,
|
||||
transform,
|
||||
});
|
||||
}
|
||||
|
@ -132,17 +139,13 @@ struct Planets {
|
|||
start: std::time::Instant,
|
||||
planets: Vec<Planet>,
|
||||
mesh: MeshHandle,
|
||||
albedo: TextureHandle,
|
||||
material: MaterialHandle,
|
||||
}
|
||||
|
||||
impl Planets {
|
||||
fn new(ren: &mut Renderer) -> Self {
|
||||
let start = std::time::Instant::now();
|
||||
let (mesh_data, albedo_data) = load_model();
|
||||
let mesh = ren.mesh_pool.allocate(&ren.device, &mesh_data);
|
||||
let albedo = ren
|
||||
.texture_pool
|
||||
.allocate(&ren.device, &ren.queue, &albedo_data);
|
||||
let (mesh, material) = load_model(ren);
|
||||
|
||||
let mut planets = Vec::new();
|
||||
for i in 0..10 {
|
||||
|
@ -159,7 +162,7 @@ impl Planets {
|
|||
start,
|
||||
planets,
|
||||
mesh,
|
||||
albedo,
|
||||
material,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +181,7 @@ impl WorldState for Planets {
|
|||
let rotation = glam::Mat4::from_rotation_y(theta);
|
||||
meshes.push(MeshInstance {
|
||||
mesh: self.mesh,
|
||||
albedo: self.albedo,
|
||||
material: self.material,
|
||||
transform: rotation * translation,
|
||||
});
|
||||
}
|
||||
|
@ -194,7 +197,7 @@ async fn make_window_renderer(window: &winit::window::Window) -> Renderer {
|
|||
let surface = unsafe { instance.create_surface(window) };
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||
power_preference: wgpu::PowerPreference::LowPower,
|
||||
compatible_surface: Some(&surface),
|
||||
force_fallback_adapter: false,
|
||||
})
|
||||
|
|
140
src/pool.rs
140
src/pool.rs
|
@ -1,5 +1,6 @@
|
|||
use super::handle::{MeshHandle, TextureHandle};
|
||||
use super::handle::{MaterialHandle, MeshHandle, TextureHandle};
|
||||
use super::mesh::MeshData;
|
||||
use slab::Slab;
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
pub struct MeshGroup {
|
||||
|
@ -38,7 +39,7 @@ impl MeshGroup {
|
|||
#[derive(Default)]
|
||||
pub struct MeshPool {
|
||||
// TODO make this private
|
||||
pub groups: slab::Slab<MeshGroup>,
|
||||
pub groups: Slab<MeshGroup>,
|
||||
}
|
||||
|
||||
impl MeshPool {
|
||||
|
@ -61,19 +62,12 @@ pub struct TextureData {
|
|||
}
|
||||
|
||||
pub struct Texture {
|
||||
// TODO make this all private
|
||||
pub texture: wgpu::Texture,
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
texture: wgpu::Texture,
|
||||
texture_view: wgpu::TextureView,
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
sampler: &wgpu::Sampler,
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
data: &TextureData,
|
||||
) -> Self {
|
||||
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, data: &TextureData) -> Self {
|
||||
let size = wgpu::Extent3d {
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
|
@ -108,33 +102,17 @@ impl Texture {
|
|||
size,
|
||||
);
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&texture_view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(sampler),
|
||||
},
|
||||
],
|
||||
label: None,
|
||||
});
|
||||
|
||||
Texture {
|
||||
texture,
|
||||
bind_group,
|
||||
texture_view,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TexturePool {
|
||||
// TODO make this all private
|
||||
pub textures: slab::Slab<Texture>,
|
||||
pub textures: Slab<Texture>,
|
||||
pub sampler: wgpu::Sampler,
|
||||
pub bind_group_layout: wgpu::BindGroupLayout,
|
||||
}
|
||||
|
||||
impl TexturePool {
|
||||
|
@ -150,33 +128,7 @@ impl TexturePool {
|
|||
..Default::default()
|
||||
});
|
||||
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
multisampled: false,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("Texture Bind Group Layout"),
|
||||
});
|
||||
|
||||
Self {
|
||||
textures,
|
||||
sampler,
|
||||
bind_group_layout,
|
||||
}
|
||||
Self { textures, sampler }
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
|
@ -185,8 +137,80 @@ impl TexturePool {
|
|||
queue: &wgpu::Queue,
|
||||
data: &TextureData,
|
||||
) -> TextureHandle {
|
||||
let texture = Texture::new(device, queue, &self.sampler, &self.bind_group_layout, data);
|
||||
let texture = Texture::new(device, queue, data);
|
||||
let id = self.textures.insert(texture);
|
||||
TextureHandle { id }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MaterialData {
|
||||
pub albedo: TextureHandle,
|
||||
}
|
||||
|
||||
pub struct Material {
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
}
|
||||
|
||||
pub struct MaterialPool {
|
||||
pub materials: Slab<Material>,
|
||||
pub bind_group_layout: wgpu::BindGroupLayout,
|
||||
}
|
||||
|
||||
impl MaterialPool {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
multisampled: false,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("Texture Bind Group Layout"),
|
||||
});
|
||||
|
||||
Self {
|
||||
materials: Default::default(),
|
||||
bind_group_layout,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
texture_pool: &TexturePool,
|
||||
data: &MaterialData,
|
||||
) -> MaterialHandle {
|
||||
let albedo_view = &texture_pool.textures[data.albedo.id].texture_view;
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &self.bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Sampler(&texture_pool.sampler),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::TextureView(albedo_view),
|
||||
},
|
||||
],
|
||||
label: None,
|
||||
});
|
||||
|
||||
let material = Material { bind_group };
|
||||
let id = self.materials.insert(material);
|
||||
MaterialHandle { id }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::camera::Camera;
|
||||
use super::commands::{Command, CommandSet};
|
||||
use super::mesh::Vertex;
|
||||
use super::pool::{MeshGroup, MeshPool, TexturePool};
|
||||
use super::pool::{MaterialPool, MeshGroup, MeshPool, TexturePool};
|
||||
use super::scene::{MeshInstance, PointLight};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
|
@ -10,6 +10,7 @@ pub struct Renderer {
|
|||
pub queue: wgpu::Queue,
|
||||
pub mesh_pool: MeshPool,
|
||||
pub texture_pool: TexturePool,
|
||||
pub material_pool: MaterialPool,
|
||||
pub size: winit::dpi::PhysicalSize<u32>,
|
||||
surface: wgpu::Surface,
|
||||
config: wgpu::SurfaceConfiguration,
|
||||
|
@ -34,6 +35,7 @@ impl Renderer {
|
|||
) -> Self {
|
||||
let mesh_pool = MeshPool::default();
|
||||
let texture_pool = TexturePool::new(&device);
|
||||
let material_pool = MaterialPool::new(&device);
|
||||
|
||||
let (depth_texture, depth_texture_view) = Self::make_depth_texture(&device, &config);
|
||||
|
||||
|
@ -131,7 +133,7 @@ impl Renderer {
|
|||
bind_group_layouts: &[
|
||||
&camera_bind_group_layout,
|
||||
&meshes_bind_group_layout,
|
||||
&texture_pool.bind_group_layout,
|
||||
&material_pool.bind_group_layout,
|
||||
],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
@ -187,6 +189,7 @@ impl Renderer {
|
|||
config,
|
||||
mesh_pool,
|
||||
texture_pool,
|
||||
material_pool,
|
||||
depth_texture,
|
||||
depth_texture_view,
|
||||
camera_uniform,
|
||||
|
@ -323,9 +326,9 @@ impl Renderer {
|
|||
rp.set_vertex_buffer(0, group.vertices.slice(..));
|
||||
rp.set_index_buffer(group.indices.slice(..), wgpu::IndexFormat::Uint32);
|
||||
}
|
||||
Command::BindTexture { texture_id } => {
|
||||
let texture = self.texture_pool.textures.get(texture_id).unwrap();
|
||||
rp.set_bind_group(2, &texture.bind_group, &[]);
|
||||
Command::BindMaterial { material_id } => {
|
||||
let material = self.material_pool.materials.get(material_id).unwrap();
|
||||
rp.set_bind_group(2, &material.bind_group, &[]);
|
||||
}
|
||||
Command::Draw {
|
||||
sub_id: _,
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::handle::*;
|
|||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct MeshInstance {
|
||||
pub mesh: MeshHandle,
|
||||
pub albedo: TextureHandle,
|
||||
pub material: MaterialHandle,
|
||||
pub transform: glam::Mat4,
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,8 @@ var<storage,read> point_lights: PointLightData;
|
|||
[[group(1), binding(0)]]
|
||||
var<storage,read> meshes: MeshData;
|
||||
|
||||
[[group(2), binding(0)]] var t_albedo: texture_2d<f32>;
|
||||
[[group(2), binding(1)]] var s_albedo: sampler;
|
||||
[[group(2), binding(0)]] var m_sampler: sampler;
|
||||
[[group(2), binding(1)]] var m_albedo: texture_2d<f32>;
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn vs_main(
|
||||
|
@ -66,7 +66,7 @@ fn vs_main(
|
|||
fn fs_main(
|
||||
frag: VertexOutput,
|
||||
) -> [[location(0)]] vec4<f32> {
|
||||
let albedo = textureSample(t_albedo, s_albedo, frag.tex_coords).rgb;
|
||||
let albedo = textureSample(m_albedo, m_sampler, frag.tex_coords).rgb;
|
||||
let normal = normalize(frag.normal);
|
||||
|
||||
var lum = vec3<f32>(0.0);
|
||||
|
|
Loading…
Reference in New Issue