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 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/texture-sep/texture-sep.gltf").unwrap();
let crate_model = resman.request::<Model>("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),

View File

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

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};
@ -66,6 +68,20 @@ pub enum AlphaMode {
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 {
fn from(value: gltf::material::AlphaMode) -> Self {
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)]
pub struct Material {
pub shader_uuid: Option<u64>,
@ -125,7 +177,7 @@ pub struct Material {
/// operator).
pub alpha_mode: AlphaMode,
//pub texture: Option<ResHandle<Texture>>,
pub specular: Option<Specular>,
}
#[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,
}
}
}

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 directional;
use std::{collections::{VecDeque, HashMap}, num::{NonZeroU64, NonZeroU32}, marker::PhantomData};
use edict::query::EpochOf;

View File

@ -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<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 shader_id: u64,
pub diffuse_texture: RenderTexture,
pub diffuse_texture: Option<RenderTexture>,
pub ambient: glam::Vec3,
pub diffuse: glam::Vec3,
pub specular: glam::Vec3,
pub shininess: f32,
pub specular: Option<MaterialSpecular>
}
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<wgpu::BindGroupLayout>, 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], */
}
}
}

View File

@ -50,7 +50,7 @@ struct MeshBufferStorage {
//#[allow(dead_code)]
//render_texture: Option<RenderTexture>,
material: Option<Material>,
texture_bindgroup: Option<BindGroup>,
diffuse_texture: Option<RenderTexture>,
// 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<BindGroupLayout>,
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() {

View File

@ -100,30 +100,33 @@ var s_diffuse: sampler;
@group(4) @binding(0)
var<uniform> u_material: Material;
@group(5) @binding(0)
var t_specular: texture_2d<f32>;
@group(5) @binding(1)
var s_specular: sampler;
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
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);
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<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_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<f32>, world_norm: vec3<f32>, 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 ////

View File

@ -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<wgpu::Texture>,
view: Arc<wgpu::TextureView>,
sampler: Arc<wgpu::Sampler>,
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<BindGroupPair>,
}
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<Self> {
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<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 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
}
}