Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
tiffany352 committed Dec 14, 2024
1 parent fe22099 commit 425b24a
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 38 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ 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.

Check out the demo in your web browser: https://tiffnix.com/starlight-demo/
Check out the demo in your web browser: https://tiffnix.com/starlight-demo

# Features

Expand Down Expand Up @@ -86,7 +86,7 @@ The following visual properties are exposed:
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 90.
value of around 45.
- `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.
- `luminosity_cap` - This is the maximum brightness a star can have. The
Expand All @@ -97,6 +97,9 @@ The following visual properties are exposed:
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.
- `texture_emission_tint` - A tint value applied to the PSF texture. The
provided PSF textures need a tint value to look correct, there is a
table in psf-textures/README.md.
- `clamp_output` - Clamps the output from 0 to 1 when enabled. Can be
useful depending on how your HDR is setup.

Expand All @@ -119,7 +122,7 @@ behavior, the shader has these properties:
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
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
Expand All @@ -142,13 +145,13 @@ from the scene.

Code is released under [MIT license](./LICENSE.md).

The default PSF texture, `jwst.exr`, is based on FITS data [obtained
from here][5]. Code for cropping, downscaling, and converting to OpenEXR
is located in `docs/fits2exr.py`.
The default PSF texture, `jwst.png`, is based on FITS data [obtained
from here][5]. Code for cropping, downscaling, and packing into PNG
is located in `docs/jwst2png.py`.

The alternative PSF textures `hst.exr`, `hex_aperture.exr`, and
`airy_disk.exr` were created using [Poppy][6] based on examples in the
documentation. Code is located in `docs/poppy psfs.ipynb`.
The alternative PSF textures `hst.png`, `hex_aperture.png`, and
`airy_disk.png` were created using [Poppy][6] based on examples in the
documentation. Code is located in `docs/poppy_psfs.ipynb`.

[5]: https://www.stsci.edu/jwst/science-planning/proposal-planning-toolbox/simulated-data
[6]: https://poppy-optics.readthedocs.io/en/latest/
81 changes: 52 additions & 29 deletions docs/fits2exr.py → docs/jwst2png.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#!/usr/bin/env python3

# Modified by Tiffany for the purposes of creating the JWST EXR file.
# Original description:
# Converts the JWST simulated PSF to the packed PNG format expected by
# the godot-starlight addon. The source PSF images must be obtained in
# FITS format from here:
# <https://www.stsci.edu/jwst/science-planning/proposal-planning-toolbox/simulated-data>

# This script was adapted by me (Tiffany) from a FITS-to-EXR conversion
# script, the original description follows.

# Presented by Min-Su Shin
# (2015 - , KASI, Republic of Korea)
Expand All @@ -19,10 +24,10 @@
# check the output EXR files.

from astropy.io import fits
import OpenEXR
import numpy
from img_scale import cbrt
from skimage.measure import block_reduce
from PIL import Image

# read FITS images
# red channel
Expand Down Expand Up @@ -64,33 +69,51 @@ def crop_center(img,cropx,cropy):
starty = y//2 - cropy//2
return img[starty:starty+cropy, startx:startx+cropx]

width = 4096
height = 4096
width = 2048
height = 2048
r_img_data = crop_center(r_img_data, width, height)
g_img_data = crop_center(g_img_data, width, height)
b_img_data = crop_center(b_img_data, width, height)

downscale = 4

r_img_data = block_reduce(r_img_data, block_size=(downscale,downscale), func=numpy.sum, cval=numpy.sum(r_img_data))
g_img_data = block_reduce(g_img_data, block_size=(downscale,downscale), func=numpy.sum, cval=numpy.sum(r_img_data))
b_img_data = block_reduce(b_img_data, block_size=(downscale,downscale), func=numpy.sum, cval=numpy.sum(r_img_data))
width = width // downscale
height = height // downscale

# write an EXR file
exr_fn = "jwst_psf.exr"
r_img_data = numpy.asarray(r_img_data, dtype=numpy.float32)
r_img_data = r_img_data.tobytes()
g_img_data = numpy.asarray(g_img_data, dtype=numpy.float32)
g_img_data = g_img_data.tobytes()
b_img_data = numpy.asarray(b_img_data, dtype=numpy.float32)
b_img_data = b_img_data.tobytes()
header = OpenEXR.Header(width, height)
out_exr = OpenEXR.OutputFile(exr_fn, header)
out_exr.writePixels({
'R': r_img_data,
'G': g_img_data,
'B': b_img_data,
})
print("write the EXR file ",exr_fn," done...")
downscale = 1

if downscale != 1:
r_img_data = block_reduce(r_img_data, block_size=(downscale,downscale), func=numpy.sum, cval=numpy.sum(r_img_data))
g_img_data = block_reduce(g_img_data, block_size=(downscale,downscale), func=numpy.sum, cval=numpy.sum(r_img_data))
b_img_data = block_reduce(b_img_data, block_size=(downscale,downscale), func=numpy.sum, cval=numpy.sum(r_img_data))
width = width // downscale
height = height // downscale

coords = numpy.mgrid[0:width, 0:height]
xcoord = coords[0] - (width / 2)
ycoord = coords[1] - (height / 2)
dist_sq = xcoord * xcoord + ycoord * ycoord + 0

r_img_data = r_img_data * dist_sq
g_img_data = g_img_data * dist_sq
b_img_data = b_img_data * dist_sq

r_max = numpy.max(r_img_data)
g_max = numpy.max(g_img_data)
b_max = numpy.max(b_img_data)

r_img_data = r_img_data / r_max
g_img_data = g_img_data / g_max
b_img_data = b_img_data / b_max

b = 1000
log_b = numpy.log(b)
r_img_data = numpy.log(1.0 + r_img_data * (b - 1.0)) / log_b
g_img_data = numpy.log(1.0 + g_img_data * (b - 1.0)) / log_b
b_img_data = numpy.log(1.0 + b_img_data * (b - 1.0)) / log_b

print("max values: ", r_max, g_max, b_max)

r_img_data = numpy.asarray(r_img_data * 255.0, dtype=numpy.uint8)
g_img_data = numpy.asarray(g_img_data * 255.0, dtype=numpy.uint8)
b_img_data = numpy.asarray(b_img_data * 255.0, dtype=numpy.uint8)

rgb = numpy.dstack((r_img_data, g_img_data, b_img_data))

image = Image.fromarray(rgb)
image.save("jwst.png")
File renamed without changes.

0 comments on commit 425b24a

Please sign in to comment.