Skip to content

Commit

Permalink
update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
tiffany352 committed Oct 15, 2023
1 parent 5e8b769 commit 1930d87
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 41 deletions.
114 changes: 85 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
![Screenshot](docs/screenshot.jpg)
(Planet rendered using [Atmosphere Shader v0.4](https://godotengine.org/asset-library/asset/2002))

Starlight is a Godot addon that renders 100,000 stars in realtime, with
Starlight is a Godot addon that renders 100 000 stars in realtime, with
low performance cost. It's an alternative to using a skybox, and
also may be relevant to anyone making a space game.

Expand All @@ -18,23 +18,28 @@ Check out the demo in your web browser: https://tiffnix.com/starlight-demo/
see stars go by.
- Exact position, luminosity, and temperature of each star can be
configured by you.
- Default star generator is based on real main sequence stars (classes M through O).
- Physically based light model: Using a [Point Spread Function
(PSF)][1], rather than a texture that grows or shrinks with
distance/brightness.
- Based on [MultiMeshInstance3D][2] for performance.
- Uses a trick to avoid being clipped by the far plane, to let stars be
very far away.
- Works with Forward+, Mobile, and Compatibility renderers.
- Comes with a random star generator based on main sequence stars (classes M through O).

[1]: https://en.wikipedia.org/wiki/Point_spread_function
[2]: https://docs.godotengine.org/en/stable/classes/class_multimeshinstance3d.html

# Usage Guide

To get started, insert `Stars.tscn` into your scene. This will
automatically spawn 100,000 randomly generated stars.
To get started, insert `Stars.tscn` into your scene. By default, nothing
will be visible. You can attach the script `StarGenerator.gd` to
randomly generate stars. The default will be 10 000.

On the instance itself there are some properties you can configure that
affect the star spawning. These are:
## StarGenerator

This script procedurally generates stars in a ball centered on the
origin. It has these properties:

- `size`: Stars are spawned inside of a sphere of this radius.
- `star_count`: The number of stars to create.
Expand All @@ -47,40 +52,91 @@ affect the star spawning. These are:
For further customization of the star generator, I recommend editing the
script directly.

To make changes to the visual appearance you will need to edit the
Material. You can do this either by opening Stars.tscn, or by clicking
the dropdown arrow on the MultiMesh resource and click "Make unique".
You'll then need to do this again on the Mesh resource inside it. Expand
the Mesh, expand the Material, expand the Shader Parameters section.
Inside here you will find more properties to configure.
## StarManager / Stars.tscn

There is only 1 script property exported, which is which shader to use.
The default points to `Star.gdshader`. You can fork the shader easily by
changing this.

The script also forwards the shader parameters which you can edit
directly.

If you want to load your own star catalog, or use a custom random star
generator, you will need to call `set_star_list()` with an array of `Star`.

The Star constructor takes 3 arguments:

1. `position`: 3D position in model space units.
2. `luminosity`: Luminosity in [solar luminosity][3]. Approximately 1.0 for Sol.
3. `temperature`: [Effective temperature][4] in Kelvin. Approximately 5778 for Sol.

[3]: https://en.wikipedia.org/wiki/Solar_luminosity
[4]: https://en.wikipedia.org/wiki/Effective_temperature

## Star.gdshader

The following visual properties are exposed:

- `emission_energy` - Multiplier for how bright stars should be.
Generally this is some extremely large number like `50000000000` -
Generally this is some extremely large number like `500000000` -
you'll need to add or remove zeros until it looks right.
- `camera_vertical_fov` - The vertical camera FOV. By default in Godot
this is 70, but if you change it you may need to adjust it here. For
example, if you're zooming in the camera, you'll need to adjust this.
- `color_gamma` - How strongly colors should show through. A value of 1
should be close to real life, while a very high value of 5-10
resembles what you see in false-color images from telescopes. A value
of 3 or 4 is a good balance.
- `billboard_size_deg` - This controls how much of the screen the PSF
texture takes up, in degrees. For the default JWST PSF I recommend a
value of around 70.
- `min_size_ratio` - There is a performance optimization where the PSF texture
is cropped for stars that are dim. This will be 99.999% of stars.
Generally set this to some low value like 0.005.
- `debug_show_rects` - This can be useful while tweaking the values of
`billboard_size_deg` and `min_size_ratio`.
- `max_luminosity` - This is the point at which the cropping stops and
the full PSF texture is used. If your PSF looks cut off, you may need
to lower this.
value of around 90.
- `meters_per_lightyear` - This is a scaling setting, you'll need to set
it depending on how far away you want your stars to be.
- `distance_limit` - This acts as an upper bound on how bright stars can
be. Once you get closer to a star than this distance, it stops getting
any brighter. This setting can be used to prevent blowing out the PSF
texture.
- `luminosity_cap` - This is the maximum brightness a star can have. The
main usage of this is to prevent the PSF texture from being blown out
and showing as a white square. This mainly happens when very close to
stars.
- `texture_emission` - This is the actual PSF texture. The default one
is the PSF from the James Webb Space Telescope, because it looks cool.
There are a few others in the `psf-textures` folder which can be used
instead.
- `clamp_output` - Clamps the output from 0 to 1 when enabled. Can be
useful depending on how your HDR is setup.

In order to have good performance, the PSF texture needs to be cropped
depending on how bright the star is on screen. The majority of stars
only appear as a couple of pixels in size, as opposed to covering almost
the entire screen for a star you're very close to. This cropping
behavior directly affects how much overdraw there is, which can
massively impact performance. You will need to adjust these properties
if you change the PSF texture from the default JWST one. To control this
behavior, the shader has these properties:

- `min_size_ratio` - This is the minimum size that a star can render at.
This corresponds to the innermost bright spot of the PSF texture, and
is usually a very small value like 0.003.
- `max_luminosity` - This is the point at which the cropping stops and
the full PSF texture is used. To set this value, try to find the point
at which the PSF texture is fully visible, specifically things like
diffraction spikes reach the edge of the texture. Then adjust
max_luminosity until it's just below that point.
- `scaling_gamma` - Diffraction spikes usually fall in brightness
according to distance^2 from the center of the texture, which means a
value of 0.5 is ideal. You may need to use other values depending on
your PSF texture. For a perfect airy disk in particular, the falloff
is faster than quadratic.
- `debug_show_rects` - This can be useful while tweaking any of these
values. It helps visualize whether any stars are being over-cropped,
or if there is too much overdraw in your scene.

Be careful when tweaking these values. You may want to reduce the star
count to something more manageable like 1000 or 10,000 while doing this.
Setting `scaling_gamma` to 0 by accident, for example, can crash Godot,
your graphics drivers, or even your entire PC.

The shader also requires knowledge of the camera FOV to work correctly.
StarManager tries to automatically find the Camera3D of the current
viewport, but in some cases this auto-detection may be wrong, and you
will need to edit StarManager.gd for your needs. It also does not
display correctly in the editor due to it using different FOV settings
from the scene.

# Credit

Expand Down
18 changes: 11 additions & 7 deletions addons/starlight/Star.gdshader
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
shader_type spatial;
render_mode blend_add,depth_draw_never,cull_front,shadows_disabled,skip_vertex_transform,unshaded;


// Visual properties:
uniform sampler2D texture_emission : hint_default_black;
uniform float emission_energy;
uniform float billboard_size_deg : hint_range(0, 90) = 90;
uniform float min_size_ratio : hint_range(0, 1.0) = 1.0;
uniform float scaling_gamma : hint_range(0.0, 2.0) = 1.0;
uniform float max_luminosity;
uniform float meters_per_lightyear = 100.0;
uniform float luminosity_cap = 1e300;
uniform float camera_vertical_fov = 70;
uniform float meters_per_lightyear = 100.0;
uniform float color_gamma : hint_range(0.0, 10.0) = 1.0;
uniform bool debug_show_rects = false;
uniform bool clamp_output = false;

// This should really be a godot shader builtin.
uniform float camera_vertical_fov = 70;

// PSF cropping related uniforms:
uniform float min_size_ratio : hint_range(0, 1.0) = 1.0;
uniform float max_luminosity;
uniform float scaling_gamma : hint_range(0.0, 2.0) = 1.0;
uniform bool debug_show_rects = false;


varying vec3 STAR_COLOR;

Expand Down
5 changes: 5 additions & 0 deletions addons/starlight/StarGenerator.gd
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
@tool
extends "res://addons/starlight/StarManager.gd"
## Procedurally generates main sequence stars and populates StarManager with them.

## Radius of a sphere in which to place stars.
@export var size: float = 5000: set = _set_extents
## Number of stars to generate.
@export var star_count: int = 10000: set = _set_star_count
## RNG seed, which can be used to re-roll the random generation.
@export var rng_seed: int = 1234: set = _set_rng_seed
## If set to true, a Sol-like star will be placed at 0,0,0.
@export var generate_at_origin: bool = false: set = _set_generate_at_origin


Expand Down
15 changes: 15 additions & 0 deletions addons/starlight/StarManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extends Node3D
@export var shader: Shader


## Class used to represent stars for StarManager. Passed to set_star_list().
class Star:
# Position of the star.
var position: Vector3
Expand All @@ -19,6 +20,11 @@ class Star:
self.temperature = temperature


## Most stars have an "Effective temperature" which is the black body temperature that most closely
## matches their emitted spectra.
##
## This describes the color of the star as a single value, a temperature in Kelvin, from the range
## of ~500 through to 60,000 and beyond.
static func blackbody_to_rgb(kelvin):
var temperature = kelvin / 100.0
var red
Expand Down Expand Up @@ -101,11 +107,14 @@ static func blackbody_to_rgb(kelvin):

var material: ShaderMaterial
var mesh: MultiMesh
# Hide these parameters because they're set by StarManager:
var internal_shader_params = {
'camera_vertical_fov': true
}


# This forwards the shader parameters, which would otherwise be inaccessible because the Material
# is generated at runtime.
func _get_property_list():
var props = []
var shader_params := RenderingServer.get_shader_parameter_list(shader.get_rid())
Expand Down Expand Up @@ -137,6 +146,10 @@ func _set(p_key: StringName, value):
material.set_shader_parameter(param_name, value)


# In order to render the stars without polluting the .tscn file with MultiMesh buffer data, this
# technique is used of creating the instance and adding it as a child in _init(). This somehow
# doesn't actually add the child to the scene in the editor, even though the code is running as a
# tool script.
func _init():
material = ShaderMaterial.new()
material.shader = shader
Expand Down Expand Up @@ -174,6 +187,8 @@ func set_star_list(star_list: Array[Star]):
func _process(_delta):
var camera = get_viewport().get_camera_3d()
var fov = 70
# The camera can be null if the scene doesn't have one set.
# This value will also not match the editor camera.
if camera:
fov = camera.fov

Expand Down
10 changes: 5 additions & 5 deletions addons/starlight/Stars.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ script = ExtResource("1_u877o")
shader = ExtResource("2_6rhhm")
shader_params/emission_energy = 1e+07
shader_params/billboard_size_deg = 90.0
shader_params/min_size_ratio = 0.003
shader_params/scaling_gamma = 0.5
shader_params/max_luminosity = 100000.0
shader_params/meters_per_lightyear = 100.0
shader_params/luminosity_cap = 4e+06
shader_params/meters_per_lightyear = 100.0
shader_params/color_gamma = 4.0
shader_params/debug_show_rects = false
shader_params/clamp_output = false
shader_params/min_size_ratio = 0.003
shader_params/max_luminosity = 100000.0
shader_params/scaling_gamma = 0.5
shader_params/debug_show_rects = false
shader_params/texture_emission = ExtResource("3_wqe40")

0 comments on commit 1930d87

Please sign in to comment.