[Feature Request] Save objects position at a given time

Hi

I wondered if it would be possible to have a function which saves the positions of all objects at a given time?

Ideally, a binary array of [id, x, y, z] with the asteroid id could be the AstDyS id so I can find out later its name, size and type, and just the name for planets and moons.  The coordinates could be a long which should be enough to store the position at meter precision.

Btw I only need one set of data (i.e. 1 Jan 2020).

Thanks for an excellent project.

Comments

  • edited February 2020
    Here are functions that print x,y,z position for sun, planets, and moons (this part is easy):
    func print_body_positions() -> void:
    	var time: float = 20.0 * 365.25 # days from J2000 epoch
    	var scale: float = Global.scale # Godot length units per km
    	var registrar: Registrar = Global.objects.Registrar
    	var bodies_by_name: Dictionary = registrar.bodies_by_name
    	for body_name in bodies_by_name:
    		var body: Body = bodies_by_name[body_name]
    		var orbit: Orbit = body.orbit
    		var position: Vector3
    		if orbit:
    			position = orbit.get_position(time)
    		else: # the Sun doesn't have an Orbit!
    			position = Vector3.ZERO
    		var position_in_km: Vector3 = position / scale
    		prints(tr(body_name), position_in_km)
    
    Note that above gives you each Body's position relative to its parent. The Sun is 0,0,0 so this only matters for moons. If you want moon positions to be absolute, do it recursively from top down:
    func print_body_positions() -> void:
    	var time: float = 20.0 * 365.25 # days from J2000 epoch
    	var scale: float = Global.scale # Godot length units per km
    	var registrar: Registrar = Global.objects.Registrar
    	var top_body: Body = registrar.top_body # the Sun
    	print_recursive(top_body, Vector3.ZERO, time, scale)
    
    func print_recursive(body: Body, parent_position: Vector3,
    		time: float, scale: float) -> void:
    	var orbit: Orbit = body.orbit
    	var position: Vector3
    	if orbit:
    		position = orbit.get_position(time)
    	else: # the Sun doesn't have an Orbit!
    		position = Vector3.ZERO
    	position += parent_position
    	var position_in_km: Vector3 = position / scale
    	prints(tr(body.name), position_in_km)
    	for child_body in body.satellites:
    		print_recursive(child_body, position, time, scale)
    There is a function in Timekeeper that is supposed to convert strings like "2020-01-01 12:00" to time (days from J2000 epoch), but it appears to be broken now. (I've opened an issue.) [This is working now.]

    OK, asteroids...
    Unfortunately, they are not objects and the CPU doesn't know where they are. Fixed orbital parameters for the 647,000 asteroids* are held in compact "pool" arrays (in AsteroidGroup objects) that are passed to the GPU as mesh arrays. The CPU passes "time" to the GPU each frame that asteroids are visible (this happens in HUDPoints). From here on, everything is done by "shaders" in the GPU. So only the GPU knows the asteroid positions. And it is not easy to get data from the GPU back to the CPU.

    (* Actually, only 64,738 are currently imported based on mag_cutoff=15 in data/solar_system/asteroid_group_data.csv. If you have a good graphics card, set mag_cutoff=100 for all groups to see all 647,000! Or set mag_cutoff=100 for "Near Earth" if you want to see all NEOs no matter how small; that's not a huge number.)

    This is why you can't currently "visit" an asteroid in I, Voyager. However, we absolutely want to be able to visit asteroids! In outline, here is what we need:
    1. Some way to select one or a few asteroids. Perhaps from a list.
    2. Asteroid models. For the core I, Voyager system, I'll probably limit this to the list of explored asteroids. However, it would be great to have a procedural model generator for non-explored asteroids as an add-on (if anyone knows of open-source code that already does this, please let me know!).
    3. When user selects an individual asteroid, that asteroid is instanced as a Body with an Orbit (and Model, HUDOrbit, HUDLabel, etc.) from data in AsteroidGroup. 
    So, back to your question. What you really need is code for step #3 above. Then you would get position from the Orbit object exactly as above. It's code that I need to write at some point, but I can't promise when. I'll post again here if I do get to it...
  • Btw, it is possible to get data from GPU to CPU. Cryptocurrency miners do it. If anyone knows how to pass vertex coordinates back to the CPU, please tell me how to do it! This would make it possible to select an asteroid point via mouse click.
  • Thanks. I will study this.
  • Godot 4.0 is supposed to have features for gpu computing. Maybe that will help.
  • That will help a lot. I'll wait for 4.0 before trying to solve the asteroid selection (from screen points) problem. I had a crazy hack partly programmed using steganography...
  • Do you mean something like oldschool object picking by color? That should be possible using existing features. Godot can render to a hidden viewport and that viewports texture can be read. That's a way to get data from the gpu.
  • TassuP said:
    Do you mean something like oldschool object picking by color? That should be possible using existing features. Godot can render to a hidden viewport and that viewports texture can be read. That's a way to get data from the gpu.
    Maybe. I'm not always aware of existing "oldschool" solutions. The basic problem is that only the shader vertex function knows where the asteroid is at any particular time. The only way I know to get that info out is having each vertex pass its ID to the fragment function and then encode ID in the pixel color. Then the problem is searching around and decoding nearby pixel colors for valid IDs when the user mouse-clicks.

    My original idea was to use least significant bits of color, but there are not enough "non-noticeable" bits to encode >millions of IDs (without using adjacent pixels, but that gets hellishly complicated to program). The next idea was to do it all in a single frame and hope the user doesn't see that.

    I have not messed around with viewports at all so I'm currently pondering your "hidden viewport" idea. Would this mean that all of the asteroids (which are a ShaderMaterial instance for each "group" of asteroids) would have to be instantiated again under this hidden viewport? That would be a problem -- the asteroids are already expensive and cause a small hang with the user first makes them visible.

  • edited February 2020
    If you google "opengl picking by color" you will find many old tutorials. This used to be a very common trick, but these days raycasting has replaced it.
    The basic idea is pretty much like you described, but using the full color range instead of just the least significant bits. This was hidden from the user by simply not swapping the buffers for that frame. In Godot another viewport can be used to hide this, and it can even have smaller resolution to speed it up. And only render the frame when needed.
    This has the limitation of 65536 unique colors for 16-bit viewport texture and that's not enough for all asteroids. I guess you will need multiple renders.
    I'm studying your code, but haven't yet figured out how everything works. I assume that you have a MeshInstance somewhere with the asteroid data as Mesh and a custom shader. The Mesh can be shared between MeshInstances that have different material overrides, so there would be no duplicate data.
    But the hang might be caused by Godot compiling the shader. That's a common problem when working with particle effects. People often get around it by instantiating every particle effect once when starting the program.
  • Thanks! That all confirms my view that I should wait for 4.0 to see what can be done then.

    tree_nodes/hud_points.gd is the MeshInstance, and this uses either shaders/orbit_points.shader or shaders/orbit_points_lagrangian.shader.
Sign In or Register to comment.