Compare commits
No commits in common. "3a80c069c991bbcda8a0249133bed5784b78fd01" and "c4aebdb25dc479cba3b3c6b6f29973944194b432" have entirely different histories.
3a80c069c9
...
c4aebdb25d
26 changed files with 604 additions and 1322 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -3075,16 +3075,6 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shadows"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-std",
|
|
||||||
"lyra-engine",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"examples/testbed",
|
||||||
"lyra-resource",
|
"lyra-resource",
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-reflect",
|
"lyra-reflect",
|
||||||
|
@ -13,12 +14,10 @@ members = [
|
||||||
"lyra-math",
|
"lyra-math",
|
||||||
"lyra-scene",
|
"lyra-scene",
|
||||||
|
|
||||||
"examples/testbed",
|
|
||||||
"examples/many-lights",
|
"examples/many-lights",
|
||||||
"examples/fixed-timestep-rotating-model",
|
"examples/fixed-timestep-rotating-model",
|
||||||
"examples/lua-scripting",
|
"examples/lua-scripting",
|
||||||
"examples/simple_scene",
|
"examples/simple_scene"
|
||||||
"examples/shadows",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
Binary file not shown.
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "shadows"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
lyra-engine = { path = "../../", features = ["tracy"] }
|
|
||||||
anyhow = "1.0.75"
|
|
||||||
async-std = "1.12.0"
|
|
||||||
tracing = "0.1.37"
|
|
|
@ -1,59 +0,0 @@
|
||||||
---Return the userdata's name from its metatable
|
|
||||||
---@param val userdata
|
|
||||||
---@return string
|
|
||||||
function udname(val)
|
|
||||||
return getmetatable(val).__name
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_init()
|
|
||||||
local cube = world:request_res("../assets/cube-texture-embedded.gltf")
|
|
||||||
print("Loaded textured cube (" .. udname(cube) .. ")")
|
|
||||||
|
|
||||||
cube:wait_until_loaded()
|
|
||||||
local scenes = cube:scenes()
|
|
||||||
local cube_scene = scenes[1]
|
|
||||||
|
|
||||||
local pos = Transform.from_translation(Vec3.new(0, 0, -8.0))
|
|
||||||
|
|
||||||
local e = world:spawn(pos, cube_scene)
|
|
||||||
print("spawned entity " .. tostring(e))
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[ function on_first()
|
|
||||||
print("Lua's first function was called")
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_pre_update()
|
|
||||||
print("Lua's pre-update function was called")
|
|
||||||
end ]]
|
|
||||||
|
|
||||||
function on_update()
|
|
||||||
--[[ ---@type number
|
|
||||||
local dt = world:resource(DeltaTime)
|
|
||||||
local act = world:resource(ActionHandler)
|
|
||||||
---@type number
|
|
||||||
local move_objs = act:get_axis("ObjectsMoveUpDown")
|
|
||||||
|
|
||||||
world:view(function (t)
|
|
||||||
if move_objs ~= nil then
|
|
||||||
t:translate(0, move_objs * 0.35 * dt, 0)
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
end, Transform) ]]
|
|
||||||
|
|
||||||
---@type number
|
|
||||||
local dt = world:resource(DeltaTime)
|
|
||||||
|
|
||||||
world:view(function (t)
|
|
||||||
t:translate(0, 0.15 * dt, 0)
|
|
||||||
return t
|
|
||||||
end, Transform)
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[ function on_post_update()
|
|
||||||
print("Lua's post-update function was called")
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_last()
|
|
||||||
print("Lua's last function was called")
|
|
||||||
end ]]
|
|
|
@ -1,165 +0,0 @@
|
||||||
use lyra_engine::{
|
|
||||||
assets::{gltf::Gltf, ResourceManager},
|
|
||||||
game::Game,
|
|
||||||
input::{
|
|
||||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
|
||||||
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
|
||||||
},
|
|
||||||
math::{self, Transform, Vec3},
|
|
||||||
render::light::directional::DirectionalLight,
|
|
||||||
scene::{
|
|
||||||
CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, WorldTransform,
|
|
||||||
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN,
|
|
||||||
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[async_std::main]
|
|
||||||
async fn main() {
|
|
||||||
let action_handler_plugin = |game: &mut Game| {
|
|
||||||
let action_handler = ActionHandler::builder()
|
|
||||||
.add_layout(LayoutId::from(0))
|
|
||||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_MOVE_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_MOVE_UP_DOWN, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_LOOK_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_LOOK_UP_DOWN, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_LOOK_ROLL, Action::new(ActionKind::Axis))
|
|
||||||
.add_action("Debug", Action::new(ActionKind::Button))
|
|
||||||
.add_mapping(
|
|
||||||
ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0))
|
|
||||||
.bind(
|
|
||||||
ACTLBL_MOVE_FORWARD_BACKWARD,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_MOVE_LEFT_RIGHT,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_MOVE_UP_DOWN,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_LOOK_LEFT_RIGHT,
|
|
||||||
&[
|
|
||||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
|
|
||||||
ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_LOOK_UP_DOWN,
|
|
||||||
&[
|
|
||||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
|
|
||||||
ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_LOOK_ROLL,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
"Debug",
|
|
||||||
&[ActionSource::Keyboard(KeyCode::B).into_binding()],
|
|
||||||
)
|
|
||||||
.finish(),
|
|
||||||
)
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let world = game.world_mut();
|
|
||||||
world.add_resource(action_handler);
|
|
||||||
game.with_plugin(InputActionPlugin);
|
|
||||||
};
|
|
||||||
|
|
||||||
Game::initialize()
|
|
||||||
.await
|
|
||||||
.with_plugin(lyra_engine::DefaultPlugins)
|
|
||||||
.with_plugin(setup_scene_plugin)
|
|
||||||
.with_plugin(action_handler_plugin)
|
|
||||||
//.with_plugin(camera_debug_plugin)
|
|
||||||
.with_plugin(FreeFlyCameraPlugin)
|
|
||||||
.run()
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_scene_plugin(game: &mut Game) {
|
|
||||||
let world = game.world_mut();
|
|
||||||
let resman = world.get_resource_mut::<ResourceManager>();
|
|
||||||
|
|
||||||
/* let camera_gltf = resman
|
|
||||||
.request::<Gltf>("../assets/AntiqueCamera.glb")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
camera_gltf.wait_recurse_dependencies_load();
|
|
||||||
let camera_mesh = &camera_gltf.data_ref().unwrap().scenes[0];
|
|
||||||
drop(resman);
|
|
||||||
|
|
||||||
world.spawn((
|
|
||||||
camera_mesh.clone(),
|
|
||||||
WorldTransform::default(),
|
|
||||||
Transform::from_xyz(0.0, -5.0, -2.0),
|
|
||||||
)); */
|
|
||||||
|
|
||||||
let cube_gltf = resman
|
|
||||||
.request::<Gltf>("../assets/cube-texture-embedded.gltf")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
cube_gltf.wait_recurse_dependencies_load();
|
|
||||||
let cube_mesh = &cube_gltf.data_ref().unwrap().scenes[0];
|
|
||||||
|
|
||||||
let platform_gltf = resman
|
|
||||||
.request::<Gltf>("../assets/wood-platform.glb")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
platform_gltf.wait_recurse_dependencies_load();
|
|
||||||
let platform_mesh = &platform_gltf.data_ref().unwrap().scenes[0];
|
|
||||||
|
|
||||||
drop(resman);
|
|
||||||
|
|
||||||
world.spawn((
|
|
||||||
cube_mesh.clone(),
|
|
||||||
WorldTransform::default(),
|
|
||||||
Transform::from_xyz(0.0, -2.0, -5.0),
|
|
||||||
));
|
|
||||||
|
|
||||||
world.spawn((
|
|
||||||
platform_mesh.clone(),
|
|
||||||
WorldTransform::default(),
|
|
||||||
Transform::from_xyz(0.0, -5.0, -5.0),
|
|
||||||
));
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut light_tran = Transform::from_xyz(-5.5, 2.5, -3.0);
|
|
||||||
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
|
||||||
light_tran.rotate_x(math::Angle::Degrees(-45.0));
|
|
||||||
light_tran.rotate_y(math::Angle::Degrees(-35.0));
|
|
||||||
world.spawn((
|
|
||||||
cube_mesh.clone(),
|
|
||||||
DirectionalLight {
|
|
||||||
enabled: true,
|
|
||||||
color: Vec3::new(1.0, 0.95, 0.9),
|
|
||||||
intensity: 1.0,
|
|
||||||
},
|
|
||||||
light_tran,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut camera = CameraComponent::new_3d();
|
|
||||||
camera.transform.translation += math::Vec3::new(0.0, 2.0, 10.5);
|
|
||||||
camera.transform.rotate_x(math::Angle::Degrees(-17.0));
|
|
||||||
world.spawn((camera, FreeFlyCamera::default()));
|
|
||||||
}
|
|
|
@ -444,11 +444,6 @@ impl World {
|
||||||
.and_then(|r| r.try_get_mut())
|
.and_then(|r| r.try_get_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_resource_data<T: ResourceObject>(&self) -> Option<ResourceData> {
|
|
||||||
self.resources.get(&TypeId::of::<T>())
|
|
||||||
.map(|r| r.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Increments the TickTracker which is used for tracking changes to components.
|
/// Increments the TickTracker which is used for tracking changes to components.
|
||||||
///
|
///
|
||||||
/// Most users wont need to call this manually, its done for you through queries and views.
|
/// Most users wont need to call this manually, its done for you through queries and views.
|
||||||
|
|
|
@ -95,9 +95,9 @@ struct NodeEntry {
|
||||||
struct BindGroupEntry {
|
struct BindGroupEntry {
|
||||||
label: RenderGraphLabelValue,
|
label: RenderGraphLabelValue,
|
||||||
/// BindGroup
|
/// BindGroup
|
||||||
bg: Arc<wgpu::BindGroup>,
|
bg: Rc<wgpu::BindGroup>,
|
||||||
/// BindGroupLayout
|
/// BindGroupLayout
|
||||||
layout: Option<Arc<wgpu::BindGroupLayout>>,
|
layout: Option<Rc<wgpu::BindGroupLayout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -368,23 +368,22 @@ impl RenderGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn try_bind_group<L: Into<RenderGraphLabelValue>>(&self, label: L) -> Option<&Arc<wgpu::BindGroup>> {
|
pub fn try_bind_group<L: Into<RenderGraphLabelValue>>(&self, label: L) -> Option<&Rc<wgpu::BindGroup>> {
|
||||||
self.bind_groups.get(&label.into()).map(|e| &e.bg)
|
self.bind_groups.get(&label.into()).map(|e| &e.bg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bind_group<L: Into<RenderGraphLabelValue>>(&self, label: L) -> &Arc<wgpu::BindGroup> {
|
pub fn bind_group<L: Into<RenderGraphLabelValue>>(&self, label: L) -> &Rc<wgpu::BindGroup> {
|
||||||
let l = label.into();
|
self.try_bind_group(label).expect("Unknown id for bind group")
|
||||||
self.try_bind_group(l.clone()).unwrap_or_else(|| panic!("Unknown label '{:?}' for bind group layout", l.clone()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn try_bind_group_layout<L: Into<RenderGraphLabelValue>>(&self, label: L) -> Option<&Arc<wgpu::BindGroupLayout>> {
|
pub fn try_bind_group_layout<L: Into<RenderGraphLabelValue>>(&self, label: L) -> Option<&Rc<wgpu::BindGroupLayout>> {
|
||||||
self.bind_groups.get(&label.into()).and_then(|e| e.layout.as_ref())
|
self.bind_groups.get(&label.into()).and_then(|e| e.layout.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bind_group_layout<L: Into<RenderGraphLabelValue>>(&self, label: L) -> &Arc<wgpu::BindGroupLayout> {
|
pub fn bind_group_layout<L: Into<RenderGraphLabelValue>>(&self, label: L) -> &Rc<wgpu::BindGroupLayout> {
|
||||||
let l = label.into();
|
let l = label.into();
|
||||||
self.try_bind_group_layout(l.clone())
|
self.try_bind_group_layout(l.clone())
|
||||||
.unwrap_or_else(|| panic!("Unknown label '{:?}' for bind group layout", l.clone()))
|
.unwrap_or_else(|| panic!("Unknown label '{:?}' for bind group layout", l.clone()))
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cell::{Ref, RefCell, RefMut}, num::NonZeroU32, rc::Rc, sync::Arc};
|
use std::{cell::{Ref, RefCell, RefMut}, num::NonZeroU32, rc::Rc};
|
||||||
|
|
||||||
use bind_match::bind_match;
|
use bind_match::bind_match;
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
|
@ -54,16 +54,16 @@ pub enum SlotValue {
|
||||||
/// The value will be set during a later phase of the render graph. To see the type of value
|
/// The value will be set during a later phase of the render graph. To see the type of value
|
||||||
/// this will be set to, see the slots type.
|
/// this will be set to, see the slots type.
|
||||||
Lazy,
|
Lazy,
|
||||||
TextureView(Arc<wgpu::TextureView>),
|
TextureView(Rc<wgpu::TextureView>),
|
||||||
Sampler(Rc<wgpu::Sampler>),
|
Sampler(Rc<wgpu::Sampler>),
|
||||||
Texture(Rc<wgpu::Texture>),
|
Texture(Rc<wgpu::Texture>),
|
||||||
Buffer(Arc<wgpu::Buffer>),
|
Buffer(Rc<wgpu::Buffer>),
|
||||||
RenderTarget(Rc<RefCell<RenderTarget>>),
|
RenderTarget(Rc<RefCell<RenderTarget>>),
|
||||||
Frame(Rc<RefCell<Option<Frame>>>),
|
Frame(Rc<RefCell<Option<Frame>>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SlotValue {
|
impl SlotValue {
|
||||||
pub fn as_texture_view(&self) -> Option<&Arc<wgpu::TextureView>> {
|
pub fn as_texture_view(&self) -> Option<&Rc<wgpu::TextureView>> {
|
||||||
bind_match!(self, Self::TextureView(v) => v)
|
bind_match!(self, Self::TextureView(v) => v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ impl SlotValue {
|
||||||
bind_match!(self, Self::Texture(v) => v)
|
bind_match!(self, Self::Texture(v) => v)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_buffer(&self) -> Option<&Arc<wgpu::Buffer>> {
|
pub fn as_buffer(&self) -> Option<&Rc<wgpu::Buffer>> {
|
||||||
bind_match!(self, Self::Buffer(v) => v)
|
bind_match!(self, Self::Buffer(v) => v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,8 +189,8 @@ pub struct NodeDesc {
|
||||||
/// This makes the bind groups accessible to other Nodes.
|
/// This makes the bind groups accessible to other Nodes.
|
||||||
pub bind_groups: Vec<(
|
pub bind_groups: Vec<(
|
||||||
RenderGraphLabelValue,
|
RenderGraphLabelValue,
|
||||||
Arc<wgpu::BindGroup>,
|
Rc<wgpu::BindGroup>,
|
||||||
Option<Arc<wgpu::BindGroupLayout>>,
|
Option<Rc<wgpu::BindGroupLayout>>,
|
||||||
)>,
|
)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ impl NodeDesc {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
pass_type: NodeType,
|
pass_type: NodeType,
|
||||||
pipeline_desc: Option<PipelineDescriptor>,
|
pipeline_desc: Option<PipelineDescriptor>,
|
||||||
bind_groups: Vec<(&dyn RenderGraphLabel, Arc<wgpu::BindGroup>, Option<Arc<wgpu::BindGroupLayout>>)>,
|
bind_groups: Vec<(&dyn RenderGraphLabel, Rc<wgpu::BindGroup>, Option<Rc<wgpu::BindGroupLayout>>)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ty: pass_type,
|
ty: pass_type,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use glam::UVec2;
|
use glam::UVec2;
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
|
@ -56,8 +56,8 @@ impl Node for BasePass {
|
||||||
.buffer_dynamic_offset(false)
|
.buffer_dynamic_offset(false)
|
||||||
.contents(&[self.screen_size])
|
.contents(&[self.screen_size])
|
||||||
.finish_parts(graph.device());
|
.finish_parts(graph.device());
|
||||||
let screen_size_bgl = Arc::new(screen_size_bgl);
|
let screen_size_bgl = Rc::new(screen_size_bgl);
|
||||||
let screen_size_bg = Arc::new(screen_size_bg);
|
let screen_size_bg = Rc::new(screen_size_bg);
|
||||||
|
|
||||||
let (camera_bgl, camera_bg, camera_buf, _) = BufferWrapper::builder()
|
let (camera_bgl, camera_bg, camera_buf, _) = BufferWrapper::builder()
|
||||||
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
|
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
|
||||||
|
@ -66,17 +66,17 @@ impl Node for BasePass {
|
||||||
.buffer_dynamic_offset(false)
|
.buffer_dynamic_offset(false)
|
||||||
.contents(&[CameraUniform::default()])
|
.contents(&[CameraUniform::default()])
|
||||||
.finish_parts(graph.device());
|
.finish_parts(graph.device());
|
||||||
let camera_bgl = Arc::new(camera_bgl);
|
let camera_bgl = Rc::new(camera_bgl);
|
||||||
let camera_bg = Arc::new(camera_bg);
|
let camera_bg = Rc::new(camera_bg);
|
||||||
|
|
||||||
// create the depth texture using the utility struct, then take all the required fields
|
// create the depth texture using the utility struct, then take all the required fields
|
||||||
let mut depth_texture = RenderTexture::create_depth_texture(graph.device(), self.screen_size, "depth_texture");
|
let mut depth_texture = RenderTexture::create_depth_texture(graph.device(), self.screen_size, "depth_texture");
|
||||||
depth_texture.create_bind_group(&graph.device);
|
depth_texture.create_bind_group(&graph.device);
|
||||||
|
|
||||||
let dt_bg_pair = depth_texture.bindgroup_pair.unwrap();
|
let dt_bg_pair = depth_texture.bindgroup_pair.unwrap();
|
||||||
let depth_texture_bg = Arc::new(dt_bg_pair.bindgroup);
|
let depth_texture_bg = Rc::new(dt_bg_pair.bindgroup);
|
||||||
let depth_texture_bgl = dt_bg_pair.layout;
|
let depth_texture_bgl = dt_bg_pair.layout;
|
||||||
let depth_texture_view = Arc::new(depth_texture.view);
|
let depth_texture_view = Rc::new(depth_texture.view);
|
||||||
|
|
||||||
let mut desc = NodeDesc::new(
|
let mut desc = NodeDesc::new(
|
||||||
NodeType::Node,
|
NodeType::Node,
|
||||||
|
@ -102,12 +102,12 @@ impl Node for BasePass {
|
||||||
desc.add_buffer_slot(
|
desc.add_buffer_slot(
|
||||||
BasePassSlots::ScreenSize,
|
BasePassSlots::ScreenSize,
|
||||||
SlotAttribute::Output,
|
SlotAttribute::Output,
|
||||||
Some(SlotValue::Buffer(Arc::new(screen_size_buf))),
|
Some(SlotValue::Buffer(Rc::new(screen_size_buf))),
|
||||||
);
|
);
|
||||||
desc.add_buffer_slot(
|
desc.add_buffer_slot(
|
||||||
BasePassSlots::Camera,
|
BasePassSlots::Camera,
|
||||||
SlotAttribute::Output,
|
SlotAttribute::Output,
|
||||||
Some(SlotValue::Buffer(Arc::new(camera_buf))),
|
Some(SlotValue::Buffer(Rc::new(camera_buf))),
|
||||||
);
|
);
|
||||||
|
|
||||||
desc
|
desc
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ pub struct FxaaPassLabel;
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct FxaaPass {
|
pub struct FxaaPass {
|
||||||
target_sampler: Option<wgpu::Sampler>,
|
target_sampler: Option<wgpu::Sampler>,
|
||||||
bgl: Option<Arc<wgpu::BindGroupLayout>>,
|
bgl: Option<Rc<wgpu::BindGroupLayout>>,
|
||||||
/// Store bind groups for the input textures.
|
/// Store bind groups for the input textures.
|
||||||
/// The texture may change due to resizes, or changes to the view target chain
|
/// The texture may change due to resizes, or changes to the view target chain
|
||||||
/// from other nodes.
|
/// from other nodes.
|
||||||
|
@ -54,7 +54,7 @@ impl Node for FxaaPass {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
let bgl = Arc::new(bgl);
|
let bgl = Rc::new(bgl);
|
||||||
self.bgl = Some(bgl.clone());
|
self.bgl = Some(bgl.clone());
|
||||||
self.target_sampler = Some(device.create_sampler(&wgpu::SamplerDescriptor {
|
self.target_sampler = Some(device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
label: Some("fxaa sampler"),
|
label: Some("fxaa sampler"),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{mem, rc::Rc, sync::Arc};
|
use std::{mem, rc::Rc};
|
||||||
|
|
||||||
use glam::Vec2Swizzles;
|
use glam::Vec2Swizzles;
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
|
@ -63,7 +63,7 @@ impl Node for LightCullComputePass {
|
||||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
});
|
});
|
||||||
|
|
||||||
let light_indices_bg_layout = Arc::new(device.create_bind_group_layout(
|
let light_indices_bg_layout = Rc::new(device.create_bind_group_layout(
|
||||||
&wgpu::BindGroupLayoutDescriptor {
|
&wgpu::BindGroupLayoutDescriptor {
|
||||||
entries: &[
|
entries: &[
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
@ -128,7 +128,7 @@ impl Node for LightCullComputePass {
|
||||||
array_layer_count: None,
|
array_layer_count: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let light_indices_bg = Arc::new(device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let light_indices_bg = Rc::new(device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
layout: &light_indices_bg_layout,
|
layout: &light_indices_bg_layout,
|
||||||
entries: &[
|
entries: &[
|
||||||
wgpu::BindGroupEntry {
|
wgpu::BindGroupEntry {
|
||||||
|
@ -194,7 +194,7 @@ impl Node for LightCullComputePass {
|
||||||
desc.add_buffer_slot(
|
desc.add_buffer_slot(
|
||||||
LightCullComputePassSlots::IndexCounterBuffer,
|
LightCullComputePassSlots::IndexCounterBuffer,
|
||||||
SlotAttribute::Output,
|
SlotAttribute::Output,
|
||||||
Some(SlotValue::Buffer(Arc::new(light_index_counter_buffer))),
|
Some(SlotValue::Buffer(Rc::new(light_index_counter_buffer))),
|
||||||
);
|
);
|
||||||
|
|
||||||
desc
|
desc
|
||||||
|
|
|
@ -1,767 +0,0 @@
|
||||||
use std::{
|
|
||||||
collections::{HashSet, VecDeque},
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use glam::{UVec2, Vec3};
|
|
||||||
use image::GenericImageView;
|
|
||||||
use itertools::izip;
|
|
||||||
use lyra_ecs::{
|
|
||||||
query::{
|
|
||||||
filter::{Has, Not, Or},
|
|
||||||
Entities, Res, ResMut, TickOf,
|
|
||||||
},
|
|
||||||
relation::{ChildOf, RelationOriginComponent},
|
|
||||||
Component, Entity, ResourceObject, World,
|
|
||||||
};
|
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
|
||||||
use lyra_math::Transform;
|
|
||||||
use lyra_resource::{gltf::Mesh, ResHandle};
|
|
||||||
use lyra_scene::{SceneGraph, WorldTransform};
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
use tracing::{debug, instrument};
|
|
||||||
use uuid::Uuid;
|
|
||||||
use wgpu::util::DeviceExt;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
render::{
|
|
||||||
graph::{Node, NodeDesc, NodeType},
|
|
||||||
render_buffer::BufferStorage,
|
|
||||||
render_job::RenderJob,
|
|
||||||
texture::{res_filter_to_wgpu, res_wrap_to_wgpu},
|
|
||||||
transform_buffer_storage::{TransformBuffers, TransformGroup},
|
|
||||||
vertex::Vertex,
|
|
||||||
},
|
|
||||||
DeltaTime,
|
|
||||||
};
|
|
||||||
|
|
||||||
type MeshHandle = ResHandle<Mesh>;
|
|
||||||
type SceneHandle = ResHandle<SceneGraph>;
|
|
||||||
|
|
||||||
pub struct MeshBufferStorage {
|
|
||||||
pub buffer_vertex: BufferStorage,
|
|
||||||
pub buffer_indices: Option<(wgpu::IndexFormat, BufferStorage)>,
|
|
||||||
|
|
||||||
// maybe this should just be a Uuid and the material can be retrieved though
|
|
||||||
// MeshPass's `material_buffers` field?
|
|
||||||
pub material: Option<Arc<GpuMaterial>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Component)]
|
|
||||||
struct InterpTransform {
|
|
||||||
last_transform: Transform,
|
|
||||||
alpha: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Copy, Hash, RenderGraphLabel)]
|
|
||||||
pub struct MeshPrepNodeLabel;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MeshPrepNode {
|
|
||||||
pub material_bgl: Arc<wgpu::BindGroupLayout>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MeshPrepNode {
|
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
|
||||||
let bgl = GpuMaterial::create_bind_group_layout(device);
|
|
||||||
|
|
||||||
Self { material_bgl: bgl }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the mesh buffers in the GPU need to be updated.
|
|
||||||
#[instrument(skip(self, device, mesh_buffers, queue, mesh_han))]
|
|
||||||
fn check_mesh_buffers(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
mesh_buffers: &mut FxHashMap<uuid::Uuid, MeshBufferStorage>,
|
|
||||||
mesh_han: &ResHandle<Mesh>,
|
|
||||||
) {
|
|
||||||
let mesh_uuid = mesh_han.uuid();
|
|
||||||
|
|
||||||
if let (Some(mesh), Some(buffers)) = (mesh_han.data_ref(), mesh_buffers.get_mut(&mesh_uuid))
|
|
||||||
{
|
|
||||||
// check if the buffer sizes dont match. If they dont, completely remake the buffers
|
|
||||||
let vertices = mesh.position().unwrap();
|
|
||||||
if buffers.buffer_vertex.count() != vertices.len() {
|
|
||||||
debug!("Recreating buffers for mesh {}", mesh_uuid.to_string());
|
|
||||||
let (vert, idx) = self.create_vertex_index_buffers(device, &mesh);
|
|
||||||
|
|
||||||
// have to re-get buffers because of borrow checker
|
|
||||||
let buffers = mesh_buffers.get_mut(&mesh_uuid).unwrap();
|
|
||||||
buffers.buffer_indices = idx;
|
|
||||||
buffers.buffer_vertex = vert;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update vertices
|
|
||||||
let vertex_buffer = buffers.buffer_vertex.buffer();
|
|
||||||
let vertices = vertices.as_slice();
|
|
||||||
// align the vertices to 4 bytes (u32 is 4 bytes, which is wgpu::COPY_BUFFER_ALIGNMENT)
|
|
||||||
let (_, vertices, _) = bytemuck::pod_align_to::<Vec3, u32>(vertices);
|
|
||||||
queue.write_buffer(vertex_buffer, 0, bytemuck::cast_slice(vertices));
|
|
||||||
|
|
||||||
// update the indices if they're given
|
|
||||||
if let Some(index_buffer) = buffers.buffer_indices.as_ref() {
|
|
||||||
let aligned_indices = match mesh.indices.as_ref().unwrap() {
|
|
||||||
// U16 indices need to be aligned to u32, for wpgu, which are 4-bytes in size.
|
|
||||||
lyra_resource::gltf::MeshIndices::U16(v) => {
|
|
||||||
bytemuck::pod_align_to::<u16, u32>(v).1
|
|
||||||
}
|
|
||||||
lyra_resource::gltf::MeshIndices::U32(v) => {
|
|
||||||
bytemuck::pod_align_to::<u32, u32>(v).1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let index_buffer = index_buffer.1.buffer();
|
|
||||||
queue.write_buffer(index_buffer, 0, bytemuck::cast_slice(aligned_indices));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, device, mesh))]
|
|
||||||
fn create_vertex_index_buffers(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
mesh: &Mesh,
|
|
||||||
) -> (BufferStorage, Option<(wgpu::IndexFormat, BufferStorage)>) {
|
|
||||||
let positions = mesh.position().unwrap();
|
|
||||||
let tex_coords: Vec<glam::Vec2> = mesh
|
|
||||||
.tex_coords()
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(|| vec![glam::Vec2::new(0.0, 0.0); positions.len()]);
|
|
||||||
let normals = mesh.normals().unwrap();
|
|
||||||
|
|
||||||
assert!(positions.len() == tex_coords.len() && positions.len() == normals.len());
|
|
||||||
|
|
||||||
let mut vertex_inputs = vec![];
|
|
||||||
for (v, t, n) in izip!(positions.iter(), tex_coords.iter(), normals.iter()) {
|
|
||||||
vertex_inputs.push(Vertex::new(*v, *t, *n));
|
|
||||||
}
|
|
||||||
|
|
||||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Vertex Buffer"),
|
|
||||||
contents: bytemuck::cast_slice(vertex_inputs.as_slice()), //vertex_combined.as_slice(),
|
|
||||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
let vertex_buffer = BufferStorage::new(vertex_buffer, 0, vertex_inputs.len());
|
|
||||||
|
|
||||||
let indices = match mesh.indices.as_ref() {
|
|
||||||
Some(indices) => {
|
|
||||||
let (idx_type, len, contents) = match indices {
|
|
||||||
lyra_resource::gltf::MeshIndices::U16(v) => {
|
|
||||||
(wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v))
|
|
||||||
}
|
|
||||||
lyra_resource::gltf::MeshIndices::U32(v) => {
|
|
||||||
(wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Index Buffer"),
|
|
||||||
contents,
|
|
||||||
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
|
|
||||||
let buffer_indices = BufferStorage::new(index_buffer, 0, len);
|
|
||||||
|
|
||||||
Some((idx_type, buffer_indices))
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
(vertex_buffer, indices)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, device, queue, material_buffers, mesh))]
|
|
||||||
fn create_mesh_buffers(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
material_buffers: &mut RenderAssets<Arc<GpuMaterial>>,
|
|
||||||
mesh: &Mesh,
|
|
||||||
) -> MeshBufferStorage {
|
|
||||||
let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(device, mesh);
|
|
||||||
|
|
||||||
let material = mesh
|
|
||||||
.material
|
|
||||||
.as_ref()
|
|
||||||
.expect("Material resource not loaded yet");
|
|
||||||
let material_ref = material.data_ref().unwrap();
|
|
||||||
|
|
||||||
let material = material_buffers.entry(material.uuid()).or_insert_with(|| {
|
|
||||||
debug!(
|
|
||||||
uuid = material.uuid().to_string(),
|
|
||||||
"Sending material to gpu"
|
|
||||||
);
|
|
||||||
Arc::new(GpuMaterial::from_resource(
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
&self.material_bgl,
|
|
||||||
&material_ref,
|
|
||||||
))
|
|
||||||
});
|
|
||||||
|
|
||||||
MeshBufferStorage {
|
|
||||||
buffer_vertex: vertex_buffer,
|
|
||||||
buffer_indices,
|
|
||||||
material: Some(material.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed.
|
|
||||||
#[instrument(skip(
|
|
||||||
self,
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
mesh_buffers,
|
|
||||||
material_buffers,
|
|
||||||
entity_meshes,
|
|
||||||
mesh,
|
|
||||||
entity
|
|
||||||
))]
|
|
||||||
fn process_mesh(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
mesh_buffers: &mut RenderAssets<MeshBufferStorage>,
|
|
||||||
material_buffers: &mut RenderAssets<Arc<GpuMaterial>>,
|
|
||||||
entity_meshes: &mut FxHashMap<Entity, uuid::Uuid>,
|
|
||||||
entity: Entity,
|
|
||||||
mesh: &Mesh,
|
|
||||||
mesh_uuid: Uuid,
|
|
||||||
) -> bool {
|
|
||||||
#[allow(clippy::map_entry)]
|
|
||||||
if !mesh_buffers.contains_key(&mesh_uuid) {
|
|
||||||
// create the mesh's buffers
|
|
||||||
let buffers = self.create_mesh_buffers(device, queue, material_buffers, mesh);
|
|
||||||
mesh_buffers.insert(mesh_uuid, buffers);
|
|
||||||
entity_meshes.insert(entity, mesh_uuid);
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the resource does not exist in the world, add the default
|
|
||||||
fn try_init_resource<T: ResourceObject + Default>(world: &mut World) {
|
|
||||||
if !world.has_resource::<T>() {
|
|
||||||
world.add_resource_default::<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for MeshPrepNode {
|
|
||||||
fn desc(
|
|
||||||
&mut self,
|
|
||||||
_: &mut crate::render::graph::RenderGraph,
|
|
||||||
) -> crate::render::graph::NodeDesc {
|
|
||||||
NodeDesc::new(NodeType::Node, None, vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare(
|
|
||||||
&mut self,
|
|
||||||
_: &mut crate::render::graph::RenderGraph,
|
|
||||||
world: &mut lyra_ecs::World,
|
|
||||||
context: &mut crate::render::graph::RenderGraphContext,
|
|
||||||
) {
|
|
||||||
let device = &context.device;
|
|
||||||
let queue = &context.queue;
|
|
||||||
let render_limits = device.limits();
|
|
||||||
|
|
||||||
let last_epoch = world.current_tick();
|
|
||||||
let mut alive_entities = HashSet::new();
|
|
||||||
|
|
||||||
{
|
|
||||||
// prepare the world with resources
|
|
||||||
if !world.has_resource::<TransformBuffers>() {
|
|
||||||
let buffers = TransformBuffers::new(device);
|
|
||||||
world.add_resource(buffers);
|
|
||||||
}
|
|
||||||
Self::try_init_resource::<RenderMeshes>(world);
|
|
||||||
Self::try_init_resource::<RenderAssets<MeshBufferStorage>>(world);
|
|
||||||
Self::try_init_resource::<RenderAssets<Arc<GpuMaterial>>>(world);
|
|
||||||
Self::try_init_resource::<FxHashMap<Entity, uuid::Uuid>>(world);
|
|
||||||
|
|
||||||
let mut render_meshes = world.get_resource_mut::<RenderMeshes>();
|
|
||||||
render_meshes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
let view = world.view_iter::<(
|
|
||||||
Entities,
|
|
||||||
&Transform,
|
|
||||||
TickOf<Transform>,
|
|
||||||
Or<(&MeshHandle, TickOf<MeshHandle>), (&SceneHandle, TickOf<SceneHandle>)>,
|
|
||||||
Option<&mut InterpTransform>,
|
|
||||||
Res<DeltaTime>,
|
|
||||||
ResMut<TransformBuffers>,
|
|
||||||
ResMut<RenderMeshes>,
|
|
||||||
ResMut<RenderAssets<MeshBufferStorage>>,
|
|
||||||
ResMut<RenderAssets<Arc<GpuMaterial>>>,
|
|
||||||
ResMut<FxHashMap<Entity, uuid::Uuid>>,
|
|
||||||
)>();
|
|
||||||
|
|
||||||
// used to store InterpTransform components to add to entities later
|
|
||||||
let mut component_queue: Vec<(Entity, InterpTransform)> = vec![];
|
|
||||||
|
|
||||||
for (
|
|
||||||
entity,
|
|
||||||
transform,
|
|
||||||
_transform_epoch,
|
|
||||||
(mesh_pair, scene_pair),
|
|
||||||
interp_tran,
|
|
||||||
delta_time,
|
|
||||||
mut transforms,
|
|
||||||
mut render_meshes,
|
|
||||||
mut mesh_buffers,
|
|
||||||
mut material_buffers,
|
|
||||||
mut entity_meshes,
|
|
||||||
) in view
|
|
||||||
{
|
|
||||||
alive_entities.insert(entity);
|
|
||||||
|
|
||||||
// Interpolate the transform for this entity using a component.
|
|
||||||
// If the entity does not have the component then it will be queued to be added
|
|
||||||
// to it after all the entities are prepared for rendering.
|
|
||||||
let interp_transform = match interp_tran {
|
|
||||||
Some(mut interp_transform) => {
|
|
||||||
// found in https://youtu.be/YJB1QnEmlTs?t=472
|
|
||||||
interp_transform.alpha = 1.0 - interp_transform.alpha.powf(**delta_time);
|
|
||||||
|
|
||||||
interp_transform.last_transform = interp_transform
|
|
||||||
.last_transform
|
|
||||||
.lerp(*transform, interp_transform.alpha);
|
|
||||||
interp_transform.last_transform
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let interp = InterpTransform {
|
|
||||||
last_transform: *transform,
|
|
||||||
alpha: 0.5,
|
|
||||||
};
|
|
||||||
component_queue.push((entity, interp));
|
|
||||||
|
|
||||||
*transform
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
// expand the transform buffers if they need to be.
|
|
||||||
// this is done in its own scope to avoid multiple mutable references to self at
|
|
||||||
// once; aka, make the borrow checker happy
|
|
||||||
if transforms.needs_expand() {
|
|
||||||
debug!("Expanding transform buffers");
|
|
||||||
transforms.expand_buffers(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((mesh_han, mesh_epoch)) = mesh_pair {
|
|
||||||
if let Some(mesh) = mesh_han.data_ref() {
|
|
||||||
// if process mesh did not just create a new mesh, and the epoch
|
|
||||||
// shows that the scene has changed, verify that the mesh buffers
|
|
||||||
// dont need to be resent to the gpu.
|
|
||||||
if !self.process_mesh(
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
&mut mesh_buffers,
|
|
||||||
&mut material_buffers,
|
|
||||||
&mut entity_meshes,
|
|
||||||
entity,
|
|
||||||
&mesh,
|
|
||||||
mesh_han.uuid(),
|
|
||||||
) && mesh_epoch == last_epoch
|
|
||||||
{
|
|
||||||
self.check_mesh_buffers(device, queue, &mut mesh_buffers, &mesh_han);
|
|
||||||
}
|
|
||||||
|
|
||||||
let group = TransformGroup::EntityRes(entity, mesh_han.uuid());
|
|
||||||
let transform_id = transforms.update_or_push(
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
&render_limits,
|
|
||||||
group,
|
|
||||||
interp_transform.calculate_mat4(),
|
|
||||||
glam::Mat3::from_quat(interp_transform.rotation),
|
|
||||||
);
|
|
||||||
|
|
||||||
let material = mesh.material.as_ref().unwrap().data_ref().unwrap();
|
|
||||||
let shader = material.shader_uuid.unwrap_or(0);
|
|
||||||
let job = RenderJob::new(entity, shader, mesh_han.uuid(), transform_id);
|
|
||||||
render_meshes.push_back(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((scene_han, scene_epoch)) = scene_pair {
|
|
||||||
if let Some(scene) = scene_han.data_ref() {
|
|
||||||
if scene_epoch == last_epoch {
|
|
||||||
let view = scene.world().view::<(
|
|
||||||
Entities,
|
|
||||||
&mut WorldTransform,
|
|
||||||
&Transform,
|
|
||||||
Not<Has<RelationOriginComponent<ChildOf>>>,
|
|
||||||
)>();
|
|
||||||
lyra_scene::system_update_world_transforms(scene.world(), view).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (mesh_han, pos) in
|
|
||||||
scene.world().view_iter::<(&MeshHandle, &WorldTransform)>()
|
|
||||||
{
|
|
||||||
if let Some(mesh) = mesh_han.data_ref() {
|
|
||||||
let mesh_interpo = interp_transform + **pos;
|
|
||||||
|
|
||||||
// if process mesh did not just create a new mesh, and the epoch
|
|
||||||
// shows that the scene has changed, verify that the mesh buffers
|
|
||||||
// dont need to be resent to the gpu.
|
|
||||||
if !self.process_mesh(
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
&mut mesh_buffers,
|
|
||||||
&mut material_buffers,
|
|
||||||
&mut entity_meshes,
|
|
||||||
entity,
|
|
||||||
&mesh,
|
|
||||||
mesh_han.uuid(),
|
|
||||||
) && scene_epoch == last_epoch
|
|
||||||
{
|
|
||||||
self.check_mesh_buffers(
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
&mut mesh_buffers,
|
|
||||||
&mesh_han,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let scene_mesh_group =
|
|
||||||
TransformGroup::Res(scene_han.uuid(), mesh_han.uuid());
|
|
||||||
let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
|
|
||||||
let transform_id = transforms.update_or_push(
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
&render_limits,
|
|
||||||
group,
|
|
||||||
mesh_interpo.calculate_mat4(),
|
|
||||||
glam::Mat3::from_quat(mesh_interpo.rotation),
|
|
||||||
);
|
|
||||||
|
|
||||||
let material = mesh.material.as_ref().unwrap().data_ref().unwrap();
|
|
||||||
let shader = material.shader_uuid.unwrap_or(0);
|
|
||||||
let job = RenderJob::new(entity, shader, mesh_han.uuid(), transform_id);
|
|
||||||
render_meshes.push_back(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (en, interp) in component_queue {
|
|
||||||
world.insert(en, interp);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut transforms = world.get_resource_mut::<TransformBuffers>();
|
|
||||||
transforms.send_to_gpu(queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute(
|
|
||||||
&mut self,
|
|
||||||
_: &mut crate::render::graph::RenderGraph,
|
|
||||||
_: &crate::render::graph::NodeDesc,
|
|
||||||
_: &mut crate::render::graph::RenderGraphContext,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct RenderAssets<T>(FxHashMap<Uuid, T>);
|
|
||||||
|
|
||||||
impl<T> Deref for RenderAssets<T> {
|
|
||||||
type Target = FxHashMap<Uuid, T>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> DerefMut for RenderAssets<T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for RenderAssets<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> RenderAssets<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct GpuMaterial {
|
|
||||||
pub bind_group: Arc<wgpu::BindGroup>,
|
|
||||||
bind_group_layout: Arc<wgpu::BindGroupLayout>,
|
|
||||||
material_properties_buffer: wgpu::Buffer,
|
|
||||||
diffuse_texture: wgpu::Texture,
|
|
||||||
diffuse_texture_sampler: wgpu::Sampler,
|
|
||||||
/* specular_texture: wgpu::Texture,
|
|
||||||
specular_texture_sampler: wgpu::Sampler, */
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GpuMaterial {
|
|
||||||
fn create_bind_group_layout(device: &wgpu::Device) -> Arc<wgpu::BindGroupLayout> {
|
|
||||||
Arc::new(
|
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
label: Some("bgl_material"),
|
|
||||||
entries: &[
|
|
||||||
// material properties
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Buffer {
|
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: None, /* Some(
|
|
||||||
NonZeroU64::new(mem::size_of::<MaterialPropertiesUniform>() as _)
|
|
||||||
.unwrap(),
|
|
||||||
) */
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// diffuse texture
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Texture {
|
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// diffuse texture sampler
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 2,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// specular texture
|
|
||||||
/* wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 3,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Texture {
|
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: false },
|
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
// specular texture sampler
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 4,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
|
|
||||||
count: None,
|
|
||||||
}, */
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn texture_desc(label: &str, size: UVec2) -> wgpu::TextureDescriptor {
|
|
||||||
//debug!("Texture desc size: {:?}", size);
|
|
||||||
wgpu::TextureDescriptor {
|
|
||||||
label: Some(label),
|
|
||||||
size: wgpu::Extent3d {
|
|
||||||
width: size.x,
|
|
||||||
height: size.y,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
},
|
|
||||||
mip_level_count: 1, // TODO
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
|
||||||
view_formats: &[],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_texture(queue: &wgpu::Queue, texture: &wgpu::Texture, img: &lyra_resource::Image) {
|
|
||||||
let dim = img.dimensions();
|
|
||||||
//debug!("Write texture size: {:?}", dim);
|
|
||||||
queue.write_texture(
|
|
||||||
wgpu::ImageCopyTexture {
|
|
||||||
aspect: wgpu::TextureAspect::All,
|
|
||||||
texture: &texture,
|
|
||||||
mip_level: 0,
|
|
||||||
origin: wgpu::Origin3d::ZERO,
|
|
||||||
},
|
|
||||||
&img.to_rgba8(),
|
|
||||||
wgpu::ImageDataLayout {
|
|
||||||
offset: 0,
|
|
||||||
bytes_per_row: std::num::NonZeroU32::new(4 * dim.0),
|
|
||||||
rows_per_image: std::num::NonZeroU32::new(dim.1),
|
|
||||||
},
|
|
||||||
wgpu::Extent3d {
|
|
||||||
width: dim.0,
|
|
||||||
height: dim.1,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_resource(
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
layout: &Arc<wgpu::BindGroupLayout>,
|
|
||||||
mat: &lyra_resource::gltf::Material,
|
|
||||||
) -> Self {
|
|
||||||
//let specular = mat.specular.as_ref().unwrap_or_default();
|
|
||||||
//let specular_
|
|
||||||
|
|
||||||
let prop = MaterialPropertiesUniform {
|
|
||||||
ambient: Vec3::ONE,
|
|
||||||
_padding1: 0,
|
|
||||||
diffuse: Vec3::ONE,
|
|
||||||
shininess: 32.0,
|
|
||||||
specular_factor: 0.0,
|
|
||||||
_padding2: [0; 3],
|
|
||||||
specular_color_factor: Vec3::ZERO,
|
|
||||||
_padding3: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let properties_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("buffer_material"),
|
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
|
||||||
contents: bytemuck::bytes_of(&prop),
|
|
||||||
});
|
|
||||||
|
|
||||||
let diffuse_tex = mat.base_color_texture.as_ref().unwrap();
|
|
||||||
let diffuse_tex = diffuse_tex.data_ref().unwrap();
|
|
||||||
let diffuse_tex_img = diffuse_tex.image.data_ref().unwrap();
|
|
||||||
let diffuse_tex_dim = diffuse_tex_img.dimensions();
|
|
||||||
let diffuse_texture = device.create_texture(&Self::texture_desc(
|
|
||||||
"material_diffuse_texture",
|
|
||||||
UVec2::new(diffuse_tex_dim.0, diffuse_tex_dim.1),
|
|
||||||
));
|
|
||||||
let diffuse_tex_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
let sampler_desc = match &diffuse_tex.sampler {
|
|
||||||
Some(sampler) => {
|
|
||||||
let magf = res_filter_to_wgpu(
|
|
||||||
sampler
|
|
||||||
.mag_filter
|
|
||||||
.unwrap_or(lyra_resource::FilterMode::Linear),
|
|
||||||
);
|
|
||||||
let minf = res_filter_to_wgpu(
|
|
||||||
sampler
|
|
||||||
.min_filter
|
|
||||||
.unwrap_or(lyra_resource::FilterMode::Nearest),
|
|
||||||
);
|
|
||||||
let mipf = res_filter_to_wgpu(
|
|
||||||
sampler
|
|
||||||
.mipmap_filter
|
|
||||||
.unwrap_or(lyra_resource::FilterMode::Nearest),
|
|
||||||
);
|
|
||||||
|
|
||||||
let wrap_u = res_wrap_to_wgpu(sampler.wrap_u);
|
|
||||||
let wrap_v = res_wrap_to_wgpu(sampler.wrap_v);
|
|
||||||
let wrap_w = res_wrap_to_wgpu(sampler.wrap_w);
|
|
||||||
|
|
||||||
wgpu::SamplerDescriptor {
|
|
||||||
address_mode_u: wrap_u,
|
|
||||||
address_mode_v: wrap_v,
|
|
||||||
address_mode_w: wrap_w,
|
|
||||||
mag_filter: magf,
|
|
||||||
min_filter: minf,
|
|
||||||
mipmap_filter: mipf,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => wgpu::SamplerDescriptor {
|
|
||||||
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::Nearest,
|
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let diffuse_sampler = device.create_sampler(&sampler_desc);
|
|
||||||
|
|
||||||
Self::write_texture(queue, &diffuse_texture, &diffuse_tex_img);
|
|
||||||
|
|
||||||
debug!("TODO: specular texture");
|
|
||||||
|
|
||||||
let bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
label: Some("bg_material"),
|
|
||||||
layout: &layout,
|
|
||||||
entries: &[
|
|
||||||
// material properties
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
|
||||||
buffer: &properties_buffer,
|
|
||||||
offset: 0,
|
|
||||||
size: None,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
// diffuse texture
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: wgpu::BindingResource::TextureView(&diffuse_tex_view),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 2,
|
|
||||||
resource: wgpu::BindingResource::Sampler(&diffuse_sampler),
|
|
||||||
},
|
|
||||||
// TODO: specular textures
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
Self {
|
|
||||||
bind_group: Arc::new(bg),
|
|
||||||
bind_group_layout: layout.clone(),
|
|
||||||
material_properties_buffer: properties_buffer,
|
|
||||||
diffuse_texture,
|
|
||||||
diffuse_texture_sampler: diffuse_sampler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Uniform for MaterialProperties in a shader
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
pub struct MaterialPropertiesUniform {
|
|
||||||
ambient: glam::Vec3,
|
|
||||||
_padding1: u32,
|
|
||||||
diffuse: glam::Vec3,
|
|
||||||
shininess: f32,
|
|
||||||
specular_factor: f32,
|
|
||||||
_padding2: [u32; 3],
|
|
||||||
specular_color_factor: glam::Vec3,
|
|
||||||
_padding3: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct RenderMeshes(VecDeque<RenderJob>);
|
|
||||||
|
|
||||||
impl Deref for RenderMeshes {
|
|
||||||
type Target = VecDeque<RenderJob>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for RenderMeshes {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,153 +1,279 @@
|
||||||
use std::{rc::Rc, sync::Arc};
|
use std::{collections::{HashSet, VecDeque}, rc::Rc};
|
||||||
|
|
||||||
use lyra_ecs::{AtomicRef, ResourceData};
|
use glam::Vec3;
|
||||||
|
use itertools::izip;
|
||||||
|
use lyra_ecs::{query::{filter::{Has, Not, Or}, Entities, Res, TickOf}, relation::{ChildOf, RelationOriginComponent}, Component, Entity};
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
use tracing::{instrument, warn};
|
use lyra_math::Transform;
|
||||||
|
use lyra_resource::{gltf::Mesh, ResHandle};
|
||||||
|
use lyra_scene::{SceneGraph, WorldTransform};
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use tracing::{debug, instrument, warn};
|
||||||
|
use uuid::Uuid;
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
use crate::render::{
|
use crate::{
|
||||||
desc_buf_lay::DescVertexBufferLayout,
|
render::{
|
||||||
graph::{Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext},
|
desc_buf_lay::DescVertexBufferLayout, graph::{
|
||||||
resource::{FragmentState, RenderPipeline, RenderPipelineDescriptor, Shader, VertexState},
|
Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext
|
||||||
texture::RenderTexture,
|
}, material::{Material, MaterialUniform}, render_buffer::{BufferStorage, BufferWrapper}, render_job::RenderJob, resource::{FragmentState, RenderPipeline, RenderPipelineDescriptor, Shader, VertexState}, texture::RenderTexture, transform_buffer_storage::{TransformBuffers, TransformGroup}, vertex::Vertex
|
||||||
transform_buffer_storage::TransformBuffers,
|
},
|
||||||
vertex::Vertex,
|
DeltaTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{BasePassSlots, LightBasePassSlots, LightCullComputePassSlots};
|
||||||
BasePassSlots, LightBasePassSlots, LightCullComputePassSlots, MeshBufferStorage, RenderAssets,
|
|
||||||
RenderMeshes,
|
type MeshHandle = ResHandle<Mesh>;
|
||||||
};
|
type SceneHandle = ResHandle<SceneGraph>;
|
||||||
|
|
||||||
#[derive(Debug, Hash, Clone, Default, PartialEq, RenderGraphLabel)]
|
#[derive(Debug, Hash, Clone, Default, PartialEq, RenderGraphLabel)]
|
||||||
pub struct MeshesPassLabel;
|
pub struct MeshesPassLabel;
|
||||||
|
|
||||||
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
|
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
|
||||||
pub enum MeshesPassSlots {
|
pub enum MeshesPassSlots {
|
||||||
Material,
|
Material
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[derive(Default)]
|
struct MeshBufferStorage {
|
||||||
#[allow(dead_code)]
|
buffer_vertex: BufferStorage,
|
||||||
|
buffer_indices: Option<(wgpu::IndexFormat, BufferStorage)>,
|
||||||
|
|
||||||
|
// maybe this should just be a Uuid and the material can be retrieved though
|
||||||
|
// MeshPass's `material_buffers` field?
|
||||||
|
material: Option<Rc<Material>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Component)]
|
||||||
|
struct InterpTransform {
|
||||||
|
last_transform: Transform,
|
||||||
|
alpha: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct MeshPass {
|
pub struct MeshPass {
|
||||||
|
transforms: Option<TransformBuffers>,
|
||||||
|
mesh_buffers: FxHashMap<uuid::Uuid, MeshBufferStorage>,
|
||||||
|
render_jobs: VecDeque<RenderJob>,
|
||||||
|
|
||||||
|
texture_bind_group_layout: Option<Rc<wgpu::BindGroupLayout>>,
|
||||||
|
material_buffer: Option<wgpu::Buffer>,
|
||||||
|
material_buffers: FxHashMap<uuid::Uuid, Rc<Material>>,
|
||||||
|
entity_meshes: FxHashMap<Entity, uuid::Uuid>,
|
||||||
|
|
||||||
default_texture: Option<RenderTexture>,
|
default_texture: Option<RenderTexture>,
|
||||||
|
|
||||||
pipeline: Option<RenderPipeline>,
|
pipeline: Option<RenderPipeline>,
|
||||||
material_bgl: Arc<wgpu::BindGroupLayout>,
|
material_bgl: Option<Rc<wgpu::BindGroupLayout>>,
|
||||||
transform_buffers: Option<ResourceData>,
|
|
||||||
// TODO: find a better way to extract these resources from the main world to be used in the
|
|
||||||
// render stage.
|
|
||||||
render_meshes: Option<ResourceData>,
|
|
||||||
mesh_buffers: Option<ResourceData>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MeshPass {
|
impl MeshPass {
|
||||||
pub fn new(material_bgl: Arc<wgpu::BindGroupLayout>) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self::default()
|
||||||
default_texture: None,
|
}
|
||||||
pipeline: None,
|
|
||||||
material_bgl,
|
/// Checks if the mesh buffers in the GPU need to be updated.
|
||||||
transform_buffers: None,
|
#[instrument(skip(self, device, queue, mesh_han))]
|
||||||
render_meshes: None,
|
fn check_mesh_buffers(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, mesh_han: &ResHandle<Mesh>) {
|
||||||
mesh_buffers: None,
|
let mesh_uuid = mesh_han.uuid();
|
||||||
|
|
||||||
|
if let (Some(mesh), Some(buffers)) = (mesh_han.data_ref(), self.mesh_buffers.get_mut(&mesh_uuid)) {
|
||||||
|
// check if the buffer sizes dont match. If they dont, completely remake the buffers
|
||||||
|
let vertices = mesh.position().unwrap();
|
||||||
|
if buffers.buffer_vertex.count() != vertices.len() {
|
||||||
|
debug!("Recreating buffers for mesh {}", mesh_uuid.to_string());
|
||||||
|
let (vert, idx) = self.create_vertex_index_buffers(device, &mesh);
|
||||||
|
|
||||||
|
// have to re-get buffers because of borrow checker
|
||||||
|
let buffers = self.mesh_buffers.get_mut(&mesh_uuid).unwrap();
|
||||||
|
buffers.buffer_indices = idx;
|
||||||
|
buffers.buffer_vertex = vert;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update vertices
|
||||||
|
let vertex_buffer = buffers.buffer_vertex.buffer();
|
||||||
|
let vertices = vertices.as_slice();
|
||||||
|
// align the vertices to 4 bytes (u32 is 4 bytes, which is wgpu::COPY_BUFFER_ALIGNMENT)
|
||||||
|
let (_, vertices, _) = bytemuck::pod_align_to::<Vec3, u32>(vertices);
|
||||||
|
queue.write_buffer(vertex_buffer, 0, bytemuck::cast_slice(vertices));
|
||||||
|
|
||||||
|
// update the indices if they're given
|
||||||
|
if let Some(index_buffer) = buffers.buffer_indices.as_ref() {
|
||||||
|
let aligned_indices = match mesh.indices.as_ref().unwrap() {
|
||||||
|
// U16 indices need to be aligned to u32, for wpgu, which are 4-bytes in size.
|
||||||
|
lyra_resource::gltf::MeshIndices::U16(v) => bytemuck::pod_align_to::<u16, u32>(v).1,
|
||||||
|
lyra_resource::gltf::MeshIndices::U32(v) => bytemuck::pod_align_to::<u32, u32>(v).1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let index_buffer = index_buffer.1.buffer();
|
||||||
|
queue.write_buffer(index_buffer, 0, bytemuck::cast_slice(aligned_indices));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_buffers(&self) -> AtomicRef<TransformBuffers> {
|
#[instrument(skip(self, device, mesh))]
|
||||||
self.transform_buffers
|
fn create_vertex_index_buffers(&mut self, device: &wgpu::Device, mesh: &Mesh) -> (BufferStorage, Option<(wgpu::IndexFormat, BufferStorage)>) {
|
||||||
.as_ref()
|
let positions = mesh.position().unwrap();
|
||||||
.unwrap()
|
let tex_coords: Vec<glam::Vec2> = mesh.tex_coords().cloned()
|
||||||
.get()
|
.unwrap_or_else(|| vec![glam::Vec2::new(0.0, 0.0); positions.len()]);
|
||||||
|
let normals = mesh.normals().unwrap();
|
||||||
|
|
||||||
|
assert!(positions.len() == tex_coords.len() && positions.len() == normals.len());
|
||||||
|
|
||||||
|
let mut vertex_inputs = vec![];
|
||||||
|
for (v, t, n) in izip!(positions.iter(), tex_coords.iter(), normals.iter()) {
|
||||||
|
vertex_inputs.push(Vertex::new(*v, *t, *n));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_meshes(&self) -> AtomicRef<RenderMeshes> {
|
let vertex_buffer = device.create_buffer_init(
|
||||||
self.render_meshes
|
&wgpu::util::BufferInitDescriptor {
|
||||||
.as_ref()
|
label: Some("Vertex Buffer"),
|
||||||
.unwrap()
|
contents: bytemuck::cast_slice(vertex_inputs.as_slice()),//vertex_combined.as_slice(),
|
||||||
.get()
|
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages:: COPY_DST,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let vertex_buffer = BufferStorage::new(vertex_buffer, 0, vertex_inputs.len());
|
||||||
|
|
||||||
|
let indices = match mesh.indices.as_ref() {
|
||||||
|
Some(indices) => {
|
||||||
|
let (idx_type, len, contents) = match indices {
|
||||||
|
lyra_resource::gltf::MeshIndices::U16(v) => (wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v)),
|
||||||
|
lyra_resource::gltf::MeshIndices::U32(v) => (wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let index_buffer = device.create_buffer_init(
|
||||||
|
&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Index Buffer"),
|
||||||
|
contents,
|
||||||
|
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages:: COPY_DST,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let buffer_indices = BufferStorage::new(index_buffer, 0, len);
|
||||||
|
|
||||||
|
Some((idx_type, buffer_indices))
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
( vertex_buffer, indices )
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mesh_buffers(&self) -> AtomicRef<RenderAssets<MeshBufferStorage>> {
|
#[instrument(skip(self, device, queue, mesh))]
|
||||||
self.mesh_buffers
|
fn create_mesh_buffers(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, mesh: &Mesh) -> MeshBufferStorage {
|
||||||
.as_ref()
|
let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(device, mesh);
|
||||||
.unwrap()
|
|
||||||
.get()
|
let material = mesh.material.as_ref()
|
||||||
|
.expect("Material resource not loaded yet");
|
||||||
|
let material_ref = material.data_ref()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let material = self.material_buffers.entry(material.uuid())
|
||||||
|
.or_insert_with(|| {
|
||||||
|
debug!(uuid=material.uuid().to_string(), "Sending material to gpu");
|
||||||
|
Rc::new(Material::from_resource(device, queue, self.texture_bind_group_layout.clone().unwrap(), &material_ref))
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: support material uniforms from multiple uniforms
|
||||||
|
let uni = MaterialUniform::from(&**material);
|
||||||
|
queue.write_buffer(self.material_buffer.as_ref().unwrap(), 0, bytemuck::bytes_of(&uni));
|
||||||
|
|
||||||
|
MeshBufferStorage {
|
||||||
|
buffer_vertex: vertex_buffer,
|
||||||
|
buffer_indices,
|
||||||
|
material: Some(material.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed.
|
||||||
|
#[instrument(skip(self, device, queue, mesh, entity))]
|
||||||
|
fn process_mesh(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, entity: Entity, mesh: &Mesh, mesh_uuid: Uuid) -> bool {
|
||||||
|
#[allow(clippy::map_entry)]
|
||||||
|
if !self.mesh_buffers.contains_key(&mesh_uuid) {
|
||||||
|
// create the mesh's buffers
|
||||||
|
let buffers = self.create_mesh_buffers(device, queue, mesh);
|
||||||
|
self.mesh_buffers.insert(mesh_uuid, buffers);
|
||||||
|
self.entity_meshes.insert(entity, mesh_uuid);
|
||||||
|
|
||||||
|
true
|
||||||
|
} else { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for MeshPass {
|
impl Node for MeshPass {
|
||||||
fn desc(
|
fn desc(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut crate::render::graph::RenderGraph,
|
graph: &mut crate::render::graph::RenderGraph,
|
||||||
) -> crate::render::graph::NodeDesc {
|
) -> crate::render::graph::NodeDesc {
|
||||||
// load the default texture
|
|
||||||
//let bytes = include_bytes!("../../default_texture.png");
|
|
||||||
//self.default_texture = Some(RenderTexture::from_bytes(device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap());
|
|
||||||
|
|
||||||
NodeDesc::new(
|
|
||||||
NodeType::Render,
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
//(&MeshesPassSlots::Material, material_bg, Some(material_bgl)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, graph, world))]
|
|
||||||
fn prepare(
|
|
||||||
&mut self,
|
|
||||||
graph: &mut RenderGraph,
|
|
||||||
world: &mut lyra_ecs::World,
|
|
||||||
_: &mut RenderGraphContext,
|
|
||||||
) {
|
|
||||||
if self.pipeline.is_none() {
|
|
||||||
let device = graph.device();
|
let device = graph.device();
|
||||||
let surface_config_format = graph.view_target().format();
|
|
||||||
|
|
||||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
let transforms = TransformBuffers::new(device);
|
||||||
|
//let transform_bgl = transforms.bindgroup_layout.clone();
|
||||||
|
self.transforms = Some(transforms);
|
||||||
|
|
||||||
|
let texture_bind_group_layout = Rc::new(RenderTexture::create_layout(device));
|
||||||
|
self.texture_bind_group_layout = Some(texture_bind_group_layout.clone());
|
||||||
|
|
||||||
|
let (material_bgl, material_bg, material_buf, _) = BufferWrapper::builder()
|
||||||
|
.label_prefix("material")
|
||||||
|
.visibility(wgpu::ShaderStages::FRAGMENT)
|
||||||
|
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
|
||||||
|
.contents(&[MaterialUniform::default()])
|
||||||
|
.finish_parts(device);
|
||||||
|
let material_bgl = Rc::new(material_bgl);
|
||||||
|
self.material_bgl = Some(material_bgl.clone());
|
||||||
|
let material_bg = Rc::new(material_bg);
|
||||||
|
|
||||||
|
self.material_buffer = Some(material_buf);
|
||||||
|
|
||||||
|
// load the default texture
|
||||||
|
let bytes = include_bytes!("../../default_texture.png");
|
||||||
|
self.default_texture = Some(RenderTexture::from_bytes(device, &graph.queue, texture_bind_group_layout.clone(), bytes, "default_texture").unwrap());
|
||||||
|
|
||||||
|
// get surface config format
|
||||||
|
/* let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
|
||||||
|
.and_then(|s| s.as_render_target())
|
||||||
|
.expect("missing main render target");
|
||||||
|
let surface_config_format = main_rt.format();
|
||||||
|
drop(main_rt); */
|
||||||
|
|
||||||
|
/* let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||||
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||||
let light_grid_bgl =
|
let light_grid_bgl = graph
|
||||||
graph.bind_group_layout(LightCullComputePassSlots::LightIndicesGridGroup);
|
.bind_group_layout(LightCullComputePassSlots::LightIndicesGridGroup);
|
||||||
|
|
||||||
let shader = Rc::new(Shader {
|
let shader = Rc::new(Shader {
|
||||||
label: Some("base_shader".into()),
|
label: Some("base_shader".into()),
|
||||||
source: include_str!("../../shaders/base.wgsl").to_string(),
|
source: include_str!("../../shaders/base.wgsl").to_string(),
|
||||||
});
|
}); */
|
||||||
|
|
||||||
|
|
||||||
let transforms = world
|
|
||||||
.try_get_resource_data::<TransformBuffers>()
|
|
||||||
.expect("Missing transform buffers");
|
|
||||||
self.transform_buffers = Some(transforms.clone());
|
|
||||||
|
|
||||||
let render_meshes = world
|
NodeDesc::new(
|
||||||
.try_get_resource_data::<RenderMeshes>()
|
NodeType::Render,
|
||||||
.expect("Missing transform buffers");
|
None,
|
||||||
self.render_meshes = Some(render_meshes.clone());
|
/* Some(PipelineDescriptor::Render(RenderPipelineDescriptor {
|
||||||
|
|
||||||
let mesh_buffers = world
|
|
||||||
.try_get_resource_data::<RenderAssets<MeshBufferStorage>>()
|
|
||||||
.expect("Missing render meshes");
|
|
||||||
self.mesh_buffers = Some(mesh_buffers.clone());
|
|
||||||
|
|
||||||
|
|
||||||
let transforms = transforms.get::<TransformBuffers>();
|
|
||||||
|
|
||||||
self.pipeline = Some(RenderPipeline::create(
|
|
||||||
device,
|
|
||||||
&RenderPipelineDescriptor {
|
|
||||||
label: Some("meshes".into()),
|
label: Some("meshes".into()),
|
||||||
layouts: vec![
|
layouts: vec![
|
||||||
self.material_bgl.clone(),
|
texture_bind_group_layout.clone(),
|
||||||
transforms.bindgroup_layout.clone(),
|
transform_bgl,
|
||||||
camera_bgl.clone(),
|
camera_bgl.clone(),
|
||||||
lights_bgl.clone(),
|
lights_bgl.clone(),
|
||||||
|
material_bgl.clone(),
|
||||||
|
texture_bind_group_layout,
|
||||||
light_grid_bgl.clone(),
|
light_grid_bgl.clone(),
|
||||||
],
|
],
|
||||||
push_constant_ranges: vec![],
|
push_constant_ranges: vec![],
|
||||||
vertex: VertexState {
|
vertex: VertexState {
|
||||||
module: shader.clone(),
|
module: shader.clone(),
|
||||||
entry_point: "vs_main".into(),
|
entry_point: "vs_main".into(),
|
||||||
buffers: vec![Vertex::desc().into()],
|
buffers: vec![
|
||||||
|
Vertex::desc().into(),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
fragment: Some(FragmentState {
|
fragment: Some(FragmentState {
|
||||||
module: shader,
|
module: shader,
|
||||||
|
@ -168,8 +294,204 @@ impl Node for MeshPass {
|
||||||
primitive: wgpu::PrimitiveState::default(),
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
multiview: None,
|
multiview: None,
|
||||||
|
})), */
|
||||||
|
vec![
|
||||||
|
(&MeshesPassSlots::Material, material_bg, Some(material_bgl)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, graph, world, context))]
|
||||||
|
fn prepare(&mut self, graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
|
||||||
|
let device = &context.device;
|
||||||
|
let queue = &context.queue;
|
||||||
|
let render_limits = device.limits();
|
||||||
|
|
||||||
|
let last_epoch = world.current_tick();
|
||||||
|
let mut alive_entities = HashSet::new();
|
||||||
|
|
||||||
|
let view = world.view_iter::<(
|
||||||
|
Entities,
|
||||||
|
&Transform,
|
||||||
|
TickOf<Transform>,
|
||||||
|
Or<
|
||||||
|
(&MeshHandle, TickOf<MeshHandle>),
|
||||||
|
(&SceneHandle, TickOf<SceneHandle>)
|
||||||
|
>,
|
||||||
|
Option<&mut InterpTransform>,
|
||||||
|
Res<DeltaTime>,
|
||||||
|
)>();
|
||||||
|
|
||||||
|
// used to store InterpTransform components to add to entities later
|
||||||
|
let mut component_queue: Vec<(Entity, InterpTransform)> = vec![];
|
||||||
|
|
||||||
|
for (
|
||||||
|
entity,
|
||||||
|
transform,
|
||||||
|
_transform_epoch,
|
||||||
|
(
|
||||||
|
mesh_pair,
|
||||||
|
scene_pair
|
||||||
|
),
|
||||||
|
interp_tran,
|
||||||
|
delta_time,
|
||||||
|
) in view
|
||||||
|
{
|
||||||
|
alive_entities.insert(entity);
|
||||||
|
|
||||||
|
// Interpolate the transform for this entity using a component.
|
||||||
|
// If the entity does not have the component then it will be queued to be added
|
||||||
|
// to it after all the entities are prepared for rendering.
|
||||||
|
let interp_transform = match interp_tran {
|
||||||
|
Some(mut interp_transform) => {
|
||||||
|
// found in https://youtu.be/YJB1QnEmlTs?t=472
|
||||||
|
interp_transform.alpha = 1.0 - interp_transform.alpha.powf(**delta_time);
|
||||||
|
|
||||||
|
interp_transform.last_transform = interp_transform.last_transform.lerp(*transform, interp_transform.alpha);
|
||||||
|
interp_transform.last_transform
|
||||||
},
|
},
|
||||||
));
|
None => {
|
||||||
|
let interp = InterpTransform {
|
||||||
|
last_transform: *transform,
|
||||||
|
alpha: 0.5,
|
||||||
|
};
|
||||||
|
component_queue.push((entity, interp));
|
||||||
|
|
||||||
|
*transform
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
// expand the transform buffers if they need to be.
|
||||||
|
// this is done in its own scope to avoid multiple mutable references to self at
|
||||||
|
// once; aka, make the borrow checker happy
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
|
if transforms.needs_expand() {
|
||||||
|
debug!("Expanding transform buffers");
|
||||||
|
transforms.expand_buffers(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((mesh_han, mesh_epoch)) = mesh_pair {
|
||||||
|
if let Some(mesh) = mesh_han.data_ref() {
|
||||||
|
// if process mesh did not just create a new mesh, and the epoch
|
||||||
|
// shows that the scene has changed, verify that the mesh buffers
|
||||||
|
// dont need to be resent to the gpu.
|
||||||
|
if !self.process_mesh(device, queue, entity, &mesh, mesh_han.uuid())
|
||||||
|
&& mesh_epoch == last_epoch {
|
||||||
|
self.check_mesh_buffers(device, queue, &mesh_han);
|
||||||
|
}
|
||||||
|
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
|
let group = TransformGroup::EntityRes(entity, mesh_han.uuid());
|
||||||
|
let transform_id = transforms.update_or_push(device, queue, &render_limits,
|
||||||
|
group, interp_transform.calculate_mat4(), glam::Mat3::from_quat(interp_transform.rotation));
|
||||||
|
|
||||||
|
let material = mesh.material.as_ref().unwrap()
|
||||||
|
.data_ref().unwrap();
|
||||||
|
let shader = material.shader_uuid.unwrap_or(0);
|
||||||
|
let job = RenderJob::new(entity, shader, mesh_han.uuid(), transform_id);
|
||||||
|
self.render_jobs.push_back(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((scene_han, scene_epoch)) = scene_pair {
|
||||||
|
if let Some(scene) = scene_han.data_ref() {
|
||||||
|
if scene_epoch == last_epoch {
|
||||||
|
let view = scene.world().view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
||||||
|
lyra_scene::system_update_world_transforms(scene.world(), view).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mesh_han, pos) in scene.world().view_iter::<(&MeshHandle, &WorldTransform)>() {
|
||||||
|
if let Some(mesh) = mesh_han.data_ref() {
|
||||||
|
let mesh_interpo = interp_transform + **pos;
|
||||||
|
|
||||||
|
// if process mesh did not just create a new mesh, and the epoch
|
||||||
|
// shows that the scene has changed, verify that the mesh buffers
|
||||||
|
// dont need to be resent to the gpu.
|
||||||
|
if !self.process_mesh(device, queue, entity, &mesh, mesh_han.uuid())
|
||||||
|
&& scene_epoch == last_epoch {
|
||||||
|
self.check_mesh_buffers(device, queue, &mesh_han);
|
||||||
|
}
|
||||||
|
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
|
let scene_mesh_group = TransformGroup::Res(scene_han.uuid(), mesh_han.uuid());
|
||||||
|
let group = TransformGroup::OwnedGroup(entity, scene_mesh_group.into());
|
||||||
|
let transform_id = transforms.update_or_push(device, queue, &render_limits,
|
||||||
|
group, mesh_interpo.calculate_mat4(), glam::Mat3::from_quat(mesh_interpo.rotation) );
|
||||||
|
|
||||||
|
let material = mesh.material.as_ref().unwrap()
|
||||||
|
.data_ref().unwrap();
|
||||||
|
let shader = material.shader_uuid.unwrap_or(0);
|
||||||
|
let job = RenderJob::new(entity, shader, mesh_han.uuid(), transform_id);
|
||||||
|
self.render_jobs.push_back(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (en, interp) in component_queue {
|
||||||
|
world.insert(en, interp);
|
||||||
|
}
|
||||||
|
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
|
transforms.send_to_gpu(queue);
|
||||||
|
|
||||||
|
if self.pipeline.is_none() {
|
||||||
|
let device = graph.device();
|
||||||
|
let surface_config_format = graph.view_target().format();
|
||||||
|
|
||||||
|
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||||
|
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||||
|
let light_grid_bgl = graph
|
||||||
|
.bind_group_layout(LightCullComputePassSlots::LightIndicesGridGroup);
|
||||||
|
|
||||||
|
let shader = Rc::new(Shader {
|
||||||
|
label: Some("base_shader".into()),
|
||||||
|
source: include_str!("../../shaders/base.wgsl").to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.pipeline = Some(RenderPipeline::create(device, &RenderPipelineDescriptor {
|
||||||
|
label: Some("meshes".into()),
|
||||||
|
layouts: vec![
|
||||||
|
self.texture_bind_group_layout.as_ref().unwrap().clone(),
|
||||||
|
//transform_bgl
|
||||||
|
self.transforms.as_ref().unwrap().bindgroup_layout.clone(),
|
||||||
|
camera_bgl.clone(),
|
||||||
|
lights_bgl.clone(),
|
||||||
|
self.material_bgl.as_ref().unwrap().clone(),
|
||||||
|
self.texture_bind_group_layout.as_ref().unwrap().clone(),
|
||||||
|
light_grid_bgl.clone(),
|
||||||
|
],
|
||||||
|
push_constant_ranges: vec![],
|
||||||
|
vertex: VertexState {
|
||||||
|
module: shader.clone(),
|
||||||
|
entry_point: "vs_main".into(),
|
||||||
|
buffers: vec![
|
||||||
|
Vertex::desc().into(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fragment: Some(FragmentState {
|
||||||
|
module: shader,
|
||||||
|
entry_point: "fs_main".into(),
|
||||||
|
targets: vec![Some(wgpu::ColorTargetState {
|
||||||
|
format: surface_config_format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
|
format: RenderTexture::DEPTH_FORMAT,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Less,
|
||||||
|
stencil: wgpu::StencilState::default(), // TODO: stencil buffer
|
||||||
|
bias: wgpu::DepthBiasState::default(),
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,23 +518,22 @@ impl Node for MeshPass {
|
||||||
.as_texture_view()
|
.as_texture_view()
|
||||||
.expect("BasePassSlots::DepthTextureView was not a TextureView slot");
|
.expect("BasePassSlots::DepthTextureView was not a TextureView slot");
|
||||||
|
|
||||||
let camera_bg = graph.bind_group(BasePassSlots::Camera);
|
let camera_bg = graph
|
||||||
|
.bind_group(BasePassSlots::Camera);
|
||||||
|
|
||||||
let lights_bg = graph.bind_group(LightBasePassSlots::Lights);
|
let lights_bg = graph
|
||||||
|
.bind_group(LightBasePassSlots::Lights);
|
||||||
|
|
||||||
let light_grid_bg = graph.bind_group(LightCullComputePassSlots::LightIndicesGridGroup);
|
let light_grid_bg = graph
|
||||||
|
.bind_group(LightCullComputePassSlots::LightIndicesGridGroup);
|
||||||
|
|
||||||
//let material_bg = graph.bind_group(MeshesPassSlots::Material);
|
let material_bg = graph
|
||||||
|
.bind_group(MeshesPassSlots::Material);
|
||||||
|
|
||||||
/* let pipeline = graph.pipeline(context.label.clone())
|
/* let pipeline = graph.pipeline(context.label.clone())
|
||||||
.expect("Failed to find pipeline for MeshPass"); */
|
.expect("Failed to find pipeline for MeshPass"); */
|
||||||
let pipeline = self.pipeline.as_ref().unwrap();
|
let pipeline = self.pipeline.as_ref().unwrap();
|
||||||
|
|
||||||
let transforms = self.transform_buffers();
|
|
||||||
let render_meshes = self.render_meshes();
|
|
||||||
let mesh_buffers = self.mesh_buffers();
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("Render Pass"),
|
label: Some("Render Pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
@ -241,11 +562,13 @@ impl Node for MeshPass {
|
||||||
|
|
||||||
pass.set_pipeline(pipeline);
|
pass.set_pipeline(pipeline);
|
||||||
|
|
||||||
//let default_texture = self.default_texture.as_ref().unwrap();
|
//let material_buffer_bg = self.material_buffer.as_ref().unwrap().bindgroup();
|
||||||
|
let default_texture = self.default_texture.as_ref().unwrap();
|
||||||
|
let transforms = self.transforms.as_mut().unwrap();
|
||||||
|
|
||||||
for job in render_meshes.iter() {
|
while let Some(job) = self.render_jobs.pop_front() {
|
||||||
// get the mesh (containing vertices) and the buffers from storage
|
// get the mesh (containing vertices) and the buffers from storage
|
||||||
let buffers = mesh_buffers.get(&job.mesh_uuid);
|
let buffers = self.mesh_buffers.get(&job.mesh_uuid);
|
||||||
if buffers.is_none() {
|
if buffers.is_none() {
|
||||||
warn!("Skipping job since its mesh is missing {:?}", job.mesh_uuid);
|
warn!("Skipping job since its mesh is missing {:?}", job.mesh_uuid);
|
||||||
continue;
|
continue;
|
||||||
|
@ -253,7 +576,7 @@ impl Node for MeshPass {
|
||||||
let buffers = buffers.unwrap();
|
let buffers = buffers.unwrap();
|
||||||
|
|
||||||
// Bind the optional texture
|
// Bind the optional texture
|
||||||
/* if let Some(tex) = buffers.material.as_ref()
|
if let Some(tex) = buffers.material.as_ref()
|
||||||
.and_then(|m| m.diffuse_texture.as_ref()) {
|
.and_then(|m| m.diffuse_texture.as_ref()) {
|
||||||
pass.set_bind_group(0, tex.bind_group(), &[]);
|
pass.set_bind_group(0, tex.bind_group(), &[]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -266,44 +589,32 @@ impl Node for MeshPass {
|
||||||
pass.set_bind_group(5, tex.bind_group(), &[]);
|
pass.set_bind_group(5, tex.bind_group(), &[]);
|
||||||
} else {
|
} else {
|
||||||
pass.set_bind_group(5, default_texture.bind_group(), &[]);
|
pass.set_bind_group(5, default_texture.bind_group(), &[]);
|
||||||
} */
|
|
||||||
if let Some(mat) = buffers.material.as_ref() {
|
|
||||||
pass.set_bind_group(0, &mat.bind_group, &[]);
|
|
||||||
} else {
|
|
||||||
todo!("cannot render mesh without material");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 bindgroup = transforms.bind_group(job.transform_id);
|
let bindgroup = transforms.bind_group(job.transform_id);
|
||||||
let offset = transforms.buffer_offset(job.transform_id);
|
let offset = transforms.buffer_offset(job.transform_id);
|
||||||
pass.set_bind_group(1, bindgroup, &[offset]);
|
pass.set_bind_group(1, bindgroup, &[ offset, ]);
|
||||||
|
|
||||||
pass.set_bind_group(2, camera_bg, &[]);
|
pass.set_bind_group(2, camera_bg, &[]);
|
||||||
pass.set_bind_group(3, lights_bg, &[]);
|
pass.set_bind_group(3, lights_bg, &[]);
|
||||||
//pass.set_bind_group(4, material_bg, &[]);
|
pass.set_bind_group(4, material_bg, &[]);
|
||||||
|
|
||||||
pass.set_bind_group(4, light_grid_bg, &[]);
|
pass.set_bind_group(6, light_grid_bg, &[]);
|
||||||
|
|
||||||
// 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() {
|
||||||
let indices_len = indices.count() as u32;
|
let indices_len = indices.count() as u32;
|
||||||
|
|
||||||
pass.set_vertex_buffer(
|
pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
|
||||||
buffers.buffer_vertex.slot(),
|
|
||||||
buffers.buffer_vertex.buffer().slice(..),
|
|
||||||
);
|
|
||||||
pass.set_index_buffer(indices.buffer().slice(..), *idx_type);
|
pass.set_index_buffer(indices.buffer().slice(..), *idx_type);
|
||||||
pass.draw_indexed(0..indices_len, 0, 0..1);
|
pass.draw_indexed(0..indices_len, 0, 0..1);
|
||||||
} else {
|
} else {
|
||||||
let vertex_count = buffers.buffer_vertex.count();
|
let vertex_count = buffers.buffer_vertex.count();
|
||||||
|
|
||||||
pass.set_vertex_buffer(
|
pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
|
||||||
buffers.buffer_vertex.slot(),
|
|
||||||
buffers.buffer_vertex.buffer().slice(..),
|
|
||||||
);
|
|
||||||
pass.draw(0..vertex_count as u32, 0..1);
|
pass.draw(0..vertex_count as u32, 0..1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,3 @@ pub use tint::*;
|
||||||
|
|
||||||
mod fxaa;
|
mod fxaa;
|
||||||
pub use fxaa::*;
|
pub use fxaa::*;
|
||||||
|
|
||||||
/* mod shadow_maps;
|
|
||||||
pub use shadow_maps::*; */
|
|
||||||
|
|
||||||
mod mesh_prepare;
|
|
||||||
pub use mesh_prepare::*;
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ pub struct TintPassLabel;
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TintPass {
|
pub struct TintPass {
|
||||||
target_sampler: Option<wgpu::Sampler>,
|
target_sampler: Option<wgpu::Sampler>,
|
||||||
bgl: Option<Arc<wgpu::BindGroupLayout>>,
|
bgl: Option<Rc<wgpu::BindGroupLayout>>,
|
||||||
/// Store bind groups for the input textures.
|
/// Store bind groups for the input textures.
|
||||||
/// The texture may change due to resizes, or changes to the view target chain
|
/// The texture may change due to resizes, or changes to the view target chain
|
||||||
/// from other nodes.
|
/// from other nodes.
|
||||||
|
@ -54,7 +54,7 @@ impl Node for TintPass {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
let bgl = Arc::new(bgl);
|
let bgl = Rc::new(bgl);
|
||||||
self.bgl = Some(bgl.clone());
|
self.bgl = Some(bgl.clone());
|
||||||
self.target_sampler = Some(device.create_sampler(&wgpu::SamplerDescriptor::default()));
|
self.target_sampler = Some(device.create_sampler(&wgpu::SamplerDescriptor::default()));
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lyra_ecs::{Entity, Tick, World};
|
||||||
pub use point::*;
|
pub use point::*;
|
||||||
pub use spotlight::*;
|
pub use spotlight::*;
|
||||||
|
|
||||||
use std::{collections::{HashMap, VecDeque}, marker::PhantomData, mem, sync::Arc};
|
use std::{collections::{HashMap, VecDeque}, marker::PhantomData, mem, rc::Rc};
|
||||||
|
|
||||||
use crate::math::Transform;
|
use crate::math::Transform;
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ impl<U: Default + bytemuck::Pod + bytemuck::Zeroable> LightBuffer<U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct LightUniformBuffers {
|
pub(crate) struct LightUniformBuffers {
|
||||||
pub buffer: Arc<wgpu::Buffer>,
|
pub buffer: Rc<wgpu::Buffer>,
|
||||||
pub bind_group: Arc<wgpu::BindGroup>,
|
pub bind_group: Rc<wgpu::BindGroup>,
|
||||||
pub bind_group_layout: Arc<wgpu::BindGroupLayout>,
|
pub bind_group_layout: Rc<wgpu::BindGroupLayout>,
|
||||||
max_light_count: u64,
|
max_light_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,9 +155,9 @@ impl LightUniformBuffers {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
buffer: Arc::new(buffer),
|
buffer: Rc::new(buffer),
|
||||||
bind_group: Arc::new(bindgroup),
|
bind_group: Rc::new(bindgroup),
|
||||||
bind_group_layout: Arc::new(bindgroup_layout),
|
bind_group_layout: Rc::new(bindgroup_layout),
|
||||||
max_light_count: max_buffer_sizes / mem::size_of::<LightUniform>() as u64,
|
max_light_count: max_buffer_sizes / mem::size_of::<LightUniform>() as u64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use lyra_resource::{ResHandle, Texture};
|
use lyra_resource::{ResHandle, Texture};
|
||||||
|
|
||||||
use super::texture::RenderTexture;
|
use super::texture::RenderTexture;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct MaterialSpecular {
|
pub struct MaterialSpecular {
|
||||||
pub factor: f32,
|
pub factor: f32,
|
||||||
pub color_factor: glam::Vec3,
|
pub color_factor: glam::Vec3,
|
||||||
|
@ -12,7 +11,7 @@ pub struct MaterialSpecular {
|
||||||
pub color_texture: Option<RenderTexture>,
|
pub color_texture: Option<RenderTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn texture_to_render(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: &Arc<wgpu::BindGroupLayout>, i: &Option<ResHandle<Texture>>) -> Option<RenderTexture> {
|
fn texture_to_render(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: &Rc<wgpu::BindGroupLayout>, i: &Option<ResHandle<Texture>>) -> Option<RenderTexture> {
|
||||||
if let Some(tex) = i {
|
if let Some(tex) = i {
|
||||||
RenderTexture::from_resource(device, queue, bg_layout.clone(), tex, None).ok()
|
RenderTexture::from_resource(device, queue, bg_layout.clone(), tex, None).ok()
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,7 +20,7 @@ fn texture_to_render(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: &Arc
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialSpecular {
|
impl MaterialSpecular {
|
||||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Specular) -> Self {
|
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Rc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Specular) -> Self {
|
||||||
let tex = texture_to_render(device, queue, &bg_layout, &value.texture);
|
let tex = texture_to_render(device, queue, &bg_layout, &value.texture);
|
||||||
let color_tex = texture_to_render(device, queue, &bg_layout, &value.color_texture);
|
let color_tex = texture_to_render(device, queue, &bg_layout, &value.color_texture);
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ pub struct Material {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material {
|
impl Material {
|
||||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Material) -> Self {
|
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Rc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Material) -> Self {
|
||||||
let diffuse_texture = texture_to_render(device, queue, &bg_layout, &value.base_color_texture);
|
let diffuse_texture = texture_to_render(device, queue, &bg_layout, &value.base_color_texture);
|
||||||
|
|
||||||
let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), s));
|
let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), s));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{num::NonZeroU32, sync::Arc};
|
use std::{num::NonZeroU32, rc::Rc};
|
||||||
|
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
@ -23,11 +23,11 @@ impl RenderBuffer {
|
||||||
|
|
||||||
pub struct BindGroupPair {
|
pub struct BindGroupPair {
|
||||||
pub bindgroup: wgpu::BindGroup,
|
pub bindgroup: wgpu::BindGroup,
|
||||||
pub layout: Arc<wgpu::BindGroupLayout>,
|
pub layout: Rc<wgpu::BindGroupLayout>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindGroupPair {
|
impl BindGroupPair {
|
||||||
pub fn create_bind_group(device: &wgpu::Device, layout: Arc<wgpu::BindGroupLayout>, entries: &[wgpu::BindGroupEntry<'_>]) -> Self {
|
pub fn create_bind_group(device: &wgpu::Device, layout: Rc<wgpu::BindGroupLayout>, entries: &[wgpu::BindGroupEntry<'_>]) -> Self {
|
||||||
let bindgroup = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bindgroup = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
layout: &layout,
|
layout: &layout,
|
||||||
entries,
|
entries,
|
||||||
|
@ -43,7 +43,7 @@ impl BindGroupPair {
|
||||||
pub fn new(bindgroup: wgpu::BindGroup, layout: wgpu::BindGroupLayout) -> Self {
|
pub fn new(bindgroup: wgpu::BindGroup, layout: wgpu::BindGroupLayout) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bindgroup,
|
bindgroup,
|
||||||
layout: Arc::new(layout),
|
layout: Rc::new(layout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ impl BufferWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the bind group layout, the bind group, and the buffer out of the wrapper.
|
/// Take the bind group layout, the bind group, and the buffer out of the wrapper.
|
||||||
pub fn parts(self) -> (Option<Arc<wgpu::BindGroupLayout>>, Option<wgpu::BindGroup>, wgpu::Buffer) {
|
pub fn parts(self) -> (Option<Rc<wgpu::BindGroupLayout>>, Option<wgpu::BindGroup>, wgpu::Buffer) {
|
||||||
if let Some(pair) = self.bindgroup_pair {
|
if let Some(pair) = self.bindgroup_pair {
|
||||||
(Some(pair.layout), Some(pair.bindgroup), self.inner_buf)
|
(Some(pair.layout), Some(pair.bindgroup), self.inner_buf)
|
||||||
} else {
|
} else {
|
||||||
|
@ -297,7 +297,7 @@ impl BufferWrapperBuilder {
|
||||||
|
|
||||||
BindGroupPair {
|
BindGroupPair {
|
||||||
bindgroup: bg,
|
bindgroup: bg,
|
||||||
layout: Arc::new(bg_layout),
|
layout: Rc::new(bg_layout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -308,7 +308,7 @@ impl BufferWrapperBuilder {
|
||||||
len: Some(self.count.unwrap_or_default() as usize),
|
len: Some(self.count.unwrap_or_default() as usize),
|
||||||
} */
|
} */
|
||||||
|
|
||||||
(Arc::try_unwrap(bg_pair.layout).unwrap(), bg_pair.bindgroup, buffer, self.count.unwrap_or_default() as usize)
|
(Rc::try_unwrap(bg_pair.layout).unwrap(), bg_pair.bindgroup, buffer, self.count.unwrap_or_default() as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(self, device: &wgpu::Device) -> BufferWrapper {
|
pub fn finish(self, device: &wgpu::Device) -> BufferWrapper {
|
||||||
|
@ -316,7 +316,7 @@ impl BufferWrapperBuilder {
|
||||||
|
|
||||||
BufferWrapper {
|
BufferWrapper {
|
||||||
bindgroup_pair: Some(BindGroupPair {
|
bindgroup_pair: Some(BindGroupPair {
|
||||||
layout: Arc::new(bgl),
|
layout: Rc::new(bgl),
|
||||||
bindgroup: bg
|
bindgroup: bg
|
||||||
}),
|
}),
|
||||||
inner_buf: buff,
|
inner_buf: buff,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use lyra_game_derive::RenderGraphLabel;
|
||||||
use tracing::{debug, instrument, warn};
|
use tracing::{debug, instrument, warn};
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, FxaaPass, FxaaPassLabel, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshPrepNode, MeshPrepNodeLabel, MeshesPassLabel, PresentPass, PresentPassLabel, RenderGraphLabelValue, RenderTarget, SubGraphNode, ViewTarget};
|
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, FxaaPass, FxaaPassLabel, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel, RenderGraphLabelValue, RenderTarget, SubGraphNode, ViewTarget};
|
||||||
|
|
||||||
use super::graph::RenderGraph;
|
use super::graph::RenderGraph;
|
||||||
use super::{resource::RenderPipeline, render_job::RenderJob};
|
use super::{resource::RenderPipeline, render_job::RenderJob};
|
||||||
|
@ -147,13 +147,9 @@ impl BasicRenderer {
|
||||||
forward_plus_graph.add_node(LightCullComputePassLabel, LightCullComputePass::new(size));
|
forward_plus_graph.add_node(LightCullComputePassLabel, LightCullComputePass::new(size));
|
||||||
|
|
||||||
debug!("Adding mesh pass");
|
debug!("Adding mesh pass");
|
||||||
let mesh_prep = MeshPrepNode::new(&device);
|
forward_plus_graph.add_node(MeshesPassLabel, MeshPass::new());
|
||||||
let material_bgl = mesh_prep.material_bgl.clone();
|
|
||||||
forward_plus_graph.add_node(MeshPrepNodeLabel, mesh_prep);
|
|
||||||
forward_plus_graph.add_node(MeshesPassLabel, MeshPass::new(material_bgl));
|
|
||||||
|
|
||||||
forward_plus_graph.add_edge(LightBasePassLabel, LightCullComputePassLabel);
|
forward_plus_graph.add_edge(LightBasePassLabel, LightCullComputePassLabel);
|
||||||
forward_plus_graph.add_edge(MeshPrepNodeLabel, MeshesPassLabel);
|
|
||||||
|
|
||||||
main_graph.add_sub_graph(TestSubGraphLabel, forward_plus_graph);
|
main_graph.add_sub_graph(TestSubGraphLabel, forward_plus_graph);
|
||||||
main_graph.add_node(TestSubGraphLabel, SubGraphNode::new(TestSubGraphLabel,
|
main_graph.add_node(TestSubGraphLabel, SubGraphNode::new(TestSubGraphLabel,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{ops::Deref, rc::Rc, sync::Arc};
|
use std::{ops::Deref, rc::Rc};
|
||||||
|
|
||||||
use wgpu::PipelineLayout;
|
use wgpu::PipelineLayout;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use super::Shader;
|
||||||
//#[derive(Debug, Clone)]
|
//#[derive(Debug, Clone)]
|
||||||
pub struct ComputePipelineDescriptor {
|
pub struct ComputePipelineDescriptor {
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
pub layouts: Vec<Arc<wgpu::BindGroupLayout>>,
|
pub layouts: Vec<Rc<wgpu::BindGroupLayout>>,
|
||||||
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
|
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
|
||||||
// TODO: make this a ResHandle<Shader>
|
// TODO: make this a ResHandle<Shader>
|
||||||
/// The compiled shader module for the stage.
|
/// The compiled shader module for the stage.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{num::NonZeroU32, ops::Deref, sync::Arc};
|
use std::{num::NonZeroU32, ops::Deref, rc::Rc};
|
||||||
|
|
||||||
use wgpu::PipelineLayout;
|
use wgpu::PipelineLayout;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use super::{FragmentState, VertexState};
|
||||||
//#[derive(Debug, Clone)]
|
//#[derive(Debug, Clone)]
|
||||||
pub struct RenderPipelineDescriptor {
|
pub struct RenderPipelineDescriptor {
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
pub layouts: Vec<Arc<wgpu::BindGroupLayout>>,
|
pub layouts: Vec<Rc<wgpu::BindGroupLayout>>,
|
||||||
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
|
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
|
||||||
pub vertex: VertexState,
|
pub vertex: VertexState,
|
||||||
pub fragment: Option<FragmentState>,
|
pub fragment: Option<FragmentState>,
|
||||||
|
@ -87,7 +87,7 @@ impl RenderPipeline {
|
||||||
// an Rc was used here so that this shader could be reused by the fragment stage if
|
// an Rc was used here so that this shader could be reused by the fragment stage if
|
||||||
// they share the same shader. I tried to do it without an Rc but couldn't get past
|
// they share the same shader. I tried to do it without an Rc but couldn't get past
|
||||||
// the borrow checker
|
// the borrow checker
|
||||||
let vrtx_shad = Arc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let vrtx_shad = Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: desc.vertex.module.label.as_deref(),
|
label: desc.vertex.module.label.as_deref(),
|
||||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
|
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
|
||||||
&desc.vertex.module.source,
|
&desc.vertex.module.source,
|
||||||
|
@ -103,7 +103,7 @@ impl RenderPipeline {
|
||||||
if f.module == desc.vertex.module {
|
if f.module == desc.vertex.module {
|
||||||
vrtx_shad.clone()
|
vrtx_shad.clone()
|
||||||
} else {
|
} else {
|
||||||
Arc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: f.module.label.as_deref(),
|
label: f.module.label.as_deref(),
|
||||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&f.module.source)),
|
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&f.module.source)),
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -87,31 +87,28 @@ fn vs_main(
|
||||||
// Fragment shader
|
// Fragment shader
|
||||||
|
|
||||||
struct Material {
|
struct Material {
|
||||||
ambient: vec3<f32>,
|
ambient: vec4<f32>,
|
||||||
diffuse: vec3<f32>,
|
diffuse: vec4<f32>,
|
||||||
|
specular: vec4<f32>,
|
||||||
shininess: f32,
|
shininess: f32,
|
||||||
specular_factor: f32,
|
|
||||||
specular_color: vec3<f32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
var<uniform> u_material: Material;
|
|
||||||
@group(0) @binding(1)
|
|
||||||
var t_diffuse: texture_2d<f32>;
|
var t_diffuse: texture_2d<f32>;
|
||||||
@group(0) @binding(2)
|
@group(0) @binding(1)
|
||||||
var s_diffuse: sampler;
|
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)
|
@group(5) @binding(0)
|
||||||
var t_specular: texture_2d<f32>;
|
var t_specular: texture_2d<f32>;
|
||||||
@group(5) @binding(1)
|
@group(5) @binding(1)
|
||||||
var s_specular: sampler;*/
|
var s_specular: sampler;
|
||||||
|
|
||||||
@group(4) @binding(0)
|
@group(6) @binding(0)
|
||||||
var<storage, read_write> u_light_indices: array<u32>;
|
var<storage, read_write> u_light_indices: array<u32>;
|
||||||
@group(4) @binding(1)
|
@group(6) @binding(1)
|
||||||
var t_light_grid: texture_storage_2d<rg32uint, read_write>; // vec2<u32>
|
var t_light_grid: texture_storage_2d<rg32uint, read_write>; // vec2<u32>
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
|
@ -121,7 +118,7 @@ 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> = vec3<f32>(0.0); //textureSample(t_specular, s_specular, in.tex_coords).xyz;
|
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);
|
||||||
|
|
||||||
if (object_color.a < ALPHA_CUTOFF) {
|
if (object_color.a < ALPHA_CUTOFF) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
use lyra_resource::{FilterMode, ResHandle, Texture, WrappingMode};
|
use lyra_resource::{FilterMode, ResHandle, Texture, WrappingMode};
|
||||||
|
@ -44,7 +44,7 @@ impl RenderTexture {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_bind_group_pair(device: &wgpu::Device, layout: Arc<wgpu::BindGroupLayout>, view: &wgpu::TextureView, sampler: &wgpu::Sampler) -> BindGroupPair {
|
fn create_bind_group_pair(device: &wgpu::Device, layout: Rc<wgpu::BindGroupLayout>, view: &wgpu::TextureView, sampler: &wgpu::Sampler) -> BindGroupPair {
|
||||||
let bg = device.create_bind_group(
|
let bg = device.create_bind_group(
|
||||||
&wgpu::BindGroupDescriptor {
|
&wgpu::BindGroupDescriptor {
|
||||||
layout: &layout,
|
layout: &layout,
|
||||||
|
@ -68,12 +68,12 @@ impl RenderTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
|
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Rc<wgpu::BindGroupLayout>, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
|
||||||
let img = image::load_from_memory(bytes)?;
|
let img = image::load_from_memory(bytes)?;
|
||||||
Self::from_image(device, queue, bg_layout, &img, Some(label))
|
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> {
|
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Rc<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();
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ impl RenderTexture {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, texture_res: &ResHandle<Texture>, label: Option<&str>) -> anyhow::Result<Self> {
|
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Rc<wgpu::BindGroupLayout>, texture_res: &ResHandle<Texture>, label: Option<&str>) -> anyhow::Result<Self> {
|
||||||
let texture_ref = texture_res.data_ref().unwrap();
|
let texture_ref = texture_res.data_ref().unwrap();
|
||||||
let img = texture_ref.image.data_ref().unwrap();
|
let img = texture_ref.image.data_ref().unwrap();
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ impl RenderTexture {
|
||||||
|
|
||||||
/// Convert [`lyra_resource::WrappingMode`] to [`wgpu::AddressMode`]
|
/// Convert [`lyra_resource::WrappingMode`] to [`wgpu::AddressMode`]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn res_wrap_to_wgpu(wmode: WrappingMode) -> wgpu::AddressMode {
|
fn res_wrap_to_wgpu(wmode: WrappingMode) -> wgpu::AddressMode {
|
||||||
match wmode {
|
match wmode {
|
||||||
WrappingMode::ClampToEdge => wgpu::AddressMode::ClampToEdge,
|
WrappingMode::ClampToEdge => wgpu::AddressMode::ClampToEdge,
|
||||||
WrappingMode::MirroredRepeat => wgpu::AddressMode::MirrorRepeat,
|
WrappingMode::MirroredRepeat => wgpu::AddressMode::MirrorRepeat,
|
||||||
|
@ -381,7 +381,7 @@ pub(crate) fn res_wrap_to_wgpu(wmode: WrappingMode) -> wgpu::AddressMode {
|
||||||
|
|
||||||
/// Convert [`lyra_resource::FilterMode`] to [`wgpu::FilterMode`]
|
/// Convert [`lyra_resource::FilterMode`] to [`wgpu::FilterMode`]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn res_filter_to_wgpu(fmode: FilterMode) -> wgpu::FilterMode {
|
fn res_filter_to_wgpu(fmode: FilterMode) -> wgpu::FilterMode {
|
||||||
match fmode {
|
match fmode {
|
||||||
FilterMode::Nearest => wgpu::FilterMode::Nearest,
|
FilterMode::Nearest => wgpu::FilterMode::Nearest,
|
||||||
FilterMode::Linear => wgpu::FilterMode::Linear,
|
FilterMode::Linear => wgpu::FilterMode::Linear,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::{HashMap, VecDeque}, hash::{BuildHasher, DefaultHasher, Hash, Hasher, RandomState}, num::NonZeroU64, sync::Arc};
|
use std::{collections::{HashMap, VecDeque}, hash::{BuildHasher, DefaultHasher, Hash, Hasher, RandomState}, num::NonZeroU64, rc::Rc};
|
||||||
|
|
||||||
use lyra_ecs::Entity;
|
use lyra_ecs::Entity;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
@ -165,7 +165,7 @@ impl<K: Hash + Eq + PartialEq + Clone, V: Clone, S: BuildHasher> CachedValMap<K,
|
||||||
/// [`TransformGroup`]s are used to represent entries in the buffer. They are used to insert,
|
/// [`TransformGroup`]s are used to represent entries in the buffer. They are used to insert,
|
||||||
/// update, and retrieve the transforms.
|
/// update, and retrieve the transforms.
|
||||||
pub struct TransformBuffers {
|
pub struct TransformBuffers {
|
||||||
pub bindgroup_layout: Arc<wgpu::BindGroupLayout>,
|
pub bindgroup_layout: Rc<wgpu::BindGroupLayout>,
|
||||||
//groups: CachedValMap<TransformGroupId, TransformIndex>,
|
//groups: CachedValMap<TransformGroupId, TransformIndex>,
|
||||||
//groups: SlotMap<TransformGroupId, TransformIndex>,
|
//groups: SlotMap<TransformGroupId, TransformIndex>,
|
||||||
entries: Vec<BufferEntry>,
|
entries: Vec<BufferEntry>,
|
||||||
|
@ -195,7 +195,7 @@ impl TransformBuffers {
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut s = Self {
|
let mut s = Self {
|
||||||
bindgroup_layout: Arc::new(bindgroup_layout),
|
bindgroup_layout: Rc::new(bindgroup_layout),
|
||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
max_transform_count: (limits.max_uniform_buffer_binding_size) as usize / (limits.min_uniform_buffer_offset_alignment as usize), //(mem::size_of::<glam::Mat4>()),
|
max_transform_count: (limits.max_uniform_buffer_binding_size) as usize / (limits.min_uniform_buffer_offset_alignment as usize), //(mem::size_of::<glam::Mat4>()),
|
||||||
limits,
|
limits,
|
||||||
|
@ -345,6 +345,9 @@ impl TransformBuffers {
|
||||||
/// Returns a boolean indicating if the buffers need to be expanded
|
/// Returns a boolean indicating if the buffers need to be expanded
|
||||||
pub fn needs_expand(&self) -> bool {
|
pub fn needs_expand(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
/* self.entries.last()
|
||||||
|
.map(|entry| entry.len >= self.max_transform_count)
|
||||||
|
.unwrap_or(false) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl From<gltf::material::AlphaMode> for AlphaMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Reflect, Default)]
|
#[derive(Clone, Reflect)]
|
||||||
pub struct Specular {
|
pub struct Specular {
|
||||||
/// The strength of the specular reflection, default of 1.0
|
/// The strength of the specular reflection, default of 1.0
|
||||||
pub factor: f32,
|
pub factor: f32,
|
||||||
|
|
Loading…
Add table
Reference in a new issue