#big_space
1 messages ยท Page 2 of 1
At that distance, you would likely use imposters.
Or bake the skybox when travelling. I think this is what Elite:Dangerous does
you're saying I could really spawn all my stars and planets at the same time?
without streaming?
and then swap meshes based on distance
Sure. It's just a matter of optimization, your perf budget, and how much time you have.
LODs already exist in bevy, so this is already easy to do
that's encouraging
do you maybe have an advice for rendering these giant upclose planets? sure it's supercool they're the real diameter, but .. doesn't that mean lots of triangles for GPU to handle? like really lots
is that something Bevy can also automatically LOD somehow
or would I need to chop planets into distinct renderable bits
to not render the back side of the planet for example
This is what my dynamic LOD planet in #showcase is! When you're far away, it can be as few as 20 triangles, but when you're on the surface, you get sub-meter resolution
So I can have a whole solar system full of planets with no perf impact at all (in practice I despawn them completely when they're too far away to see)
For stars in the sky, the plan is to bake them since you can't move between systems fast enough to see them moving
But you could also use billboards or something for very far-away stars so each one is just a single triangle, then batch them
With that approach I could see you easily hitting millions of stars without setting the GPU on fire
yup just looked at it. The explanation melted my brain a bit, but at least I already know it's doable. Alright, so Bevy definitely doesn't subdivide out of the box
How does your approach compare to what someone else suggested elsewhere - modifying the mesh vertices in a compute shader?
Or is that too complex and hardcore by comparison
Hmmmm I wouldn't actually know where to start on that one, unless you're doing double-precision in the compute shader. In that case I imagine it'd be a lot like my impl but with GPU acceleration (I'm not really seeing performance problems, but I'm also being very conservative with the resolution). If they're talking about something more complicated, it's a little above my pay grade at the moment.
That said, I was planning on making the repo with my planet generator public once it's cleaned up a bit. I'm happy to ping you once I do if you're interested in looking through it
If you are doing all terrain gen on the GPU, you still need to pass it back to the CPU to do physics and stuff
You don't necessarily have to pass it back. You might not need the same resolution for physics, so maybe you'd just have the same algorithm run on both CPU and GPU, but run more iterations on the GPU
I'm looking into implementing an octree structure with big space which i assume you're doing
Would you be willing to share some insight into how you got it working?
Are your nodes all entities ?
I'm not building an octree actually! The closest thing I have is my sphere volume hierarchy, but that's not quite what you're wanting probably. I have considered writing an implementation before, but I was waiting on something like the relations impl coming in 0.16, that way you can create a relationship component where every entity tracks its parent octree cell, and every octree cell knows exactly what entities are in it. For that you probably could use entities as nodes, but since I haven't written the impl, I'm not sure what roadblocks you'd hit.
@celest obsidian's voxel planet does use an octree I believe, I'm sure they'll have better information for you
Also: why no threads in posts Discord ๐ฉ
Hmm interesting. The lod changes in your method are very similar to an octree. Is it homebrew or are there any papers out there describing your method?
What about it is different from octrees, advantages/disadvantages?
Also yes @celest obsidian if you have any insights you are willing to share I would be grateful ๐
It's fully homebrew, but it's not particularly complicated: the sphere starts as 20 meshes at the lowest LOD. Each mesh is its own entity, and I put a bounding sphere around each that's 1.5x as big as it needs to be to contain it. When the player enters the sphere, I hide the mesh and spawn four child meshes, each with their own bounding spheres. When the player leaves a bounding sphere, I make the parent mesh visible and I despawn its children.
The source is here, but I warn you, it's not done yet. I'm working on adding noise octaves right now, and there are a couple places (notably mesh generation) that I've cleaned up but haven't pushed yet
Oh I forgot to add a license before I made it public, but I just did that. It's MIT/Apache-2.0, so go ahead and do whatever with it!
I use slotmap to store my octree. I used to use nodes as entities, but there were so many nodes in my octrees that Bevy was lagging. Even entities without rendering components were dropping my FPS, but that's been fixed for a while IIRC. I might try to make the nodes entities again, taking into account the future relations features coming.
I love slotmap
Me too, it's very easy to use
I'm actually surprised nodes-as-entities was killing your framerate. If you try again with relations, I'll be interested to see how it goes!
I just think it was because even simple entities with a marker component lowered the FPS after ~10,000 entities. But now we can reach more than tens of millions without any issue.
Ok, I had forgotten at what number of entities it starts to lag. I slightly underestimated that number. I did this test a long time ago
-1000 FPS for 1M entities at the start
Wow yeah that tanks surprisingly fast. Does it stay low even if you stop adding entities?
I guess this was a while ago
yes
but now it's no longer a problem, at least not when I did a test in october
Oh nice! Yeah I wouldn't really expect performance hits just having entities around, glad it's resolved
i've just been using .as_ref() and .as_mut() explicitly
Sounds like the slotmap thing is a more cache friendly version of HashMap? Or is there more to it?
...except you don't get to choose keys
It's more like a stable, generational Vec
Stable meaning that, with a Vec, if you remove an element, the others might bounce around. You can't rely on an element staying at index 5, for example.
And generational meaning that it'll reuse memory. If you remove an element at slot 1 for example and then insert a new element, it might go in slot 1. But they keys store generations on them so they don't get confused in the map
Meaning even if they reuse the same slot, they won't reuse the same key
Honestly just play with it. It makes a lot more sense that way than my explanation ๐
It's a fine explanation, thanks
ah, okay so you're not creating the actual octree with entities, but the leaf node meshes are still entities right?
My issue, which might be a misunderstanding of the use of big_space, is that when i try to split my node i get precision errors.
I know that when spawning entities or placing the absoloutly, i should be doing so through the grid struct. However, i'm unsure of what the best way to get the nearest Grid of an entity is. My first thought was to loop through the parents until i find one, but it doesn't feel very clean.
what reference frame is the entity in?
-# may be the wrong terminology
You can convert double precision to a grid cell using translation_to_grid and a couple other useful helpers
A component that defines a spatial grid that child entities are located on. Child entities are located on this grid with the GridCell component.
It just means your octree might have to be in double precision all the way until you finalize it into the hierarchy. That's how my giant planet works: I compute meshes and mesh offsets in double precision, then convert it at the last moment to f32 for bevy, but by that point everything is in a grid, so precision stays good
Yeah i've read about that in the docs, my issues is finding the correct parent grid
Do you know of an easier way of accessing the parent grid entity of an entity than iterating parents until i find one ?
Grids:
/// Get the ID of the grid that `this` `Entity` is a child of, if it exists.
#[inline]
pub fn parent_grid_entity(&self, this: Entity) -> Option<Entity> {
?
Yes!, Thanks!
You shouldn't need to iterate, it will just be the parent
if it isn't the parent, it isn't an entity that lives in a grid anyway
What i'm trying to build is an octree where each node splits into eight child nodes, and it is these child nodes i'm attempting to place correctly within the parent node.
This was fairly easy to do outside of big space, but i'm running into issues placing the child nodes, is that because each node itself should also be a grid for its children ?
You don't need to nest the grids, no.
Calculate their position in double precision and set their cell and transform.
must they all be direct children of the grid?
If you want high precision rendering, yes.
Otherwise you will be using bevy's built in Transform propagation limited to f32
You can also just use f32 for everything, and simply set the Transform of all your child entities, with the same parent. The GridCell will be computed for you automatically. There will just be some precision loss compared to using f64, though it depends on your use case if that matters or not.
I haven't tried integrating myself yet, but I'm not sure whether Rapier or Avian are fully compatible with BigSpace, would be good to know
In broad strokes, would you recommend hacking either of them for support, or would it be easier to roll my own physics for whatever small scope I might need?
You could probably hack something together
There is already an implementation for avian floating around
Doing it "right" will take more effort though
sad
i can do it though
how do i spawn an entity in the root_grid outside of the original root_grid definition? Every single instance of an entity being spawned in the examples happens in the setup and not in an update?
the general logic is: https://gist.github.com/motgenror/bed91ee62874983ce742589d9fe2c875
Included my convenience wrapper in the gist
@mighty crescent Is there a way to force big_space to update an objects translation-gridcell coordinates? Like how it does automatically between frames when you 'push' it out of a gridcell. Or should I calculate and directly set its gridcell myself?
Meaning - if I update its transform many times during a single frame, the translation will blow up really big - and may have crossed gridcell boundaries.
#1171171694526869554 message
Right but this is relevant to the origin not the previously occupied GridCell?
Mostly just wanted to confirm that there wasn't any other way to handle this case.
You can add grid cell indices. This can be used relative to your current position as well.
Can you treat cell xyz like global transform translate? Look_at a cell's xyz, for example?
translation_to_grid is exactly for this case
@mighty crescent kind Sir, the hierarchy validator doesn't like having a Bevy UI Node in the root grid. Is there really a reason to deny this state of things? I'm trying to place a UI Node on a 3d object deep into the BigSpace hierarchy, to map parts of UI to 3d objects in space, and the UI nodes themselves don't want to be detached from a Node hierarchy, i.e. they want Nodes to be present all the way up to the root as I understand. But BigSpace is against that.
If it's located on a grid, it needs a grid cell
But bevy UI probably expects the UI node to be in a non-big space anyway
Why are you trying to add a UI node to a 3d entity? The types are the same, but UI transforms have different semantics
https://pastebin.com/4SNVWrYp after slapping Node on the root grid itself
for convenience of querying, nothing more. I want to render a 2d border around every planet in the 3d world, I thought adding Node to the planet entity itself is handy
Bevy UI doesn't play nice with mixing UI and 3d transforms, I'd recommend against it
oh
@umbral ledge usability data^
man this task of simply drawing a 2d rect around 3d objects is not as simple as I thought
It's super easy in immediate mode ui
Billboarding please T_T
Wouldn't really help here
(I would implement it myself but my rendering skills aren't good enough)
Couldn't you do a transparent billboard?
This is more like having an immediate canvas api
Hmm, okay
well yeah I thought so, so I took Gizmos and tried that
but Gizmos is really weird, it doesn't want to play nice with my 2d screen coordinate. The game window is 3840 pixels wide, but the 2d rect gizmo is getting positioned at the edge of the screen as soon as it hits x=300, I just can't understand why, how to adjust it properly, ngghh
You need to draw a rectangle that bounds a 3d object
@umbral ledge this is exactly what I mean about needing a canvas api
Basically eguis painter
Tbh, I would probably reach for egui here
and mix egui with the rest of the ui being bevy ui? it's probably better than nothing, but..
In other words, "gizmos" with screen space support
Probably not, then
hehe
I'll try moving those nodes to the root of the hierarchy.. hope it works this time
thanks
Sorry it isn't easier
Is there a simple way to draw gizmos with big space? ๐ค
you mean 3d gizmos?
oh hmmmmmmmmmm what the heck was I doing before...
My brain is fried sorry guys ๐
I should be asleep right now probably
@mighty crescent now that I have hundreds or thousands of spaceships spawned, I wanted to ask about adding a Grid<i64> on each of them. Currently I do simply because my camera has GridCell and I want to easily reparent it between spaceships. But I don't actually need a grid, let alone an i64 grid on each spaceship. Would you say these QOL ship grids are inconsequential and don't really cost anything?
There is a cost to propagation, but if it doesn't show up in a profile then I wouldn't worry about it
If the camera isn't far from its parent, you wouldn't need a grid though right? Propagation would cost about the same for low-precision hierarchies and high-precision
(well technically probably less for low-precision but probably sixes I'd think)
can't reparent a camera from grid to a non-grid entity, that's the problem
like your planetary system got a grid, and a camera can live in that grid. then you want to attach it to a specific object within that grid, so that object ought to have a grid, otherwise BigSpace validator freaks out
so you'd need to remove/add camera gridcell depending on where you want the camera, which is um, whats the word, clunky
Ahhhhhhhhhhhhh makes sense!
Course that still means all your grids need the same precision
If your solar system has a Grid<i64> but your spaceships have a Grid<i8>, you'll run into similar problems
yep, that too
That's only if you put the floating origin on the camera
There's no reason you can't move the floating origin to the ship itself, which is already in a grid.
is everything running smoothly? I know I had some problem when I tested it a long time ago
Yeah, it seems way, way better than the last few times I've used it. I think I might actually stick with it this time.
interesting, I'll probably also try RustRover again to see if it suits me now
Plus, you can add icons and colors to projects, which is clearly the most useful feature
Might have to give it another try myself
I won't have much time to work on this today, but I did some investigation last night and this morning.
My plan is to add a physics simulation context entity that handles physics at a partition granularity.
This seems pretty easy to do with rapier, because it is built as a plain old rust struct that I can call a method on to step the simulation or update the simulation objects.
In a client server setup, the server would tell the client the location of all relevant physics contexts and entities for local prediction.
The physics contexts can all be simulated in parallel because they do not overlap.
Syncing the results between the two is an open question, but my plan is to let the physics context "own" entities, and update their position relative to the physics context's cell using just Transform, and let big space handle the position if it gets too large. Syncing positions from the ECS back into the physics simulation isn't something I've thought about too hard though.
@celest obsidian @worthy vector any complaints if I change GridPrecision to a feature instead of a generic? At this point it just seems like a footgun to me, and isn't actually useful to have different grid precisions in the same binary.
All of those generics would disappear, and you would instead choose it with a feature. I'd probably use i64 as the default.
Personally, I don't use multiple grid precision at once so moving from using generics to features is not a problem for me
Out of curiousity, what do you use?
Which grid precision I use? i64
I created type aliases to use this precision everywhere in my code
Yeah that makes sense to me. Nice to not have to keep track of the generics. Literally what I do right now is I type alias P to i64 and just use P everywhere. That's basically the same as a feature
Also i64 is what I use as well. That seems a really good default to me
The only downside is that for people using multiple grid precision, they now have to use the highest common precision. Honestly doesn't seem like a horrible trade-off to me
Yeah, and mixing precision is already going to cause bugs if you aren't being diligent.
Okay, thanks for the input!
๐ซก
could do an odd overengineered version, with the exported Grid, etc being premade type aliases chosen by feature
that ends up sounding pretty simple, but the indirection might be odd
Ended up with
#[cfg(feature = "i8")]
pub type GridPrecision = i8;
#[cfg(feature = "i16")]
pub type GridPrecision = i16;
#[cfg(feature = "i32")]
pub type GridPrecision = i32;
#[cfg(feature = "i64")]
pub type GridPrecision = i64;
#[cfg(feature = "i128")]
pub type GridPrecision = i128;
#[cfg(not(any(
feature = "i8",
feature = "i16",
feature = "i32",
feature = "i64",
feature = "i128"
)))]
pub type GridPrecision = i64;
This seems to work better than using a default feature, because it means you can run with features=i8, and you don't need to disable default features. That also means the examples that rely on a certain precision can specify this, and have the same feature ergonomics.
Removes a ton of sigils, and reduces total line count. Big W.
Fairly new to big_space so forgive me if this is a silly question
If I have a grid precision of i16 and I wanted to make an area more precise and using multiple grid precisions is risky as you've mentioned. Should I change the grid precision globally?
Or thinking about it now, would I just make a smaller sub-grid?
Then that way I get more precision at the same grid precision
Is that how that works or am I misunderstanding
grid precision is how many grid cells there are, you want smaller cells
there's a pretty relevant example with increasing and decreasing -ly sized spheres
As mentioned, the grid precision is the amount of bits available to index into the grid. If you want to have smaller error tolerances, you need to make your cells smaller. That is the only variable that affects the amount of floating point error.
Gotcha, makes sense, thanks!
I'm still working my way through the examples but good to know!
One little suggestion, something like this would be neat to make diagnosing simpler in the unlikely event that incompatible features are enabled together
I had this initially, but it didn't seem necessary. If you enable multiple of these features, it will result in a compile failure anyway.
When there is a conflict, choose one feature over another. The cfg-if package can help with writing more complex cfg expressions.
This is an interesting idea.
I could nest the compile time features, so that the GridPrecision is the highest precision enabled. E.g. if you have i8 and i64 enabled, the GridPrecision will just be i64.
So it is "additive" in the sense that you can only add precision by adding features.
Simple solution: no features is i8. Then we add features x2, also_x2, another_x2 and last_x2. If you want i64, you enable three of the x2 features. If you only want i16, you only enable one of them. i128 you enable all 4 /j
My thought process was that if a beginner accidentally enables incompatible features, they might not be able to diagnose easily what is wrong. But of course cargo could actually be already helpful there, but I assumed it probably isn't
I think that's a reasonable way around this!
I would prefer if the default, no feature state, was i64 though. I'd rather the default be the most common case.
- no features: i64
- i8: i8
- i8 + i32: i32
I'm personally not a fan of this, but there's also the possibility of doing what Rapier does; different crates for the different types
I definitely don't want to add the overhead of multiple crates. What properties of this don't you like?
As far as I can tell, it follows the "additive" model for features. If two crates need different levels of precision, you should use the maximum, and you can fulfil the needs of both.
Maybe instead of no features, i64 should be a default feature. That would be more idiomatic.
I meant to say that I'm not a fan of having multiple crates, sorry if that wasn't clear! I like the solution you proposed, as you said it seems to follow recommendations from the cargo book and I that it makes sense conceptually
What happens if no-default-features is true in that case?
Lots of compilation errors
I don't think it would be crazy to document that you need to select at least one precision to build.
Most users won't hit this, my impression is that turning off default features is usually reserved for people who want full control of the features/deps they turn on, and that often comes with understanding what is needed on a per-crate basis.
Going this route, adding a compile error macro with a note when no precision feature is enabled would be helpful.
hmmm
I guess the problem and the reason I avoided this was that if you add the crate and specify i32 or lower, it will end up using i64, which would be very confusing. So maybe default features really are harmful here.
Yup, that doesn't sound like behaviour you'd want. Your first proposition of i64 being the default when there are no features sounds better knowing that
This is a good practice
@mighty crescent got a recommended route for using big_space on main bevy? Currently I'm thinking of just vendoring it solely to adjust the Cargo.toml and apply patches, which seems like the correct approach
That's pretty much it, yeah.
Ideally, make a branch of the crate and open a PR so others can use it, and we can use as a starting point for the next release

