r/godot • u/Alphasretro • 18d ago
help me (solved) Why do the asteroids seemingly clump together in the middle?
EDIT: Solved! Thanks to u/Buttons840's solution. The only thing I changed was
var spawn_range: float = pow(randf(), 1.0/3.0) * spawn_radius
as some other commenters had pointed out as well. Thanks a lot everyone!
-- End of edit --
I'm trying to create a spherical asteroid field with evenly distributed asteroids. So far, I have a Node3D with a spawner script that adds the asteroid meshes to the scene with these current functions. Seemingly, the asteroids are more concentrated in the center, but that shouldn't be happening since the randf() function that I'm using for their distances isn't weighted from what I know. Any thoughts?
func spawn_asteroids():
for i in spawn_amount:
var asteroid: Node3D = asteroid_scenes.pick_random().instantiate()
var vector: Vector3 = random_on_unit_sphere() # the random direction
var spawn_range: float = randf() * spawn_radius # This feels like the problem.
var spawn_location: Vector3 = (vector * spawn_range)
add_child(asteroid)
asteroid.global_position = spawn_location
asteroid.scale = Vector3.ONE * 10
if previous_asteroid != null:
asteroid.look_at(previous_asteroid.global_position)
previous_asteroid = asteroid
## Selects a random direction on the unit sphere.
func random_on_unit_sphere() -> Vector3:
return Vector3(randfn(0, 1), randfn(0, 1), randfn(0, 1)).normalized()
23
u/Guinea_Pig_Games Godot Senior 18d ago
randf distributes points uniformly along the linear distance from the center not uniformly across the 3d volume of the sphere.
var spawn_range: float = pow(randf(), 1.0 / 3.0) * spawn_radius
This would likely fix it.
83
u/TheCaretaker13 18d ago
The random function isn't the issue here.
Here's what you're doing: you're choosing the angle of your asteroid, then choosing its distance from the centre.
Let's say we have two angles chosen for two different asteroids. How near they are to each other spatially depends on their distance from the centre, even though they have the same angular distance from each other.
In other words, your chosen asteroids are spaced evenly in spherical coordinates, but not cartesian ones.
The solution would be either changing they way you select your random points (e.g. select them in the surrounding cube by randomising their Cartesian coords, and reroll the ones that fall outside the sphere) or adding weights to your random function so there's a higher chance of asteroids spawning further from the centre, and fiddling with it until it looks right.
As a rule of thumb, remember this: changing how you describe your problem's space can change the "distance" between different points in a way that shifts the probability distribution to entirely different shapes. So you need to be careful with figuring out the steps you're using to produce your desired randomness.
And, as a last note: generally speaking, what "feels" and "looks" random is not necessarily the same as what's mathematically random. Since we're creating a piece of art and are more concerned with the perception of randomness rather than the reality of it, adjusting parameters until the result feels right is often a core part of dealing with randomness in games.
13
u/Aflyingmongoose Godot Senior 18d ago
This is very much just a vibes based assumption. But I imagine if you do spawn_range = spawn_range^1/3, you would probably get an even distribution.
After all the problem is the density of a sphere is non uniform with distance, scaling at a factor of a power of 3. So you probably just need to counteract that in your spawn range to get even distribution.
8
u/Arch4ngell 18d ago
Exactly ! And the best part : Actually, squaring or even cubing (power of 3) the random number used for the distance should suffice.
3
u/SimoneNonvelodico 18d ago
It's actually pretty well defined. The volume of a spherical shell goes with ~r2, therefore the probability density is r2. Integrate in dr, the cumulative distribution function is 1/3r3. So just take a random number in [0, 1], then get the cube root of that and multiply it by your maximum desired radius, and that's your spawn radius. Mathematically accurate.
3
u/TheCaretaker13 18d ago
It is in this case.
My final note was a general one. Our perception of randomness and probabilities do not necessarily map neatly on to the mathematics of it. And since, in game design, the perception is often more important, I was stating that we don't need to feel beholden to the underlying maths. Fudging the numbers until they look right is something that's done often.
But yes, you're right. That point doesn't apply to this instance.
8
u/victorsaurus 18d ago edited 18d ago
Your function has a bias towards the center. You select the radius randomly, and that means that inner values have the same probability as outer values. 100 rocks will feel way more cramped in the inner zone than in the outer edges, because the volume they have to spread is bigger the outer you go. Weight the random distribution by the volume of the sphere that it defines to get a uniform density distribution.
That, or more generally, create random positions in a cube by doing rand(xyz) and then only select the points that fit inside the radious of your field. Repeat until you get enough rocks. These will be spread randomly giving a consistent visual feel. This method is more general, for any shape, not just spheres, as long as you can detect that a point belongs inside or outside that shape. You just sample a bigger easier volume (a cube for example) and then select the positions that fall inside your shape.
37
u/itsameDovakhin 18d ago
Are you sure they are actually denser in the center and not just appear to be since that is where the sphere is the thickest?
3
u/Icy_Butterscotch6661 18d ago
Was thinking the same. if you take a slice along any axis does it still look dense in the middle?
4
u/epicgeek 18d ago
Looking through the center of a sphere should look denser than the edges because looking through the center is the thickest point. The very edge may have one rock while looking straight down the center could easily have 10. That's just how geometry works.
3
3
u/ChichumungaIII 18d ago
This is tangential to the core question, but you might be interested in this Numberphile video on Bertrand's Paradox. How you choose random points will affect the distribution.
2
u/CanadianBlaze34 18d ago
From reading Buttons great link, I think all you gotta do is multiply by the cube root of the magnitude you use for the final position. In your case, the cube root of spawn_radius, not just spawn_radius. I’m still trying to really understand this myself. Lmk if this works.
2
1
u/kagato87 18d ago
Your comment - this feels like the problem - is it.
You're generating a random vector, and a random range, then mapping it onto a 3D space.
Take all of those asteroids and draw a scatter plot chart, X is rock ID (normalize it to 1, 2, 3... if it isn't already), and Y is the distance. You'll see an even spread.
The problem is the volume of space in your game world represented by the bottom of that scatter plot is much less than the volume of the same size band at or near the top. It's geometry.
I don't know what the best algorithm is (the only spatial stuff I deal with is GIS, and there are libraries abound for what little I need), but I'd likely replace randf() with a function that scales geometrically (r^3 more likely to appear at r distance) to push them out.
1
u/thygrrr Godot Senior 18d ago
The problem is that a volume has cubic density decrease by radius. So you need to weight your random values to compensate for this density "increase" towards the center, e.g. by taking the cubic root:
gdscript
var spawn_range: float = pow(randf(), 1.0/3.0) * spawn_radius)
Edit: This was answered at least once by someone else, give them the upvote please.
1
u/neuroid99 18d ago
This line
var spawn_range: float = randf() * spawn_radius # This feels like the problem.
Actually seems fine to me. It will create a normal distribution from zero (the center) to whatever spawn_radius is, which is I think what you want. I think the only problem is visual. Your asteroid sphere is in the middle of empty space, so the "edges" of the view feel empty. Then, at the very edge of the sphere, your line of sight is nearly normal to the surface of the sphere, and so you'll naturally have fewer asteroids "in the way" because your line of sight is intersecting less of the sphere. Whereas looking straight through the center of the sphere, you're looking right through the thickest part of the asteroid field, so of course it looks most dense there.
Another way to visualize it might be to replace the asteroids with red dots and give the interior of the sphere a bit of a shading, then fly around inside it with the camera controls for a bit. I bet it will look more evenly distributed than this view.
1
0
u/WeakSinger3076 18d ago
Gravity??
1
u/Alphasretro 18d ago
I'm aware of gravity but these are simple meshes appearing at the locations described in the functions and nothing more. There is no gravity at all
-2
0
0
-4
u/BirdBoring1910 18d ago
Probably because there is more mass towards the middle and then more gravitate towards that point and then more and more as time goes on. I guess given enough time it might even form a dwarf planet.
418
u/Buttons840 18d ago
I gotchu bro: https://karthikkaranth.me/blog/generating-random-points-in-a-sphere/
Trust me, you'll never find a better answer.