-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Ability to set Transform fundamental native type to f64 or fixed-point types #1680
Comments
this would probably need glam to support avx instructions for f64 types |
When downcasting to I solved this problem by creating my own |
Oh, right, you can just have both position representations on the same entity. That is simple and clever, good point! |
As part of this, we'd want |
Relevant to #1678. |
I completely agree with doing this, lol. Godot is currently trying to do the same thing, so the earlier we do this, the less work we have to do in the long run. I know rapier already does something like this also, so that might be something to look towards |
This is extremely important for deterministic simulations. You can certainly work around it by having other types on a component and syncing the transform, but that's not ideal. Might be worth looking into how nalgebra / nphysics is handling this https://www.rustsim.org/blog/2020/06/01/this-month-in-rustsim/ |
I'd like to chime in support for this. The recent rendering rework seems to adopt separate game/rendering entities concept and should help with the rendering issues. We just have to transform the game world locations relative to some floating " Edit: with rendering done in a completely separate context, I think making the game world default to f64 should be considered. |
This should definitely be benchmarked if we ever decide to do so. Losing widespread support for SSE2 on f32s in both software and hardware, lower cache coherency due to the larger data types, and limited/no support for in both glam and hardware support AVX for f64s may have serious performance implications. |
I'd also like to note my support for this change and my willingness to help with work on this. I have grand plans to use Bevy and I've been meaning to get into helping with development while simultaneously building using the engine. |
I am also interested in 64-bit Transforms! Currently experimenting with a Minecraft server using Bevy, and the math puts |
## Objective A step towards `f64` `Transform`s (#1680). For now, I am rolling my own `Transform`. But in order to derive Reflect, I specifically need `DQuat` to be reflectable. ```rust #[derive(Component, Reflect, Copy, Clone, PartialEq, Debug)] #[reflect(Component, PartialEq)] pub struct Transform { pub translation: DVec3, pub rotation: DQuat, // error: the trait `bevy::prelude::Reflect` is not implemented for `DQuat` pub scale: DVec3, } ``` ## Solution I have added a `DQuat` impl for `Reflect` alongside the other glam impls. I've also added impls for `DMat3` and `DMat4` to match.
## Objective A step towards `f64` `Transform`s (bevyengine#1680). For now, I am rolling my own `Transform`. But in order to derive Reflect, I specifically need `DQuat` to be reflectable. ```rust #[derive(Component, Reflect, Copy, Clone, PartialEq, Debug)] #[reflect(Component, PartialEq)] pub struct Transform { pub translation: DVec3, pub rotation: DQuat, // error: the trait `bevy::prelude::Reflect` is not implemented for `DQuat` pub scale: DVec3, } ``` ## Solution I have added a `DQuat` impl for `Reflect` alongside the other glam impls. I've also added impls for `DMat3` and `DMat4` to match.
Any news on this ? How would I practically switch my game to f64 coordinates, transforms etc. ? |
@LucCADORET I wouldn't hold my breath for something to be done about this soon, so here's what worked for me: I have a very large world and one main actor that the camera is focused on at all times. As you would expect, moving too far away from the physics origin leads to precision loss and undesired behavior. So what I did was to introduce a floating physics frame origin within which all physics calculations happen. So the "global" position is always |
Next step in this space is likely to be #4379, but further work around transform types will be a slow-and-steady design conversation :) |
Actually, my understanding is that As for fixed point, this is the same story, and only helps because non-deterministic instructions are generally floating point ones, which fixed-point calculations don't use. But you can easily make a fixed-point simulation non-deterministic if you're not careful. The statement "we switched to fixed point so we're deterministic" is likely wrong. At best it's rather "we switched to fixed point and the source of non-determinism we had identified is gone". That being said, switching to |
Just to clarify, the ability to better control the underlying type of a transform here would serve multiple discrete goals. Using That said, I don't think |
## Objective A step towards `f64` `Transform`s (bevyengine#1680). For now, I am rolling my own `Transform`. But in order to derive Reflect, I specifically need `DQuat` to be reflectable. ```rust #[derive(Component, Reflect, Copy, Clone, PartialEq, Debug)] #[reflect(Component, PartialEq)] pub struct Transform { pub translation: DVec3, pub rotation: DQuat, // error: the trait `bevy::prelude::Reflect` is not implemented for `DQuat` pub scale: DVec3, } ``` ## Solution I have added a `DQuat` impl for `Reflect` alongside the other glam impls. I've also added impls for `DMat3` and `DMat4` to match.
a possible direction for double precision translations (wrt rendering): https://godotengine.org/article/emulating-double-precision-gpu-render-large-worlds/ |
Would love to see this, I always seem to end up in projects hitting this issue for one reason or another, mostly it's trying to make large maps multiplayer that just ends up making multiple other aspects extra complicated. |
Note that for many applications, using a floating origin can be a very viable alternative, and be both faster and capable of representing much larger differences. https://github.com/aevyrie/big_space is well-maintained and has impressive showcase results: perhaps consider that as an alternative? |
Some prior art context (since it hadn't already been mentioned) As of Unreal 5.0 most parts of the engine have moved from 32 to 64 bit floats for positions, and as of 5.1 the default max world extents were upgraded from 22km to 88m km. Their naming for this feature is large world coordinates (LWC), the linked docs have more information about how LWC interacts with things like shaders and particles which couldn't be fully transitioned. |
One potential way forward on this is to open the space up to allow people to slot in their own This would let you define your own transform type (i.e. with f64s, fixed point values, spherical geometry, or hyperbolic geometry) and so long as the final result is mappable back to a The primary thing needed here is a way to do generic property propagation down the hierarchy that operates on a trait. Like seen in #5673 and related PRs. Footnotes
|
Regarding hyperbolic or spherical geometry, the most natural way to represent them in 3D games requires all 16 entries of the transformation matrix to be manipulable, so the final output would not be mappable back to a |
That would be great and might allow other cases besides f64. |
FYI, that mapping from many different transform types back to |
Yes, hello! We do want to make it easier to use custom transform representations of all sorts, subject to two constraints:
We have a bit of a vague plan, and I'm open to any specific proposals or designs that can operate in that constraint space. |
@alice-i-cecile are those mappings at all related to interpolation, eg for lower physics tick rate but objects still move smoothly at higher render rates. |
Not inherently, but splitting apart gameplay transforms and render transforms is definitely a possible outcome. We should form a working group for this in the 0.15 cycle. See #1259 for the main thread on interpolation in Bevy. |
What problem does this solve or what need does it fill?
For very large game worlds, or for multiplayer games, it can be difficult to work within the floating point confines of f32. Giving users control over the native floating- or fixed-point type that bevy uses for rendering and other position-driven logic would enable for a wider range of potential games and simulations without having to hack through bevy internal systems.
What solution would you like?
Expose a compile-time configuration option that controls the inherent type that bevy uses for its position and transform components in rendering and other related (e.g. audio) systems. In the case of a custom fixed-point solution, this would require a conversion method on the user's part. In the case of f64, in a perfect world, this would use 64-sized SIMD intrinsics wherever 32-sized intrinsics are used for f32. For rendering, at some point in the pipeline, a conversion to f32 is almost inevitable, but objects far enough away from the camera would likely be culled to where precision loss would be irrelevant.
What alternative(s) have you considered?
Separating gameplay entities from rendering entities. Gameplay entities are given a homemade position component using f64/fixed-point values in world space, while rendering entities use f32 in a transformed camera-relative space. This is undesirable because it necessitates a large-scale copy of data from gameplay to rendering entities each frame. On top of that, this copy process is rife with cache misses, as the decision of which entities are close enough to the camera to bother transforming creates an effectively random set of gameplay/render entity links, and each lookup for this process is then a random access.
Not using bevy's transform components at all and rendering manually in batches. This avoids the copy and entity-linking process, but requires a lot of manual work on the user's part to pass over each gameplay entity, determine if it's worth rendering, convert its coordinates into camera-relative space, bin it into proper instances, and send it out for rendering. This essentially recreates, or requires forks of, entire crates like bevy_sprite and such in the process.
Additional context
Not sure how much it matters, but regarding SIMD instructions, SSE up to 4.2 has an adoption rate of at least 98% on the Steam hardware survey, and AVX is just shy of 95%. This covers the bulk of support for f64-sized SIMD intrinsics as far as I know.
The text was updated successfully, but these errors were encountered: