Skip to content

Commit

Permalink
Add dedicated material for texts (#273)
Browse files Browse the repository at this point in the history
* Add `Text2DMaterial`
* Remove front texture from `Default2DMaterial`
  • Loading branch information
Nicolas-Ferre authored Dec 22, 2023
1 parent 6bd09d8 commit c716a50
Show file tree
Hide file tree
Showing 26 changed files with 212 additions and 231 deletions.
31 changes: 3 additions & 28 deletions crates/modor_graphics/res/default.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ struct Material {
color: vec4<f32>,
texture_part_position: vec2<f32>,
texture_part_size: vec2<f32>,
front_color: vec4<f32>,
}

struct Vertex {
Expand All @@ -32,8 +31,6 @@ struct Fragment {
position: vec4<f32>,
@location(0)
texture_position: vec2<f32>,
@location(1)
front_texture_position: vec2<f32>,
};

@group(0)
Expand All @@ -52,14 +49,6 @@ var texture: texture_2d<f32>;
@binding(2)
var texture_sampler: sampler;

@group(1)
@binding(3)
var front_texture: texture_2d<f32>;

@group(1)
@binding(4)
var front_texture_sampler: sampler;

@vertex
fn vs_main(vertex: Vertex, instance: Instance) -> Fragment {
let transform = mat4x4<f32>(
Expand All @@ -68,31 +57,17 @@ fn vs_main(vertex: Vertex, instance: Instance) -> Fragment {
instance.transform_2,
instance.transform_3,
);
let front_texture_size = textureDimensions(front_texture);
let transform_front_texture_ratio = length(instance.transform_0.xyz) / length(instance.transform_1.xyz)
* f32(front_texture_size.y) / f32(front_texture_size.x);
let front_ratio = vec2(
max(transform_front_texture_ratio, 1.),
max(1. / transform_front_texture_ratio, 1.),
);
return Fragment(
camera.transform * transform * vec4<f32>(vertex.position, 1.),
vertex.texture_position * material.texture_part_size + material.texture_part_position,
vertex.texture_position * front_ratio + (vec2(1., 1.) - front_ratio) / 2.,
);
}

@fragment
fn fs_main(fragment: Fragment) -> @location(0) vec4<f32> {
let back_color = textureSample(texture, texture_sampler, fragment.texture_position)
* material.color;
let front_color = textureSample(front_texture, front_texture_sampler, fragment.front_texture_position)
* material.front_color;
let back_alpha = (1. - front_color.a) * back_color.a;
let alpha = front_color.a + back_alpha;
let rgb = (front_color.a * front_color.rgb + back_alpha * back_color.rgb) / alpha;
if (alpha == 0.) {
let color = textureSample(texture, texture_sampler, fragment.texture_position) * material.color;
if (color.a == 0.) {
discard;
}
return vec4(rgb, alpha);
return color;
}
31 changes: 3 additions & 28 deletions crates/modor_graphics/res/ellipse.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ struct Material {
color: vec4<f32>,
texture_part_position: vec2<f32>,
texture_part_size: vec2<f32>,
front_color: vec4<f32>,
}

struct Vertex {
Expand Down Expand Up @@ -34,8 +33,6 @@ struct Fragment {
texture_position: vec2<f32>,
@location(1)
inner_position: vec2<f32>,
@location(2)
front_texture_position: vec2<f32>,
};

@group(0)
Expand All @@ -54,14 +51,6 @@ var texture: texture_2d<f32>;
@binding(2)
var texture_sampler: sampler;

@group(1)
@binding(3)
var front_texture: texture_2d<f32>;

@group(1)
@binding(4)
var front_texture_sampler: sampler;

@vertex
fn vs_main(vertex: Vertex, instance: Instance) -> Fragment {
let transform = mat4x4<f32>(
Expand All @@ -70,36 +59,22 @@ fn vs_main(vertex: Vertex, instance: Instance) -> Fragment {
instance.transform_2,
instance.transform_3,
);
let front_texture_size = textureDimensions(front_texture);
let transform_front_texture_ratio = length(instance.transform_0.xyz) / length(instance.transform_1.xyz)
* f32(front_texture_size.y) / f32(front_texture_size.x);
let front_ratio = vec2(
max(transform_front_texture_ratio, 1.),
max(1. / transform_front_texture_ratio, 1.),
);
return Fragment(
camera.transform * transform * vec4<f32>(vertex.position, 1.),
vertex.texture_position * material.texture_part_size + material.texture_part_position,
vec2<f32>(vertex.position.x, vertex.position.y),
vertex.texture_position * front_ratio + (vec2(1., 1.) - front_ratio) / 2.,
);
}

@fragment
fn fs_main(fragment: Fragment) -> @location(0) vec4<f32> {
let back_color = textureSample(texture, texture_sampler, fragment.texture_position)
* material.color;
let front_color = textureSample(front_texture, front_texture_sampler, fragment.front_texture_position)
* material.front_color;
let back_alpha = (1. - front_color.a) * back_color.a;
let alpha = front_color.a + back_alpha;
let rgb = (front_color.a * front_color.rgb + back_alpha * back_color.rgb) / alpha;
if (alpha == 0.) {
let color = textureSample(texture, texture_sampler, fragment.texture_position) * material.color;
if (color.a == 0.) {
discard;
}
let distance = sqrt(pow(fragment.inner_position.x, 2.) + pow(fragment.inner_position.y, 2.));
if (distance > 0.5) {
discard;
}
return vec4(rgb, alpha);
return color;
}
37 changes: 4 additions & 33 deletions crates/modor_graphics/src/components/material_source.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(clippy::trailing_empty_array)]

use crate::components::material_source::internal::MaterialData;
use crate::components::texture::{INVISIBLE_TEXTURE, WHITE_TEXTURE};
use crate::components::texture::WHITE_TEXTURE;
use crate::entities::module::{DEFAULT_SHADER, ELLIPSE_SHADER};
use crate::{AnimatedMaterialSource, Color, Shader, Texture};
use bytemuck::Pod;
Expand Down Expand Up @@ -300,6 +300,7 @@ impl InstanceData for NoInstanceData {
///
/// - [`Material`](crate::Material)
/// - [`MaterialSync`](crate::MaterialSync)
/// - [`Texture`](crate::Texture)
///
/// # Examples
///
Expand Down Expand Up @@ -334,28 +335,6 @@ pub struct Default2DMaterial {
///
/// Default is [`Vec2::ONE`].
pub texture_size: Vec2,
/// Key of the foreground texture.
///
/// This texture is placed on top of the main texture defined using
/// [`texture_key`](#structfield.texture_key). In contrary to the main texture, the initial
/// aspect ratio is always kept during rendering. For example with a rectangle instance:
/// - Main texture is stretched to cover the whole rectangle, so the aspect ratio might not be
/// kept.
/// - Foreground texture is centered on the rectangle and keeps its aspect ratio,
/// which means the texture might not cover the whole rectangle.
///
/// For example, the foreground texture is useful for rendering a text that should not be
/// stretched.
///
/// If the texture is not loaded, then the instances attached to the material are not rendered.
///
/// Default is [`None`].
pub front_texture_key: Option<ResKey<Texture>>,
/// Color that is multiplied to the foreground texture when
/// [`front_texture_key`](#structfield.front_texture_key) is defined.
///
/// Default is [`Color::BLACK`].
pub front_color: Color,
/// Whether the instance is rendered as an ellipse.
///
/// If `false`, then the instance is displayed as a rectangle.
Expand All @@ -371,8 +350,6 @@ impl Default for Default2DMaterial {
texture_key: None,
texture_position: Vec2::ZERO,
texture_size: Vec2::ONE,
front_texture_key: None,
front_color: Color::BLACK,
is_ellipse: false,
}
}
Expand All @@ -394,15 +371,11 @@ impl MaterialSource for Default2DMaterial {
color: self.color.into(),
texture_part_position: [self.texture_position.x, self.texture_position.y],
texture_part_size: [self.texture_size.x, self.texture_size.y],
front_color: self.front_color.into(),
}
}

fn texture_keys(&self) -> Vec<ResKey<Texture>> {
vec![
self.texture_key.unwrap_or(WHITE_TEXTURE),
self.front_texture_key.unwrap_or(INVISIBLE_TEXTURE),
]
vec![self.texture_key.unwrap_or(WHITE_TEXTURE)]
}

fn shader_key(&self) -> ResKey<Shader> {
Expand All @@ -414,8 +387,7 @@ impl MaterialSource for Default2DMaterial {
}

fn is_transparent(&self) -> bool {
(self.color.a > 0. && self.color.a < 1.)
|| (self.front_color.a > 0. && self.front_color.a < 1.)
self.color.a > 0. && self.color.a < 1.
}
}

Expand All @@ -433,6 +405,5 @@ mod internal {
pub(crate) color: [f32; 4],
pub(crate) texture_part_position: [f32; 2],
pub(crate) texture_part_size: [f32; 2],
pub(crate) front_color: [f32; 4],
}
}
1 change: 0 additions & 1 deletion crates/modor_graphics/src/components/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use wgpu::{
pub(crate) type TextureRegistry = ResourceRegistry<Texture>;

pub(crate) const WHITE_TEXTURE: ResKey<Texture> = ResKey::new("white(modor_graphics)");
pub(crate) const INVISIBLE_TEXTURE: ResKey<Texture> = ResKey::new("invisible(modor_graphics)");

#[must_use]
#[derive(Component, Debug)]
Expand Down
7 changes: 1 addition & 6 deletions crates/modor_graphics/src/entities/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::components::mesh::{Mesh, MeshRegistry};
use crate::components::render_target::RenderTargetRegistry;
use crate::components::renderer::Renderer;
use crate::components::shader::{Shader, ShaderRegistry};
use crate::components::texture::{TextureRegistry, INVISIBLE_TEXTURE, WHITE_TEXTURE};
use crate::components::texture::{TextureRegistry, WHITE_TEXTURE};
use crate::{NoInstanceData, Size, Texture};
use modor::{BuiltEntity, EntityBuilder};
use modor_input::InputModule;
Expand Down Expand Up @@ -60,11 +60,6 @@ pub fn module() -> impl BuiltEntity {
))
.child_component(Mesh::rectangle())
.child_component(Texture::from_size(WHITE_TEXTURE, Size::ONE))
.child_component(Texture::from_buffer(
INVISIBLE_TEXTURE,
Size::ONE,
vec![0; 4],
))
.dependency::<PhysicsModule, _, _>(modor_physics::module)
.dependency::<InputModule, _, _>(modor_input::module)
}
Expand Down
Binary file modified crates/modor_graphics/tests/expected/shader#default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified crates/modor_graphics/tests/expected/shader#ellipse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 0 additions & 9 deletions crates/modor_graphics/tests/integration/shader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,6 @@ fn textures() -> impl BuiltEntity {
))
.with(|t| t.is_smooth = false)
.with(|t| t.is_repeated = false)
.child_component(Texture::from_path(
FRONT_TEXTURE,
"../tests/assets/no-border.png",
))
.with(|t| t.is_smooth = false)
.with(|t| t.is_repeated = false)
}

fn instance(is_ellipse: bool) -> impl BuiltEntity {
Expand All @@ -159,8 +153,6 @@ fn instance(is_ellipse: bool) -> impl BuiltEntity {
.updated(|m: &mut Default2DMaterial| m.texture_key = Some(BACK_TEXTURE))
.updated(|m: &mut Default2DMaterial| m.texture_position = Vec2::new(0.5, 0.))
.updated(|m: &mut Default2DMaterial| m.texture_size = Vec2::new(0.5, 1.))
.updated(|m: &mut Default2DMaterial| m.front_color = Color::RED)
.updated(|m: &mut Default2DMaterial| m.front_texture_key = Some(FRONT_TEXTURE))
.updated(|m: &mut Default2DMaterial| m.is_ellipse = is_ellipse)
}

Expand Down Expand Up @@ -204,7 +196,6 @@ impl MaterialSource for CustomMaterial {
}

const BACK_TEXTURE: ResKey<Texture> = ResKey::new("background");
const FRONT_TEXTURE: ResKey<Texture> = ResKey::new("foreground");
const CUSTOM_SHADER: ResKey<Shader> = ResKey::new("custom");
const CUSTOM_SHADER_CODE: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
Expand Down
50 changes: 0 additions & 50 deletions crates/modor_graphics/tests/integration/z_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,31 +97,6 @@ fn create_for_transparent_texture() {
);
}

#[modor_test(disabled(macos, android, wasm))]
fn create_for_transparent_front_texture() {
App::new()
.with_entity(modor_graphics::module())
.with_entity(texture_target(0, Size::new(30, 20), true))
.with_entity(transparent_blue_front_texture_rectangle(-0.09, 0))
.with_entity(transparent_blue_front_texture_rectangle(0.03, u16::MAX - 1))
.with_entity(transparent_green_front_texture_rectangle(-0.03, 1))
.with_entity(transparent_green_front_texture_rectangle(0.09, u16::MAX).component(Marker))
.updated_until_all::<(), Texture>(Some(100), wait_resource_loading)
.assert::<With<TextureBuffer>>(1, has_component_diff("z_index#transparent_texture", 10, 1))
.with_update::<(), _>(|i: &mut ZIndex2D| *i = ZIndex2D::from(u16::MAX - u16::from(*i)))
.updated()
.assert::<With<TextureBuffer>>(
1,
has_component_diff("z_index#transparent_texture_reversed", 10, 1),
)
.with_deleted_components::<With<Marker>, ZIndex2D>()
.updated()
.assert::<With<TextureBuffer>>(
1,
has_component_diff("z_index#transparent_texture_reversed", 10, 1),
);
}

fn opaque_blue_rectangle(position: f32, z_index: u16) -> impl BuiltEntity {
rectangle(position, z_index).updated(|m: &mut Default2DMaterial| m.color = Color::BLUE)
}
Expand Down Expand Up @@ -161,31 +136,6 @@ fn transparent_green_texture_rectangle(position: f32, z_index: u16) -> impl Buil
.with(|t| t.is_smooth = false)
}

