Improve module hierarchy of custom_shader example

This commit is contained in:
Héctor Ramón Jiménez 2023-11-14 15:48:01 +01:00
parent b1b2467b45
commit 811aa673e9
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
10 changed files with 122 additions and 126 deletions

View file

@ -0,0 +1,53 @@
use glam::{mat4, vec3, vec4};
use iced::Rectangle;
#[derive(Copy, Clone)]
pub struct Camera {
eye: glam::Vec3,
target: glam::Vec3,
up: glam::Vec3,
fov_y: f32,
near: f32,
far: f32,
}
impl Default for Camera {
fn default() -> Self {
Self {
eye: vec3(0.0, 2.0, 3.0),
target: glam::Vec3::ZERO,
up: glam::Vec3::Y,
fov_y: 45.0,
near: 0.1,
far: 100.0,
}
}
}
pub const OPENGL_TO_WGPU_MATRIX: glam::Mat4 = mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.5, 0.0),
vec4(0.0, 0.0, 0.5, 1.0),
);
impl Camera {
pub fn build_view_proj_matrix(&self, bounds: Rectangle) -> glam::Mat4 {
//TODO looks distorted without padding; base on surface texture size instead?
let aspect_ratio = bounds.width / (bounds.height + 150.0);
let view = glam::Mat4::look_at_rh(self.eye, self.target, self.up);
let proj = glam::Mat4::perspective_rh(
self.fov_y,
aspect_ratio,
self.near,
self.far,
);
OPENGL_TO_WGPU_MATRIX * proj * view
}
pub fn position(&self) -> glam::Vec4 {
glam::Vec4::from((self.eye, 0.0))
}
}

View file

