diff --git a/src/main.rs b/src/main.rs index 1f03dea..1b426e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,20 +113,35 @@ impl Camera { } } -pub struct Skybox { + +pub struct SamplerBindGroups { + clamp: wgpu::BindGroup, +} + +pub struct GraphicsBindGroups { + camera: wgpu::BindGroup, + skybox_texture: wgpu::BindGroup, + sampler: SamplerBindGroups, +} + +pub struct GraphicsPipelines { + skybox: wgpu::RenderPipeline, + entity: wgpu::RenderPipeline, +} + +pub struct GraphicsData { start_time: std::time::Instant, camera: Camera, physics: strafe_client::body::PhysicsState, - sky_pipeline: wgpu::RenderPipeline, - entity_pipeline: wgpu::RenderPipeline, - main_bind_group: wgpu::BindGroup, + pipelines: GraphicsPipelines, + bind_groups: GraphicsBindGroups, camera_buf: wgpu::Buffer, models: Vec, depth_view: wgpu::TextureView, staging_belt: wgpu::util::StagingBelt, } -impl Skybox { +impl GraphicsData { const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth24Plus; fn create_depth_texture( @@ -211,7 +226,7 @@ fn add_obj(device:&wgpu::Device,modeldatas:& mut Vec,data:obj::ObjDat } } -impl strafe_client::framework::Example for Skybox { +impl strafe_client::framework::Example for GraphicsData { fn optional_features() -> wgpu::Features { wgpu::Features::TEXTURE_COMPRESSION_ASTC | wgpu::Features::TEXTURE_COMPRESSION_ETC2 @@ -258,7 +273,7 @@ impl strafe_client::framework::Example for Skybox { modeldatas[2].transforms[0]=glam::Mat4::from_translation(glam::vec3(-10.,5.,10.)); modeldatas[3].transforms[0]=glam::Mat4::from_translation(glam::vec3(0.,0.,0.))*glam::Mat4::from_scale(glam::vec3(160.0, 1.0, 160.0)); - let main_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + let camera_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: None, entries: &[ wgpu::BindGroupLayoutEntry { @@ -271,8 +286,13 @@ impl strafe_client::framework::Example for Skybox { }, count: None, }, + ], + }); + let skybox_texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[ wgpu::BindGroupLayoutEntry { - binding: 1, + binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, @@ -281,8 +301,13 @@ impl strafe_client::framework::Example for Skybox { }, count: None, }, + ], + }); + let texture_filter_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[ wgpu::BindGroupLayoutEntry { - binding: 2, + binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: None, @@ -377,7 +402,12 @@ impl strafe_client::framework::Example for Skybox { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, - bind_group_layouts: &[&main_bind_group_layout, &model_bind_group_layout], + bind_group_layouts: &[ + &camera_bind_group_layout, + &model_bind_group_layout, + &skybox_texture_bind_group_layout, + &texture_filter_bind_group_layout, + ], push_constant_ranges: &[], }); @@ -414,7 +444,7 @@ impl strafe_client::framework::Example for Skybox { layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &shader, - entry_point: "vs_entity", + entry_point: "vs_entity_texture", buffers: &[wgpu::VertexBufferLayout { array_stride: std::mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, @@ -423,7 +453,7 @@ impl strafe_client::framework::Example for Skybox { }, fragment: Some(wgpu::FragmentState { module: &shader, - entry_point: "fs_entity", + entry_point: "fs_entity_texture", targets: &[Some(config.view_formats[0].into())], }), primitive: wgpu::PrimitiveState { @@ -441,8 +471,8 @@ impl strafe_client::framework::Example for Skybox { multiview: None, }); - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { - label: None, + let clamp_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("Clamp Sampler"), address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, @@ -502,9 +532,9 @@ impl strafe_client::framework::Example for Skybox { _ => unreachable!(), }; - let image = ddsfile::Dds::read(&mut std::io::Cursor::new(&bytes)).unwrap(); + let skybox_image = ddsfile::Dds::read(&mut std::io::Cursor::new(&bytes)).unwrap(); - let texture = device.create_texture_with_data( + let skybox_texture = device.create_texture_with_data( queue, &wgpu::TextureDescriptor { size, @@ -513,45 +543,67 @@ impl strafe_client::framework::Example for Skybox { dimension: wgpu::TextureDimension::D2, format: skybox_format, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - label: None, + label: Some("Skybox Texture"), view_formats: &[], }, - &image.data, + &skybox_image.data, ); - let texture_view = texture.create_view(&wgpu::TextureViewDescriptor { - label: None, + let skybox_texture_view = skybox_texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("Skybox Texture View"), dimension: Some(wgpu::TextureViewDimension::Cube), ..wgpu::TextureViewDescriptor::default() }); - let main_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &main_bind_group_layout, + + let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &camera_bind_group_layout, entries: &[ wgpu::BindGroupEntry { binding: 0, resource: camera_buf.as_entire_binding(), }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::TextureView(&texture_view), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::Sampler(&sampler), - }, ], label: Some("Camera"), }); + let skybox_texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &skybox_texture_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&skybox_texture_view), + }, + ], + label: Some("Sky Texture"), + }); + + let clamp_sampler_texture_filter_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &texture_filter_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Sampler(&clamp_sampler), + }, + ], + label: Some("Clamp Sampler Bind Group"), + }); let depth_view = Self::create_depth_texture(config, device); - Skybox { + GraphicsData { start_time: Instant::now(), camera, physics, - sky_pipeline, - entity_pipeline, - main_bind_group, + pipelines:GraphicsPipelines{ + skybox:sky_pipeline, + entity:entity_pipeline + }, + bind_groups:GraphicsBindGroups{ + camera:camera_bind_group, + skybox_texture:skybox_texture_bind_group, + sampler:SamplerBindGroups{ + clamp:clamp_sampler_texture_filter_bind_group, + } + }, camera_buf, models, depth_view, @@ -722,9 +774,11 @@ impl strafe_client::framework::Example for Skybox { }), }); - rpass.set_bind_group(0, &self.main_bind_group, &[]); + rpass.set_bind_group(0, &self.bind_groups.camera, &[]); + rpass.set_bind_group(2, &self.bind_groups.skybox_texture, &[]); + rpass.set_bind_group(3, &self.bind_groups.sampler.repeat, &[]); - rpass.set_pipeline(&self.entity_pipeline); + rpass.set_pipeline(&self.pipelines.entity); for model in self.models.iter() { rpass.set_bind_group(1, &model.bind_group, &[]); rpass.set_vertex_buffer(0, model.vertex_buf.slice(..)); @@ -735,7 +789,9 @@ impl strafe_client::framework::Example for Skybox { } } - rpass.set_pipeline(&self.sky_pipeline); + rpass.set_pipeline(&self.pipelines.skybox); + rpass.set_bind_group(2, &self.bind_groups.skybox_texture, &[]); + rpass.set_bind_group(3, &self.bind_groups.sampler.clamp, &[]); rpass.draw(0..3, 0..1); } @@ -746,7 +802,7 @@ impl strafe_client::framework::Example for Skybox { } fn main() { - strafe_client::framework::run::( + strafe_client::framework::run::( format!("Strafe Client v{}", env!("CARGO_PKG_VERSION") ).as_str() diff --git a/src/shader.wgsl b/src/shader.wgsl index bcfa5fc..a43b102 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -1,9 +1,4 @@ -struct SkyOutput { - @builtin(position) position: vec4, - @location(0) sampledir: vec3, -}; - -struct Data { +struct Camera { // from camera to screen proj: mat4x4, // from screen to camera @@ -15,7 +10,12 @@ struct Data { }; @group(0) @binding(0) -var r_data: Data; +var camera: Camera; + +struct SkyOutput { + @builtin(position) position: vec4, + @location(0) sampledir: vec3, +}; @vertex fn vs_sky(@builtin(vertex_index) vertex_index: u32) -> SkyOutput { @@ -30,8 +30,8 @@ fn vs_sky(@builtin(vertex_index) vertex_index: u32) -> SkyOutput { ); // transposition = inversion for this orthonormal matrix - let inv_model_view = transpose(mat3x3(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz)); - let unprojected = r_data.proj_inv * pos; + let inv_model_view = transpose(mat3x3(camera.view[0].xyz, camera.view[1].xyz, camera.view[2].xyz)); + let unprojected = camera.proj_inv * pos; var result: SkyOutput; result.sampledir = inv_model_view * unprojected.xyz; @@ -39,7 +39,7 @@ fn vs_sky(@builtin(vertex_index) vertex_index: u32) -> SkyOutput { return result; } -struct EntityOutput { +struct EntityOutputTexture { @builtin(position) position: vec4, @location(1) texture: vec2, @location(2) normal: vec3, @@ -48,45 +48,52 @@ struct EntityOutput { const MAX_ENTITY_INSTANCES=1024; @group(1) @binding(0) -var r_EntityTransform: array,MAX_ENTITY_INSTANCES>; +var entity_transforms: array,MAX_ENTITY_INSTANCES>; +//var entity_texture_transforms: array,MAX_ENTITY_INSTANCES>; +//my fancy idea is to create a megatexture for each model that includes all the textures each intance will need +//the texture transform then maps the texture coordinates to the location of the specific texture +//how to do no texture? @vertex -fn vs_entity( +fn vs_entity_texture( @builtin(instance_index) instance: u32, @location(0) pos: vec3, @location(1) texture: vec2, @location(2) normal: vec3, -) -> EntityOutput { - var position: vec4 = r_EntityTransform[instance] * vec4(pos, 1.0); - var result: EntityOutput; - result.normal = (r_EntityTransform[instance] * vec4(normal, 0.0)).xyz; - result.texture=texture; - result.view = position.xyz - r_data.cam_pos.xyz; - result.position = r_data.proj * r_data.view * position; +) -> EntityOutputTexture { + var position: vec4 = entity_transforms[instance] * vec4(pos, 1.0); + var result: EntityOutputTexture; + result.normal = (entity_transforms[instance] * vec4(normal, 0.0)).xyz; + result.texture=texture;//(entity_texture_transforms[instance] * vec3(texture, 1.0)).xy; + result.view = position.xyz - camera.cam_pos.xyz; + result.position = camera.proj * camera.view * position; return result; } -@group(0) -@binding(1) -var r_texture: texture_cube; -@group(0) -@binding(2) -var r_sampler: sampler; +//group 2 is texture bindings +@group(2) +@binding(0) +var cube_texture: texture_cube; + +//group 3 is texture sampler +@group(3) +@binding(0) +var texture_sampler: sampler; @fragment fn fs_sky(vertex: SkyOutput) -> @location(0) vec4 { - return textureSample(r_texture, r_sampler, vertex.sampledir); + return textureSample(cube_texture, texture_sampler, vertex.sampledir); } @fragment -fn fs_entity(vertex: EntityOutput) -> @location(0) vec4 { +fn fs_entity_texture(vertex: EntityOutputTexture) -> @location(0) vec4 { let incident = normalize(vertex.view); let normal = normalize(vertex.normal); let d = dot(normal, incident); let reflected = incident - 2.0 * d * normal; let dir = vec3(-1.0)+2.0*vec3(vertex.texture.x,0.0,vertex.texture.y); - let texture_color = textureSample(r_texture, r_sampler, dir).rgb; - let reflected_color = textureSample(r_texture, r_sampler, reflected).rgb; - return vec4(mix(vec3(0.1) + 0.5 * reflected_color,texture_color,1.0-pow(1.0-abs(d),2.0)), 1.0); + let fragment_color = textureSample(cube_texture, texture_sampler, dir).rgb; + let reflected_color = textureSample(cube_texture, texture_sampler, reflected).rgb; + return vec4(mix(vec3(0.1) + 0.5 * reflected_color,fragment_color,1.0-pow(1.0-abs(d),2.0)), 1.0); }