usually just means one of the systems has a non-SystemParam param
yea just a matter of "which??"
use a .chain() on each
found it, yippee
https://github.com/aevyrie/big_space/pull/42 for posterity
@mighty crescent boo, i'm back
is there a correct way to get the position of one object relative to a specific other object
(with the assumption that those objects are "relatively close" within the overall world space and as such the result is representable as Vec3)
(and I understand that this operation Can be very expensive if the two objects are very far apart in the hierarchy)
What is "relatively close" for you? You could just take the two global transform and do the diff of the two translation. But if you mean a stable relative position I think you would have to do operations on grid transform
within a few hundred units tops is "relatively close" here
so yea ig the global xform should Just Work?
I think so. For a few hundred units there will be no floating point precision errors in the difference of the two global translations
Yup
gotcha
Sorry for the ping, I'm saving this comment for later
Do I understand it right that big_space comes with spatial hashing built in? So for collisions, you could just query for ships in your cell plus adjacent cells which you can easily get by manipulating the cell's coordinates I guess
btw, if you click on the trippy screenshot in the repo's readme, it gives 404 instead of loading a larger version of the image
and - uh oh - the link embeds a JWT
that's just an image uploaded to gh... huh
yup
idk, for me the image is a link that leads to https://private-user-images.githubusercontent.com/2632925/401431930-cff0c58e-766c-41a0-92f7-de174807e447.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDE0ODE3NjksIm5iZiI6MTc0MTQ4MTQ2OSwicGF0aCI6Ii8yNjMyOTI1LzQwMTQzMTkzMC1jZmYwYzU4ZS03NjZjLTQxYTAtOTJmNy1kZTE3NDgwN2U0NDcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDMwOSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAzMDlUMDA1MTA5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzQ4ZTgzMjIyYzBkMTFmMWQ4NDRhMmQxN2RmOWIxY2EzZjFjYjY0OTU4NjRkZjQ1OGI4ZThmM2QxZGU1OTkyOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.6y7X3xT1mT5pOerS3Yx5eEYS6qN4RU-eLv8Sfef_hVw and it gives 404
It's still roughly the same url, but now it loads, I'm guessing because the JWT isn't expired yet
gonna save it to local filesystem while I can ๐
Did big_space use to have a type called BigPosition? I wasn't able to find it in docs, including going through some older docs, but both ChatGPT and Claude keep conjuring that type up like it's a real thing.
use big_space::{BigPosition, BigVec3, CellManager};
very bizarre
Nope
so weird.. why would they hallucinate the exact same thing, and not hallucinate for anything else I've been querying them for. oh well
I'm guessing they can't because "grid" is in the name, but can grids and gridcells be shapes other than cuboids?
Like if we have a planet, can we make a gridcell a sphere that's slightly bigger than the planet?
I'd like to use it as faux collision mesh of sorts so I can query for all entities within the planet's atmosphere
A grid is a coordinate system that tracks x, y, and z values. The question doesn't make much sense in that context.
If you made the gridcell the size of the planet, you would lose the entire advantage of cells in the first place.
Perhaps I'm using the wrong term
@mighty crescent so when working with the lib, does every parent in the hierarchy need to be a Grid or is having low-precision parents acceptable
Only if you want it to be high precision.
Otherwise it is a normal bevy 32bit hierarchy
if your entity's got a GridCell on it, then it has to be under a parent with a Grid
which makes camera clunky to reparent.. say if you wanted to attach it to different planets, objects in space. all these objects will have to have their own Grid on them
unless I'm missing a simpler solution
If you are reparenting, then you already need to recompute your transforms.
not sure what you mean by that? I'm mostly referring to the semantic mismatch: you create grids when you want nested space. Adding grids everywhere just for the ease of reparenting your camera easily feels like going against what the Grid component was designed for. maybe I'm wrong
(For context) This question came up because I was unsure how to actually use the API to conveniently spawn stuff in a grid-aware manner. I noticed that Grids doesn't have any "recursive" APIs AFAICT if I want to get the "first grid + grid cell up the hierarchy". Are there any helpers like that that we're overlooking or do I gotta bring my own (not that it's very hard)?
(The use case here is a simple "spawn a new entity at position of another entity without assuming that entity is GridCell")
I'm saying that just slapping a new parent on the entity isn't enough if you want to reparent without yeeting off into space, whether you are using big space or bevy transform.
You need to compute your new component values anyway depending on your new parent, so it shouldn't be any more onerous to also decide what to set the cell to. If the parent has no grid, the cell shouldn't (?) do anything.
if the parent has no grid and your camera has a gridcell, Bevy crashes with an archetype validation error, that's the problem I'm highlighting
so I just put Grid on everything I want my camera to be able to teleport to, even if I don't really need any precision subspace
just to satisfy the validator
it's not a big deal I guess, just feels hacky
Sounds like a bug in the validator then.
The validator is just a linting tool though.
It's not required or anything like that.
It should probably be a warning though. If you have a cell on an entity not in a grid, 99% of the time it really is a mistake that needs correcting.
that's an interesting point
maybe tweak the validator (give it a param?) to ignore these checks/warns for entities with a Camera on them
or is camera required to be under a grid parent because it's a floating origin?
The floating origin is whatever entity has that component
And that definitely needs to be a child of a grid.
Is there a visual representation of how the big space, grid, entity hierarchy looks? I've been reading the docs but I'm struggling to get it to stick
grid
\- gridcell (0,1,0)
\- transform
\- gridcell (2,3,4)
\- other transform
\- nested grid, also with transform
then entities are moved between gridcells when one of their transform's translation coordinates exceeds some absolute value
the gif on the crate's main pages shows two entities, one moving, in gridcells on a grid
High precision only. If an entity has a GridCell it must have a parent Grid:
(BigSpace, Grid)
(GridCell, Transform)
(GridCell, Transform, Grid)
(GridCell, Transform)
(GridCell, Transform, Grid)
You can add low precision Transform-only hierarchies wherever
(BigSpace, Grid)
(GridCell, Transform)
(Transform)
(Transform)
(GridCell, Transform, Grid)
(GridCell, Transform)
(Transform)
(Transform)
(GridCell, Transform, Grid)
tbh, for most cases, you probably don't need to nest grids, you can keep it really simple and use only Transform after the first level:
(BigSpace, Grid)
(GridCell, Transform)
(GridCell, Transform)
(Transform)
(Transform)
(GridCell, Transform)
(Transform)
(Transform)
(GridCell, Transform)
yeah that's way better than mine
What would be an example of a case where you would nest grids? Like if you had a "grounded"-like game where you want to shrink to really small in an area?
I saw someone mentioning having a spaceship you can go inside having its own grid within the parent solar system or galaxy grid
But I don't know if that was because it was nice to have or if it was needed for precision
If you need transform propagation, and the subtree of transforms needs high precision. The classic example is a planet moving about a star needs high precision, and if you want to walk on the surface of the planet and move with the planet you will need a high precision child grid because the surface of the planet is very far from its center.
For the space ship example, unless the ship is huge, you can just use normal Transforms.
The only time you need to reach for a grid is if the x/y/z coordinates become very large in your current reference frame.
If you are on a ship, you will likely always be within ~100 meters from the center of the ship, so the 32 bit Transform is just fine. If you are on an earth-sized planet, you will be 6,000,000 meters from the center of the planet, and Transform alone will not give you enough precision.
Ah ok, I think that's what I was thinking of the other day in this message
That makes more sense then
So in my example I would have a grid for the "galaxy", then a grid inside of that for the solar system, then a grid inside of that for the star and planets
Sure
Then when a person walks on the planet they would need a gridcell
As it'll need high precision
yup
Ok that's starting to make sense now
You can also flatten the hierarchy and have everything in the same grid.
But nesting grids makes it easy to move all entities inside that grid as one.
Right, so in that case I'd just need to make sure I was using a high enough precision right?
For the one grid
Yup
If you are using i128 there is going to be more precision than you could ever possibly use
Yeah, I think the highest I'd ever go is i64
Appreciate you taking the time to clear that up for me! Thank you!
Is there an example that sets up the big_space hierarchy without using the helper methods? I'm trying to add entites in separate functions but I'm unable to query for the root grid for some reason
probably just insert a gridcell and set the parent to a grid
and the root grid might have to have BigSpace on it manually
Yup. Same as normal bevy parenting really.
Ok then I should have that setup correctly. I'm just unable to query for the root grid/big space entity inside a system
I'll keep trying
Even when I put a normal custom component and query normally it's complaining
Thought it was working, was just giving me a complier error before the runtime panic from single
Ran it with query instead of single and it says 0 found
With the new Requires component system in .15, should the BigSpace component require GlobalTransform?
Ok I've figured it out and it's just me being dumb. Ignore me!
what was it, specifically?
I was creating the BigSpace in a Startup system and querying for it in a different Startup system
Which meant it didn't exist when querying as they were either running in parallel or running in inconsistent ordering
I've moved the BigSpace Startup system to PreStartup and the queries are running smoothly now
You need to make sure your systems are ordered relative to each other. Commands are applied at sync points between systems.
I think maybe at real-scale distances the point lights aren't working properly. The light range and falloff seem perfect, but objects seem to have trouble obstructing that light, for example if my spaceship is behind a planet that's blocking the sun, the spaceship will still reflect light instead of being in total dark. I was told this may be how shadows behave. Is there a common solution to how to deal with that at bigspace distances?
Directional light doesn't seem like a good fit at all, because it doesn't have the falloff
Directional lights and manually computing the falloff yourself is the answer I believe
at these scales no commodity lighting engine is going to work ootb, you need to be a little clearer to the engine about what you want
I just watched an explanation on how shadows work and I think JoshValjosh was right - it's the limitation of shadow mapping. The obstructing object isn't even visible on the depth map. How would directional light help with that?
Sounds like CSM or PSSM is a solution
I'm curious what will end up working. I've thought of a could different solutions, and they either turned out not to work or else I don't much like them.
How are people handling textures on planet sized models?
Procedurally generated simple textures?
at those scales, you'd want a directional light and to manually implement obstruction using a light texture (i.e. what https://github.com/bevyengine/bevy/pull/18031 implements)
anything large enough to cast a shadow at planetary scales is large enough said shadow can be approximated as something infinitely long
(note: you probably need something more clever for multiple shadowcasting bodies, but the fact it has to be done manually stands)
You want a directional light
And computing the values for intensity manually
(physically dividing the space with a plane or approximation of the body curve that shades everything 'below' it in depth might do it)
Shadows work using that method.
At planetary distances, the sun is a directional light, and isnt going to suffer from the precision or perf issues of a massive point light
You will probably need one directional light per star-planet pair in the current system, and use render layers.
Interesting, thanks
Anyone have any idea what the best way to pass the cellgrid offset and precision type to a vertex shader is?
Getting the above on my materials, whether it's a standard material with a texture or a vertex shader
Seems to be due to the planet sized mesh, as there's no issue when I test on a 100m diameter mesh, so I think I'm going to have to break up my mesh into a bunch of smaller meshes, which is probably a good decision anyway if I wanted to use meshlets
But I was hoping to avoid splitting the mesh and somehow find a way to keep the mesh whole
I'm screwing around with something right now. Mostly procgen but I really want to be able to generate repeating image noise over the planet as well. I'll let you know if I figure anything out
Also just wanted to pop in to say that it's wild that bevy is flexible enough that a 3rd-party lib can completely replace its transform system and have most everything "just work"
You generally want all rendering code to use the GlobalTransform. The entire point of the plugin is to keep that value small enough to avoid issues with rendering. ๐
Yeah, you will need to do this, or you will have scaling issues on the mesh, this plugin cant fix that.
Yeah, even though the global transform for the planet is zero, the mesh is ridiculous
Yeah I'll do that then, thanks!
Confirming this worked great, but now I have 10 million meshes so bevy is struggling hard lol
You need a terrain system. ๐
Some other people in this chat have posted some WIP terrain systems with big_space, to give you some ideas.
I've taken a look at a few already, one of them was by @worthy vector
I'll take another look to see if I'm missing something, but I believe they aren't suitable for what I'm currently building
Hopefully I'm wrong and this can easily sort my problem
I'm testing decreasing the mesh count and I arrive back at the wobbly vertices
I'll go back over the terrain systems more in-depth in case I'm missing something, but for context, even with the 10M meshes I had before each one was 1km squared
๐ฑ you need LOD
I could probably live with the wobbly meshes far away (it's not noticeable beyond a few hundred meters) and just heavily implement LODs
Yeah I know, but each mesh is only 12 vertices (basically cubes)
you had 10M 1km squared meshes?
oh okay I see
Yeah, it handles it really well, compared to not handling it at all, which is what I expected
I think I'll need to look into how spheres and other basic shapes can be vertex perfect even at large sizes Then that way I can go back to a small number of meshes
I think the problem is just that Bevy's Mesh uses f32 for vertices. That means with a small number of meshes, many vertices will be very far from the Mesh origin and start to lose precision
icosphere with dynamic subdivisions?
^
We all want to know what you're doing that precludes dynamic lod! ๐
If you can't do dynamic lods, it's worth noting that trying to pick a mesh size that has "good enough" precision but also big enough to keep memory usage down will eventually run into issues with larger and larger planets: your memory usage will go up with the square of the planet radius. A super-earth would use up substantially more memory. By contrast, the dynamic lod scheme increases memory usage linearly as you approach the planet. That means I can actually do almost arbitrarily-sized planets: a planet the radius of the solar system subdivided down to sub-meter polygons will use on average double the memory of an earth-sized planet at the same resolution when viewed from the surface.
No lods and your memory usage goes up by a factor of 1 trillion
-# not that you'd want planets that big but... just something to keep in mind
I've been making some very slow, incremental progress on physics.
It's going to be pretty barebones, but I need to focus on the basics to test the core ideas.
It's turning into an ECS wrapper + physics backend trait. I'm implementing the physics trait with rapier to start, because it works standalone, unlike avian. I'm not certain how an avian integration would work, but the trait means you can theoretically add any physics backend you want (e.g. jolt, physx, havok, etc).
Oh interesting, went to look at physx, and this is pretty close to the model I'm using for big space physics contexts:
(in very broad strokes)
From playing with rapier, it seems like rapier is internally doing a bunch of DoD/ECS-y stuff, so it's probably very similar to if an avian physics context was just avian running in its own little World.
Seek help
Big space on the Gameboy, here we come
I just need to make one more crate no_std compatible. I promise one more and I'll be done
Big Space on the Little Boy lets go
Holy moly that's extensive
Yeah it's probably impractical to merge as a single big PR
Also, I'm going to be forever salty about Parent -> ChildOf
Yeah I preferred Parent too. Could just type alias it lol
I an seriously considering it for this crate especially
I need to query for the child and... childof of this entity
C'est la vie
The only "real" change I had to make (aside from general 0.16 migrations) was just making a singlethreaded alternative to GridHash::update because bevy_utils::Parallel is a thread-local and that just doesn't exist outside std
Speaking of naming, just sharing my 2ยข ... With Bigspace there are three different transforms now: Transform, GlobalTransform, GridTransform. If you like reflecting that in var names to avoid confusion you'll be perplexed that the latter two abbreviate to the same "gt" acronym. But, looking at GridTransform, it's made of Cell + Transform, so it kinda makes sense to call it CellTransform instead. Which is what I'm type aliasing to, which makes for very nice disambiguated var names, especially if you're querying for both GlobalTransform and GridTransform: foo_t, foo_gt, foo_ct as opposed to foo_gt and foo_gt (???).
Probably doesn't bother anyone else though. ๐ But, type aliases are sure nice.
Weird. Just noticed the camera's global rotation quat stays the same no matter how I rotate the parent the camera is attached to. Is that how it's supposed to be under Bigspace?
Is the camera the floating origin?
I would expect the cameras global transform would not be affected by rotating the parent in that case. The parent grid is the relative root of the hierarchy - it defines what the root coordinate system is for the purposes of computing global transforms.
Like, let's say your floating origin camera is on a ship, moving through space. That ship is now the root coordinate system, it doesn't matter what rotation your ship has, or the rotation of the planet the ship is on. The ship is the fixed reference frame for the entire universe, and global transforms are computed relative to it.
If that wasn't the case, nested reference frames would accumulate error.
Can't say I truly understood the reasoning in all its details, but I'll just remember that this is normal, thanks.
This seems to work, but I was wondering if there's an easier way? Or is that idiomatic enough:
pub fn camera_global_orientation(
ship_camera: Single<(Entity, &Transform), (With<PilotingShipCamera>)>,
ancestors: Query<&Parent>,
transforms: Query<&Transform>,
) {
let (camera_id, camera_t) = ship_camera.into_inner();
let mut camera_hierarchy = SmallVec::<[Quat; 4]>::new();
camera_hierarchy.push(camera_t.rotation);
for entity_id in ancestors.iter_ancestors(camera_id) {
if let Ok(ancestor_t) = transforms.get(entity_id) {
camera_hierarchy.push(ancestor_t.rotation);
}
}
camera_hierarchy.reverse();
// Find out camera's global transform orientation by multiplying quaternions
// for each transform in the entity hierarchy. The order should be from the root
// to the camera (leaf).
let camera_gt_orientation = camera_hierarchy.into_iter().reduce(|acc, quat| acc * quat).unwrap();
// TODO now do something with the real camera's orientation
}
Feels like I'm reinventing the wheel and this function must exist somewhere already
What are you trying to accomplish?
Thanks for pointing that out, tbh, I don't use the GridTransform at all, I'm not a huge fan of hiding the components behind more layers of stuff, but someone else wanted it, so.
Sync orientation of a 3d object with the camera's. For minimap for example.
If you want to sync it, why not put that 3d object on the camera?
That object is part of the UI render layer with its own camera. So, the UI object syncs with the main 3d world camera.
What do you mean by "sync" here? Is there some reason you can't look at the GlobalTransform of the things you want to show in the UI?
e.g. if you want the orientation of the ship in its reference frame, take the difference of the two transforms
or in any reference frame
In the UI layer, I have a sphere (a minimap basically) onto which I project the surrounding objects/spaceships. I want that sphere to rotate along with my main world camera, to align the cockpit view direction with the minimap direction.
Yeah, then I would look at the difference of the two globaltransforms you care about, that way you aren't trying to replicate transform propagation yourself.
Bear with me here, I'm slow lol. Between which two globaltransforms? Give an example?
Transforms are just a way to map between reference frames, right?
So, to go from the root to the ship's origin, you apply the ships transform.
To get to the players origin on the ship, you apply the players transform relative to the ship
etc etc
The global transform is absolute. This plugin (and bevy's) do all that relative transformation for you to compute the position of all entities in the root reference frame.
In the case of this plugin, the global reference frame is the grid the floating origin is located in
This maximizes precision, because all transforms are computed outward from that point
But, the GlobalTransform for all entities is in the same reference frame, regardless, that is the important bit
That is why rendering works, you can directly compare all entities by looking at their GlobalTransform, you don't need to worry about hierarchy or anything, that has been handled for you
So, if you are trying to draw a minimap, the question is, what is your frame of reference for the minimap?
If you can answer that, you can apply the inverse of this "static" reference frame to any GlobalTransform, and you will know its position relative to that reference frame (the minimap)
The center of the minimap is my spaceship
The camera sits on the spaceship, fixed, immovable. I turn the ship, and the camera turns as well.
And I just need to orient the minimap into the same direction that the camera is looking in
But the camera doesn't update its gt.rotation() at all .. which is where I'm lost in the explanations
if the minimap's reference frame is the spaceship, and the camera rotates with the spaceship, then how can your minimap rotate?
You just said they are fixed relative to each other
So, what is "north" on the minimap, if not the spaceship's forward direction?
It sounds like it is actually the reference frame that the ship itself is located in
So, the camera is always looking into some direction in the world space, right? Doesn't matter what makes the camera turn - either it's the camera's own transform that's changed, or its parent's (spaceship's).
The minimap sphere, if it's fixed, then when the ship turns, so must the ship in the middle of it. That's called "no minimap rotation". Usually games also have the other mode, where the ship (player) in the middle of the minimap always looks up, and it's the minimap itself that rotates around the player. Which is what I'm doing.
Makes sense that way?
the world space, right?
This is what I'm getting at - what is "world space"?
The reference frame that your map measures. It's probably the grid that your ship sits in.
Not the ship itself.
And the map rotation is the difference beetween that grid's orientation and you cameras.
Even if your camera orientation is zero/identity, the orientation of this "world" reference frame will not be.
The minimap sphere, if it's fixed, then when the ship turns, so must the ship in the middle of it. That's called "no minimap rotation". Usually games also have the other mode, where the ship (player) in the middle of the minimap always looks up, and it's the minimap itself that rotates around the player. Which is what I'm doing.
You do this by picking your reference frame (ship reference frame vs space reference frame) and you compute the position of all objects on the map relative to that reference frame.
Like, Sun?
Again, all that you need to do for this is to take the object you are projecting, and apply the inverse transform of the reference frame you want to be in.
This transforms the object into that reference frame.
If your map projection is a sphere, you then project those transformed objects onto the sphere
But you need to make sure you are computing their position in the correct reference frame first
I can make an example, I'm not sure when I will have time though.
I feel like I'm missing some fundamental understanding, after which it'll auto-click. Maybe I need to think some more. Appreciate the explanation.
Without Bigspace, the reference frame would be the origin. With Bigspace, it has to be a spawned object or otherwise chosen coordinates. A local star like Sun would work, right?
it should be something like
// some awful psuedocode
let map_reference_frame: GlobalTransform = sun; // can be any object
let gt_to_map_frame = map_reference_frame.inverse();
// compute position of all map objects relative to the map reference frame
for object_pos in map_objects {
let map_pos = object_pos * gt_to_map_frame;
// you now have the position of the object relative to your chosen map reference frame
let sphere_pos = map_pos.translation().normalize(); //idk haven't thought about this one too hard
}
What I'm talking about here applies to bevy transform hierarchies in general. In bevy stock, the root of the hierarchy is the reference frame used by GlobalTransform. In big space, the grid cell that the floating origin is located in is the reference frame that all GlobalTransforms are in.
But it doesn't matter what is used as the reference frame, because GlobalTransforms are in the same reference frame (the "global" part), you can compare them directly.
To reiterate this point, that is why I always say "use GlobalTransform". It doesn't matter how that GT is being produced, it will work in bevy or big space. That's why rendering works, it uses GT. All the magic big space is doing, all of that amounts to the same GT at the end of the day, but in the case of big space, it is making sure that GT has maximum precision near the floating origin, that's it.
How can the floating origin camera not have a global orientation? Sorry I don't get it. When I turn the camera (via turning its parent), it is turning.
I can see the world shifting in my view!
The world is shifting around you
because you are the global reference frame/orientation in this case
the floating origin, is, well, the origin of the coordinate system.
(technically, the origin is the cell the floating origin is inside)
It's really, really, easy to overcomplicate this in your head, because there is no fixed global reference frame. That's why I'm constantly suggesting people use the GT, because then the complexity of big space (mostly) dissolves away.
It's also why rendering works! it doesn't care what the root reference frame is, it just computes the position of everything relative to the camera! It's the same exact concept. In the case of rendering, it chooses the camera to be the reference frame it cares about, because it wants to project everythign onto your screen.
sounds like I should align my visual 3d grid on the minimap sphere with Sun's axes .. and that would be the reference frame. And the player would see the grid rotating as the camera is turning, which is kinda important for the vibe
ok I don't know how many hours you just saved me, but thanks ๐
The minimap is actually a really great example case I should write, and would really help if you had more rendering familiarity, I'm guessing. It's pretty much identical to the concept of the view transform in rendering.
Drawing a map is just transforming things into a particular reference frame.
Just to clarify: each GridCell has an xyz. These coordinates are static inside of a Grid, right? Therefore, they can be used as reference frames. Meaning, I don't necessarily need to spawn Sun in a random location and then use that as reference to spawn the rest of the objects around it. And "north" can be .. Grid's (GridCell's) Y or something?
Or is that exactly what you're discouraging from
doesn't seem easy to get a vec3 from a gridcell directly
if you wanted to do a spherical minimap without globaltransforms, you'd probably have to loop through everything in a different gridcell and add the difference between the two gridcells to some kind of cached transform
then to make it simpler, you might as well just compute that for everything
oh hey, that's globaltransform
These are coordinates in the parent grid, like a Transform.translation().
Not sure I'm understanding the question.
No, I understand, I love globaltransform, it's my friend. I only have trouble with figuring out what my camera is looking at, because its globaltransform is toast due to Bigspace. It's not about the location of the camera in space, it's about how it's oriented in space. Yes, it's always 0,0,0 (not always because the origin is actually the cell, yes). But it's looking at some specific thing in space. What is that thing in the middle of my screen? Because I want to make another arbitrary 3d object also look (be oriented) at the same thing.
If there were no Bigspace, I'd take my camera's gt.rotation() and that would be it. But this doesn't work with Bigspace, the cam's rotation is fixed in place, and as Aevyrie put it, instead the world rotates around the camera. That's all fine, but it doesn't help me understand my camera's orientation.
And Aevyrie tried best to explain something very important about all this with reference frames, but I haven't digested that yet.
I still don't understand why my "figure out GT" approach is wrong. Doesn't it show correct data? If it doesn't, why? If it does, why is it wrong? And the answer seems to be "because you don't need to compute your own gt, just take any other one to do the same thing" - but this is where I think I still don't get it conceptually. Say, I take the Sun's gt. How would that help me understand where my camera is oriented at? In code, I don't even know if the Sun is in front of the camera or behind it or what. It's not about translation, it's about camera's orientation. I don't need the Sun's orientation, I need my camera's. And my camera's orientation is apparently non-existent and it's driving me nuts lol.
Like, how do I know where the Sun is even thought I'm always at 0,0,0? Easy! Just take Sun's gt.translate. But the same logic doesn't apply to my camera's orientation, whenever the world is "shifting around me instead". Or if it does, I don't see how.
well, you can get orientation with just the camera's local Transform
assuming it's a direct child of the grid
Ah-ha! That's the thing! The camera's local transform is immutable basically, because it sits on the spaceship, with fixed translate and orientation. I turn the camera by turning the ship.
then get the ship's local transform's rotation

Or is that not the same thing
Wait, did I just need to take my camera's parent local transform all this time, without going all the way up the hierarchy?
probably
whichever is the moving part you're actually accounting for
I'm just thinking, what if the ship gets a parent. Like... a mothership. For gameplay reasons. I'll need the full hierarchy then, no?
well who's got the minimap on them?
I got on me
๐ถ i got that minimap on me
When I created the minimap mesh, suppose I put a visual indicator for one side of it (the "north"). I want that north to always be pointing the exact same direction as the player is looking at in the "real" world.
if globaltransform rotates, isn't that just -z
So if my spaceship is child of a mothership and my main 3d camera is looking at Sun, I want the minimap's north to be also pointing at the sun
Two very disturbing questions about that statement:
- Whose globaltransform? The player's main camera doesn't have one, because it's the floating origin.
- What does it mean "just -z"? Sorry I'm a noob at spatial math. Aren't rotations expressed as either Euler angles or quaternion multiplications?
the minimap's viewpoint, and its z coordinate
direction, rather than rotation, is what i was saying
What do you mean? The minimap's coordinates are fixed, it only rotates
to be clear my interpretation is "fixed minimap, with moving pointer for your look direction"
you might've meant the opposite
I need to figure out how to make these short videos of a portion of the screen for a short demo.
obs vkcapture + ffmpeg works pretty well for me
To try and restate what I was saying earlier.
If there were no Bigspace, I'd take my camera's gt.rotation() and that would be it.
This works if your map's reference frame is the root in bevy, which has a GT == identity. Applying the inverse to objects to transform them into this space does nothing, so you can just omit it entirely, this is a special case.
If you want to use any other reference frame for your map (a mothership, a planet, etc), or use big_space, you need to do that inverse, always. But it works everywhere, including using stock bevy and the root of the hierarchy.
You see how the minimap aligns itself?
This would probably be 100x clearer in code. I'll try to make something when I have time. This weekend, if I'm lucky.
But I know exactly what you are trying to achieve.
The elite dangerous minimap, pretty much
In the sense that you're in the middle of it, and the objects around you in the cockpit space and also around you on the minimap, yes. But I don't remember how exactly ED shows it. You might be right.
I might be misremembeering too, lol
And so, rendering surrounding objects on that map is not a problem. The problem was figuring out how to rotate the map in sync with the 0,0,0 FO player camera.
You want the map to rotate so the orientation matches the way the camera is facing, and the map should always be centered on the camera
right?
(like a compass)
You want the map to rotate so the orientation matches the way the camera is facing,
Exactly.
and the map should always be centered on the camera
Yep.
And the fixed reference frame is the grid that the ship/camera are in?
Yes
e.g. the grid spins/translates underneath the static ship
tbh I'm still not sure how the grid underneath it all works, I'm blanking at that
I would imagine it should match the grid you are flying through
so if you drew the grid in 3d space around the ship, it should match
Yeah, that's a good way to put it. But I didn't use that in my explanations because like I said, it's still a blank space in my head how the parent Grid works
you need to do that inverse, always
You're saying I can take the parent Grid'sinverse()to figure out my FO camera's orientation?
I've only got a vague idea that I'm in Grid, and each GridCell has an xyz and they seem to be kind of like stable global space coordinates, like CMB in real space.
Of the globaltransform, yeah. Though, that could lead to some nasty floting point precision issues if it is far away, so you might be forced to do some grid math.
Would that be faster/more accurate than what I'm currently doing with manual gt propagation?
the Grid itself is really no different from the normal Transform -> Transform -> Transform hierarchy in bevy. It's only needed to store the scale of the grid.
Accuracy is the only issue I can think of.
idk, at some point I need to write the code, it's a bit hard to discuss the details with words 
It's probable that I am also missing something or there is a gap in the API for this use case.
๐ I'd appreciate you giving it a conceptual review
I think you should be able to do
map_orientation = (camera_gt * grid_gt.inverse()).rotation()
my brain is a terrible IDE though
you would need to get the affine/mat4 inside the gt iirc
but dealing with the rotations alone should work
map_orientation = camera_gt.rotation() * grid_gt.rotation().inverse();
I can never remember quat/mat multiplication though
Thanks, I'll try that.
Btw, while the topic's hot, something I wanted to ask for a long time. If working directly with two gts is too erroneous due to large distances, is it fair to take GridCells of those objects instead? Or even GridTransformOwned for which std::ops are also implemented and work with that? Like subtract them etc, like two vec3s.
yeah, that's totally valid
only issue is it only works if they are both in the same grid, but that's no different than trying to do math ops on Transforms
never know ๐
You are free to modify or do math with the (GridCell, Transform) pair. Big space will renormalize it every frame.
๐
That doesn't seem to do anything, the minimap (tacsphere) is locked in place no matter what.
pub fn sync_sphere_to_camera(
ship_camera: Single<(Entity, &GlobalTransform), With<PilotingShipCamera>>,
grid_gts: Query<&GlobalTransform, With<Grid<GP>>>,
grids: Grids<GP>,
mut tacsphere: Single<&mut Transform, With<Tacsphere>>,
) {
let (camera_id, camera_gt) = ship_camera.into_inner();
let mut tacsphere_t = tacsphere.into_inner();
let grid_id = grids.parent_grid_entity(camera_id).unwrap();
let grid_gt = grid_gts.get(grid_id).unwrap();
let camera_gt_rotate = camera_gt.rotation() * grid_gt.rotation().inverse();
tacsphere_t.rotation = camera_gt_rotate;
}
The camera's parent Grid in this case is the spaceship's Grid (which has to exist on the spaceship, otherwise a FO camera doesn't want to be there saying it has to be under a Grid directly).
And the spaceship itself is under the Sun's Grid.
It's Bigspace standard stuff -> Sun (Grid) -> Spaceship (Grid) -> Camera.
you could put the FO on the ship directly
True, but that would make switching camera to other objects clunky I imagine. Like when you want to temporarily "look at" some object other than your space ship, up close. Maybe an enemy or a planet or some other object.
Idk maybe the camera wasn't designed for how I'm trying to use it. I parent it to whatever thing I want to look at.
my system's set up for siblings, copies the transform and modifies it instead of trying to compensate for character rotation
Thought I found a really cool-sounding name for the minimap: Tactical Sphere, aka tacsphere in the code. I was happy right until the moment I realized TacphereObject abbreviates into taco, and now the code's all in tacos...
-# extremely dirty, but
fn apply_camera_transform(
habit: Single<&Transform, With<crate::player::Inhabited>>,
camera: Single<
(&mut Transform, &ForwardFromCamera, &CameraControl),
(
With<crate::player::Inhabitor>,
Without<crate::player::Inhabited>,
),
>,
) {
let player_transform = habit.into_inner();
let (mut transform, ffc, opts) = camera.into_inner();
let pos = player_transform.translation.adjust_precision()
+ opts.fade * opts.height * ffc.up
+ opts.fade * opts.back * -ffc.forward;
*transform = (&*ffc).into();
transform.translation = pos.f32();
let pitch_axis = transform.left().adjust_precision();
transform.rotate_around(
pos.f32(),
Quaternion::from_axis_angle(pitch_axis, ffc.pitch_angle).f32(),
);
let back = (opts.back_rel * opts.fade) as f32 * -transform.forward();
transform.translation += back;
}
kind of a body/soul dichotomy thing, since the 'habit' can be destroyed or swapped to another entity
this sounds like a feature
can probably justify it in lore: the viewscreen is concave and uses a mirror hologram to project the map
Oh yeah, for sure. Before starting the programming part, I spend weeks writing design docs for the lore. Massive world building. Even the list of hard sci-fi technologies unlocked in the world's timeline are all consistent and everything else stems from it.
What's really cool is once you've got hard sci-fi constraints going on, game mechanics crystallize all by themselves. You don't make up arbitrary things like in Everspace (even though it's fun), or in EVE Online (which is also fun). But idk, when I see spaceships warping into an arbitrary point in space, it immediately breaks immersion because warp bombing. And why does all body contact lead to "bumping" instead of destruction? So yeah, I spent a long time on the design part to avoid things like that. Could almost forget about the game and just write a book instead it feels like. ...but I'm getting carried away.
imo, the arbitrary point in space repels from gravity wells and is highly telegraphed
kronchy ships my beloved
Someone's been on projectrho.com
I wanted to make a hard sci fi expanse-like game, but it ended up being kinda... difficult. Still working on it but it turned out to be much easier to turn into a DnD campaign
(reminded me because you said you should just write a book)
Idk what that is, but this was funny: "This site started out as a small sheet of equations I wrote in 1997", because "1997" is exactly what I thought by looking at the design. Like time travel, that's how web was 25 years ago. ๐ Nostalgia
Ugh, can't create a thread here... quick question then to avoid heavy offtopicking: difficult in what sense? Coherent backing lore? Coming up with interesting mechanics? Programming them? That pesky art/sound part programmers aren't usually good at?
Go for it, this is clearly the gathering point for a certain kind of nerd and I'm all for it. 
(it's me, I am that nerd)
Difficult deciding what kind of game I wanted it to be. I like first person games with a lot of action, but I also wanted the turbo realism. It's still in the works, but very much a fantasy project. Basically it's an MMO with realistic physics (besides warp travel and torch drives), and the goal is player-driven everything: no in-game economy or government, procedural infinite tech tree, voxel ships, procedural 1:1 galaxy. Part of it is already built out, mostly the backend, and the thing I'm most proud of is that the location of every object is computed from static parameters: rather than ticking the position of every ship every frame, I store data like "departed from X station for Y destination at Z time on W trajectory". The backend schedules an update that fires at the calculated arrival time to update the ship's position to "at Y". This way I can persist large numbers of ships without using much processing power
-# That was a bit more than the answer you wanted
procedural 1:1 galaxy
๐ซ
Idk, I feel like that's one of the easier parts haha as long as your detail standards aren't too high
galactic dwarf fortress you say?
Sounds like a lot. Might even suspect Chris Roberts behind the account name!
noooooooooooooooooo
(pronounced with a long 'o')
Making everything player-driven removes the need for me to make content ๐ except the procgen. But I'm already partway there haha
Anyway there's a reason this is a fantasy project
I don't put a whole lot of time towards it, just when I need a break from my more realistic projects
why put the granularity at 'individual point-to-point trip'?
Torch drives are interesting. They're a great story element. Because low-level tech nations should ban them, since they're basically the most powerful weapons ever, and if you want your station to accept torch drive ships for docking, you either gotta believe in reincarnation or be on a tech level where your station can shrug off an accidental 100km plasma exhaust.
Because I still want players to be able to adjust trajectories to schedule encounters, avoid certain areas, etc. Do you have a specific granularity in mind?
Or make them run on handwavium
Nooo
'on x schedule from y time with z complication'
or wider, but that's the easiest *difference
The only thing I hand-w..woven? Waved? Was the new physics field that allows for Mach Effect Thruster drives to meaningfully operate and allow for the Lentz soliton.
"Our ships have neutrino drives. We figured out how to emit neutrinos in a single direction. Most of them don't interact with anything so the exhaust is not dangerous, but we still get all the momentum from firing them off"
wimp drive
When I started this lib, I was playing with the idea of a game entirely based on interplanetary travel. KSP's flight planning and execution is really fun, so I thought, what if route planning itself was something you could build a multiplayer experience around? Part of the idea was to make the timewarp part of the route planning mechanic, instead of a problem for multiplayer, it becomes a feature.
Depending on your route and distance to bodies, you could find more optimal routes by getting clever with your route planning to maximize the amount of timewarp you could use. It would be interesting if that was somehow part of player economy too, selling route plans. If the planets moved over time, those routes would be constantly invalidated, driving demand for new routes.
ships with preplanned routes for the next hundred thousand years belonging to massive trading groups
Another problem though is vulnerability. If your exhaust was harmful, that would at least compensate for the huge vuln in the back, as you could use that in battle. I wonder though if missiles / slugs would be vaporized by the exhaust. Idk it sounds like an interesting tradeoff that directly translates into game mechanics.
Wow.. I just realized. What is plasma exhaust? That's basically a huge plasma shield, so it would even protect against high energy weapons.
Yeah initially I wanted to ban torch drives altogether, but the more I think about them, the more they look like very juicy game mechanic with tradeoffs and interesting stories around them.
Part of the idea was to make the timewarp part of the route planning mechanic, instead of a problem for multiplayer
problem in what way?
Desync - if one player wants to timewarp, everyone needs to timewarp to be consistent.
At least in a world with slower-than-light travel.
you mean fast forward the server time?
Have you played KSP?
You can fast forward physics, so travel to mars doesn't take 4 irl years
oh yeah
But if you have multiplayer, how do you resolve that? You would need everyone on the server to fast forward together
This really came about because I find straight-line FTL pretty uninteresting. Another way to frame it is FTL with orbital mechanics.
Off the top, introduce sync points. Like every so often the server fast-forwards the time, making it a turn-based game with real time action in between the turns ๐ Sounds silly, I must admit...
But how could you solve that?
this^
But what does it mean?
i once played a game that had the mechanic of being realtime for a week and multiplayer
You can travel FTL, but you have to follow orbital paths. You aren't speeding up time, you are just moving FTL thanks to some handwavium scifi
speeding up your ship's trajectory?
Pretty much
I find most interplanetary traversal uninteresting - point ship at destination and press button
It would be more like all the scifi where they have to plan a route, before a jump
Ahhh yeah. I see what you mean. Yeah arbitrary FTL breaks everything, warfare first of all, if that's what you meant. So what you end up needing is constrained FTL. I came up with these space highways for that reason.
and based on playing lots of KSP, that route planning turns out to be a ton of fun
Oh you mean actively search for specific paths. Yeah that's something different.
Orbital mechanics - slingshotting yourself around bodies, etc
yk speeding up your trajectory (in newtonian mechanics) is just increasing your velocity and the force gravity exerts on you
Applying a force during transit is different than coasting, you will follow a different trajectory
I can see that being fun, yep
But somehow this feels like.. um.. more like an engineering/exploring game, rather than good old action combat game. But you did say it was inspired by KSP, so that makes sense ๐
totally
I wish we saw more scifi games that explored traversal, instead of hopping from setpiece to setpiece instantaneously.
LIke, instead of "dropping in" from ftl somehow with the exact same velocity as the ships magically hovering stationary over a planet, what if you dropped in going 7km/s 
play exo one
Could you use that to your advantage with kinetic weapons inheriting all your velocity?
Haven't played it, but it gives me Tribes vibes. The movement in that game was so fun.
nuh uh, btw
if you pick some instant, double your velocity, double the acceleration from gravity from that point onward, and halve the play speed, there's no difference
Oh, I thought you were saying something completely different
Firing a 1kg slug with muzzle velocity of 12km/s from a 100t ship, the ship should only lose 0.12km/s of own speed, if you're firing straight ahead. So yeah, the slug would go about 19km/s.
That sounds fast enough to ruin somoene's day.
is there a reason you can't strap a time accelerator to a brick and toss it
where do I get a time accelerator
whatever the ftl is that technically doesn't
If you can hit ๐ Space is big!
Can't believe I just said that to the creator of Bigspace
that's why trajectory planners get paid the big bucks
Space is big!
This changes everything.
surely there's a computer strong enough to solve the entire manufold all at once
computers ruin all the fun
real trajectory planners use slide rules and snort space spice
see what you do is add more phlebtonium that makes the exact multiplier random every time it turns on
an n-radius hole through a manifold seems more computationally difficult than a single path
Still working on the minimap aesthetics, but the logic seems to be fine.
This is how SpaceEngine ships work and honestly its infuriating.
If you simply remove those lines, it will mess up the system ordering though
@crude dagger if you just want to run the example, you can
cargo run --example planets
Checking out 0.9.1 release tag, this does not work. Gives the same weird runtime error and crashes:
thread 'main' panicked at /home/damccull/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.15.3/src/schedule/schedule.rs:383:33:
Error when initializing schedule PostUpdate: Tried to order against `SystemTypeSet(fn FunctionSystem<fn(Query<(Entity, Children, Ref<Transform>, &mut GlobalTransform), Without<Parent>>, RemovedComponents<Parent>, Query<(Ref<Transform>, &mut GlobalTransform, Option<Children>), With<Parent>>, Query<(Entity, Ref<Parent>), With<GlobalTransform>>, Local<Vec<Entity>>), propagate_transforms>())` in a schedule that has more than one `SystemTypeSet(fn FunctionSystem<fn(Query<(Entity, Children, Ref<Transform>, &mut GlobalTransform), Without<Parent>>, RemovedComponents<Parent>, Query<(Ref<Transform>, &mut GlobalTransform, Option<Children>), With<Parent>>, Query<(Entity, Ref<Parent>), With<GlobalTransform>>, Local<Vec<Entity>>), propagate_transforms>())` instance. `SystemTypeSet(fn FunctionSystem<fn(Query<(Entity, Children, Ref<Transform>, &mut GlobalTransform), Without<Parent>>, RemovedComponents<Parent>, Query<(Ref<Transform>, &mut GlobalTransform, Option<Children>), With<Parent>>, Query<(Entity, Ref<Parent>), With<GlobalTransform>>, Local<Vec<Entity>>), propagate_transforms>())` is a `SystemTypeSet` and cannot be used for ordering if ambiguous. Use a different set without this restriction.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
But the main branch removes those lines and doing so on 0.9.1 also runs it seemingly fine.
ahh, got it. Yeah, same for me. Turns out I made the mistake of forgetting to switch the sources to 0.9.1 before going through examples. ๐
Happens.
was there no test for it or does ci not run tests
It's an example.
I've never run examples in CI before due to rendering issues, but if that has changed, I'd love to know about it.
I'd also need a way to kill them after N frames or N time.
Anyone able to help me understand what this function does ?
As far as I can tell all it does is flip (invert?) the camera so it's at -0.0, because it should initially be at 0.0, same as the sun position
Rotating my DirectionalLight 180 degrees seems to give the same result so I'm guessing that is all it does
Not sure why it's a whole system, Is there some interaction with the GlobalTransform there I'm missing?
Weird that it doesn't work when I do Transform::from_translation(Vec3::ZERO).looking_at(planet_position, Vec3::Y)
But I'll chalk that up to my inexperience with Bevy
oh good, big_space is completely broken on bevy 0.16 
0.16 release candidate :p Thank you for testing!
transform prop is disabled, best guess is the change to parenting ChildOfing is breaking stuff
it looks like a transform hierarchy validation resource disappeared into the ether
Welcome to the release candidate! Please do not resist
welp, this is very confusing
what the heck is RelatedSpawnerCommands, looks like I have some reading to do
I'm not sure where to start with this one. 
I've never even seen this kind of failure before. It really, really, does not like moving between cells.
Just wait, it's totally gonna be my own fault with transform prop changes 
oh god, it is
I bet it's the leaf transforms
yuuuuuup
welp
๐ถ it's me, hi, I'm the problem it's me ๐ต
@umbral ledge FYI everything works fine on main
The issue was the released version (that did not have the dirty tree PR), has an optimization that updates leaf nodes. It's not strictly a problem, because you can work around it if you are disabling the transform plugin already. It is an annoyance because you can't reuse the built in systems.
Good!
We've had first perf issue, yes
I'm simulating millions of entities, and I noticed a stutter when moving between cells - update_mesh_previous_global_transforms is taking over 100 ms
Why on earth are we always using commands there??
We should be mutating if possible
Waaay faster
Lemme PR that...
oh, good catch, yeah that is in commands
for (entity, transform) in &meshes {
commands
.entity(entity)
.try_insert(PreviousGlobalTransform(transform.affine()));
}
oof, that's not great
oops, I made a fix
I beat you :p
I avoided branching statically:
pub fn update_mesh_previous_global_transforms(
mut commands: Commands,
views: Query<&Camera, Or<(With<Camera3d>, With<ShadowView>)>>,
new_meshes: Query<
(Entity, &GlobalTransform),
(PreviousMeshFilter, Without<PreviousGlobalTransform>),
>,
mut meshes: Query<(&GlobalTransform, &mut PreviousGlobalTransform), PreviousMeshFilter>,
) {
let should_run = views.iter().any(|camera| camera.is_active);
if should_run {
for (entity, transform) in &new_meshes {
let new_previous_transform = PreviousGlobalTransform(transform.affine());
commands.entity(entity).try_insert(new_previous_transform);
}
for (transform, mut previous) in &mut meshes {
previous.set_if_neq(PreviousGlobalTransform(transform.affine()));
}
}
}
you use the command if it is missing the component, and just mutate it when it has it
Yeah that's better
I left an approval, gonna patch and test quick
oh, should make it parallel too
Let's wait on benches for that?
I'd also prefer using required components to avoid the insertions if possible
I don't think you can
You just add it to Mesh3d / Meshlet3d
unless you can add foriegn req components?
oh, I thought you meant on GT
It's going to be faster
lol
it's stupidly parallel
kk!
woof, yeah, it still shows up on traces when I spawn
it takes longer than spawning the meshes
but good news, it is down to 3ms from 115ms on main
(this is with the par query)
Cool, I stole this so that should be accurate
oof check_entities_needing_specialization is also very slow
it is doing a linear scan as well
It looks trivially parallelizable too
same with visibility ranges, though I doubt it would be trivial
I need to sleep now โค๏ธ
But bug me and I can slap some par_iter on that too if you want
Slap some par_iter on it is like the #1 Rust perf optimization
Especially in terms of effect to effort
brrrr
to give a sense for how much perf bevy is leaving on the table by not unifying the thread pool, this is what it looks like if I force the compute task pool to actually use my cores
I get double the cores to work with
yeah I see that in Avian too, collision detection is way faster if I force it to actually use enough cores
(or use Rayon which also uses all the cores)
More excellent validation for the release candidate process.
So cool to see these regressions getting caught.
the release branch (https://github.com/bevyengine/bevy/commits/release-0.16.0/) has all the latest commits marked for the 0.16 if you want to try
I'm guessing it's this https://github.com/bevyengine/bevy/blob/main/docs/profiling.md
Tracy, and using custom settings for the task pool in the task plugin on setup.
I'm considering throwing together a crate to simplify using gizmos with big_space. Is there already such a thing? And if not, am I overcomplicating things?
Not that I know of. What kinda stuff are you doing?
I use gizmos pretty often, using the GT, everything seems to work normally.
When you say using the GT, you're talking about positioning gizmos relative to object with a GT right? I'm finding it's sometimes a pain to grab the GT, like when you get absolute coordinates from a picking backend
Not even relative - I'm probably using it differently from you, but generally I will just draw cuboids or similar and pass in the GT of the entity I want it on.
wdym by absolute coords from picking?
you assume that there is an entity :p
I would expect you could just do everything in global space like normal bevy
oh?
Like if I want to put a gizmo at the world origin
What on earth do I pass to the gizmo function?
the bigspace entity's globaltransfrom?
Huh
or the grid entity's globaltransform
you can see that in action with the built in debug plugin iirc
it draws coordinate axes at each grid
The fact that the root bigspace has a gt slipped my mind
What happened? ๐
The fact that the root bigspace has a gt slipped my mind
This. I sometimes make the mistake of thinking I finally understood how to work with Bigspace, and then there's another "ohhhhh, riiight" moment.
I find myself confused by grids again haha
I have a planet sized mesh with a grid and a gridcell
Let's say for examples sake the mesh has 20 sides, and each of those sides has a grid
I'm then trying to get the "real" position of the player (which lives on one of the 20 planet surface meshes)
I'm trying to do this following the demo.rs example, using grid.grid_position_double
But everyway I try it I'm being given the position of the player in relation to the surface grid
Which is basically 0, 0, 0 as the player is on the surface
I can get the "real" position of the planet using the same method and that works without issues, but the moment I move to the player it fails
Should I not have a grid within a grid?
Why do you have 20 child grids? ๐
Ages back you said having a planet sized grid defeats the purpose big space
So I made them smaller
Might have misunderstood what you meant though lol
You must've misunderstood or I misspoke
But that sounds really overcomplicated.
Let me try to understand what you're doing
Grid_position_double just combines the index with the cell translation to give you the position of something in a single double precision float.
So, it's like you are now working with a double precision Transform.
But it's still a Transform which is relative to its parent transform.
So, this is AI working as intended as far as I can see. You are asking it to give you the position of the entity as a double, relative to its parent, and it is.
Right ok
The setup you have here is equivalent to having a deeply nested tree of transforms to represent a planet, and all of your entities are now in different reference frames
I guess from the demo I would've expected the "real" position to always be absolute*, but it's just the position relative to the parent
Is there anyway to get the absolute position?
Without traversing all the parents and combining the transforms
Actually no, that's not what I want
I want to get the relative position of the player to the planet grid
You really just want a single planet grid
Ah I'm misremembering, you said gridcell the size of a planet would defeat the point. That part I get now at least haha
Yeah it looks like it. I'll test out removing the other grids now
Everything in a grid moves together, I would only add more nested grids if there is a subset of things moving together that should inherit from the parent grid.
There isn't an absolute position per se, it's always a matter of traversing the hierarchy and getting all the transforms you are dealing with in the same reference frame (grid) so you can compare directly
You could use the root as your global reference frame, but there is likely no need to traverse all the way to the root, losing precision along the way
I'll definitely want to go back and figure out why I couldn't get the position relative to the planet grid eventually, but for now having a single planet grid will likely suffice
What you probably care about is finding some common ancestor
And hopefully make things easier
One issue I don't see you mentioning is rendering the planet mesh itself
Yeah, thankfully I've solved that (mostly)
I've got the mesh split into 360 chunks, each with 4 faces
Each face vertex has colour on it and seems to be stable
Those meshes should probably also be in the planets grid
Yeah they are
Wow, phone autocorrect is terrible today
Hahah
They were grids nested inside the planet grid, but now they're just directly in the planet grid
If your objects/players/terrain are all in the same reference frame, that should make your life easier
Probably yeah. There were a couple of optimisations I was hoping to do by having each face be it's own grid, but it's probably not worth the hassle
If you use that conversion to doubles, you can compare everything directly. You can also use the wrapper type for (Transform, GridCell) and compared those directly
Initially I was using Transform and GridCell but it kept giving me weird outputs, which is why I tested the grid_position_double command
Which then gave me the same output, which led me here
Yup, you were on the right track before, I think
Oh, I remember why I needed the nested grids
My planet isn't actually a planet, it's a ringworld
So I've got the ring split into 360 chunks along the circumference
Then at the center angle/position of each of the chunks I have an entity that handles the transform from the center of the ring
Then from there I have each face of the ring chunk under the chunk entity with a small transform for each of them
That way I don't have massive numbers everywhere, only one big transform, then little ones for the faces
It sounds like you are trying to write your own big space inside of big space
If everything is in the same grid, you won't need to worry about precision, and you won't need to transform between reference frames.
I'm just trying to keep them parented together so I can manage them easily, not for precisions sake
And it keeps my code simplified
Parenting is going to require conversions between reference frames, so be prepared for that added complexity.
There are other ways to group entities instead of using parenting, which is tied to transform propagation
Hmm, okay I'll take a look at that then
I don't know your game as well as you do, but my recommendation would be to keep the transform hierarchy as flat as possible in places where things need to interact or have positions compared to one another.
It's not a hard rule or anything, but it's (probably) going to make a lot of things simpler.
Otherwise you will need to transform entities into a common reference frame before doing any comparisons.
fwiw in my impl, I'm using multiple grids, but only because I have different reference frames: the root grid is for the whole solar system, the sun sits at the origin in this frame. The planets are also in the root frame, but each planet has a pair of grids: one without a rotation for orbiting things, and one that rotates with the planet for things on the surface or in the atmosphere. The planet mesh chunks sit inside the rotating grid. Apart from that, I don't really use parenting at all. Chunks need to know who their superchunks are, but I don't use parent/child for that, I position each sub-chunk in the main planet grid and it makes things much simpler
So the short version is: I only use grid parenting for orbiting bodies. In the context of a single planet, everything's in one grid
That's pretty much identical to how I would do it
Good to know! I will say the API took me a bit to fully grok but once I got it, I'd describe the design as "obvious". It's intuitive and makes a ton of sense
Weird to say it's intuitive in the same breath that I say it took a bit to understand ๐
Always happy to hear how the docs can be improved
I think this crate would benefit from tutorials too
It's hard to build intuition for concepts in the docs+examples format
Ok cool, this matches what I was doing at the celestial level so that's good
Not parenting things and instead just putting them on the parent's grid is interesting
And having two grids per planet is also interesting
That's really only necessary for me because I have things in realistic orbits
I've currently got a sun, with a planet rotating around it, with the ring orbiting around the planet
In that case I have them parented like in the planets example
And now I've got the meshes and the player on the ring itself, so that'll be easier
Thanks for both of your help once again!
FYI, I'm also happy to upstream this too. Would be interested to see what use cases you need.
I'm still deciding if it's actually helpful. It's really nice to be able to specify world coordinates, like "draw this ellipse to represent this orbit" without needing to look up global transforms. At any rate, I think my brain is fried, I can't make myself understand how to get a local cell/position from a global position when the floating origin is potentially deep in a grid hierarchy. Is there a utility to make that easier or do I just need to copy paste the right code?
No utility no, sorry. I know that is a pain point if you aren't me.
Note that every grid stores a local transform in the component, so regardless of where it is in the hierarchy, you could use that to draw things in that coordinate space
It allows you to reuse the hierarchy traversal used for floating origin propagation, and jump straight into any grid's reference frame
Getting a weird one today
I get to what I'm assuming is the edge of my gridcell then get moved to the opposite edge of my gridcell
Rather than smoothly continuing on with the grid cell updating behind the scenes
Although, I haven't confirmed that is actually what's happening, that's just what it looks like. Let me double check that now
Ok, after double checking using the debug text system from the demo example it appears to be working as it should, but when we move gridcells my terrain is being moved to 0 of the new gridcell
Which is odd
Ok figured it out, error was on my end!
Will things break if I have a hierarchy like:
(BigSpace, Grid)
- (Transform, GridCell)
- (Transform) <-- no `LowPrecisionRoot`
Basically when a low-precision entity doesn't have LowPrecisionRoot but its parent is a high-precision entity?
the low precision root is added automatically
it's a perf optimization
otherwise the plugin would need to traverse the hierarchy every update to find them
So, that should be fine
In that case I think I'm hitting a bug. Basically I've got this hierarchy:
(BigSpace, Grid) // planet reference frame
- (Transform, GridCell) // 1st stage
- (Transform, Mesh, LowPrecisionRoot, ...) // 1st stage graphics
- Transform // 2nd stage
- (Transform, Mesh, ...) // 2nd stage graphics
Then at stage separation, I'm unparenting the 2nd stage from the 1st stage, reparenting it to the planet reference frame, and adding a GridCell to it. The graphics wig out and start flying around (wrapping from the left side of the cell to the right). What's weird is the 2nd stage entity itself is in the right place. BRP is showing that none of the 2nd stages children have LowPrecisionRoot. If I manually add them, the graphics look normal.
I can try to debug if you help me understand where/under what conditions LowPrecisionRoot is supposed to be auto-added
Or I can slap together an MVP
A minimal case would be helpful. I won't have time to debug for a week or so, sorry.
I'd refer to source, it only shows up in a couple spots iirc
No worries, I'll PR when I figure it out ๐
Thank you.
I'll do my best to reply to questions here, but life is a bit too busy for OSS at the moment.
It happens! Take care of yourself ๐
Honestly crazy how much time people do have for OSS considering most work for free
I have been seriously considering making some of the future big_space stuff closed-source for that reason tbh.
... because you don't have enough time, or..?
I value my time ๐
do you have open source example of 100m+ entities?
Oh, entity count?
you can just play with the spatial hashing example
for maximum perf, disable the parts where the meshes are added to the spawned entities
The slowdown is generally on the rendering side if you are relying on the out-of-the-box instancing.
@crude dagger
Oh, sweet. Thanks.
So...I am currently writing up a design for an Escape Velocity clone to get my self started in bevy. I wanted to go hard, though, and create an absolutely massive play are with precedural generated stars and planets the size of the milky way.
My original idea for coordinates was to create a grid of sub-grids, with each top-level grid containing an i64 x,y coordinate, and each subgrid containing another i64 x,y coordinate. This would give me an extremely precise coordinate over a huge distance. Then I was going to give the camera its own coordinate within my grid and subtract the positions of the objects within a 'render range' from the position of the camera, math the coordinates into an f32 location relative to the camera, and display them, always keeping things close to avoid jitter/error. I hope I explained this well.
big_space seems to, maybe, solve some of this for me in a similar manner, though it uses a float within an int grid. I did read some info at the top of this about physics at the borders of the gridcells being an issue.
I also read some of the beginning of this discussion forum and ya'll were talking about how big_space can be the source of truth, or another system can, and that confuses me. Why would I make another system the source of truth? How would that even work?
Lastly, is there any tutorials beyond the examples and docs.rs entries that explain how to use this crate in its basics? "by example" is great when the why and how get explained well, and in pieces that build on the previous, but just splatting a bunch of example code into the internet and hoping newbies will understand it makes things much harder. No offsense; I know how hard writing good docs can be. I'm just asking if there's any baby-steps tutorials out there.
Thanks!
I'm just asking if there's any baby-steps tutorials out there.
There's not much to use. Bigspace does its magic behind the scenes. You just follow the guidelines described on the docs.rs front page. At least from my POV. @worthy vector has more hands-on experience, maybe he can point to some nuances.
Yeah I feel like the best way to explain this crate might be visually. Maybe someone should go make a video explaining how it works.
Well, yes this crate will probably do exactly what you want. It has an example of giving you proton scale across the observable universe, so your milky way isn't an issue at all. The biggest issue you'll run into is making sure rendering/LODs are performant with 400 billion stars.
To try and explain how it works, basically in bevy, the difference between Transform and GlobalTransform is that GlobalTransform can be thought of as "absolute" coordinates, and Transform is like local coordinates. This crate breaks the whole universe into a grid of configurable cell size (say, 1km), then uses Transform to describe local position within your current cell. When rendering, GlobalTransforms are computed relative to the camera's cell. That means you always have precision near the camera where it's needed, and precision increases as you get closer to something.
There aren't really any tutorials I can point to beyond the docs and examples, I think the current best way to learn the crate right now is using it and asking questions here. I'm happy to help try and explain it better, maybe draw up some visuals as well ๐
For you case, I'd probably use a grid cell size of 1km and a precision of i64. That'll give you a total play area of almost 2 million light years (much larger than our galaxy) with a worst-case precision of about 1/10th of a millimeter. If you want a bit more precision, you could shrink your grid cell down to 50m and still contain the whole galaxy, and your precision would go to about 5 micrometers in the worst case
(if I'm doing all my math right haha)
As others have said, for the most part this crate tries to get out of your way and make simple things easy and unsurprising. As long as you follow the guidelines, you can often just work with transform and global transform like normal bevy.
That said, it functions very similarly to what you described.
So what's the deal with border physics? I didn't fully understand that conversation from the beginning
Basically all objects have their transforms constrained to an area the size of the grid cell. That means two objects that are right next to each other and potentially colliding, but are in different grid cells, won't be next to each other as far as the physics engine is concerned. You can write your own collision system if you don't need a robust physics engine, or there are some workarounds. Not sure on the status but @wild tangle was working on simulation islands, which will offer a potential solution I believe. He can probably give you a better idea for how to solve the issue (if he's not busy)
So basically, existing physics engines are unaware of the grid and re-origin technique of this library, so they would see two things about to meet at the edge of a gridcell as being on opposite sides of the origin and never even able to touch....that right?
So physics has to be written with the gridcell coordinate in mind as well.
Pretty much.
It's something you can solve at the integration level though, the engine itself doesn't need to worry about it.
well i'm not even started yet, so i'm not worried about it just yet lol.
Yup
Hey, I'm enjoying this crate as it allows me to make a space game more easily. However, I have one question - how bad/good does it work with existing crates like avian/rapier3D physics?
Physics integration is wip
Kind of waiting on avian's simulation islands iiuc
If you're willing to hack around I think you can make it work with caveats, but I just built my own physics system since my needs are minimal
Couldnt I manipulate it manually through this? It seems promising (rapier)
Could probably cheat it through collision bit mask
Yup those are potentially valid options. Main thing to be aware of is that all your entities will have their translations in the same cell-sized area
it might be practical to not even collide things that aren't in the floating origin's cell
Could just reduce it to nearby cells to be really honest
it would use big_space's spatial hashing and neighbor flooding to group nearby entities into islands, which would be separate physics simulation instances
(different from simulation islands, those are a physics optimization for sleeping/waking and basic solver parallelism, unrelated to big_space support)
This bit is already first class and optimized, they are called partitions. ๐
Oh, cool!
Detect and update groups of nearby occupied cells.
@naive elk you're currently using big_space right? Have you updated to bevy 0.16? Curious if you're using big_space main and if so how it's working for you
I wanted to finally put something inspiring into the 3d world besides a capsule mesh, so started to learn modelling. It completely sucked me in, I haven't touched code in a while. ๐ The way I see it, the longer I'm busy modelling, the more cool features Bevy/BS gets in background. ๐ Hopefully, that is. Maybe Mr Jondolf integrates with BS, or something. So... I'm gonna migrate later.
Why, is it easy?
Haven't tried it but it looks straightforward.
Also yes I get sucked into blender sometimes ๐
It's on my list of legitimate excuses to pause whatever thing I'm currently sick of
I wonder if it makes sense to skip segmentation / lods during modelling and instead try throwing a vertex rich mesh at Bevy's experimental meshlets? The idea seems appealing with BS's real-scale objects
๐
That's... a great freaking idea
Somewhere in the future there is a paradise where you get BS, Avian and virtual geometry and it all just works and with good frame rate, too ๐
Sorry for the delay in release. Life has been hectic.
No problems here. You mentioned you were a bit busy for open source and I think that's fair. Physical and mental health should always come before making us happy of course (plus I haven't gotten around to updating to 0.16 anyway)
Does big_space support multiplayer? Or is that out of scope for the crate?
The only thing that could stand in the way of multiplayer, as I understand, is whenever clients run their own world simulations and to avoid desyncs you need the simulations to be identical. So the question boils down to if big_space uses any non-deterministic math.
Oh, forgot I can't create threads because we're in a thread already. But here is a 0.9.1 codebase analysis for non-determinism. Keep in mind that, I'm pretty sure GlobalTransform doesn't need to be replicated across network so how it's calculated shouldn't matter. But the other stuff mentioned in the report might matter, not sure.
this looks pretty accurate to me
That's a pretty open ended question. The short answer is that it supports it just as much as bevy's own Transform and GlobalTransform do.
It doesn't have the problems that a world-recentering solution might have.
I'm specifically asking because i'm pretty sure a FloatingOrigin doesn't make much sense server-side, is there some way i should turn off GlobalTransform translation propagation, or should i just set it somewhere and ignore the translation? (I'm probably going to replace it with a fixed-point solution for when i need to read global positions anyway)
Also Grid and GridCell don't implement Serialize and Deserialize, and i'm pretty sure i have to replicate those to clients?
I'm not sure i have my head fully wrapped around this crate and am little tired atm, so i might be thinking about things completely wrong here
have you looked at Bevy Replicon yet?
Yep! That's what i'm using, it requires replicated components to be serializable
Cool, because I haven't ๐ So I don't know what it requires. Yeah you definitely need Grid, GridCell serializable. ๐ค Without their replication, the client's bigspace logic wouldn't work.
Well, worst case you could just fork big_space, add serialization to those components, see that multiplayer works, and PR that back to aevyrie ๐
that's why I made these changes
I believe the gpt thing posted above also mentions this
Server doesn't need to compute or care about GlobalTransform, it can just do the gridcell recentering. All the clients need are updates to GridCell and Transform
Adding serde derives is a welcome addition. Should stick it behind a feature flag.
Thank you! Adding serde sounds pretty easy, so i shall work on that and PR when i'm done
The server might still care about GlobalTransforms for rotation and scale, and it seems like disabling BigSpacePropagationPlugin will disable the propagation of that as well
that said i can't think of a use case off the top of my head, so it might very well not be a big deal
GlobalTransform is purely client side for rendering and is relative to the floating origin, which will be different for every client.
the transform and gridcell (hierarchy) are what is needed to define the position of all entities in space.
question: so I'm trying to use big space but I can't initialize it, I have
use big_space::prelude::*; at the top of my file but I keep getting this error
```error[E0425]: cannot find value BigSpaceDefaultPlugins in this scope
--> src\core\mod.rs:27:22
|
27 | .add_plugins(BigSpaceDefaultPlugins)
|
are you using the same version as the one with BigSpaceDefaultPlugins
iirc that is not released on crates.io yet
ah
yeah I'm on 0.9.1
okay, well switching to the 0.16 branch method, I now get this error
```error[E0277]: the trait bound big_space::plugin::BigSpacePlugin<_>: Plugins<_> is not satisfied
--> src\core\mod.rs:27:22
|
27 | .add_plugins(BigSpacePlugin::default())
| ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait bevy::bevy_app::plugin::sealed::Plugins<_> is not implemented for big_space::plugin::BigSpacePlugin<_>
| |
| required by a bound introduced by this call
|
sync up the bevy version too, probably
bevy version is 0.16.1
There is not a released version of big_space that is compatible with bevy 0.16
edit: ah I see you said you are using the branch
What branch? main?
oh, just main branch?
Yup.
ah, I guess I'll wait to include it for bevy 0.17 since I don't like using the main branch for projects
Is there a way to get a GridCommands from a query in a different system? I am trying to spawn additional grids after the root grid has been created.
https://gist.github.com/motgenror/bed91ee62874983ce742589d9fe2c875 that's what I used in 0.15
Spawning entities on a Grid outside of initial helper functions - bigspace.rs
Huh... I actually looked at that while scrolling up looking for clues. I definitely have no idea what I'm doing, but I was trying to spawn a new grid like the planets example where they use with_grid_default. I'll keep reading, thanks for your help!
If you want to create a new Grid, just add it as a new component:
commands.spawn((
Grid::<i8>::default(),
// other components
));
woah wait a minute... So spawn a new entity with a Grid component as a child of the root grid entity?
maybe this is way easier than I thought it was
can I mix grid precision? like if the root is i64 and I want an i32 for some moon or whatever?
yep
https://docs.rs/big_space/latest/big_space/
Grids can be nested, like Transforms.
Uhh I don't remember where it says you can nest different precisions though but I'm sure you can from previous discussions on this channel.
A floating origin plugin that uses integer grids to extend bevyโs Transform component with up to 128 bits of added precision. The plugin propagates and computes GlobalTransforms relative to floating origins, making the most of 32 bit rendering precision by reducing error near the camera.
Well that's neat! I'm still getting my head around how this actually works. I maybe need a big_brain plugin
https://github.com/zkat/big-brain there you go
HA
big_space is actually very easy to use. Place Grid where you want your grids.. children under these entities will be within that grid's coordinate system (if these entities also have a GridCell along with the usual Transform)
I'm trying to make this work using the openxr VR plugin thing and having to do some weird stuff to make it work. I went and parented the root grid to the vr_tracking_root and had to change how the library finds floatingorigins. I think that is working correctly now.
If I create an entity that is a child of a grid, and that child entity has a Grid of it's own, does that child also need a GridCell that somehow references the parent grid?
uhh not sure
one way to find out! haha, thank you for taking the time to answer my weird questions!
if you run big space with the validator enabled it will try to verify the archetypes of your entities and complain if something logically doesn't make sense
I think it's on by default
Yep! I made it unhappy a few times now
I think I should go play with a simpler example and get my head around it before i go off the deep end in VR
If you can describe what you are trying to accomplish, I might be able to help.
I think I may have it figured out. Basically I just wanted to be able to dynamically move the FloatingOrigin smoothly between grids, e.g. a player doing a space walk from a ship. Also want to dynamically create grids as i load in a star system or whatever. I think that's all totally do-able just by spawning in entities with grids
If I have an entity that is a child of the grid and has a gridcell component, do all of it's child entities need to have that component too?
no
all of its parents do, but not children
you can only decrease in precision as you move away from the BigSpace root toward children, otherwise the plugin would not be able to reliably transform between grid coordinate systems.
In many cases you can get away with only a single grid at the root, and all entities at that level having a gridcell
but all grandchildren and decendants could just be normal Transform hierarchies without high precision
the only time you need to nest grids is if you have moving reference frames that are themselves huge scale that require huge precision
the canonical example is a planet might be placed in a solar system grid, and objects on the planet would need to be in the planet's grid
But once you get down to normal 3d game scene scales, you really shouldn't need to reach for grids any more
That makes intuitive sense. I'm looking at the translation_to_grid function and it's starting to click
Thanks for helping out!
This is different on main I believe, grid precision switched from being a generic to being a crate feature
Are there any general considerations for using big_space with bevy picking/raycast? I'm having to compute global transforms for a ray starting point and it's become a little choppy if my starting point is moving fast enough. Starting point is a child of an entity with FloatingOrigin
I assume it's a scheduling issue but haven't ran it down yet
That wasn't supposed to be a reply, hold on
Not really, the scheduling is the same as normal bevy. Your best bet is to make it an entity with a transform, so the transform system computes the global transform for you.
The picking system has a helper that gives you all pointer rays precomputed, that should also work.
I think my issue was something in the bevy vr mod messing with my rotation there. Wasn't a scheduling issue at all
by not parenting it to the tracked controller space anymore, and manually updating the position and rotation, it's working fine. I was just blaming bigspace because I have no idea what im doing ๐
Attempt to explain no 2. A collision island is simply a list of entities (or a list of a bunch of relevant components in ECS sense) that are suspected to be close enough to each other. The only thing different for the collision solver would have to do is work with grid coordinates (cell + xyz), instead of just global xyz, right? I'm thinking it would have to work with grid coords and not FO-relative coords because what if you're trying to collide planets. I guess then you could use f64, it's happening on the CPU anyway so who cares? But just sticking to grid coords that, when subtracted, give you an f64 difference, still feels more universal and precise than translating coords of all island entities into a single FO-relative coord system like for renderer.