@ -0,0 +1,615 @@
pub mod cube;
mod buffer;
mod uniforms;
mod vertex;
pub use cube::Cube;
pub use uniforms::Uniforms;
use buffer::Buffer;
use vertex::Vertex;
use crate::wgpu;
use crate::wgpu::util::DeviceExt;
use iced::{Rectangle, Size};
const SKY_TEXTURE_SIZE: u32 = 128;
pub struct Pipeline {
pipeline: wgpu::RenderPipeline,
vertices: wgpu::Buffer,
cubes: Buffer,
uniforms: wgpu::Buffer,
uniform_bind_group: wgpu::BindGroup,
depth_texture_size: Size<u32>,
depth_view: wgpu::TextureView,
depth_pipeline: DepthPipeline,
}
impl Pipeline {
pub fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
format: wgpu::TextureFormat,
target_size: Size<u32>,
) -> Self {
//vertices of one cube
let vertices =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("cubes vertex buffer"),
contents: bytemuck::cast_slice(&cube::Raw::vertices()),
usage: wgpu::BufferUsages::VERTEX,
});
//cube instance data
let cubes_buffer = Buffer::new(
device,
"cubes instance buffer",
std::mem::size_of::<cube::Raw>() as u64,
wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
);
//uniforms for all cubes
let uniforms = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("cubes uniform buffer"),
size: std::mem::size_of::<Uniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
//depth buffer
let depth_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("cubes depth texture"),
size: wgpu::Extent3d {
width: target_size.width,
height: target_size.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let depth_view =
depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
let normal_map_data = load_normal_map_data();
//normal map
let normal_texture = device.create_texture_with_data(
queue,
&wgpu::TextureDescriptor {
label: Some("cubes normal map texture"),
size: wgpu::Extent3d {
width: 1024,
height: 1024,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
},
&normal_map_data,
);
let normal_view =
normal_texture.create_view(&wgpu::TextureViewDescriptor::default());
//skybox texture for reflection/refraction
let skybox_data = load_skybox_data();
let skybox_texture = device.create_texture_with_data(
queue,
&wgpu::TextureDescriptor {
label: Some("cubes skybox texture"),
size: wgpu::Extent3d {
width: SKY_TEXTURE_SIZE,
height: SKY_TEXTURE_SIZE,
depth_or_array_layers: 6, //one for each face of the cube
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
},
&skybox_data,
);
let sky_view =
skybox_texture.create_view(&wgpu::TextureViewDescriptor {
label: Some("cubes skybox texture view"),
dimension: Some(wgpu::TextureViewDimension::Cube),
..Default::default()
});
let sky_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("cubes skybox 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 uniform_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("cubes uniform bind group layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float {
filterable: true,
},
view_dimension: wgpu::TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(
wgpu::SamplerBindingType::Filtering,
),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float {
filterable: true,
},
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
],
});
let uniform_bind_group =
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("cubes uniform bind group"),
layout: &uniform_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: uniforms.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&sky_view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(&sky_sampler),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::TextureView(
&normal_view,
),
},
],
});
let layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("cubes pipeline layout"),
bind_group_layouts: &[&uniform_bind_group_layout],
push_constant_ranges: &[],
});
let shader =
device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("cubes shader"),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
include_str!("../shaders/cubes.wgsl"),
)),
});
let pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("cubes pipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[Vertex::desc(), cube::Raw::desc()],
},
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::SrcAlpha,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Max,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
multiview: None,
});
let depth_pipeline = DepthPipeline::new(
device,
format,
depth_texture.create_view(&wgpu::TextureViewDescriptor::default()),
);
Self {
pipeline,
cubes: cubes_buffer,
uniforms,
uniform_bind_group,
vertices,
depth_texture_size: target_size,
depth_view,
depth_pipeline,
}
}
fn update_depth_texture(&mut self, device: &wgpu::Device, size: Size<u32>) {
if self.depth_texture_size.height != size.height
|| self.depth_texture_size.width != size.width
{
let text = device.create_texture(&wgpu::TextureDescriptor {
label: Some("cubes depth texture"),
size: wgpu::Extent3d {
width: size.width,
height: size.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
self.depth_view =
text.create_view(&wgpu::TextureViewDescriptor::default());
self.depth_texture_size = size;
self.depth_pipeline.update(device, &text);
}
}
pub fn update(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
target_size: Size<u32>,
uniforms: &Uniforms,
num_cubes: usize,
cubes: &[cube::Raw],
) {
//recreate depth texture if surface texture size has changed
self.update_depth_texture(device, target_size);
// update uniforms
queue.write_buffer(&self.uniforms, 0, bytemuck::bytes_of(uniforms));
//resize cubes vertex buffer if cubes amount changed
let new_size = num_cubes * std::mem::size_of::<cube::Raw>();
self.cubes.resize(device, new_size as u64);
//always write new cube data since they are constantly rotating
queue.write_buffer(&self.cubes.raw, 0, bytemuck::cast_slice(cubes));
}
pub fn render(
&self,
target: &wgpu::TextureView,
encoder: &mut wgpu::CommandEncoder,
bounds: Rectangle<u32>,
num_cubes: u32,
show_depth: bool,
) {
{
let mut pass =
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("cubes.pipeline.pass"),
color_attachments: &[Some(
wgpu::RenderPassColorAttachment {
view: target,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
},
)],
depth_stencil_attachment: Some(
wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: wgpu::StoreOp::Store,
}),
stencil_ops: None,
},
),
timestamp_writes: None,
occlusion_query_set: None,
});
pass.set_scissor_rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
);
pass.set_pipeline(&self.pipeline);
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
pass.set_vertex_buffer(0, self.vertices.slice(..));
pass.set_vertex_buffer(1, self.cubes.raw.slice(..));
pass.draw(0..36, 0..num_cubes);
}
if show_depth {
self.depth_pipeline.render(encoder, target, bounds);
}
}
}
struct DepthPipeline {
pipeline: wgpu::RenderPipeline,
bind_group_layout: wgpu::BindGroupLayout,
bind_group: wgpu::BindGroup,
sampler: wgpu::Sampler,
depth_view: wgpu::TextureView,
}
impl DepthPipeline {
pub fn new(
device: &wgpu::Device,
format: wgpu::TextureFormat,
depth_texture: wgpu::TextureView,
) -> Self {
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("cubes.depth_pipeline.sampler"),
..Default::default()
});
let bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("cubes.depth_pipeline.bind_group_layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(
wgpu::SamplerBindingType::NonFiltering,
),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float {
filterable: false,
},
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
],
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("cubes.depth_pipeline.bind_group"),
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Sampler(&sampler),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(
&depth_texture,
),
},
],
});
let layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("cubes.depth_pipeline.layout"),
bind_group_layouts: &[&bind_group_layout],
push_constant_ranges: &[],
});
let shader =
device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("cubes.depth_pipeline.shader"),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
include_str!("../shaders/depth.wgsl"),
)),
});
let pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("cubes.depth_pipeline.pipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[],
},
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
multiview: None,
});
Self {
pipeline,
bind_group_layout,
bind_group,
sampler,
depth_view: depth_texture,
}
}
pub fn update(
&mut self,
device: &wgpu::Device,
depth_texture: &wgpu::Texture,
) {
self.depth_view =
depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
self.bind_group =
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("cubes.depth_pipeline.bind_group"),
layout: &self.bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Sampler(&self.sampler),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(
&self.depth_view,
),
},
],
});
}
pub fn render(
&self,
encoder: &mut wgpu::CommandEncoder,
target: &wgpu::TextureView,
bounds: Rectangle<u32>,
) {
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("cubes.pipeline.depth_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: target,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: Some(
wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_view,
depth_ops: None,
stencil_ops: None,
},
),
timestamp_writes: None,
occlusion_query_set: None,
});
pass.set_scissor_rect(bounds.x, bounds.y, bounds.width, bounds.height);
pass.set_pipeline(&self.pipeline);
pass.set_bind_group(0, &self.bind_group, &[]);
pass.draw(0..6, 0..1);
}
}
fn load_skybox_data() -> Vec<u8> {
let pos_x: &[u8] = include_bytes!("../textures/skybox/pos_x.jpg");
let neg_x: &[u8] = include_bytes!("../textures/skybox/neg_x.jpg");
let pos_y: &[u8] = include_bytes!("../textures/skybox/pos_y.jpg");
let neg_y: &[u8] = include_bytes!("../textures/skybox/neg_y.jpg");
let pos_z: &[u8] = include_bytes!("../textures/skybox/pos_z.jpg");
let neg_z: &[u8] = include_bytes!("../textures/skybox/neg_z.jpg");
let data: [&[u8]; 6] = [pos_x, neg_x, pos_y, neg_y, pos_z, neg_z];
data.iter().fold(vec![], |mut acc, bytes| {
let i = image::load_from_memory_with_format(
bytes,
image::ImageFormat::Jpeg,
)
.unwrap()
.to_rgba8()
.into_raw();
acc.extend(i);
acc
})
}
fn load_normal_map_data() -> Vec<u8> {
let bytes: &[u8] = include_bytes!("../textures/ice_cube_normal_map.png");
image::load_from_memory_with_format(bytes, image::ImageFormat::Png)
.unwrap()
.to_rgba8()
.into_raw()
}

