Prototype implementation of specular maps

This commit is contained in:
SeanOMik 2023-11-18 11:36:33 -05:00
parent a0e6a16f03
commit e412e589d1
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
13 changed files with 401 additions and 152 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

View File

@ -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"
}
]
}

View File

@ -71,9 +71,10 @@ async fn main() {
let mut resman = world.get_resource_mut::<ResourceManager>().unwrap(); let mut resman = world.get_resource_mut::<ResourceManager>().unwrap();
//let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap(); //let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
//let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap(); let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap();
//let cube_model = resman.request::<Model>("assets/cube-texture-bin.glb").unwrap(); //let cube_model = resman.request::<Model>("assets/cube-texture-bin.glb").unwrap();
let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").unwrap(); let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").unwrap();
let crate_model = resman.request::<Model>("assets/crate/crate.gltf").unwrap();
drop(resman); drop(resman);
/* world.spawn(( /* world.spawn((
@ -81,10 +82,10 @@ async fn main() {
TransformComponent::from(Transform::from_xyz(3.0, 0.5, -2.2)), TransformComponent::from(Transform::from_xyz(3.0, 0.5, -2.2)),
)); */ )); */
/* world.spawn(( world.spawn((
ModelComponent(antique_camera_model), ModelComponent(antique_camera_model),
TransformComponent::from(Transform::from_xyz(0.0, -5.0, -10.0)), TransformComponent::from(Transform::from_xyz(0.0, -5.0, -10.0)),
)); */ ));
/* let light = PointLight { /* let light = PointLight {
color: Vec3::new(1.0, 1.0, 1.0), color: Vec3::new(1.0, 1.0, 1.0),
@ -105,7 +106,7 @@ async fn main() {
quadratic: 0.0075, quadratic: 0.0075,
}, */ }, */
TransformComponent::from(cube_tran), TransformComponent::from(cube_tran),
ModelComponent(cube_model.clone()), ModelComponent(crate_model.clone()),
CubeFlag, CubeFlag,
)); ));
@ -114,7 +115,7 @@ async fn main() {
world.spawn(( world.spawn((
PointLight { PointLight {
color: Vec3::new(1.0, 1.0, 1.0), //Vec3::new(0.361, 0.984, 0.0), 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, /* constant: 1.0,
linear: 0.045, linear: 0.045,
quadratic: 0.0075, */ quadratic: 0.0075, */
@ -123,9 +124,9 @@ async fn main() {
linear: 0.09, linear: 0.09,
quadratic: 0.032, quadratic: 0.032,
ambient: 0.2, ambient: 0.3,
diffuse: 0.5, diffuse: 1.0,
specular: 1.0, specular: 1.3,
}, },
TransformComponent::from(light_tran), TransformComponent::from(light_tran),
ModelComponent(cube_model), ModelComponent(cube_model),

View File

@ -10,7 +10,7 @@ anyhow = "1.0.75"
base64 = "0.21.4" base64 = "0.21.4"
edict = "0.5.0" edict = "0.5.0"
glam = "0.24.1" 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" image = "0.24.7"
# not using custom matcher, or file type from file path # not using custom matcher, or file type from file path
infer = { version = "0.15.0", default-features = false } infer = { version = "0.15.0", default-features = false }

View File

@ -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}; use crate::{Texture, ResHandle, util, loader::model::GltfLoadContext};
@ -66,6 +68,20 @@ pub enum AlphaMode {
Blend, Blend,
} }
#[derive(Clone)]
pub enum MaterialExtension {
SpecularTexture(ResHandle<Texture>),
}
impl MaterialExtension {
/// Returns the GLTF name of this extension
pub fn gltf_name(&self) -> &str {
match self {
MaterialExtension::SpecularTexture(_) => "KHR_materials_specular",
}
}
}
impl From<gltf::material::AlphaMode> for AlphaMode { impl From<gltf::material::AlphaMode> for AlphaMode {
fn from(value: gltf::material::AlphaMode) -> Self { fn from(value: gltf::material::AlphaMode) -> Self {
match value { match value {
@ -76,6 +92,42 @@ impl From<gltf::material::AlphaMode> 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<ResHandle<Texture>>,
/// 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<ResHandle<Texture>>,
}
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)] #[derive(Clone, Default)]
pub struct Material { pub struct Material {
pub shader_uuid: Option<u64>, pub shader_uuid: Option<u64>,
@ -125,7 +177,7 @@ pub struct Material {
/// operator). /// operator).
pub alpha_mode: AlphaMode, pub alpha_mode: AlphaMode,
//pub texture: Option<ResHandle<Texture>>, pub specular: Option<Specular>,
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -224,6 +276,8 @@ impl Material {
let metallic_roughness_texture = pbr_rough.metallic_roughness_texture() let metallic_roughness_texture = pbr_rough.metallic_roughness_texture()
.map(|info| Material::load_texture(context, info)); .map(|info| Material::load_texture(context, info));
let specular = gltf_mat.specular().map(|s| Specular::from_gltf(context, s));
Material { Material {
name: gltf_mat.name() name: gltf_mat.name()
.map(|s| s.to_string()), .map(|s| s.to_string()),
@ -240,6 +294,7 @@ impl Material {
// TODO // TODO
base_color_texture, base_color_texture,
metallic_roughness_texture, metallic_roughness_texture,
specular,
} }
} }
} }

View File

@ -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,
}

View File

@ -1,4 +1,6 @@
pub mod point; pub mod point;
pub mod directional;
use std::{collections::{VecDeque, HashMap}, num::{NonZeroU64, NonZeroU32}, marker::PhantomData}; use std::{collections::{VecDeque, HashMap}, num::{NonZeroU64, NonZeroU32}, marker::PhantomData};
use edict::query::EpochOf; use edict::query::EpochOf;

View File

@ -1,29 +1,62 @@
use std::sync::Arc;
use super::texture::RenderTexture; use super::texture::RenderTexture;
use super::texture::RenderTexture; use super::texture::RenderTexture;
#[derive(Clone)] pub struct MaterialSpecular {
pub factor: f32,
pub color_factor: glam::Vec3,
pub texture: Option<RenderTexture>,
pub color_texture: Option<RenderTexture>,
}
impl MaterialSpecular {
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, 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 struct Material {
pub shader_id: u64, pub shader_id: u64,
pub diffuse_texture: RenderTexture, pub diffuse_texture: Option<RenderTexture>,
pub ambient: glam::Vec3, pub ambient: glam::Vec3,
pub diffuse: glam::Vec3, pub diffuse: glam::Vec3,
pub specular: glam::Vec3,
pub shininess: f32, pub shininess: f32,
pub specular: Option<MaterialSpecular>
} }
impl Material { impl Material {
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, value: &lyra_resource::Material) -> Self { pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, 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 = value.base_color_texture.as_ref().map(|t| &t.data.as_ref().unwrap().image)
let diffuse_texture = RenderTexture::from_image(device, queue, image, None).unwrap(); .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 { Self {
shader_id: value.shader_uuid.unwrap_or(0), shader_id: value.shader_uuid.unwrap_or(0),
diffuse_texture, 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(value.base_color.x, value.base_color.y, value.base_color.z),
diffuse: glam::Vec3::new(1.0, 0.5, 0.31), //diffuse: glam::Vec3::new(1.0, 0.5, 0.31),
specular: glam::Vec3::new(0.5, 0.5, 0.5), //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, shininess: 32.0,
specular
} }
} }
} }
@ -43,17 +76,15 @@ pub struct MaterialUniform {
impl From<&Material> for MaterialUniform { impl From<&Material> for MaterialUniform {
fn from(value: &Material) -> Self { 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 { Self {
ambient: glam::Vec4::new(value.ambient.x, value.ambient.y, value.ambient.z, 0.0), 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), 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, shininess: value.shininess,
_padding1: [0; 3] _padding1: [0; 3]
/* _padding: 0,
_padding2: 0,
_padding3: 0,
_padding4: [0; 3], */
} }
} }
} }

View File

@ -50,7 +50,7 @@ struct MeshBufferStorage {
//#[allow(dead_code)] //#[allow(dead_code)]
//render_texture: Option<RenderTexture>, //render_texture: Option<RenderTexture>,
material: Option<Material>, material: Option<Material>,
texture_bindgroup: Option<BindGroup>, diffuse_texture: Option<RenderTexture>,
// The index of the transform for this entity. // The index of the transform for this entity.
// The tuple is structured like this: (transform index, index of transform inside the buffer) // 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_buffer: wgpu::Buffer,
camera_bind_group: wgpu::BindGroup, camera_bind_group: wgpu::BindGroup,
texture_bind_group_layout: BindGroupLayout, bgl_texture: Arc<BindGroupLayout>,
default_texture_bind_group: BindGroup, default_texture: RenderTexture,
depth_buffer_texture: RenderTexture, depth_buffer_texture: RenderTexture,
material_buffer: BufferWrapper, material_buffer: BufferWrapper,
@ -130,7 +130,7 @@ impl BasicRenderer {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
let mut v = wgpu::Limits::default(); let mut v = wgpu::Limits::default();
v.max_bind_groups = 5; v.max_bind_groups = 8;
v v
}, },
label: None, label: None,
@ -163,30 +163,7 @@ impl BasicRenderer {
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
let texture_bind_group_layout = let bgl_texture = Arc::new(RenderTexture::create_layout(&device));
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 shader_src = include_str!("shaders/base.wgsl"); let shader_src = include_str!("shaders/base.wgsl");
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
@ -235,23 +212,7 @@ impl BasicRenderer {
// load the default texture // load the default texture
let bytes = include_bytes!("default_texture.png"); let bytes = include_bytes!("default_texture.png");
let tex = RenderTexture::from_bytes(&device, &queue, bytes, "default_texture").unwrap(); let default_texture = RenderTexture::from_bytes(&device, &queue, bgl_texture.clone(), 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 light_uniform_buffers = LightUniformBuffers::new(&device); let light_uniform_buffers = LightUniformBuffers::new(&device);
@ -287,8 +248,8 @@ impl BasicRenderer {
camera_buffer, camera_buffer,
camera_bind_group, camera_bind_group,
texture_bind_group_layout, bgl_texture,
default_texture_bind_group: default_tex_bindgroup, default_texture,
depth_buffer_texture: depth_texture, depth_buffer_texture: depth_texture,
entity_last_transforms: HashMap::new(), entity_last_transforms: HashMap::new(),
@ -300,8 +261,9 @@ impl BasicRenderer {
let mut pipelines = HashMap::new(); let mut pipelines = HashMap::new();
pipelines.insert(0, Arc::new(FullRenderPipeline::new(&s.device, &s.config, &shader, pipelines.insert(0, Arc::new(FullRenderPipeline::new(&s.device, &s.config, &shader,
vec![super::vertex::Vertex::desc(),], vec![super::vertex::Vertex::desc(),],
vec![&s.texture_bind_group_layout, &s.transform_buffers.bindgroup_layout, &camera_bind_group_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.light_buffers.bindgroup_layout, &s.material_buffer.bindgroup_pair.as_ref().unwrap().layout,
&s.bgl_texture])));
s.render_pipelines = pipelines; s.render_pipelines = pipelines;
s s
@ -396,33 +358,7 @@ impl BasicRenderer {
fn create_mesh_buffers(&mut self, mesh: &Mesh, transform_indices: TransformBufferIndices) -> MeshBufferStorage { fn create_mesh_buffers(&mut self, mesh: &Mesh, transform_indices: TransformBufferIndices) -> MeshBufferStorage {
let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh);
let material = Material::from_resource(&self.device, &self.queue, &mesh.material()); let material = Material::from_resource(&self.device, &self.queue, self.bgl_texture.clone(), &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 uni = MaterialUniform::from(&material); let uni = MaterialUniform::from(&material);
self.queue.write_buffer(&self.material_buffer.inner_buf, 0, bytemuck::bytes_of(&uni)); self.queue.write_buffer(&self.material_buffer.inner_buf, 0, bytemuck::bytes_of(&uni));
debug!("Wrote material to buffer"); debug!("Wrote material to buffer");
@ -431,7 +367,7 @@ impl BasicRenderer {
buffer_vertex: vertex_buffer, buffer_vertex: vertex_buffer,
buffer_indices, buffer_indices,
material: Some(material), 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, let indices = self.transform_buffers.update_or_insert(&self.queue, &self.render_limits,
entity, || ( transform.calculate_mat4(), glam::Mat3::from_quat(transform.rotation) )); 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)] #[allow(clippy::map_entry)]
if !self.mesh_buffers.contains_key(&mesh.uuid) { if !self.mesh_buffers.contains_key(&mesh.uuid) {
// create the mesh's buffers // create the mesh's buffers
@ -569,7 +502,7 @@ impl Renderer for BasicRenderer {
})], })],
// enable depth buffer // enable depth buffer
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: self.depth_buffer_texture.view(), view: &self.depth_buffer_texture.view,
depth_ops: Some(wgpu::Operations { depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0), load: wgpu::LoadOp::Clear(1.0),
store: true, store: true,
@ -588,29 +521,30 @@ impl Renderer for BasicRenderer {
let buffers = self.mesh_buffers.get(&job.mesh_buffer_id).unwrap(); let buffers = self.mesh_buffers.get(&job.mesh_buffer_id).unwrap();
// Bind the optional texture // Bind the optional texture
if let Some(tex) = buffers.texture_bindgroup.as_ref() { if let Some(tex) = buffers.material.as_ref()
render_pass.set_bind_group(0, tex, &[]); .and_then(|m| m.diffuse_texture.as_ref()) {
render_pass.set_bind_group(0, tex.bind_group(), &[]);
} else { } 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. // 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 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.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; let offset = TransformBuffers::index_offset(&self.render_limits, transform_indices) as u32;
render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]); render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]);
// Bind camera
render_pass.set_bind_group(2, &self.camera_bind_group, &[]); 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(3, &self.light_buffers.bindgroup, &[]);
render_pass.set_bind_group(4, &self.material_buffer.bindgroup_pair.as_ref().unwrap().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 this mesh uses indices, use them to draw the mesh
if let Some((idx_type, indices)) = buffers.buffer_indices.as_ref() { if let Some((idx_type, indices)) = buffers.buffer_indices.as_ref() {

View File

@ -100,30 +100,33 @@ var s_diffuse: sampler;
@group(4) @binding(0) @group(4) @binding(0)
var<uniform> u_material: Material; var<uniform> u_material: Material;
@group(5) @binding(0)
var t_specular: texture_2d<f32>;
@group(5) @binding(1)
var s_specular: sampler;
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, in.tex_coords); let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, in.tex_coords);
let specular_color: vec3<f32> = textureSample(t_specular, s_specular, in.tex_coords).xyz;
var light_res = vec3<f32>(0.0); var light_res = vec3<f32>(0.0);
for (var i = 0u; i < u_lights.point_light_count; i++) { 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, specular_color);
light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material);
} }
let light_object_res = light_res * (object_color.xyz/* * u_material.diffuse.xyz*/); let light_object_res = light_res * (object_color.xyz/* * u_material.diffuse.xyz*/);
return vec4<f32>(light_object_res, object_color.a); return vec4<f32>(light_object_res, object_color.a);
} }
fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_light: PointLight, material: Material) -> vec3<f32> { fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_light: PointLight, material: Material, specular_factor: vec3<f32>) -> vec3<f32> {
let light_color = point_light.color.xyz; let light_color = point_light.color.xyz;
let light_pos = point_light.position.xyz; let light_pos = point_light.position.xyz;
let camera_view_pos = u_camera.view_pos.xyz; let camera_view_pos = u_camera.view_pos.xyz;
// We don't need (or want) much ambient light, so 0.1 is fine // We don't need (or want) much ambient light, so 0.1 is fine
//let ambient_strength = 0.1; //let ambient_strength = 0.1;
var ambient_color = light_color * material.ambient.xyz; var ambient_color = light_color * material.ambient.xyz * material.diffuse.xyz;
//let ambient_strength = 0.1;
var ambient_color = light_color * material.ambient.xyz;
//// diffuse //// //// diffuse ////
let light_dir = normalize(light_pos - world_pos); let light_dir = normalize(light_pos - world_pos);
@ -137,10 +140,9 @@ fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_li
let view_dir = normalize(camera_view_pos - world_pos); let view_dir = normalize(camera_view_pos - world_pos);
let half_dir = normalize(view_dir + light_dir); let half_dir = normalize(view_dir + light_dir);
let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess); 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);
let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess);
var specular_color = specular_strength * (light_color * material.specular.xyz);
//// end of specular //// //// end of specular ////
//// point light attenuation //// //// point light attenuation ////

View File

@ -3,6 +3,8 @@ use std::sync::Arc;
use image::GenericImageView; use image::GenericImageView;
use lyra_resource::{Resource, Texture}; use lyra_resource::{Resource, Texture};
use super::render_buffer::BindGroupPair;
/* #[derive(Clone)] /* #[derive(Clone)]
pub struct Texture { pub struct Texture {
texture_id: u32, texture_id: u32,
@ -22,23 +24,75 @@ impl Texture {
#[derive(Clone)]
#[allow(dead_code)] #[allow(dead_code)]
pub struct RenderTexture { pub struct RenderTexture {
texture: Arc<wgpu::Texture>, pub inner_texture: wgpu::Texture,
view: Arc<wgpu::TextureView>, pub view: wgpu::TextureView,
sampler: Arc<wgpu::Sampler>, pub sampler: wgpu::Sampler,
/// Most RenderTextures will have this, but things like depth buffers wont
pub bindgroup_pair: Option<BindGroupPair>,
} }
impl RenderTexture { impl RenderTexture {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; 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<Self> { pub fn create_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
let img = image::load_from_memory(bytes)?; device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
Self::from_image(device, queue, &img, Some(label)) 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<Self> { fn create_bind_group_pair(device: &wgpu::Device, layout: Arc<wgpu::BindGroupLayout>, 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<wgpu::BindGroupLayout>, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
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<wgpu::BindGroupLayout>, img: &image::DynamicImage, label: Option<&str>) -> anyhow::Result<Self> {
let rgba = img.to_rgba8(); let rgba = img.to_rgba8();
let dimensions = img.dimensions(); let dimensions = img.dimensions();
@ -89,10 +143,13 @@ impl RenderTexture {
} }
); );
let bgp = Self::create_bind_group_pair(device, bg_layout, &view, &sampler);
Ok(Self { Ok(Self {
texture: Arc::new(texture), inner_texture: texture,
view: Arc::new(view), view: view,
sampler: Arc::new(sampler), sampler: sampler,
bindgroup_pair: Some(bgp),
}) })
} }
@ -109,7 +166,7 @@ impl RenderTexture {
queue.write_texture( queue.write_texture(
wgpu::ImageCopyTexture { wgpu::ImageCopyTexture {
aspect: wgpu::TextureAspect::All, aspect: wgpu::TextureAspect::All,
texture: &self.texture, texture: &self.inner_texture,
mip_level: 0, mip_level: 0,
origin: wgpu::Origin3d::ZERO, origin: wgpu::Origin3d::ZERO,
}, },
@ -159,21 +216,18 @@ impl RenderTexture {
); );
Self { Self {
texture: Arc::new(texture), inner_texture: texture,
view: Arc::new(view), view: view,
sampler: Arc::new(sampler), sampler: sampler,
bindgroup_pair: None,
} }
} }
pub fn inner_texture(&self) -> &wgpu::Texture { /// Returns the bind group stored inside the bind group pair.
&self.texture ///
} /// Panics:
/// * This will panic if the texture isn't storing its bind group.
pub fn view(&self) -> &wgpu::TextureView { pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.view &self.bindgroup_pair.as_ref().unwrap().bindgroup
}
pub fn sampler(&self) -> &wgpu::Sampler {
&self.sampler
} }
} }