sprite: add color to TextureAtlasSprite and make Vec3 16 bytes again to account for glsl UBO layout

This commit is contained in:
Carter Anderson 2020-06-21 17:43:36 -07:00
parent 17d70f7d67
commit faacd2778d
13 changed files with 81 additions and 65 deletions

View file

@ -91,58 +91,11 @@ unsafe impl Byteable for i64 {}
unsafe impl Byteable for isize {}
unsafe impl Byteable for f32 {}
unsafe impl Byteable for f64 {}
impl Bytes for Vec2 {
fn write_bytes(&self, buffer: &mut [u8]) {
let array: [f32; 2] = (*self).into();
array.write_bytes(buffer);
}
fn byte_len(&self) -> usize {
std::mem::size_of::<Self>()
}
}
impl FromBytes for Vec2 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 2]>::from_bytes(bytes);
Vec2::from(array)
}
}
impl Bytes for Vec3 {
fn write_bytes(&self, buffer: &mut [u8]) {
let array: [f32; 3] = (*self).into();
array.write_bytes(buffer);
}
fn byte_len(&self) -> usize {
// cant use self here because Vec3 is a simd type / technically a vec4
std::mem::size_of::<[f32; 3]>()
}
}
impl FromBytes for Vec3 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 3]>::from_bytes(bytes);
Vec3::from(array)
}
}
impl Bytes for Vec4 {
fn write_bytes(&self, buffer: &mut [u8]) {
let array: [f32; 4] = (*self).into();
array.write_bytes(buffer);
}
fn byte_len(&self) -> usize {
std::mem::size_of::<Self>()
}
}
impl FromBytes for Vec4 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 4]>::from_bytes(bytes);
Vec4::from(array)
}
}
unsafe impl Byteable for Vec2 {}
// NOTE: Vec3 actually takes up the size of 4 floats / 16 bytes due to SIMD. This is actually convenient because GLSL
// uniform buffer objects pad Vec3s to be 16 bytes.
unsafe impl Byteable for Vec3 {}
unsafe impl Byteable for Vec4 {}
impl Bytes for Mat4 {
fn write_bytes(&self, buffer: &mut [u8]) {

View file

@ -25,7 +25,7 @@ impl AppPlugin for PbrPlugin {
.register_component::<Light>()
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_shader_def_system::<StandardMaterial>.system(),
shader::asset_shader_defs_system::<StandardMaterial>.system(),
);
let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();

View file

@ -219,6 +219,7 @@ impl<'a> DrawContext<'a> {
specialization,
)
};
draw.set_pipeline(specialized_pipeline);
self.current_pipeline = Some(specialized_pipeline);
Ok(())

View file

@ -41,6 +41,7 @@ use mesh::mesh_resource_provider_system;
use pipeline::{draw_render_pipelines_system, RenderPipelines};
use render_graph::{system::render_graph_schedule_executor_system, RenderGraph};
use render_resource::AssetRenderResourceBindings;
use shader::clear_shader_defs_system;
use std::ops::Range;
use texture::{PngTextureLoader, TextureResourceSystemState};
@ -112,7 +113,8 @@ impl AppPlugin for RenderPlugin {
stage::RENDER_GRAPH_SYSTEMS,
render_graph_schedule_executor_system,
)
.add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system());
.add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system())
.add_system_to_stage(stage::POST_RENDER, clear_shader_defs_system.system());
if let Some(ref config) = self.base_render_graph_config {
let resources = app.resources();

View file

@ -14,7 +14,7 @@ impl PipelineLayout {
.iter()
.find(|bind_group| bind_group.index == index)
}
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
let mut bind_groups = HashMap::<u32, BindGroupDescriptor>::new();
let mut vertex_buffer_descriptors = Vec::new();

View file

@ -55,7 +55,7 @@ impl ShaderDef for Option<Handle<Texture>> {
}
}
pub fn shader_def_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
pub fn shader_defs_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
where
T: ShaderDefs + Send + Sync + 'static,
{
@ -70,7 +70,17 @@ where
}
}
pub fn asset_shader_def_system<T>(
pub fn clear_shader_defs_system(mut render_pipelines: ComMut<RenderPipelines>) {
for render_pipeline in render_pipelines.pipelines.iter_mut() {
render_pipeline
.specialization
.shader_specialization
.shader_defs
.clear();
}
}
pub fn asset_shader_defs_system<T>(
assets: Res<Assets<T>>,
asset_handle: Com<Handle<T>>,
mut render_pipelines: ComMut<RenderPipelines>,

View file

@ -22,7 +22,7 @@ use bevy_asset::{AddAsset, Assets, Handle};
use bevy_render::{
mesh::{shape, Mesh},
render_graph::RenderGraph,
shader::asset_shader_def_system,
shader::asset_shader_defs_system,
};
use glam::Vec2;
use legion::prelude::IntoSystem;
@ -40,7 +40,7 @@ impl AppPlugin for SpritePlugin {
.add_system_to_stage(stage::POST_UPDATE, sprite_system())
.add_system_to_stage(
stage::POST_UPDATE,
asset_shader_def_system::<ColorMaterial>.system(),
asset_shader_defs_system::<ColorMaterial>.system(),
);
let resources = app.resources();

View file

@ -1,6 +1,7 @@
#version 450
layout(location = 0) in vec2 v_Uv;
layout(location = 1) in vec4 v_Color;
layout(location = 0) out vec4 o_Target;
@ -8,7 +9,7 @@ layout(set = 1, binding = 2) uniform texture2D TextureAtlas_texture;
layout(set = 1, binding = 3) uniform sampler TextureAtlas_texture_sampler;
void main() {
o_Target = texture(
o_Target = v_Color * texture(
sampler2D(TextureAtlas_texture, TextureAtlas_texture_sampler),
v_Uv);
}

View file

@ -5,6 +5,7 @@ layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec2 v_Uv;
layout(location = 1) out vec4 v_Color;
// TODO: remove UI shader def and replace with generic "Camera" when its easier to manually bind global RenderResourceBindings
#ifdef UI_CAMERA
@ -34,6 +35,7 @@ layout(set = 1, binding = 1) buffer TextureAtlas_textures {
layout(set = 2, binding = 0) uniform TextureAtlasSprite {
vec3 TextureAtlasSprite_position;
vec4 TextureAtlasSprite_color;
float TextureAtlasSprite_scale;
uint TextureAtlasSprite_index;
};
@ -41,7 +43,7 @@ layout(set = 2, binding = 0) uniform TextureAtlasSprite {
void main() {
Rect sprite_rect = Textures[TextureAtlasSprite_index];
vec2 sprite_dimensions = sprite_rect.end - sprite_rect.begin;
vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * TextureAtlasSprite_scale, 0.0) + TextureAtlasSprite_position;
vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * TextureAtlasSprite_scale, 0.0) + TextureAtlasSprite_position.xyz;
vec2 uvs[4] = vec2[](
vec2(sprite_rect.begin.x, sprite_rect.end.y),
sprite_rect.begin,
@ -49,5 +51,6 @@ void main() {
sprite_rect.end
);
v_Uv = uvs[gl_VertexIndex] / AtlasSize;
v_Color = TextureAtlasSprite_color;
gl_Position = ViewProj * vec4(vertex_position, 1.0);
}

View file

@ -4,6 +4,7 @@ use bevy_core::bytes::Bytes;
use bevy_render::{
render_resource::{RenderResource, RenderResources},
texture::Texture,
Color,
};
use glam::{Vec2, Vec3};
use std::collections::HashMap;
@ -21,14 +22,26 @@ pub struct TextureAtlas {
// 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 as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36
#[derive(Bytes, RenderResources, RenderResource, Default)]
#[derive(Bytes, RenderResources, RenderResource)]
#[render_resources(from_self)]
pub struct TextureAtlasSprite {
pub position: Vec3,
pub color: Color,
pub scale: f32,
pub index: u32,
}
impl Default for TextureAtlasSprite {
fn default() -> Self {
Self {
index: 0,
color: Color::WHITE,
scale: 1.0,
position: Default::default(),
}
}
}
impl TextureAtlas {
pub fn new_empty(texture: Handle<Texture>, dimensions: Vec2) -> Self {
Self {
@ -81,3 +94,36 @@ impl TextureAtlas {
.and_then(|texture_handles| texture_handles.get(&texture).cloned())
}
}
#[cfg(test)]
mod tests {
use crate::TextureAtlasSprite;
use bevy_core::bytes::{Bytes, FromBytes};
use bevy_render::Color;
use glam::Vec3;
#[test]
fn test_atlas_byte_conversion() {
let x = TextureAtlasSprite {
color: Color::RED,
index: 2,
position: Vec3::new(1., 2., 3.),
scale: 4.0,
};
assert_eq!(x.byte_len(), 36);
let mut bytes = vec![0; x.byte_len()];
x.write_bytes(&mut bytes);
let position = Vec3::from_bytes(&bytes[0..12]);
let color = Color::from_bytes(&bytes[12..28]);
let scale = f32::from_bytes(&bytes[28..32]);
let index = u32::from_bytes(&bytes[32..36]);
assert_eq!(position, x.position);
assert_eq!(color, x.color);
assert_eq!(scale, x.scale);
assert_eq!(index, x.index);
}
}

View file

@ -132,6 +132,7 @@ impl<'a> Drawable for DrawableText<'a> {
let offset = scaled_font.descent() + glyph_height;
let sprite_buffer = TextureAtlasSprite {
index: glyph_atlas_info.char_index,
color: self.style.color,
position: caret
+ Vec3::new(
0.0 + glyph_width / 2.0 + bounds.min.x,

View file

@ -42,9 +42,8 @@ fn setup(
.add_entity(SpriteSheetEntity {
texture_atlas: texture_atlas_handle,
sprite: TextureAtlasSprite {
index: 0,
scale: 6.0,
position: Vec3::new(0.0, 0.0, 0.0),
..Default::default()
},
..Default::default()
})

View file

@ -8,7 +8,7 @@ fn main() {
.add_startup_system(setup.system())
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_shader_def_system::<MyMaterial>.system(),
shader::asset_shader_defs_system::<MyMaterial>.system(),
)
.run();
}