fn transparent_blue_front_texture_rectangle(position: f32, z_index: u16) -> impl BuiltEntity {
let texture_key = ResKey::unique("transparent-green-texture-rectangle");
rectangle(position, z_index)
.updated(|m: &mut Default2DMaterial| m.front_texture_key = Some(texture_key))
.updated(|m: &mut Default2DMaterial| m.front_color = Color::BLUE)
.updated(|m: &mut Default2DMaterial| m.color = Color::INVISIBLE)
.component(Texture::from_path(
texture_key,
"../tests/assets/transparent-texture.png",
))
}

fn transparent_green_front_texture_rectangle(position: f32, z_index: u16) -> impl BuiltEntity {
let texture_key = ResKey::unique("transparent-green-texture-rectangle");
rectangle(position, z_index)
.updated(|m: &mut Default2DMaterial| m.front_texture_key = Some(texture_key))
.updated(|m: &mut Default2DMaterial| m.front_color = Color::GREEN)
.updated(|m: &mut Default2DMaterial| m.color = Color::INVISIBLE)
.component(Texture::from_path(
texture_key,
"../tests/assets/transparent-texture.png",
))
.with(|t| t.is_smooth = false)
}

fn rectangle(position: f32, z_index: u16) -> impl BuiltEntity {
instance_2d(TEXTURE_CAMERAS_2D.get(0), Default2DMaterial::new())
.updated(|t: &mut Transform2D| t.position = Vec2::new(position, position))
Expand Down
1 change: 1 addition & 0 deletions crates/modor_text/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rust-version.workspace = true

[dependencies]
ab_glyph.workspace = true
bytemuck.workspace = true
modor.workspace = true
modor_graphics.workspace = true
modor_resources.workspace = true
Expand Down
Loading

0 comments on commit c716a50

Please sign in to comment.