-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sprite3d #2814
Sprite3d #2814
Conversation
# Objective Match cases of Sprite + Texture and Sprite + Texture from Atlas. ## Solution Textures for Sprites can either be defined by Texture or TextureAtlas + TextureAtlasEntry. Functionality from former TextureAtlasSprite is split into Sprite and TextureAtlasEntry now.
# Objective Make Sprites usable in 3d space. ## Solution Rename Sprite to Sprite2d and add Sprite3d. Add Example 3d_sprite_pipelined. NOTE: Currently, differences between Sprite2d and Sprite3d and its rendering pipelines are minor. Implementations might diverge to greater extend with future iterations.
# Objective Generalize shared behaviour for Sprite2d and Sprite3d. ## Solution Sprite2d and Sprite3d implementations might diverge to greater extend with future iterations. Make functions and structs generic where appropiate to keep the code base small, temporarily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I wanna say I quite like this. :) The new API is nice and more consistent.
I also like the use of generics, to avoid code duplication, while still being able to "specialize" some functionality for 2d/3d.
I left some feedback for some changes, a few cosmetic things and one thing that seems like a bug/oversight.
@@ -29,20 +29,67 @@ impl Default for PipelinedSpriteBundle { | |||
/// A Bundle of components for drawing a single sprite from a sprite sheet (also referred | |||
/// to as a `TextureAtlas`) | |||
#[derive(Bundle, Clone)] | |||
pub struct PipelinedSpriteSheetBundle { | |||
pub struct Sprite2dSheetBundle { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name reads very awkwardly. Maybe rename the type to SpriteSheet2dBundle instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yap, thats better. Same for 3d as you noted below.
/// A Bundle of components for drawing a single sprite from a sprite sheet (also referred | ||
/// to as a `TextureAtlas`) | ||
#[derive(Bundle, Clone)] | ||
pub struct Sprite3dSheetBundle { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
pub index: u32, | ||
pub flip_x: bool, | ||
pub flip_y: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like how this simplification resulted from including Sprite2d
/Sprite3d
in the sprite sheet bundles. Nice bit of code reuse.
@@ -22,30 +22,19 @@ pub struct TextureAtlas { | |||
|
|||
#[derive(Debug, Clone, TypeUuid, Reflect)] | |||
#[uuid = "7233c597-ccfa-411f-bd59-9af349432ada"] | |||
pub struct TextureAtlasSprite { | |||
pub color: Color, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You said in the PR description that the implementation for sprite color was incomplete, and that's why you removed it. Do you mean that, previously, this field didn't do anything at all?
Just wanna make sure nothing is being regressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yap, it wasn't used anywhere (most notably: not extracted to the render world). Same applies for flipping atm.
pub flip_y: bool, | ||
/// An optional custom size for the sprite that will be used when rendering, instead of the size | ||
/// of the sprite's image | ||
pub custom_size: Option<Vec2>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that Sprite2d
/Sprite3d
is a component inside the sprite sheet (texture-atlas-based) bundles, this custom_size
field should be expected to work for those too.
It seems like it is currently broken, because I did not see this being handled in extract_atlases_{2d,3d}
? You should fix those functions to account for this field, similar to extract_sprites_{2d,3d}
.
P.S: also, I don't understand how sprite flipping is implemented, so I couldn't check that, but it's worth making sure that flip_x
/flip_y
are also handled correctly, for both standalone sprites as well as atlas/spritesheet sprites. Don't forget to test that. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into it. Maybe I've overlooked this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, sprite flipping is not available for the new rendering pipeline atm. But I will also take a look at that.
Edit: flipping is not a property of the ExtractedSprite
type. So it is not implemented currently. It was implemented in the old renderer and will probably be added back soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipping can be achieved in two ways if im correctly. Either swap the uv coords or flip the quad by 180 degrees only in the render world (since sprites are not culled) in the given direction. I don't know whats the proper implementation, though.
} | ||
} | ||
|
||
impl FromWorld for SpriteShaders<Sprite3d> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just leaving a note to say that I haven't looked at this as part of my review of your PR, because I don't understand these rendering APIs well enough to review it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SpriteShaders are basically the same as before. The difference is that in the case of 3d we need to at least declare a depth attachment for the pipeline which the 2d one doesn't have (because no depth in 2d). This is due to how the render graph is modeled.
There is room for generalization/code recycling here. But I dont think this is worth the effort atm. This is only a basic implementation making sprite available in 3d. I haven't added any feature which are possible in 3d now (e.g. normals for 3d lighting which is not possible in 2d) so the pipelines might diverge more with future additions. Just to reason about my decision for the matter of code quality here.
extracted_sprites_res.sprites.extend(extracted_sprites); | ||
} | ||
} | ||
|
||
pub fn extract_sprites( | ||
pub fn extract_sprites_3d( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this code really needs to be duplicated, for *_2d
and *_3d
? The bodies of the functions seem identical, except for the Sprite2d
/Sprite3d
types? Could/should this be made generic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say this would be generic. Now we have extract_sprites<T>
. We query for &T
. How do we access custom_size
, flip_x
or flip_y
of any type T
? So we have to implement a trait Sprite
and use it as bounds for T
. I just didn't find it worth the effort to generalize this if it probably diverges in the future as elaborated above (we might need to extract/prepare data for 3d which we do not for 2d).
I'm going to rewrite once #2642 (scheduled for 0.6) is merged. I'll take into account things pointed out with the current iteration. |
Actually, I am retracting my approval. I no longer think this is a good idea. This doesn't seem like a good direction for Bevy. After some discussions on Discord with @cart and other community members, we came to the consensus that the development direction for bevy sprites should be towards diverging their api and implementation further from 3D, not unifying them / bringing them closer. 2D and 3D should have separate distinct APIs, so that users working on 2D games can have a better experience that feels "native to 2D". We don't want the engine to feel like it was designed for 3D first, or that 2D is a "second-class citizen" hacked together as a special case of the 3D stuff. For example, 2D users shouldn't have to think about 3D rotations and transforms. Bevy sprites might even move away from using the current Be more like Godot, less like Unity. :) Additionally, having completely separate rendering for 2D may also allow for exploring more efficient and performant rendering techniques that are optimized for 2D. Bevy already moved away from drawing sprites simply as quads / 3D meshes. Sprites now have their own separate rendering pipeline configuration and shaders, and in the future, those will likely diverge even further from the 3D stuff. I agree with you that it would probably be nice to have a nice-to-use "3D quads"/"billboards" renderer in Bevy. However, those are not the same as sprites, even though they might seem superficially similar. We shouldn't try to adapt the bevy sprites code to serve that use case. Instead, it should be a separate thing, so that each of these use cases can have nice APIs and implementations that are well-suited. Maybe we should close this PR? |
I agree that the future of Bevy will likely have less overlap between 2d and 3d apis, but I do think its worth pointing out that Godot has a Sprite3d and still maintains a strict 2d/3d separation. |
Strongly agree.
I think I agree with this stance: their use cases and APIs and implementation should be related, but not identical. I think calling them As I understand it, there are actually 3 common patterns you tend to care about in 3D, which I'm giving arbitrary names for now:
I think I'll second this: the existing work and example can be reused (and should be credited!), but I suspect it will be simpler to start fresh than worry about reverting all the renames. |
Closing this out. If you're interested in this work, please check out this PR and give some credit @VVishion :) |
Objective
Make Sprites usable in 3d space.
Closes #2786.
Solution
TextureAtlasSprite
intoSprite
andTextureAtlasEntry
.Sprite
s are bundled with either Texture (Handle<Image>
) or TextureAtlas (Handle<TextureAtlas>
) +TextureAtlasEntry
.Sprite
toSprite2d
and addSprite3d
.SpritePlugin
toSprite2dPlugin
and addSprite3dPlugin
.3d_sprite_pipelined
NOTE: I have not copied the
color
property from the removedTextureAtlasSprite
since it wasn't used and wasn't onSprite
either. I think it's supposed to be onSprite2d
andSprite3d
, but that can obviously added later if needed.