sprite: more sprite sheet work (not quite operable yet)

This commit is contained in:
Carter Anderson 2020-06-03 11:39:10 -07:00
parent c9ae10a8a9
commit 13d56907ed
11 changed files with 115 additions and 74 deletions

View file

@ -119,7 +119,7 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream {
}
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
use #bevy_render_path::shader::AsFieldBindType;
use #bevy_render_path::shader::GetFieldBindType;
match name {
#struct_name_string => self.get_bind_type(),
_ => None,
@ -453,7 +453,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
use #bevy_render_path::shader::AsFieldBindType;
use #bevy_render_path::shader::GetFieldBindType;
match name {
#(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)*
_ => None,

View file

@ -1,5 +1,5 @@
use super::{BindGroupDescriptor, VertexBufferDescriptor, VertexBufferDescriptors};
use crate::shader::ShaderLayout;
use crate::shader::{GL_VERTEX_INDEX, ShaderLayout};
use std::{collections::HashMap, hash::Hash};
#[derive(Clone, Debug, Default)]
@ -65,6 +65,9 @@ impl PipelineLayout {
vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name)
{
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor);
} else if vertex_buffer_descriptor.name == GL_VERTEX_INDEX {
// GL_VERTEX_INDEX is a special attribute set on our behalf
continue;
} else {
panic!(
"Encountered unsupported Vertex Buffer: {}",
@ -84,6 +87,7 @@ pub struct UniformProperty {
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum UniformPropertyType {
// TODO: Use VertexFormat here
UInt,
Int,
IVec2,
Float,
@ -100,6 +104,7 @@ pub enum UniformPropertyType {
impl UniformPropertyType {
pub fn get_size(&self) -> u64 {
match self {
UniformPropertyType::UInt => 4,
UniformPropertyType::Int => 4,
UniformPropertyType::IVec2 => 4 * 2,
UniformPropertyType::Float => 4,

View file

@ -5,6 +5,7 @@ use crate::{
},
texture::{TextureComponentType, TextureViewDimension},
};
use bevy_core::bytes::AsBytes;
use spirv_reflect::{
types::{
ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, ReflectDimension,
@ -12,7 +13,6 @@ use spirv_reflect::{
},
ShaderModule,
};
use bevy_core::bytes::AsBytes;
use std::collections::HashSet;
// use rspirv::{binary::Parser, dr::Loader, lift::LiftContext};
@ -35,6 +35,8 @@ pub struct ShaderLayout {
pub entry_point: String,
}
pub const GL_VERTEX_INDEX: &str = "gl_VertexIndex";
impl ShaderLayout {
pub fn from_spirv(spirv_data: &[u32], bevy_conventions: bool) -> ShaderLayout {
match ShaderModule::load_u8_data(spirv_data.as_bytes()) {
@ -63,6 +65,9 @@ impl ShaderLayout {
let mut instance = false;
let current_buffer_name = {
if bevy_conventions {
if vertex_attribute_descriptor.name == GL_VERTEX_INDEX {
GL_VERTEX_INDEX.to_string()
} else {
let parts = vertex_attribute_descriptor
.name
.splitn(3, "_")
@ -79,6 +84,7 @@ impl ShaderLayout {
} else {
panic!("Vertex attributes must follow the form BUFFERNAME_PROPERTYNAME. For example: Vertex_Position");
}
}
} else {
"DefaultVertex".to_string()
}
@ -279,6 +285,7 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
}
} else {
match (number_type, traits.numeric.vector.component_count) {
(NumberType::UInt, 0) => UniformPropertyType::UInt,
(NumberType::Int, 0) => UniformPropertyType::Int,
(NumberType::Int, 2) => UniformPropertyType::IVec2,
(NumberType::Float, 0) => UniformPropertyType::Float,

View file

@ -71,6 +71,7 @@ impl ShaderDefSuffixProvider for bool {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FieldBindType {
Uniform { size: usize },
Buffer,
Texture,
}
@ -82,11 +83,11 @@ pub struct FieldInfo {
pub is_instanceable: bool,
}
pub trait AsFieldBindType {
pub trait GetFieldBindType {
fn get_bind_type(&self) -> Option<FieldBindType>;
}
impl AsFieldBindType for ColorSource {
impl GetFieldBindType for ColorSource {
fn get_bind_type(&self) -> Option<FieldBindType> {
match *self {
ColorSource::Texture(_) => Some(FieldBindType::Texture),
@ -95,7 +96,7 @@ impl AsFieldBindType for ColorSource {
}
}
impl AsFieldBindType for Option<Handle<Texture>> {
impl GetFieldBindType for Option<Handle<Texture>> {
fn get_bind_type(&self) -> Option<FieldBindType> {
match *self {
Some(_) => Some(FieldBindType::Texture),
@ -104,13 +105,13 @@ impl AsFieldBindType for Option<Handle<Texture>> {
}
}
impl AsFieldBindType for Handle<Texture> {
impl GetFieldBindType for Handle<Texture> {
fn get_bind_type(&self) -> Option<FieldBindType> {
Some(FieldBindType::Texture)
}
}
impl<T> AsFieldBindType for T
impl<T> GetFieldBindType for T
where
T: Bytes,
{

View file

@ -1,6 +1,6 @@
use crate::{
pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat},
shader::{AsFieldBindType, AsUniforms, FieldBindType, FieldInfo},
shader::{GetFieldBindType, AsUniforms, FieldBindType, FieldInfo},
texture::Texture,
};
use bevy_asset::Handle;

View file

@ -1,10 +1,9 @@
use crate::{
render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Quad, QUAD_HANDLE, SpriteSheet, SPRITE_SHEET_PIPELINE_HANDLE,
render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Quad, QUAD_HANDLE, SpriteSheet, SPRITE_SHEET_PIPELINE_HANDLE, SpriteSheetSprite,
};
use bevy_asset::Handle;
use bevy_derive::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable};
use bevy_transform::prelude::*;
#[derive(EntityArchetype)]
pub struct SpriteEntity {
@ -32,13 +31,14 @@ impl Default for SpriteEntity {
#[derive(EntityArchetype)]
pub struct SpriteSheetEntity {
pub sprite: Sprite,
pub sprite: SpriteSheetSprite,
pub sprite_sheet: Handle<SpriteSheet>,
pub renderable: Renderable,
pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
// pub local_to_world: LocalToWorld,
// pub translation: Translation,
// pub rotation: Rotation,
// pub scale: Scale,
}
impl Default for SpriteSheetEntity {
@ -50,10 +50,11 @@ impl Default for SpriteSheetEntity {
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
..Default::default()
},
local_to_world: Default::default(),
translation: Default::default(),
rotation: Default::default(),
scale: Default::default(),
mesh: QUAD_HANDLE,
// local_to_world: Default::default(),
// translation: Default::default(),
// rotation: Default::default(),
// scale: Default::default(),
}
}
}

View file

@ -1,3 +1,4 @@
use bevy_core::bytes::Byteable;
use glam::Vec2;
/// A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere (top-left, bottom-left, etc)
@ -19,3 +20,5 @@ impl Rect {
self.max.y() - self.min.y()
}
}
unsafe impl Byteable for Rect {}

View file

@ -1,4 +1,4 @@
use crate::{ColorMaterial, Quad};
use crate::{ColorMaterial, Quad, SpriteSheet, SpriteSheetSprite};
use bevy_asset::{Assets, Handle};
use bevy_render::{
base_render_graph,
@ -112,6 +112,8 @@ pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor
pub mod node {
pub const COLOR_MATERIAL: &'static str = "color_material";
pub const QUAD: &'static str = "quad";
pub const SPRITE_SHEET: &'static str = "sprite_sheet";
pub const SPRITE_SHEET_SPRITE: &'static str = "sprite_sheet_sprite";
}
pub trait SpriteRenderGraphBuilder {
@ -131,6 +133,16 @@ impl SpriteRenderGraphBuilder for RenderGraph {
self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS)
.unwrap();
self.add_system_node(
node::SPRITE_SHEET,
AssetUniformNode::<SpriteSheet>::new(true),
);
self.add_system_node(
node::SPRITE_SHEET_SPRITE,
UniformNode::<SpriteSheetSprite>::new(true),
);
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
pipelines.set(SPRITE_PIPELINE_HANDLE, build_sprite_pipeline(&mut shaders));

View file

@ -1,9 +1,22 @@
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
// TODO: consider swapping explicit mesh binding for this const
// const vec2 positions[4] = vec2[](
// vec2(0.5, -0.5),
// vec2(-0.5, -0.5),
// vec2(0.5, 0.5),
// vec2(-0.5, 0.5)
// );
// TODO: uncomment when instancing is implemented
// sprite
layout(location = 0) in vec3 Sprite_Position;
// this is a vec2 instead of an int due to WebGPU limitations
layout(location = 1) in ivec2 Sprite_Index;
// layout(location = 0) in vec3 Sprite_Position;
// // this is a vec2 instead of an int due to WebGPU limitations
// layout(location = 1) in int Sprite_Index;
layout(location = 0) out vec2 v_Uv;
@ -16,21 +29,19 @@ struct Rect {
vec2 end;
};
layout(set = 1, binding = 0) buffer SpriteSheet {
Rect[] SpriteSheet_sprites;
layout(set = 1, binding = 0) buffer SpriteSheet_sprites {
Rect[] Sprites;
};
const vec2 positions[4] = vec2[](
vec2(0.5, -0.5),
vec2(-0.5, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
layout(set = 2, binding = 0) uniform SpriteSheetSprite {
vec3 SpriteSheetSprite_position;
uint SpriteSheetSprite_index;
};
void main() {
Rect sprite_rect = SpriteSheet_sprites[Sprite_Index.x];
Rect sprite_rect = Sprites[SpriteSheetSprite_index];
vec2 dimensions = sprite_rect.end - sprite_rect.begin;
vec2 vertex_position = positions[gl_VertexIndex] * dimensions;
vec2 vertex_position = Vertex_Position.xy * dimensions;
vec2 uvs[4] = vec2[](
vec2(sprite_rect.end.x, sprite_rect.begin.y),
sprite_rect.begin,
@ -38,5 +49,5 @@ void main() {
vec2(sprite_rect.begin.x, sprite_rect.end.y)
);
v_Uv = uvs[gl_VertexIndex];
gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + Sprite_Position, 1.0);
gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + SpriteSheetSprite_position, 1.0);
}

View file

@ -1,29 +1,30 @@
use crate::Rect;
use bevy_app::{Events, GetEventReader};
use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_derive::{Uniform, Bytes};
use bevy_core::bytes::AsBytes;
use bevy_derive::{Bytes, Uniform, Uniforms};
use bevy_render::{
render_resource::{BufferInfo, BufferUsage, RenderResourceAssignment, ResourceInfo},
renderer::{RenderResourceContext, RenderResources},
texture::Texture,
Renderable,
};
use glam::{Vec3, Vec4};
use legion::prelude::*;
use std::collections::HashSet;
use glam::{Vec4, Vec3};
#[derive(Uniforms)]
pub struct SpriteSheet {
pub texture: Handle<Texture>,
pub sprites: Vec<Rect>,
}
#[repr(C)]
#[derive(Uniform, Bytes)]
// NOTE: cannot do unsafe impl Byteable here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out
// Bytes for Byteable. https://github.com/bitshifter/glam-rs/issues/36
#[derive(Uniform, Bytes, Default)]
pub struct SpriteSheetSprite {
#[uniform(vertex)]
pub postition: Vec4,
#[uniform(vertex)]
pub index: u16,
pub position: Vec3,
pub index: u32,
}
pub const SPRITE_SHEET_BUFFER_ASSET_INDEX: usize = 0;
@ -69,20 +70,20 @@ pub fn sprite_sheet_resource_provider_system(resources: &mut Resources) -> Box<d
for changed_sprite_sheet_handle in changed_sprite_sheets.iter() {
if let Some(sprite_sheet) = sprite_sheets.get(changed_sprite_sheet_handle) {
// let sprite_sheet_bytes = sprite_sheet.sprites.as_bytes();
// let sprite_sheet_buffer = render_resources.create_buffer_with_data(
// BufferInfo {
// buffer_usage: BufferUsage::STORAGE,
// ..Default::default()
// },
// &sprite_sheet_bytes,
// );
let sprite_sheet_bytes = sprite_sheet.sprites.as_slice().as_bytes();
let sprite_sheet_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::STORAGE,
..Default::default()
},
&sprite_sheet_bytes,
);
// render_resources.set_asset_resource(
// *changed_sprite_sheet_handle,
// sprite_sheet_buffer,
// SPRITE_SHEET_BUFFER_ASSET_INDEX,
// );
render_resources.set_asset_resource(
*changed_sprite_sheet_handle,
sprite_sheet_buffer,
SPRITE_SHEET_BUFFER_ASSET_INDEX,
);
}
}