diff --git a/examples/testbed/assets/crate/Image.png b/examples/testbed/assets/crate/Image.png new file mode 100644 index 0000000..b986cad Binary files /dev/null and b/examples/testbed/assets/crate/Image.png differ diff --git a/examples/testbed/assets/crate/container2.png b/examples/testbed/assets/crate/container2.png new file mode 100644 index 0000000..596e8da Binary files /dev/null and b/examples/testbed/assets/crate/container2.png differ diff --git a/examples/testbed/assets/crate/crate.bin b/examples/testbed/assets/crate/crate.bin new file mode 100644 index 0000000..c64a5af Binary files /dev/null and b/examples/testbed/assets/crate/crate.bin differ diff --git a/examples/testbed/assets/crate/crate.gltf b/examples/testbed/assets/crate/crate.gltf new file mode 100644 index 0000000..0a9cd6f --- /dev/null +++ b/examples/testbed/assets/crate/crate.gltf @@ -0,0 +1,160 @@ +{ + "asset":{ + "generator":"Khronos glTF Blender I/O v3.6.6", + "version":"2.0" + }, + "extensionsUsed":[ + "KHR_materials_specular", + "KHR_materials_ior" + ], + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 0 + ] + } + ], + "nodes":[ + { + "mesh":0, + "name":"Cube" + } + ], + "materials":[ + { + "doubleSided":true, + "extensions":{ + "KHR_materials_specular":{ + "specularColorTexture":{ + "index":0 + } + }, + "KHR_materials_ior":{ + "ior":1.4500000476837158 + } + }, + "name":"Material", + "pbrMetallicRoughness":{ + "baseColorTexture":{ + "index":1 + }, + "metallicFactor":0, + "roughnessFactor":0.5 + } + } + ], + "meshes":[ + { + "name":"Cube", + "primitives":[ + { + "attributes":{ + "POSITION":0, + "TEXCOORD_0":1, + "NORMAL":2 + }, + "indices":3, + "material":0 + } + ] + } + ], + "textures":[ + { + "sampler":0, + "source":0 + }, + { + "sampler":0, + "source":1 + } + ], + "images":[ + { + "mimeType":"image/png", + "name":"Image", + "uri":"Image.png" + }, + { + "mimeType":"image/png", + "name":"container2", + "uri":"container2.png" + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5126, + "count":24, + "max":[ + 1, + 1, + 1 + ], + "min":[ + -1, + -1, + -1 + ], + "type":"VEC3" + }, + { + "bufferView":1, + "componentType":5126, + "count":24, + "type":"VEC2" + }, + { + "bufferView":2, + "componentType":5126, + "count":24, + "type":"VEC3" + }, + { + "bufferView":3, + "componentType":5123, + "count":36, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":288, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":192, + "byteOffset":288, + "target":34962 + }, + { + "buffer":0, + "byteLength":288, + "byteOffset":480, + "target":34962 + }, + { + "buffer":0, + "byteLength":72, + "byteOffset":768, + "target":34963 + } + ], + "samplers":[ + { + "magFilter":9729, + "minFilter":9987 + } + ], + "buffers":[ + { + "byteLength":840, + "uri":"crate.bin" + } + ] +} diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index 02f4698..9c1d8a3 100644 --- a/examples/testbed/src/main.rs +++ b/examples/testbed/src/main.rs @@ -71,9 +71,10 @@ async fn main() { let mut resman = world.get_resource_mut::().unwrap(); //let diffuse_texture = resman.request::("assets/happy-tree.png").unwrap(); - //let antique_camera_model = resman.request::("assets/AntiqueCamera.glb").unwrap(); + let antique_camera_model = resman.request::("assets/AntiqueCamera.glb").unwrap(); //let cube_model = resman.request::("assets/cube-texture-bin.glb").unwrap(); let cube_model = resman.request::("assets/texture-sep/texture-sep.gltf").unwrap(); + let crate_model = resman.request::("assets/crate/crate.gltf").unwrap(); drop(resman); /* world.spawn(( @@ -81,10 +82,10 @@ async fn main() { TransformComponent::from(Transform::from_xyz(3.0, 0.5, -2.2)), )); */ - /* world.spawn(( + world.spawn(( ModelComponent(antique_camera_model), TransformComponent::from(Transform::from_xyz(0.0, -5.0, -10.0)), - )); */ + )); /* let light = PointLight { color: Vec3::new(1.0, 1.0, 1.0), @@ -105,7 +106,7 @@ async fn main() { quadratic: 0.0075, }, */ TransformComponent::from(cube_tran), - ModelComponent(cube_model.clone()), + ModelComponent(crate_model.clone()), CubeFlag, )); @@ -114,7 +115,7 @@ async fn main() { world.spawn(( PointLight { color: Vec3::new(1.0, 1.0, 1.0), //Vec3::new(0.361, 0.984, 0.0), - intensity: 1.0, + intensity: 1.2, /* constant: 1.0, linear: 0.045, quadratic: 0.0075, */ @@ -123,9 +124,9 @@ async fn main() { linear: 0.09, quadratic: 0.032, - ambient: 0.2, - diffuse: 0.5, - specular: 1.0, + ambient: 0.3, + diffuse: 1.0, + specular: 1.3, }, TransformComponent::from(light_tran), ModelComponent(cube_model), diff --git a/lyra-resource/Cargo.toml b/lyra-resource/Cargo.toml index ae214bf..bbc45e8 100644 --- a/lyra-resource/Cargo.toml +++ b/lyra-resource/Cargo.toml @@ -10,7 +10,7 @@ anyhow = "1.0.75" base64 = "0.21.4" edict = "0.5.0" glam = "0.24.1" -gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness"] } +gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] } image = "0.24.7" # not using custom matcher, or file type from file path infer = { version = "0.15.0", default-features = false } diff --git a/lyra-resource/src/material.rs b/lyra-resource/src/material.rs index d7471df..7bccf46 100644 --- a/lyra-resource/src/material.rs +++ b/lyra-resource/src/material.rs @@ -1,4 +1,6 @@ -use std::{collections::hash_map::DefaultHasher, hash::{Hash, Hasher}}; +use std::{collections::{hash_map::DefaultHasher, HashMap}, hash::{Hash, Hasher}}; + +use tracing::debug; use crate::{Texture, ResHandle, util, loader::model::GltfLoadContext}; @@ -66,6 +68,20 @@ pub enum AlphaMode { Blend, } +#[derive(Clone)] +pub enum MaterialExtension { + SpecularTexture(ResHandle), +} + +impl MaterialExtension { + /// Returns the GLTF name of this extension + pub fn gltf_name(&self) -> &str { + match self { + MaterialExtension::SpecularTexture(_) => "KHR_materials_specular", + } + } +} + impl From for AlphaMode { fn from(value: gltf::material::AlphaMode) -> Self { match value { @@ -76,6 +92,42 @@ impl From for AlphaMode { } } +#[derive(Clone)] +pub struct Specular { + /// The strength of the specular reflection, default of 1.0 + pub factor: f32, + + /// The color of the specular reflection + pub color_factor: glam::Vec3, + + /// A texture that defines the strength of the specular reflection, + /// stored in the alpha (`A`) channel. This will be multiplied by + /// `specular_factor`. + pub texture: Option>, + + /// A texture that defines the color of the specular reflection, + /// stored in the `RGB` channels and encoded in sRGB. This texture + /// will be multiplied by `specular_color_factor`. + pub color_texture: Option>, +} + +impl Specular { + pub fn from_gltf(context: &mut GltfLoadContext, value: gltf::material::Specular) -> Self { + let color_texture = value.specular_color_texture() + .map(|t| Material::load_texture(context, t)); + + let spec_texture = value.specular_texture() + .map(|t| Material::load_texture(context, t)); + + Self { + factor: value.specular_factor(), + color_factor: value.specular_color_factor().into(), + color_texture, + texture: spec_texture, + } + } +} + #[derive(Clone, Default)] pub struct Material { pub shader_uuid: Option, @@ -125,7 +177,7 @@ pub struct Material { /// operator). pub alpha_mode: AlphaMode, - //pub texture: Option>, + pub specular: Option, } #[allow(dead_code)] @@ -224,6 +276,8 @@ impl Material { let metallic_roughness_texture = pbr_rough.metallic_roughness_texture() .map(|info| Material::load_texture(context, info)); + let specular = gltf_mat.specular().map(|s| Specular::from_gltf(context, s)); + Material { name: gltf_mat.name() .map(|s| s.to_string()), @@ -240,6 +294,7 @@ impl Material { // TODO base_color_texture, metallic_roughness_texture, + specular, } } } \ No newline at end of file diff --git a/src/render/light/directional.rs b/src/render/light/directional.rs new file mode 100644 index 0000000..f5b2c30 --- /dev/null +++ b/src/render/light/directional.rs @@ -0,0 +1,10 @@ +#[repr(C)] +#[derive(Default, Debug, Copy, Clone, edict::Component)] +pub struct DirectionalLight { + pub direction: glam::Quat, + pub color: glam::Vec3, + + pub ambient: glam::Vec3, + pub diffuse: glam::Vec3, + pub specular: glam::Vec3, +} \ No newline at end of file diff --git a/src/render/light/mod.rs b/src/render/light/mod.rs index f3f9650..ae0ca55 100644 --- a/src/render/light/mod.rs +++ b/src/render/light/mod.rs @@ -1,4 +1,6 @@ pub mod point; +pub mod directional; + use std::{collections::{VecDeque, HashMap}, num::{NonZeroU64, NonZeroU32}, marker::PhantomData}; use edict::query::EpochOf; diff --git a/src/render/material.rs b/src/render/material.rs index 9d65a24..3d1463c 100755 --- a/src/render/material.rs +++ b/src/render/material.rs @@ -1,29 +1,62 @@ +use std::sync::Arc; + use super::texture::RenderTexture; use super::texture::RenderTexture; -#[derive(Clone)] +pub struct MaterialSpecular { + pub factor: f32, + pub color_factor: glam::Vec3, + pub texture: Option, + pub color_texture: Option, +} + +impl MaterialSpecular { + pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::Specular) -> Self { + let tex = value.texture.as_ref().map(|t| &t.data.as_ref().unwrap().image) + .map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), i, None).unwrap()); + + let color_tex = value.color_texture.as_ref().map(|t| &t.data.as_ref().unwrap().image) + .map(|i| RenderTexture::from_image(device, queue, bg_layout, i, None).unwrap()); + + Self { + factor: value.factor, + color_factor: value.color_factor, + texture: tex, + color_texture: color_tex, + } + } +} + +//#[derive(Clone)] pub struct Material { pub shader_id: u64, - pub diffuse_texture: RenderTexture, + pub diffuse_texture: Option, pub ambient: glam::Vec3, pub diffuse: glam::Vec3, - pub specular: glam::Vec3, pub shininess: f32, + + pub specular: Option } impl Material { - pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, value: &lyra_resource::Material) -> Self { - let image = value.base_color_texture.as_ref().map(|t| &t.data.as_ref().unwrap().image).unwrap(); - let diffuse_texture = RenderTexture::from_image(device, queue, image, None).unwrap(); + pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::Material) -> Self { + let diffuse_texture = value.base_color_texture.as_ref().map(|t| &t.data.as_ref().unwrap().image) + .map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), i, None).unwrap()); + + let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), &s)); Self { shader_id: value.shader_uuid.unwrap_or(0), diffuse_texture, - ambient: glam::Vec3::new(1.0, 0.5, 0.31), + //ambient: glam::Vec3::new(1.0, 0.5, 0.31), //diffuse: glam::Vec3::new(value.base_color.x, value.base_color.y, value.base_color.z), - diffuse: glam::Vec3::new(1.0, 0.5, 0.31), - specular: glam::Vec3::new(0.5, 0.5, 0.5), + //diffuse: glam::Vec3::new(1.0, 0.5, 0.31), + //specular: glam::Vec3::new(0.5, 0.5, 0.5), + ambient: glam::Vec3::new(1.0, 1.0, 1.0), + diffuse: glam::Vec3::new(1.0, 1.0, 1.0), shininess: 32.0, + + specular } } } @@ -43,17 +76,15 @@ pub struct MaterialUniform { impl From<&Material> for MaterialUniform { fn from(value: &Material) -> Self { + let specular_factor = value.specular.as_ref().map(|s| glam::Vec3::new(s.factor, s.factor, s.factor)) + .unwrap_or_else(|| glam::Vec3::new(0.5, 0.5, 0.5)); + Self { ambient: glam::Vec4::new(value.ambient.x, value.ambient.y, value.ambient.z, 0.0), diffuse: glam::Vec4::new(value.diffuse.x, value.diffuse.y, value.diffuse.z, 0.0), - specular: glam::Vec4::new(value.specular.x, value.specular.y, value.specular.z, 0.0), + specular: glam::Vec4::new(specular_factor.x, specular_factor.y, specular_factor.z, 0.0), shininess: value.shininess, _padding1: [0; 3] - - /* _padding: 0, - _padding2: 0, - _padding3: 0, - _padding4: [0; 3], */ } } } \ No newline at end of file diff --git a/src/render/renderer.rs b/src/render/renderer.rs index 1a1afa3..48faeea 100755 --- a/src/render/renderer.rs +++ b/src/render/renderer.rs @@ -50,7 +50,7 @@ struct MeshBufferStorage { //#[allow(dead_code)] //render_texture: Option, material: Option, - texture_bindgroup: Option, + diffuse_texture: Option, // The index of the transform for this entity. // The tuple is structured like this: (transform index, index of transform inside the buffer) @@ -90,8 +90,8 @@ pub struct BasicRenderer { camera_buffer: wgpu::Buffer, camera_bind_group: wgpu::BindGroup, - texture_bind_group_layout: BindGroupLayout, - default_texture_bind_group: BindGroup, + bgl_texture: Arc, + default_texture: RenderTexture, depth_buffer_texture: RenderTexture, material_buffer: BufferWrapper, @@ -130,7 +130,7 @@ impl BasicRenderer { wgpu::Limits::downlevel_webgl2_defaults() } else { let mut v = wgpu::Limits::default(); - v.max_bind_groups = 5; + v.max_bind_groups = 8; v }, label: None, @@ -163,30 +163,7 @@ impl BasicRenderer { }; surface.configure(&device, &config); - let texture_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, - // This should match the filterable field of the - // corresponding Texture entry above. - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - ], - label: Some("texture_bind_group_layout"), - }); + let bgl_texture = Arc::new(RenderTexture::create_layout(&device)); let shader_src = include_str!("shaders/base.wgsl"); let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { @@ -235,23 +212,7 @@ impl BasicRenderer { // load the default texture let bytes = include_bytes!("default_texture.png"); - let tex = RenderTexture::from_bytes(&device, &queue, bytes, "default_texture").unwrap(); - let default_tex_bindgroup = device.create_bind_group( - &wgpu::BindGroupDescriptor { - layout: &texture_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(tex.view()), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(tex.sampler()), - } - ], - label: Some("default_texture"), - } - ); + let default_texture = RenderTexture::from_bytes(&device, &queue, bgl_texture.clone(), bytes, "default_texture").unwrap(); let light_uniform_buffers = LightUniformBuffers::new(&device); @@ -287,8 +248,8 @@ impl BasicRenderer { camera_buffer, camera_bind_group, - texture_bind_group_layout, - default_texture_bind_group: default_tex_bindgroup, + bgl_texture, + default_texture, depth_buffer_texture: depth_texture, entity_last_transforms: HashMap::new(), @@ -300,8 +261,9 @@ impl BasicRenderer { let mut pipelines = HashMap::new(); pipelines.insert(0, Arc::new(FullRenderPipeline::new(&s.device, &s.config, &shader, vec![super::vertex::Vertex::desc(),], - vec![&s.texture_bind_group_layout, &s.transform_buffers.bindgroup_layout, &camera_bind_group_layout, - &s.light_buffers.bindgroup_layout, &s.material_buffer.bindgroup_pair.as_ref().unwrap().layout]))); + vec![&s.bgl_texture, &s.transform_buffers.bindgroup_layout, &camera_bind_group_layout, + &s.light_buffers.bindgroup_layout, &s.material_buffer.bindgroup_pair.as_ref().unwrap().layout, + &s.bgl_texture]))); s.render_pipelines = pipelines; s @@ -396,33 +358,7 @@ impl BasicRenderer { fn create_mesh_buffers(&mut self, mesh: &Mesh, transform_indices: TransformBufferIndices) -> MeshBufferStorage { let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); - let material = Material::from_resource(&self.device, &self.queue, &mesh.material()); - let diffuse_bindgroup = if let Some(model_texture) = &mesh.material().base_color_texture { - let diffuse_texture = &material.diffuse_texture; - - let diffuse_bind_group = self.device.create_bind_group( - &wgpu::BindGroupDescriptor { - layout: &self.texture_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(diffuse_texture.view()), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(diffuse_texture.sampler()), - } - ], - label: Some("diffuse_bind_group"), - } - ); - - Some(diffuse_bind_group) - } else { - None - }; - - //let mat = Material::from_resource(&self.device, &self.queue, ) + let material = Material::from_resource(&self.device, &self.queue, self.bgl_texture.clone(), &mesh.material()); let uni = MaterialUniform::from(&material); self.queue.write_buffer(&self.material_buffer.inner_buf, 0, bytemuck::bytes_of(&uni)); debug!("Wrote material to buffer"); @@ -431,7 +367,7 @@ impl BasicRenderer { buffer_vertex: vertex_buffer, buffer_indices, material: Some(material), - texture_bindgroup: diffuse_bindgroup, + diffuse_texture: None, } } @@ -444,9 +380,6 @@ impl BasicRenderer { let indices = self.transform_buffers.update_or_insert(&self.queue, &self.render_limits, entity, || ( transform.calculate_mat4(), glam::Mat3::from_quat(transform.rotation) )); - //let mat = Material::from_resource(&self.device, &self.queue, ) - //self.queue.write_buffer(&self.material_buffer.inner_buf, 0, bytemuck::bytes_of(t)) - #[allow(clippy::map_entry)] if !self.mesh_buffers.contains_key(&mesh.uuid) { // create the mesh's buffers @@ -569,7 +502,7 @@ impl Renderer for BasicRenderer { })], // enable depth buffer depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: self.depth_buffer_texture.view(), + view: &self.depth_buffer_texture.view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0), store: true, @@ -588,29 +521,30 @@ impl Renderer for BasicRenderer { let buffers = self.mesh_buffers.get(&job.mesh_buffer_id).unwrap(); // Bind the optional texture - if let Some(tex) = buffers.texture_bindgroup.as_ref() { - render_pass.set_bind_group(0, tex, &[]); + if let Some(tex) = buffers.material.as_ref() + .and_then(|m| m.diffuse_texture.as_ref()) { + render_pass.set_bind_group(0, tex.bind_group(), &[]); } else { - render_pass.set_bind_group(0, &self.default_texture_bind_group, &[]); + render_pass.set_bind_group(0, &self.default_texture.bind_group(), &[]); + } + + if let Some(tex) = buffers.material.as_ref() + .and_then(|m| m.specular.as_ref()) + .and_then(|s| s.texture.as_ref().or_else(|| s.color_texture.as_ref())) { + render_pass.set_bind_group(5, tex.bind_group(), &[]); + } else { + render_pass.set_bind_group(5, &self.default_texture.bind_group(), &[]); } // Get the bindgroup for job's transform and bind to it using an offset. let transform_indices = *self.transform_buffers.entity_indices(job.entity).unwrap(); let bindgroup = self.transform_buffers.bind_group(transform_indices).unwrap(); - //let bindgroup = self.transform_buffers.entity_bind_group(job.entity).unwrap(); let offset = TransformBuffers::index_offset(&self.render_limits, transform_indices) as u32; render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]); - // Bind camera render_pass.set_bind_group(2, &self.camera_bind_group, &[]); - - // bind light - //render_pass.set_bind_group(3, &self.point_light_bind_group, &[]); render_pass.set_bind_group(3, &self.light_buffers.bindgroup, &[]); - render_pass.set_bind_group(4, &self.material_buffer.bindgroup_pair.as_ref().unwrap().bindgroup, &[]); - ////self.light_buffers.bind_lights(&mut render_pass, 3); - // if this mesh uses indices, use them to draw the mesh if let Some((idx_type, indices)) = buffers.buffer_indices.as_ref() { diff --git a/src/render/shaders/base.wgsl b/src/render/shaders/base.wgsl index 4512e3c..a18dd44 100755 --- a/src/render/shaders/base.wgsl +++ b/src/render/shaders/base.wgsl @@ -100,30 +100,33 @@ var s_diffuse: sampler; @group(4) @binding(0) var u_material: Material; +@group(5) @binding(0) +var t_specular: texture_2d; +@group(5) @binding(1) +var s_specular: sampler; + @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.tex_coords); + let specular_color: vec3 = textureSample(t_specular, s_specular, in.tex_coords).xyz; var light_res = vec3(0.0); for (var i = 0u; i < u_lights.point_light_count; i++) { - light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material); - light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material); + light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material, specular_color); } let light_object_res = light_res * (object_color.xyz/* * u_material.diffuse.xyz*/); return vec4(light_object_res, object_color.a); } -fn blinn_phong_point_light(world_pos: vec3, world_norm: vec3, point_light: PointLight, material: Material) -> vec3 { +fn blinn_phong_point_light(world_pos: vec3, world_norm: vec3, point_light: PointLight, material: Material, specular_factor: vec3) -> vec3 { let light_color = point_light.color.xyz; let light_pos = point_light.position.xyz; let camera_view_pos = u_camera.view_pos.xyz; // We don't need (or want) much ambient light, so 0.1 is fine //let ambient_strength = 0.1; - var ambient_color = light_color * material.ambient.xyz; - //let ambient_strength = 0.1; - var ambient_color = light_color * material.ambient.xyz; + var ambient_color = light_color * material.ambient.xyz * material.diffuse.xyz; //// diffuse //// let light_dir = normalize(light_pos - world_pos); @@ -137,10 +140,9 @@ fn blinn_phong_point_light(world_pos: vec3, world_norm: vec3, point_li let view_dir = normalize(camera_view_pos - world_pos); let half_dir = normalize(view_dir + light_dir); + let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess); - var specular_color = specular_strength * (light_color * material.specular.xyz); - let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess); - var specular_color = specular_strength * (light_color * material.specular.xyz); + var specular_color = specular_strength * (light_color * specular_factor); //// end of specular //// //// point light attenuation //// diff --git a/src/render/texture.rs b/src/render/texture.rs index bb33e82..b178005 100755 --- a/src/render/texture.rs +++ b/src/render/texture.rs @@ -3,6 +3,8 @@ use std::sync::Arc; use image::GenericImageView; use lyra_resource::{Resource, Texture}; +use super::render_buffer::BindGroupPair; + /* #[derive(Clone)] pub struct Texture { texture_id: u32, @@ -22,23 +24,75 @@ impl Texture { -#[derive(Clone)] #[allow(dead_code)] pub struct RenderTexture { - texture: Arc, - view: Arc, - sampler: Arc, + pub inner_texture: wgpu::Texture, + pub view: wgpu::TextureView, + pub sampler: wgpu::Sampler, + + /// Most RenderTextures will have this, but things like depth buffers wont + pub bindgroup_pair: Option, } impl RenderTexture { pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str) -> anyhow::Result { - let img = image::load_from_memory(bytes)?; - Self::from_image(device, queue, &img, Some(label)) + pub fn create_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { + 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, + // This should match the filterable field of the + // corresponding Texture entry above. + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + label: Some("BGL_Texture"), + }) } - pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str>) -> anyhow::Result { + fn create_bind_group_pair(device: &wgpu::Device, layout: Arc, view: &wgpu::TextureView, sampler: &wgpu::Sampler) -> BindGroupPair { + let bg = device.create_bind_group( + &wgpu::BindGroupDescriptor { + layout: &layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(sampler), + } + ], + label: Some("default_texture"), + } + ); + + BindGroupPair { + layout, + bindgroup: bg + } + } + + pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, bytes: &[u8], label: &str) -> anyhow::Result { + let img = image::load_from_memory(bytes)?; + Self::from_image(device, queue, bg_layout, &img, Some(label)) + } + + pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, img: &image::DynamicImage, label: Option<&str>) -> anyhow::Result { let rgba = img.to_rgba8(); let dimensions = img.dimensions(); @@ -89,10 +143,13 @@ impl RenderTexture { } ); + let bgp = Self::create_bind_group_pair(device, bg_layout, &view, &sampler); + Ok(Self { - texture: Arc::new(texture), - view: Arc::new(view), - sampler: Arc::new(sampler), + inner_texture: texture, + view: view, + sampler: sampler, + bindgroup_pair: Some(bgp), }) } @@ -109,7 +166,7 @@ impl RenderTexture { queue.write_texture( wgpu::ImageCopyTexture { aspect: wgpu::TextureAspect::All, - texture: &self.texture, + texture: &self.inner_texture, mip_level: 0, origin: wgpu::Origin3d::ZERO, }, @@ -159,21 +216,18 @@ impl RenderTexture { ); Self { - texture: Arc::new(texture), - view: Arc::new(view), - sampler: Arc::new(sampler), + inner_texture: texture, + view: view, + sampler: sampler, + bindgroup_pair: None, } } - pub fn inner_texture(&self) -> &wgpu::Texture { - &self.texture - } - - pub fn view(&self) -> &wgpu::TextureView { - &self.view - } - - pub fn sampler(&self) -> &wgpu::Sampler { - &self.sampler + /// Returns the bind group stored inside the bind group pair. + /// + /// Panics: + /// * This will panic if the texture isn't storing its bind group. + pub fn bind_group(&self) -> &wgpu::BindGroup { + &self.bindgroup_pair.as_ref().unwrap().bindgroup } } \ No newline at end of file