diff --git a/src/main.rs b/src/main.rs index 1f03dea8..c4170cd1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,20 +113,29 @@ impl Camera { } } -pub struct Skybox { +pub struct GraphicsBindGroups { + camera: wgpu::BindGroup, + skybox_texture: wgpu::BindGroup, +} + +pub struct GraphicsPipelines { + skybox: wgpu::RenderPipeline, + model: 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 +220,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,8 +267,44 @@ 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 { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + ], + }); + let skybox_texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Skybox Texture Bind Group Layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + multisampled: false, + view_dimension: wgpu::TextureViewDimension::Cube, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + let model_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Model Bind Group Layout"), entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, @@ -277,7 +322,7 @@ impl strafe_client::framework::Example for Skybox { ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, multisampled: false, - view_dimension: wgpu::TextureViewDimension::Cube, + view_dimension: wgpu::TextureViewDimension::D2, }, count: None, }, @@ -289,20 +334,26 @@ impl strafe_client::framework::Example for Skybox { }, ], }); - let model_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Model"), - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: 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, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Linear, + ..Default::default() + }); + let repeat_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("Repeat Sampler"), + address_mode_u: wgpu::AddressMode::Repeat, + address_mode_v: wgpu::AddressMode::Repeat, + address_mode_w: wgpu::AddressMode::Repeat, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Linear, + ..Default::default() }); // Create the render pipeline @@ -362,6 +413,14 @@ impl strafe_client::framework::Example for Skybox { binding: 0, resource: model_buf.as_entire_binding(), }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&squid_texture_view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(&repeat_sampler), + }, ], label: Some(format!("ModelGraphics{}",i).as_str()), }); @@ -377,13 +436,17 @@ 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, + ], push_constant_ranges: &[], }); // Create the render pipelines let sky_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Sky"), + label: Some("Sky Pipeline"), layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &shader, @@ -409,12 +472,12 @@ impl strafe_client::framework::Example for Skybox { multisample: wgpu::MultisampleState::default(), multiview: None, }); - let entity_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Entity"), + let model_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Model Pipeline"), 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 +486,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,17 +504,6 @@ impl strafe_client::framework::Example for Skybox { multiview: None, }); - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { - label: None, - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, - ..Default::default() - }); - let device_features = device.features(); let skybox_format = if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC) { @@ -502,9 +554,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 +565,57 @@ 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), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&clamp_sampler), + }, + ], + label: Some("Sky Texture"), + }); 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, + model:model_pipeline + }, + bind_groups:GraphicsBindGroups{ + camera:camera_bind_group, + skybox_texture:skybox_texture_bind_group, + }, camera_buf, models, depth_view, @@ -722,9 +786,10 @@ 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_pipeline(&self.entity_pipeline); + rpass.set_pipeline(&self.pipelines.model); 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 +800,7 @@ impl strafe_client::framework::Example for Skybox { } } - rpass.set_pipeline(&self.sky_pipeline); + rpass.set_pipeline(&self.pipelines.skybox); rpass.draw(0..3, 0..1); } @@ -746,7 +811,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 bcfa5fce..a2f1fe7f 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 @@ -13,9 +8,16 @@ struct Data { // camera position cam_pos: vec4, }; + +//group 0 is the camera @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 +32,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,54 +41,65 @@ fn vs_sky(@builtin(vertex_index) vertex_index: u32) -> SkyOutput { return result; } -struct EntityOutput { +const MAX_ENTITY_INSTANCES=1024; +//group 1 is the model +@group(1) +@binding(0) +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? +@group(1) +@binding(1) +var model_texture: texture_2d; +@group(1) +@binding(2) +var model_sampler: sampler; + +struct EntityOutputTexture { @builtin(position) position: vec4, @location(1) texture: vec2, @location(2) normal: vec3, @location(3) view: vec3, }; -const MAX_ENTITY_INSTANCES=1024; -@group(1) -@binding(0) -var r_EntityTransform: array,MAX_ENTITY_INSTANCES>; - @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) +//group 2 is the skybox texture +@group(2) +@binding(0) +var cube_texture: texture_cube; +@group(2) @binding(1) -var r_texture: texture_cube; -@group(0) -@binding(2) -var r_sampler: sampler; +var cube_sampler: sampler; @fragment fn fs_sky(vertex: SkyOutput) -> @location(0) vec4 { - return textureSample(r_texture, r_sampler, vertex.sampledir); + return textureSample(cube_texture, model_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(model_texture, model_sampler, vertex.texture).rgb; + let reflected_color = textureSample(cube_texture, cube_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); }