View file

@ -0,0 +1,41 @@
use crate::wgpu;
// A custom buffer container for dynamic resizing.
pub struct Buffer {
pub raw: wgpu::Buffer,
label: &'static str,
size: u64,
usage: wgpu::BufferUsages,
}
impl Buffer {
pub fn new(
device: &wgpu::Device,
label: &'static str,
size: u64,
usage: wgpu::BufferUsages,
) -> Self {
Self {
raw: device.create_buffer(&wgpu::BufferDescriptor {
label: Some(label),
size,
usage,
mapped_at_creation: false,
}),
label,
size,
usage,
}
}
pub fn resize(&mut self, device: &wgpu::Device, new_size: u64) {
if new_size > self.size {
self.raw = device.create_buffer(&wgpu::BufferDescriptor {
label: Some(self.label),
size: new_size,
usage: self.usage,
mapped_at_creation: false,
});
}
}
}

View file

@ -0,0 +1,326 @@
use crate::scene::pipeline::Vertex;
use crate::wgpu;
use glam::{vec2, vec3, Vec3};
use rand::{thread_rng, Rng};
/// A single instance of a cube.
#[derive(Debug, Clone)]
pub struct Cube {
pub rotation: glam::Quat,
pub position: Vec3,
pub size: f32,
rotation_dir: f32,
rotation_axis: glam::Vec3,
}
impl Default for Cube {
fn default() -> Self {
Self {
rotation: glam::Quat::IDENTITY,
position: glam::Vec3::ZERO,
size: 0.1,
rotation_dir: 1.0,
rotation_axis: glam::Vec3::Y,
}
}
}
impl Cube {
pub fn new(size: f32, origin: Vec3) -> Self {
let rnd = thread_rng().gen_range(0.0..=1.0f32);
Self {
rotation: glam::Quat::IDENTITY,
position: origin + Vec3::new(0.1, 0.1, 0.1),
size,
rotation_dir: if rnd <= 0.5 { -1.0 } else { 1.0 },
rotation_axis: if rnd <= 0.33 {
glam::Vec3::Y
} else if rnd <= 0.66 {
glam::Vec3::X
} else {
glam::Vec3::Z
},
}
}
pub fn update(&mut self, size: f32, time: f32) {
self.rotation = glam::Quat::from_axis_angle(
self.rotation_axis,
time / 2.0 * self.rotation_dir,
);
self.size = size;
}
}
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable, Debug)]
#[repr(C)]
pub struct Raw {
transformation: glam::Mat4,
normal: glam::Mat3,
_padding: [f32; 3],
}
impl Raw {
const ATTRIBS: [wgpu::VertexAttribute; 7] = wgpu::vertex_attr_array![
//cube transformation matrix
4 => Float32x4,
5 => Float32x4,
6 => Float32x4,
7 => Float32x4,
//normal rotation matrix
8 => Float32x3,
9 => Float32x3,
10 => Float32x3,
];
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &Self::ATTRIBS,
}
}
}
impl Raw {
pub fn from_cube(cube: &Cube) -> Raw {
Raw {
transformation: glam::Mat4::from_scale_rotation_translation(
glam::vec3(cube.size, cube.size, cube.size),
cube.rotation,
cube.position,
),
normal: glam::Mat3::from_quat(cube.rotation),
_padding: [0.0; 3],
}
}
pub fn vertices() -> [Vertex; 36] {
[
//face 1
Vertex {
pos: vec3(-0.5, -0.5, -0.5),
normal: vec3(0.0, 0.0, -1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
Vertex {
pos: vec3(0.5, -0.5, -0.5),
normal: vec3(0.0, 0.0, -1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 1.0),
},
Vertex {
pos: vec3(0.5, 0.5, -0.5),
normal: vec3(0.0, 0.0, -1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(0.5, 0.5, -0.5),
normal: vec3(0.0, 0.0, -1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(-0.5, 0.5, -0.5),
normal: vec3(0.0, 0.0, -1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 0.0),
},
Vertex {
pos: vec3(-0.5, -0.5, -0.5),
normal: vec3(0.0, 0.0, -1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
//face 2
Vertex {
pos: vec3(-0.5, -0.5, 0.5),
normal: vec3(0.0, 0.0, 1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
Vertex {
pos: vec3(0.5, -0.5, 0.5),
normal: vec3(0.0, 0.0, 1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 1.0),
},
Vertex {
pos: vec3(0.5, 0.5, 0.5),
normal: vec3(0.0, 0.0, 1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(0.5, 0.5, 0.5),
normal: vec3(0.0, 0.0, 1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(-0.5, 0.5, 0.5),
normal: vec3(0.0, 0.0, 1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 0.0),
},
Vertex {
pos: vec3(-0.5, -0.5, 0.5),
normal: vec3(0.0, 0.0, 1.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
//face 3
Vertex {
pos: vec3(-0.5, 0.5, 0.5),
normal: vec3(-1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(0.0, 1.0),
},
Vertex {
pos: vec3(-0.5, 0.5, -0.5),
normal: vec3(-1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(1.0, 1.0),
},
Vertex {
pos: vec3(-0.5, -0.5, -0.5),
normal: vec3(-1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(-0.5, -0.5, -0.5),
normal: vec3(-1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(-0.5, -0.5, 0.5),
normal: vec3(-1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(0.0, 0.0),
},
Vertex {
pos: vec3(-0.5, 0.5, 0.5),
normal: vec3(-1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(0.0, 1.0),
},
//face 4
Vertex {
pos: vec3(0.5, 0.5, 0.5),
normal: vec3(1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(0.0, 1.0),
},
Vertex {
pos: vec3(0.5, 0.5, -0.5),
normal: vec3(1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(1.0, 1.0),
},
Vertex {
pos: vec3(0.5, -0.5, -0.5),
normal: vec3(1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(0.5, -0.5, -0.5),
normal: vec3(1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(0.5, -0.5, 0.5),
normal: vec3(1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(0.0, 0.0),
},
Vertex {
pos: vec3(0.5, 0.5, 0.5),
normal: vec3(1.0, 0.0, 0.0),
tangent: vec3(0.0, 0.0, -1.0),
uv: vec2(0.0, 1.0),
},
//face 5
Vertex {
pos: vec3(-0.5, -0.5, -0.5),
normal: vec3(0.0, -1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
Vertex {
pos: vec3(0.5, -0.5, -0.5),
normal: vec3(0.0, -1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 1.0),
},
Vertex {
pos: vec3(0.5, -0.5, 0.5),
normal: vec3(0.0, -1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(0.5, -0.5, 0.5),
normal: vec3(0.0, -1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(-0.5, -0.5, 0.5),
normal: vec3(0.0, -1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 0.0),
},
Vertex {
pos: vec3(-0.5, -0.5, -0.5),
normal: vec3(0.0, -1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
//face 6
Vertex {
pos: vec3(-0.5, 0.5, -0.5),
normal: vec3(0.0, 1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
Vertex {
pos: vec3(0.5, 0.5, -0.5),
normal: vec3(0.0, 1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 1.0),
},
Vertex {
pos: vec3(0.5, 0.5, 0.5),
normal: vec3(0.0, 1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(0.5, 0.5, 0.5),
normal: vec3(0.0, 1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(1.0, 0.0),
},
Vertex {
pos: vec3(-0.5, 0.5, 0.5),
normal: vec3(0.0, 1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 0.0),
},
Vertex {
pos: vec3(-0.5, 0.5, -0.5),
normal: vec3(0.0, 1.0, 0.0),
tangent: vec3(1.0, 0.0, 0.0),
uv: vec2(0.0, 1.0),
},
]
}
}

View file

@ -0,0 +1,23 @@
use crate::scene::Camera;
use iced::{Color, Rectangle};
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct Uniforms {
camera_proj: glam::Mat4,
camera_pos: glam::Vec4,
light_color: glam::Vec4,
}
impl Uniforms {
pub fn new(camera: &Camera, bounds: Rectangle, light_color: Color) -> Self {
let camera_proj = camera.build_view_proj_matrix(bounds);
Self {
camera_proj,
camera_pos: camera.position(),
light_color: glam::Vec4::from(light_color.into_linear()),
}
}
}

View file

@ -0,0 +1,31 @@
use crate::wgpu;
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct Vertex {
pub pos: glam::Vec3,
pub normal: glam::Vec3,
pub tangent: glam::Vec3,
pub uv: glam::Vec2,
}
impl Vertex {
const ATTRIBS: [wgpu::VertexAttribute; 4] = wgpu::vertex_attr_array![
//position
0 => Float32x3,
//normal
1 => Float32x3,
//tangent
2 => Float32x3,
//uv
3 => Float32x2,
];
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &Self::ATTRIBS,
}
}
}