Wiki

Clone wiki

Asteroid Image Generator / Home

Last updated: June 3rd, 2021

Requirements

  • Blender, version 2.93 at least. Blender 2.93LTS is recommended.
  • Python 3, plus Numpy.

Usage

Run main.py in Python 3, and if you agree with the settings, accept and run. The results will be saved in /Renders. In order to change the settings, head to main.py and edit them manually at the beginning of the file.

If you wish to skip the confirmation step, add -s or --skipConfirmation to the command. If you want the script to print all the settings but not render, use -p or --justPrint

IMPORTANT: You will need to write the full path to your Blender executable inside main.py the first time you use it.

Blender setup

The file asteroidImageGenerator.blend can be edited to add new objects (inside the "Targets" collection) or modify the scene in any way. If one desires to use a different Blender file, the following considerations are important:

  • In order to use shaders written in Open Shading Language, the option Render Properties / Render engine must be set to Cycles, and the Open Shading Language option underneath must be checked. (Picture of the thing)
  • It is desirable to work with real-life units in Blender, but certain glitches can appear when using very long distances. You can choose a multiplier in the Scene Properties / Units / Unit Scale to make life easier. In asteroidImageGenerator.blend the multiplier is set to 1000.
  • The asteroid shader should be either linked or appended to the project. In asteroidImageGenerator.blend, for example, the shader is linked from the asteroidShader/ folder.
  • All the target bodies must be stored in the "Targets" collection. They must be called by name from main.py (case-sensitive). If an object has children objects, these will be shown or hidden together with their parent objects. Children objects cannot be used as targets in the current implementation.

Data

If one chooses to load data from a file, the format currently has the following format:

  camera_x    camera_y    camera_z       sun_x       sun_y       sun_z      sun_irr
   4.66044     0.00000     2.42788     0.00000     3.42020     9.39693          250
   ... 

In which the positional values are in km and the solar irradiance in W·m^-2. One render will be generated per row of data.

Code

The system is run by starting main.py from Python. Python3 is required for working with Blender, I believe. The hierarchy of scripts, modules and data goes as follows:

flowchart.png

main.py

This script contains all the user options, hardcoded until a better GUI is made. After running the script from console, it will show the currently selected options and ask for confirmation, unless the --skipConfirmation flag (or -s) is added to the call.

After that, the Blender file asteroidImageGenerator.blend will be run in the background, and pass the python script blenderControl.py along with all the necessary options and data as arguments.

blenderControl.py

blender [-h] [--fromFile] [--positionalData POSITIONALDATA]
               [--spectralData SPECTRALDATA]
               [--coordinates COORDINATES COORDINATES]
               [--multispectralWlRange MULTISPECTRALWLRANGE]
               [--wavelength WAVELENGTH] [--calibration] --function FUNCTION
               --functionName FUNCTIONNAME --target TARGET --resolution
               RESOLUTION RESOLUTION --fov FOV FOV [--filter FILTER]
               [--sunIrradiance SUNIRRADIANCE] [--outDir OUTDIR]
Option Meaning
-h Help message
--fromFile Positional and Irradiance data will be read from a file. If not included, hardcoded values will be used.
--positionalData PATH Location of the positional data for the camera and Sun, only needed if --fromFile is selected
--spectralData PATH Location of the spectral data, only needed if --fromFile is selected
--coordinates SUNCOORDINATES CAMERACOORDINATES The coordinates for the Sun and Camera, required only if --fromFile is not present. Written as strings containing vectors (yes, I know, I know)
--multispectralWlRange RANGE If present, the render will be performed in the desired albedo range at regular steps
--wavelength WAVELENGTH Used if --multispectralWlRange is not selected
--calibration If present, a white calibration disk image per render will be included in the output folder
--function FUNCTION Number correspoding to the parametric function to be used in the shader
--functionName FUNCTIONNAME String containing the name of the function, to be used in foldernames and filenames
--target TARGET String containing the name of the desired target
--resolution RESOLUTIONX RESOLUTIONY Resolution of the renders, in pixels
--fov FOV FOV Field of View for the camera, in radians
--filter FILTER String containing a vector of three values from 0 to 1, representing the channels R, G and B.
--sunIrradiance SUNIRRADIANCE Value for the sun irradiance to be used if --fromFile is not selected
--outDir OUTDIR Allows to select a different render path

