render: implement 2d sprite rendering
This commit is contained in:
parent
62adcf2b50
commit
6b9561d9bd
|
@ -4,6 +4,24 @@
|
|||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug lyra dim_2d example",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path", "${workspaceFolder}/examples/2d/Cargo.toml"
|
||||
//"--bin=testbed",
|
||||
],
|
||||
"filter": {
|
||||
"name": "dim_2d",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/examples/2d"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
|
|
|
@ -414,12 +414,12 @@ impl Node for MeshPass {
|
|||
view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
load: wgpu::LoadOp::Load,/* wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
}),
|
||||
}), */
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
|
@ -441,9 +441,9 @@ impl Node for MeshPass {
|
|||
|
||||
for job in render_meshes.iter() {
|
||||
// get the mesh (containing vertices) and the buffers from storage
|
||||
let buffers = mesh_buffers.get(&job.mesh_uuid);
|
||||
let buffers = mesh_buffers.get(&job.asset_uuid);
|
||||
if buffers.is_none() {
|
||||
warn!("Skipping job since its mesh is missing {:?}", job.mesh_uuid);
|
||||
warn!("Skipping job since its mesh is missing {:?}", job.asset_uuid);
|
||||
continue;
|
||||
}
|
||||
let buffers = buffers.unwrap();
|
||||
|
|
|
@ -29,4 +29,7 @@ mod mesh_prepare;
|
|||
pub use mesh_prepare::*;
|
||||
|
||||
mod transform;
|
||||
pub use transform::*;
|
||||
pub use transform::*;
|
||||
|
||||
mod sprite;
|
||||
pub use sprite::*;
|
|
@ -963,9 +963,9 @@ fn light_shadow_pass_impl<'a>(
|
|||
|
||||
for job in render_meshes.iter() {
|
||||
// get the mesh (containing vertices) and the buffers from storage
|
||||
let buffers = mesh_buffers.get(&job.mesh_uuid);
|
||||
let buffers = mesh_buffers.get(&job.asset_uuid);
|
||||
if buffers.is_none() {
|
||||
warn!("Skipping job since its mesh is missing {:?}", job.mesh_uuid);
|
||||
warn!("Skipping job since its mesh is missing {:?}", job.asset_uuid);
|
||||
continue;
|
||||
}
|
||||
let buffers = buffers.unwrap();
|
||||
|
|
|
@ -0,0 +1,404 @@
|
|||
use std::{
|
||||
cell::RefMut,
|
||||
collections::{HashMap, VecDeque},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use glam::{Vec2, Vec3};
|
||||
use image::GenericImageView;
|
||||
use lyra_ecs::{
|
||||
query::{Entities, ResMut}, AtomicRef, Entity, ResourceData
|
||||
};
|
||||
use lyra_game_derive::RenderGraphLabel;
|
||||
use lyra_resource::{Image, Texture};
|
||||
use tracing::{info, instrument, warn};
|
||||
use uuid::Uuid;
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use crate::{
|
||||
render::{
|
||||
graph::{Node, NodeDesc, NodeType, SlotAttribute},
|
||||
render_job::RenderJob,
|
||||
resource::{
|
||||
FragmentState, PipelineDescriptor, RenderPipeline, RenderPipelineDescriptor, Shader,
|
||||
VertexState,
|
||||
},
|
||||
texture::{res_filter_to_wgpu, res_wrap_to_wgpu},
|
||||
transform_buffer_storage::{TransformBuffers, TransformIndex},
|
||||
vertex::Vertex2D,
|
||||
},
|
||||
sprite::Sprite,
|
||||
};
|
||||
|
||||
use super::{BasePassSlots, RenderAssets};
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, Hash, RenderGraphLabel)]
|
||||
pub struct SpritePassLabel;
|
||||
|
||||
#[derive(Debug, Hash, Clone, PartialEq, RenderGraphLabel)]
|
||||
pub enum SpritePassSlots {
|
||||
SpriteTexture,
|
||||
SpriteTextureView,
|
||||
SpriteTextureSampler,
|
||||
}
|
||||
|
||||
struct SpriteTexture {
|
||||
texture: wgpu::Texture,
|
||||
texture_sampler: wgpu::Sampler,
|
||||
texture_bg: Arc<wgpu::BindGroup>,
|
||||
|
||||
vertex_buffers: wgpu::Buffer,
|
||||
index_buffers: wgpu::Buffer,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SpritePass {
|
||||
pipeline: Option<RenderPipeline>,
|
||||
texture_bgl: Option<Arc<wgpu::BindGroupLayout>>,
|
||||
jobs: VecDeque<RenderJob>,
|
||||
|
||||
transform_buffers: Option<ResourceData>,
|
||||
sprite_textures: Option<ResourceData>,
|
||||
}
|
||||
|
||||
impl SpritePass {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[instrument(skip(self, device, sprite))]
|
||||
fn create_vertex_index_buffers(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
sprite: &Sprite,
|
||||
) -> (wgpu::Buffer, wgpu::Buffer) {
|
||||
let tex_dims = sprite
|
||||
.texture
|
||||
.data_ref()
|
||||
.map(|t| t.dimensions());
|
||||
if tex_dims.is_none() {
|
||||
info!("Sprite texture is not loaded, not rendering it until it is!");
|
||||
todo!("Wait until texture is loaded");
|
||||
}
|
||||
let tex_dims = tex_dims.unwrap();
|
||||
|
||||
let vertices = vec![
|
||||
// top left
|
||||
Vertex2D::new(Vec3::new(0.0, 0.0, 0.0), Vec2::new(0.0, 1.0)),
|
||||
// bottom left
|
||||
Vertex2D::new(Vec3::new(0.0, tex_dims.1 as f32, 0.0), Vec2::new(0.0, 0.0)),
|
||||
// top right
|
||||
Vertex2D::new(Vec3::new(tex_dims.0 as f32, 0.0, 0.0), Vec2::new(1.0, 1.0)),
|
||||
// bottom right
|
||||
Vertex2D::new(
|
||||
Vec3::new(tex_dims.0 as f32, tex_dims.1 as f32, 0.0),
|
||||
Vec2::new(1.0, 0.0),
|
||||
),
|
||||
];
|
||||
|
||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(vertices.as_slice()),
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
let contents: [u32; 6] = [
|
||||
//3, 1, 0,
|
||||
//0, 2, 3
|
||||
3, 1, 0, // second tri
|
||||
0, 2, 3, // first tri
|
||||
//0, 2, 3, // second tri
|
||||
];
|
||||
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(&contents),
|
||||
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
(vertex_buffer, index_buffer)
|
||||
}
|
||||
|
||||
fn load_sprite_texture(
|
||||
&self,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
uuid: &Uuid,
|
||||
image: &Image,
|
||||
) -> Option<(wgpu::Texture, wgpu::Sampler, wgpu::BindGroup)> {
|
||||
let uuid_str = uuid.to_string();
|
||||
let image_dim = image.dimensions();
|
||||
let tex = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some(&format!("sprite_texture_{}", uuid_str)),
|
||||
size: wgpu::Extent3d {
|
||||
width: image_dim.0,
|
||||
height: image_dim.1,
|
||||
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: &[],
|
||||
});
|
||||
let tex_view = tex.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Nearest,
|
||||
min_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
queue.write_texture(
|
||||
wgpu::ImageCopyTexture {
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
texture: &tex,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
&image.to_rgba8(),
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(4 * image_dim.0),
|
||||
rows_per_image: Some(image_dim.1),
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: image_dim.0,
|
||||
height: image_dim.1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
|
||||
let bgl = self.texture_bgl.as_ref().unwrap();
|
||||
let tex_bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: Some(&format!("sprite_texture_bg_{}", uuid_str)),
|
||||
layout: bgl,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&tex_view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Some((tex, sampler, tex_bg))
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for SpritePass {
|
||||
fn desc(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::NodeDesc {
|
||||
let device = &graph.device;
|
||||
|
||||
let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("bgl_sprite_main"),
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
self.texture_bgl = Some(Arc::new(bgl));
|
||||
|
||||
let mut desc = NodeDesc::new(NodeType::Render, None, vec![]);
|
||||
|
||||
desc.add_buffer_slot(BasePassSlots::Camera, SlotAttribute::Input, None);
|
||||
|
||||
desc
|
||||
}
|
||||
|
||||
fn prepare(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
world: &mut lyra_ecs::World,
|
||||
_: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
let device = graph.device();
|
||||
let vt = graph.view_target();
|
||||
|
||||
if self.pipeline.is_none() {
|
||||
let shader = Rc::new(Shader {
|
||||
label: Some("sprite_shader".into()),
|
||||
source: include_str!("../../shaders/2d/sprite_main.wgsl").to_string(),
|
||||
});
|
||||
|
||||
let diffuse_bgl = self.texture_bgl.clone().unwrap();
|
||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera).clone();
|
||||
let transforms = world
|
||||
.get_resource::<TransformBuffers>()
|
||||
.expect("Missing transform buffers");
|
||||
let transform_bgl = transforms.bindgroup_layout.clone();
|
||||
|
||||
self.pipeline = Some(RenderPipeline::create(
|
||||
device,
|
||||
&RenderPipelineDescriptor {
|
||||
label: Some("sprite_pass".into()),
|
||||
layouts: vec![diffuse_bgl, transform_bgl, camera_bgl],
|
||||
push_constant_ranges: vec![],
|
||||
vertex: VertexState {
|
||||
module: shader.clone(),
|
||||
entry_point: "vs_main".into(),
|
||||
buffers: vec![Vertex2D::desc().into()],
|
||||
},
|
||||
fragment: Some(FragmentState {
|
||||
module: shader,
|
||||
entry_point: "fs_main".into(),
|
||||
targets: vec![Some(wgpu::ColorTargetState {
|
||||
format: vt.format(),
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
depth_stencil: None,
|
||||
primitive: wgpu::PrimitiveState {
|
||||
cull_mode: Some(wgpu::Face::Back),
|
||||
..Default::default()
|
||||
},
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
},
|
||||
));
|
||||
|
||||
drop(transforms);
|
||||
world.add_resource_default_if_absent::<RenderAssets<SpriteTexture>>();
|
||||
let sprite_textures = world
|
||||
.get_resource_data::<RenderAssets<SpriteTexture>>()
|
||||
.expect("Missing sprite texture store");
|
||||
self.sprite_textures = Some(sprite_textures.clone());
|
||||
|
||||
let transforms = world
|
||||
.get_resource_data::<TransformBuffers>()
|
||||
.expect("Missing transform buffers");
|
||||
self.transform_buffers = Some(transforms.clone());
|
||||
}
|
||||
|
||||
let queue = &graph.queue;
|
||||
for (entity, sprite, transform_idx, mut sprite_store) in world
|
||||
.view::<(
|
||||
Entities,
|
||||
&Sprite,
|
||||
&TransformIndex,
|
||||
ResMut<RenderAssets<SpriteTexture>>,
|
||||
)>()
|
||||
.iter()
|
||||
{
|
||||
if let Some(image) = sprite.texture.data_ref() {
|
||||
let texture_uuid = sprite.texture.uuid();
|
||||
if !sprite_store.contains_key(&texture_uuid) {
|
||||
// returns `None` if the Texture image is not loaded.
|
||||
if let Some((tex, samp, tex_bg)) =
|
||||
self.load_sprite_texture(device, queue, &texture_uuid, &image)
|
||||
{
|
||||
let (vertex, index) = self.create_vertex_index_buffers(device, &sprite);
|
||||
|
||||
sprite_store.insert(
|
||||
texture_uuid,
|
||||
SpriteTexture {
|
||||
texture: tex,
|
||||
texture_sampler: samp,
|
||||
texture_bg: Arc::new(tex_bg),
|
||||
vertex_buffers: vertex,
|
||||
index_buffers: index,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.jobs.push_back(RenderJob {
|
||||
entity,
|
||||
shader_id: 0,
|
||||
asset_uuid: texture_uuid,
|
||||
transform_id: *transform_idx,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
_: &crate::render::graph::NodeDesc,
|
||||
context: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
let pipeline = self.pipeline.as_ref().unwrap();
|
||||
|
||||
let sprite_store = self.sprite_textures.clone().unwrap();
|
||||
let sprite_store: AtomicRef<RenderAssets<SpriteTexture>> = sprite_store.get();
|
||||
let transforms = self.transform_buffers.clone().unwrap();
|
||||
let transforms: AtomicRef<TransformBuffers> = transforms.get();
|
||||
|
||||
let vt = graph.view_target();
|
||||
let view = vt.render_view();
|
||||
|
||||
let camera_bg = graph.bind_group(BasePassSlots::Camera);
|
||||
|
||||
{
|
||||
let encoder = context.encoder.as_mut().unwrap();
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("sprite_pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
}),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
pass.set_pipeline(pipeline);
|
||||
|
||||
while let Some(job) = self.jobs.pop_front() {
|
||||
let sprite = sprite_store.get(&job.asset_uuid)
|
||||
.expect("failed to find SpriteTexture for job asset_uuid");
|
||||
|
||||
pass.set_bind_group(0, &sprite.texture_bg, &[]);
|
||||
|
||||
// Get the bindgroup for job's transform and bind to it using an offset.
|
||||
let bindgroup = transforms.bind_group(job.transform_id);
|
||||
let offset = transforms.buffer_offset(job.transform_id);
|
||||
pass.set_bind_group(1, bindgroup, &[offset]);
|
||||
|
||||
pass.set_bind_group(2, camera_bg, &[]);
|
||||
|
||||
pass.set_vertex_buffer(
|
||||
0,
|
||||
sprite.vertex_buffers.slice(..),
|
||||
);
|
||||
pass.set_index_buffer(sprite.index_buffers.slice(..), wgpu::IndexFormat::Uint32);
|
||||
pass.draw_indexed(0..6, 0, 0..1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,12 +32,12 @@ pub struct InterpTransform {
|
|||
#[derive(Default, Debug, Clone, Copy, Hash, RenderGraphLabel)]
|
||||
pub struct TransformsNodeLabel;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TransformsNode {}
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TransformsNode;
|
||||
|
||||
impl TransformsNode {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use super::transform_buffer_storage::TransformIndex;
|
|||
pub struct RenderJob {
|
||||
pub entity: Entity,
|
||||
pub shader_id: u64,
|
||||
pub mesh_uuid: uuid::Uuid,
|
||||
pub asset_uuid: uuid::Uuid,
|
||||
pub transform_id: TransformIndex,
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ impl RenderJob {
|
|||
Self {
|
||||
entity,
|
||||
shader_id,
|
||||
mesh_uuid: mesh_buffer_id,
|
||||
asset_uuid: mesh_buffer_id,
|
||||
transform_id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use lyra_game_derive::RenderGraphLabel;
|
|||
use tracing::{debug, instrument, warn};
|
||||
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, ShadowMapsPass, ShadowMapsPassLabel, SubGraphNode, TransformsNode, TransformsNodeLabel, ViewTarget};
|
||||
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, FxaaPass, FxaaPassLabel, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshPrepNode, MeshPrepNodeLabel, MeshesPassLabel, PresentPass, PresentPassLabel, RenderGraphLabelValue, RenderTarget, ShadowMapsPass, ShadowMapsPassLabel, SpritePass, SpritePassLabel, SubGraphNode, TransformsNode, TransformsNodeLabel, ViewTarget};
|
||||
|
||||
use super::graph::RenderGraph;
|
||||
use super::{resource::RenderPipeline, render_job::RenderJob};
|
||||
|
@ -163,6 +163,10 @@ impl BasicRenderer {
|
|||
forward_plus_graph.add_node(MeshesPassLabel, MeshPass::new(material_bgl));
|
||||
forward_plus_graph.add_edge(TransformsNodeLabel, MeshPrepNodeLabel);
|
||||
|
||||
debug!("Adding sprite pass");
|
||||
forward_plus_graph.add_node(SpritePassLabel, SpritePass::new());
|
||||
forward_plus_graph.add_edge(TransformsNodeLabel, SpritePassLabel);
|
||||
|
||||
forward_plus_graph.add_edge(LightBasePassLabel, LightCullComputePassLabel);
|
||||
forward_plus_graph.add_edge(LightCullComputePassLabel, MeshesPassLabel);
|
||||
forward_plus_graph.add_edge(MeshPrepNodeLabel, MeshesPassLabel);
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
const ALPHA_CUTOFF = 0.1;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) tex_coords: vec2<f32>,
|
||||
@location(1) world_position: vec3<f32>,
|
||||
}
|
||||
|
||||
struct TransformData {
|
||||
transform: mat4x4<f32>,
|
||||
normal_matrix: mat4x4<f32>,
|
||||
}
|
||||
|
||||
struct CameraUniform {
|
||||
view: mat4x4<f32>,
|
||||
inverse_projection: mat4x4<f32>,
|
||||
view_projection: mat4x4<f32>,
|
||||
projection: mat4x4<f32>,
|
||||
position: vec3<f32>,
|
||||
tile_debug: u32,
|
||||
}
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> u_model_transform_data: TransformData;
|
||||
|
||||
@group(2) @binding(0)
|
||||
var<uniform> u_camera: CameraUniform;
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
in: VertexInput,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
var world_position: vec4<f32> = u_model_transform_data.transform * vec4<f32>(in.position, 1.0);
|
||||
out.world_position = world_position.xyz;
|
||||
out.tex_coords = in.tex_coords;
|
||||
out.clip_position = u_camera.view_projection * world_position;
|
||||
return out;
|
||||
}
|
||||
|
||||
@group(0) @binding(0)
|
||||
var t_diffuse: texture_2d<f32>;
|
||||
|
||||
@group(0) @binding(1)
|
||||
var s_diffuse: sampler;
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
||||
if (object_color.a < ALPHA_CUTOFF) {
|
||||
discard;
|
||||
}
|
||||
|
||||
return object_color;
|
||||
}
|
|
@ -75,7 +75,7 @@ impl Vertex2D {
|
|||
|
||||
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||
array_stride: std::mem::size_of::<Vertex2D>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: &[
|
||||
wgpu::VertexAttribute {
|
||||
|
|
|
@ -45,7 +45,7 @@ impl Pivot {
|
|||
|
||||
#[derive(Clone, Component, Reflect)]
|
||||
pub struct Sprite {
|
||||
pub texture: ResHandle<lyra_resource::Texture>,
|
||||
pub texture: ResHandle<lyra_resource::Image>,
|
||||
pub color: Vec3,
|
||||
pub pivot: Pivot,
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use lyra_engine::{
|
||||
assets::ResourceManager, gltf::Gltf, ecs::query::View, game::App, input::{
|
||||
assets::{Image, ResourceManager, Texture}, ecs::query::View, game::App, gltf::Gltf, input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId,
|
||||
}, 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,
|
||||
}, winit::WindowOptions
|
||||
system_update_world_transforms, 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
|
||||
}, sprite::{self, Sprite}, winit::WindowOptions
|
||||
};
|
||||
|
||||
#[async_std::main]
|
||||
|
@ -85,7 +83,8 @@ async fn main() {
|
|||
.with_plugin(setup_scene_plugin)
|
||||
.with_plugin(action_handler_plugin)
|
||||
//.with_plugin(camera_debug_plugin)
|
||||
.with_plugin(FreeFlyCameraPlugin);
|
||||
.with_plugin(FreeFlyCameraPlugin)
|
||||
.with_system("system_update_world_transforms", system_update_world_transforms, &[]);
|
||||
a.run();
|
||||
}
|
||||
|
||||
|
@ -113,14 +112,28 @@ fn setup_scene_plugin(app: &mut App) {
|
|||
|
||||
cube_gltf.wait_recurse_dependencies_load();
|
||||
let cube_mesh = &cube_gltf.data_ref().unwrap().scenes[0];
|
||||
drop(resman);
|
||||
|
||||
let image = resman.request::<Image>("../assets/Egg_item.png")
|
||||
.unwrap();
|
||||
image.wait_recurse_dependencies_load();
|
||||
|
||||
drop(resman);
|
||||
world.spawn((
|
||||
cube_mesh.clone(),
|
||||
WorldTransform::default(),
|
||||
Transform::from_xyz(0.0, 0.0, -2.0),
|
||||
));
|
||||
|
||||
world.spawn((
|
||||
Sprite {
|
||||
texture: image,
|
||||
color: Vec3::ONE,
|
||||
pivot: sprite::Pivot::Center,
|
||||
},
|
||||
WorldTransform::default(),
|
||||
Transform::from_xyz(0.0, 0.0, -20.0),
|
||||
));
|
||||
|
||||
{
|
||||
let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0);
|
||||
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
||||
|
@ -136,7 +149,7 @@ fn setup_scene_plugin(app: &mut App) {
|
|||
));
|
||||
}
|
||||
|
||||
let mut camera = CameraComponent::new_2d();
|
||||
let mut camera = CameraComponent::new_3d();
|
||||
camera.transform.translation += math::Vec3::new(0.0, 0.0, 5.5);
|
||||
world.spawn((camera, FreeFlyCamera::default()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Egg_item.png
|
Loading…
Reference in New Issue