The available functions are (taken from [1]):

Number Name
1 Lommel-Seeliger
2 ROLO
3 Akimov
4 Linear-Akimov
5 Lunar-Lambert
6 Minnaert

And the available targets are:

Number Name Description
1 DRAv2.22 Low-res models of Didymos and Dimorphos
2 BISv1.0 Bennu and Itokawa's models, scaled to the size of Didymos and Dimorphos
3 RISv1.0 Ryugu and Itokawa's models, scaled to the size of Didymos and Dimorphos
4 Sphere A calibration sphere with the asteroid shader and the size of Didymos

modules/setup_functions.py

This module is in charge of setting the camera, lights, and targets into place, and of hiding or unhiding the required objects. It contains the following functions:

sunSetupCartesian(sunObject, sun_x, sun_y, sun_z)

Sets up the sunlamp at the given position.

Actually, the illumination produced by Blender's sunlamps does not change with the position, only with its orientation. The sunlamp is set to always point to the target, so as long as the position of the sunlamp is not (0,0,0), the actual location doesn't matter.

sunSetupSpherical()

TBD

Same as sunSetupCartesian, but will accept angular coordinates instead of cartesian.

cameraSetupCartesian(cameraObject, camera_x, camera_y, camera_z)

Sets up the main camera at a given position.

cameraSetupSpherical()

TBD

Same as cameraSetupCartesian, but will accept angular coordinates instead of cartesian.

targetSetup(targetName)

This function hides all objects from the Blender scene except those that need to be rendered.

proceduralDetail(targetName, state)

This function shows or hides the procedurally scattered boulders around the mesh. state should be a string containing "True" or "False".

systemRotation(targetName, angle)

Rotates the Didymos/Dimorphos system by the specified amount (in degrees) around the vertical axis. The initial positions and individual rotations are arbitrarily chosen in the blender file, lacking a defined coordinate system.

sunIrradiance(sunObject, irradiance)

This function modifies the irradiance of the sunlamp, in W/m^2.

sunDistanceToIrradiance(sunObject, distance)

TBD

This function would transform distance to the sun into the appropriate irradiance value and apply it to the sunlamp.

modules/rendering_functions.py

This module contains functions that render single frames or image sequences.

renderSingleImage(scene, resolutionX, resolutionY, foldername, filename)

Renders frame number one of the blender scene with the desired folder and file names.

renderAnimation(scene, resolutionX, resolutionY, foldername, filename)

Calls renderSingleImage() in a loop and saves the animation to a folder.

Note: because the scene is set up as an animation when multiple datapoints are used, this function could simply make Blender render the animation. However, Blender adds a counter after the filenames, and it seems it is not possible to stop it from doing that. Looping around the frames and applying the renderSingleImage function allows for complete control of the filenames, and doesn't seem to affect performance.

Notes

About the scattered boulders

Currently, the procedurally scattered boulders can be found inside the blender file, in the collection called "Boulders sculpted". It contains nine boulders with widths of approximately one meter. If more boulders, or different ones, are added in the future, scale them until they are roughly one meter long, and then press Ctrl+A and apply the scale. Otherwise the correct sizing of the scattered boulders will be lost.

Boulder size distribution

Currently, the density, minimum and maximum size of the boulders can be defined in three ranges. In order to modify these, select the object inside Blender and go to the Geometry Nodes options in the "Modifier Properties" tab. If one needs to use more than three ranges of sizes, it would be required to modify the geometry nodes tree.

Boulder size is defined in meters, and density represents, in principle, objects per square kilometer. But if the random distribution function is set to Poisson inside the geometry nodes tree, it could mean that fewer points are represented, in order to avoid overlap.

In the future, when the "Attribute Curve Map" is included in Blender, it could be useful for getting a more realistic boulder size distribution.

Based on the paper "Boulder size and shape distributions on asteroid Ryugu", we can find the following distribution of sizes, and know that boulders of over 40 meters are very rare.

ryuguBoulderDistribution.png

References

[1] Disk-resolved photometric modeling and properties of asteroid (101955) Bennu. D.R. Golish, Icarus, https://doi.org/10.1016/j.icarus.2020.113724

[2] Boulder size and shape distributions on asteroid Ryugu. T. Michikami, et al. Icarus 331 (2019) 179–191

Updated