dialog WIP paths consolidation and rendering

This commit is contained in:
Jonas H
2026-03-28 10:34:19 +01:00
parent 4c3ebca96e
commit 11b31169b1
70 changed files with 2658 additions and 485 deletions

View File

@@ -0,0 +1,48 @@
-> encounter
=== encounter ===
So. You came after all. # timer: 3.0 # parry: J
+ [hit] -> outcome_hit
+ [evaded] -> outcome_evaded
+ [wrong_parry] -> outcome_wrong
+ [parried_i] -> outcome_wrong
+ [parried_j] -> outcome_correct
+ [parried_l] -> outcome_wrong
=== outcome_correct ===
Exactly right. # timer: 2.5
-> END
=== outcome_hit ===
You hesitate. Interesting. # timer: 2.5 # parry: I
+ [hit] -> end_beaten
+ [evaded] -> end_fled
+ [wrong_parry] -> end_beaten
+ [parried_i] -> end_strong
+ [parried_j] -> end_beaten
+ [parried_l] -> end_beaten
=== outcome_evaded ===
Running already? # timer: 2.5
-> END
=== outcome_wrong ===
That wasn't the answer I expected. # timer: 2.5 # parry: L
+ [hit] -> end_beaten
+ [evaded] -> end_fled
+ [wrong_parry] -> end_beaten
+ [parried_i] -> end_beaten
+ [parried_j] -> end_beaten
+ [parried_l] -> end_strong
=== end_beaten ===
I see. You are not ready. # timer: 2.5
-> END
=== end_fled ===
So be it. # timer: 2.0
-> END
=== end_strong ===
Good. Perhaps you are worthy after all. # timer: 3.0
-> END

View File

@@ -0,0 +1 @@
{"inkVersion":21,"root":[[[{"->":"encounter"},{"#n":"g-0"}],null],"done",{"encounter":[["^So. You came after all. ","#","^timer: 3.0 ","/#","#","^parry: J","/#","\n","ev","str","^hit","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^evaded","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^wrong_parry","/str","/ev",{"*":".^.c-2","flg":4},"ev","str","^parried_i","/str","/ev",{"*":".^.c-3","flg":4},"ev","str","^parried_j","/str","/ev",{"*":".^.c-4","flg":4},"ev","str","^parried_l","/str","/ev",{"*":".^.c-5","flg":4},{"c-0":["^ ",{"->":"outcome_hit"},"\n",null],"c-1":["^ ",{"->":"outcome_evaded"},"\n",null],"c-2":["^ ",{"->":"outcome_wrong"},"\n",null],"c-3":["^ ",{"->":"outcome_wrong"},"\n",null],"c-4":["^ ",{"->":"outcome_correct"},"\n",null],"c-5":["^ ",{"->":"outcome_wrong"},"\n",null]}],null],"outcome_correct":["^Exactly right. ","#","^timer: 2.5","/#","\n","end",null],"outcome_hit":[["^You hesitate. Interesting. ","#","^timer: 2.5 ","/#","#","^parry: I","/#","\n","ev","str","^hit","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^evaded","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^wrong_parry","/str","/ev",{"*":".^.c-2","flg":4},"ev","str","^parried_i","/str","/ev",{"*":".^.c-3","flg":4},"ev","str","^parried_j","/str","/ev",{"*":".^.c-4","flg":4},"ev","str","^parried_l","/str","/ev",{"*":".^.c-5","flg":4},{"c-0":["^ ",{"->":"end_beaten"},"\n",null],"c-1":["^ ",{"->":"end_fled"},"\n",null],"c-2":["^ ",{"->":"end_beaten"},"\n",null],"c-3":["^ ",{"->":"end_strong"},"\n",null],"c-4":["^ ",{"->":"end_beaten"},"\n",null],"c-5":["^ ",{"->":"end_beaten"},"\n",null]}],null],"outcome_evaded":["^Running already? ","#","^timer: 2.5","/#","\n","end",null],"outcome_wrong":[["^That wasn't the answer I expected. ","#","^timer: 2.5 ","/#","#","^parry: L","/#","\n","ev","str","^hit","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^evaded","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^wrong_parry","/str","/ev",{"*":".^.c-2","flg":4},"ev","str","^parried_i","/str","/ev",{"*":".^.c-3","flg":4},"ev","str","^parried_j","/str","/ev",{"*":".^.c-4","flg":4},"ev","str","^parried_l","/str","/ev",{"*":".^.c-5","flg":4},{"c-0":["^ ",{"->":"end_beaten"},"\n",null],"c-1":["^ ",{"->":"end_fled"},"\n",null],"c-2":["^ ",{"->":"end_beaten"},"\n",null],"c-3":["^ ",{"->":"end_beaten"},"\n",null],"c-4":["^ ",{"->":"end_beaten"},"\n",null],"c-5":["^ ",{"->":"end_strong"},"\n",null]}],null],"end_beaten":["^I see. You are not ready. ","#","^timer: 2.5","/#","\n","end",null],"end_fled":["^So be it. ","#","^timer: 2.0","/#","\n","end",null],"end_strong":["^Good. Perhaps you are worthy after all. ","#","^timer: 3.0","/#","\n","end",null]}],"listDefs":{}}

195
assets/meshes/burrs.gltf Executable file

File diff suppressed because one or more lines are too long

Binary file not shown.

BIN
assets/meshes/terrain.bin Normal file

Binary file not shown.

561
assets/meshes/terrain.gltf Normal file
View File

@@ -0,0 +1,561 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v5.0.21",
"version":"2.0"
},
"extensionsUsed":[
"KHR_lights_punctual",
"EXT_mesh_gpu_instancing"
],
"extensionsRequired":[
"KHR_lights_punctual"
],
"extensions":{
"KHR_lights_punctual":{
"lights":[
{
"color":[
1,
1,
1
],
"intensity":543.5141306588226,
"spot":{
"innerConeAngle":0.18840259313583374,
"outerConeAngle":0.18840259313583374
},
"type":"spot",
"range":1000,
"name":"Spot",
"extras":{
"light_tag":"lighthouse"
}
}
]
}
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0,
1,
2,
3,
4,
5,
6,
7
]
}
],
"nodes":[
{
"mesh":0,
"name":"TreePrime",
"translation":[
16.22920036315918,
29.08228302001953,
39.89393615722656
]
},
{
"mesh":1,
"name":"Lighthouse_base",
"rotation":[
0,
-0.31448131799697876,
0,
0.9492637515068054
],
"scale":[
25.161100387573242,
8.222701072692871,
8.222701072692871
],
"translation":[
-367.9805908203125,
113.61730194091797,
212.62832641601562
]
},
{
"mesh":2,
"name":"Lighthouse",
"scale":[
2.1515703201293945,
24.724905014038086,
2.1515703201293945
],
"translation":[
-343.6542053222656,
152.96629333496094,
231.81927490234375
]
},
{
"children":[
8
],
"mesh":4,
"name":"TerrainPlane",
"scale":[
1.000100016593933,
1,
1
]
},
{
"name":"Main_Light_Path",
"translation":[
491.1999816894531,
0,
-66.48489379882812
]
},
{
"name":"PlayerSpawn",
"translation":[
-351.4849853515625,
119.54279327392578,
202.97006225585938
]
},
{
"extensions":{
"KHR_lights_punctual":{
"light":0
}
},
"name":"Spot",
"rotation":[
-0.16434744000434875,
-0.37808698415756226,
0.006467622704803944,
0.9110424518585205
],
"translation":[
-344.301025390625,
223.67401123046875,
232.61265563964844
]
},
{
"name":"TestCharSpawn",
"translation":[
-381.1509704589844,
106.53739166259766,
107.46959686279297
]
},
{
"extensions":{
"EXT_mesh_gpu_instancing":{
"attributes":{
"TRANSLATION":19,
"ROTATION":20,
"SCALE":21
}
}
},
"mesh":3,
"name":"TerrainPlane.0"
}
],
"materials":[
{
"doubleSided":true,
"name":"terrain"
}
],
"meshes":[
{
"name":"Cylinder",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1,
"TEXCOORD_0":2
},
"indices":3
}
]
},
{
"name":"Cube",
"primitives":[
{
"attributes":{
"POSITION":4,
"NORMAL":5,
"TEXCOORD_0":6
},
"indices":7
}
]
},
{
"name":"Cylinder.001",
"primitives":[
{
"attributes":{
"POSITION":8,
"NORMAL":9,
"TEXCOORD_0":10
},
"indices":11
}
]
},
{
"name":"Cylinder",
"primitives":[
{
"attributes":{
"POSITION":12,
"NORMAL":13,
"TEXCOORD_0":14
},
"indices":3
}
]
},
{
"name":"Plane.001",
"primitives":[
{
"attributes":{
"POSITION":15,
"NORMAL":16,
"TEXCOORD_0":17
},
"indices":18,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":1280,
"max":[
5.561562538146973,
16.066009521484375,
5.561562538146973
],
"min":[
-5.561562538146973,
0,
-5.561562538146973
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":1280,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":1280,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":2100,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":24,
"max":[
1,
1,
1
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":5,
"componentType":5126,
"count":24,
"type":"VEC3"
},
{
"bufferView":6,
"componentType":5126,
"count":24,
"type":"VEC2"
},
{
"bufferView":7,
"componentType":5123,
"count":36,
"type":"SCALAR"
},
{
"bufferView":8,
"componentType":5126,
"count":704,
"max":[
6.253715991973877,
2.2209415435791016,
6.253798961639404
],
"min":[
-6.253823757171631,
-1.9492745399475098,
-6.25374174118042
],
"type":"VEC3"
},
{
"bufferView":9,
"componentType":5126,
"count":704,
"type":"VEC3"
},
{
"bufferView":10,
"componentType":5126,
"count":704,
"type":"VEC2"
},
{
"bufferView":11,
"componentType":5123,
"count":1140,
"type":"SCALAR"
},
{
"bufferView":12,
"componentType":5126,
"count":1280,
"max":[
5.561562538146973,
16.066009521484375,
5.561562538146973
],
"min":[
-5.561562538146973,
0,
-5.561562538146973
],
"type":"VEC3"
},
{
"bufferView":13,
"componentType":5126,
"count":1280,
"type":"VEC3"
},
{
"bufferView":14,
"componentType":5126,
"count":1280,
"type":"VEC2"
},
{
"bufferView":15,
"componentType":5126,
"count":10404,
"max":[
500,
110.45686340332031,
500
],
"min":[
-500,
-0.9473495483398438,
-500
],
"type":"VEC3"
},
{
"bufferView":16,
"componentType":5126,
"count":10404,
"type":"VEC3"
},
{
"bufferView":17,
"componentType":5126,
"count":10404,
"type":"VEC2"
},
{
"bufferView":18,
"componentType":5123,
"count":61206,
"type":"SCALAR"
},
{
"bufferView":19,
"componentType":5126,
"count":2380,
"type":"VEC3"
},
{
"bufferView":20,
"componentType":5126,
"count":2380,
"type":"VEC4"
},
{
"bufferView":21,
"componentType":5126,
"count":2380,
"type":"VEC3"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":15360,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":15360,
"byteOffset":15360,
"target":34962
},
{
"buffer":0,
"byteLength":10240,
"byteOffset":30720,
"target":34962
},
{
"buffer":0,
"byteLength":4200,
"byteOffset":40960,
"target":34963
},
{
"buffer":0,
"byteLength":288,
"byteOffset":45160,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":45448,
"target":34962
},
{
"buffer":0,
"byteLength":192,
"byteOffset":45736,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":45928,
"target":34963
},
{
"buffer":0,
"byteLength":8448,
"byteOffset":46000,
"target":34962
},
{
"buffer":0,
"byteLength":8448,
"byteOffset":54448,
"target":34962
},
{
"buffer":0,
"byteLength":5632,
"byteOffset":62896,
"target":34962
},
{
"buffer":0,
"byteLength":2280,
"byteOffset":68528,
"target":34963
},
{
"buffer":0,
"byteLength":15360,
"byteOffset":70808,
"target":34962
},
{
"buffer":0,
"byteLength":15360,
"byteOffset":86168,
"target":34962
},
{
"buffer":0,
"byteLength":10240,
"byteOffset":101528,
"target":34962
},
{
"buffer":0,
"byteLength":124848,
"byteOffset":111768,
"target":34962
},
{
"buffer":0,
"byteLength":124848,
"byteOffset":236616,
"target":34962
},
{
"buffer":0,
"byteLength":83232,
"byteOffset":361464,
"target":34962
},
{
"buffer":0,
"byteLength":122412,
"byteOffset":444696,
"target":34963
},
{
"buffer":0,
"byteLength":28560,
"byteOffset":567108
},
{
"buffer":0,
"byteLength":38080,
"byteOffset":595668
},
{
"buffer":0,
"byteLength":28560,
"byteOffset":633748
}
],
"buffers":[
{
"byteLength":662308,
"uri":"terrain.bin"
}
]
}

BIN
assets/meshes/test_char.bin Normal file

Binary file not shown.

View File

@@ -0,0 +1,195 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v5.0.21",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0,
1
]
}
],
"nodes":[
{
"mesh":0,
"name":"Cylinder",
"scale":[
1,
2.6253442764282227,
1
],
"translation":[
0,
3.3726491928100586,
0
]
},
{
"mesh":1,
"name":"Sphere",
"translation":[
0,
7.17788553237915,
0
]
}
],
"meshes":[
{
"name":"Cylinder",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1,
"TEXCOORD_0":2
},
"indices":3
}
]
},
{
"name":"Sphere",
"primitives":[
{
"attributes":{
"POSITION":4,
"NORMAL":5,
"TEXCOORD_0":6
},
"indices":7
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":192,
"max":[
1.9433555603027344,
1,
1.9433555603027344
],
"min":[
-1.9433555603027344,
-1,
-1.9433555603027344
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":192,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":192,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":372,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":480,
"max":[
1,
1,
1
],
"min":[
-0.9999999403953552,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":5,
"componentType":5126,
"count":480,
"type":"VEC3"
},
{
"bufferView":6,
"componentType":5126,
"count":480,
"type":"VEC2"
},
{
"bufferView":7,
"componentType":5123,
"count":672,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":2304,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":2304,
"byteOffset":2304,
"target":34962
},
{
"buffer":0,
"byteLength":1536,
"byteOffset":4608,
"target":34962
},
{
"buffer":0,
"byteLength":744,
"byteOffset":6144,
"target":34963
},
{
"buffer":0,
"byteLength":5760,
"byteOffset":6888,
"target":34962
},
{
"buffer":0,
"byteLength":5760,
"byteOffset":12648,
"target":34962
},
{
"buffer":0,
"byteLength":3840,
"byteOffset":18408,
"target":34962
},
{
"buffer":0,
"byteLength":1344,
"byteOffset":22248,
"target":34963
}
],
"buffers":[
{
"byteLength":23592,
"uri":"test_char.bin"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

View File

@@ -0,0 +1,62 @@
# Texture Generation Scripts
## Blue Noise Generator
`generate_blue_noise.py` - Generates blue noise textures for high-quality dithering effects.
### Requirements
```bash
pip install numpy pillow scipy
```
### Usage
Basic usage (generates 128x128 texture):
```bash
python generate_blue_noise.py
```
Custom size:
```bash
python generate_blue_noise.py --width 256 --height 256
```
Custom output path:
```bash
python generate_blue_noise.py --output ../my_blue_noise.png
```
Advanced options:
```bash
python generate_blue_noise.py --width 128 --height 128 --sigma 1.5 --method void_cluster
```
### Parameters
- `--width`: Texture width in pixels (default: 128)
- `--height`: Texture height in pixels (default: 128)
- `--method`: Generation method
- `void_cluster`: High-quality void-and-cluster method (default, recommended)
- `annealing`: Simulated annealing method (slower)
- `--sigma`: Gaussian kernel sigma for void_cluster method (default: 1.5)
- Lower values (0.8-1.2): Tighter clustering, more high-frequency
- Higher values (2.0-3.0): Smoother distribution
- `--iterations`: Number of iterations (optional, auto-calculated if not specified)
- `--output`: Output file path (default: ../blue_noise.png)
### What is Blue Noise?
Blue noise is a type of noise with energy concentrated in high frequencies and minimal low-frequency content. This makes it ideal for dithering because:
- No visible patterns or clustering
- Smooth gradients without banding
- Perceptually pleasing distribution
- Better than Bayer or white noise for transparency effects
### Use Cases in snow_trail_sdl
- **Tree dissolve effect**: Dither trees between camera and player for unobstructed view
- **Temporal effects**: Screen-space dithering for transitions
- **Transparency**: High-quality alpha dithering
- **LOD transitions**: Smooth fade between detail levels

View File

@@ -0,0 +1,155 @@
#!/usr/bin/env python3
import numpy as np
from PIL import Image
import argparse
from pathlib import Path
def gaussian_kernel(size, sigma):
x = np.arange(-size // 2 + 1, size // 2 + 1)
y = np.arange(-size // 2 + 1, size // 2 + 1)
xx, yy = np.meshgrid(x, y)
kernel = np.exp(-(xx**2 + yy**2) / (2 * sigma**2))
return kernel / kernel.sum()
def apply_periodic_filter(binary_pattern, kernel):
from scipy.signal import fftconvolve
return fftconvolve(binary_pattern, kernel, mode='same')
def generate_blue_noise_void_cluster(width, height, sigma=1.5, iterations=None):
if iterations is None:
iterations = width * height
size = width * height
pattern = np.zeros((height, width), dtype=np.float32)
kernel_size = int(6 * sigma)
if kernel_size % 2 == 0:
kernel_size += 1
kernel = gaussian_kernel(kernel_size, sigma)
initial_pattern = np.random.rand(height, width)
print(f"Generating {width}x{height} blue noise texture...")
print(f"Kernel size: {kernel_size}x{kernel_size}, sigma: {sigma}")
dither_array = np.zeros(size, dtype=np.int32)
binary_pattern = np.zeros((height, width), dtype=np.float32)
for i in range(size):
if i % (size // 10) == 0:
print(f"Progress: {i}/{size} ({100*i//size}%)")
filtered = apply_periodic_filter(binary_pattern, kernel)
if i < size // 2:
initial_energy = initial_pattern + filtered
coords = np.unravel_index(np.argmax(initial_energy), initial_energy.shape)
else:
coords = np.unravel_index(np.argmin(filtered), filtered.shape)
dither_array[i] = coords[0] * width + coords[1]
binary_pattern[coords[0], coords[1]] = 1.0
print("Converting to threshold map...")
threshold_map = np.zeros((height, width), dtype=np.float32)
for rank, pos in enumerate(dither_array):
y = pos // width
x = pos % width
threshold_map[y, x] = rank / size
print("Done!")
return threshold_map
def generate_blue_noise_simulated_annealing(width, height, iterations=10000):
print(f"Generating {width}x{height} blue noise using simulated annealing...")
pattern = np.random.rand(height, width)
def energy(pattern):
fft = np.fft.fft2(pattern)
power = np.abs(fft) ** 2
h, w = pattern.shape
cy, cx = h // 2, w // 2
y, x = np.ogrid[:h, :w]
dist = np.sqrt((x - cx)**2 + (y - cy)**2)
low_freq_mask = dist < min(h, w) * 0.1
low_freq_energy = np.sum(power * low_freq_mask)
return low_freq_energy
current_energy = energy(pattern)
temperature = 1.0
cooling_rate = 0.9995
for i in range(iterations):
if i % (iterations // 10) == 0:
print(f"Iteration {i}/{iterations}, Energy: {current_energy:.2f}, Temp: {temperature:.4f}")
y1, x1 = np.random.randint(0, height), np.random.randint(0, width)
y2, x2 = np.random.randint(0, height), np.random.randint(0, width)
pattern[y1, x1], pattern[y2, x2] = pattern[y2, x2], pattern[y1, x1]
new_energy = energy(pattern)
delta_energy = new_energy - current_energy
if delta_energy < 0 or np.random.rand() < np.exp(-delta_energy / temperature):
current_energy = new_energy
else:
pattern[y1, x1], pattern[y2, x2] = pattern[y2, x2], pattern[y1, x1]
temperature *= cooling_rate
print("Done!")
return pattern
def main():
parser = argparse.ArgumentParser(description='Generate blue noise texture for dithering')
parser.add_argument('--width', type=int, default=128, help='Texture width (default: 128)')
parser.add_argument('--height', type=int, default=128, help='Texture height (default: 128)')
parser.add_argument('--method', choices=['void_cluster', 'annealing'], default='void_cluster',
help='Generation method (default: void_cluster)')
parser.add_argument('--sigma', type=float, default=1.5,
help='Gaussian kernel sigma for void_cluster method (default: 1.5)')
parser.add_argument('--iterations', type=int, default=None,
help='Number of iterations (optional)')
parser.add_argument('--output', type=str, default='../blue_noise.png',
help='Output file path (default: ../blue_noise.png)')
args = parser.parse_args()
try:
from scipy.signal import fftconvolve
except ImportError:
print("Error: scipy is required for this script.")
print("Install it with: pip install scipy")
return
if args.method == 'void_cluster':
noise = generate_blue_noise_void_cluster(args.width, args.height, args.sigma, args.iterations)
else:
noise = generate_blue_noise_simulated_annealing(args.width, args.height,
args.iterations or 10000)
noise_normalized = ((noise - noise.min()) / (noise.max() - noise.min()) * 255).astype(np.uint8)
img = Image.fromarray(noise_normalized, mode='L')
output_path = Path(__file__).parent / args.output
output_path.parent.mkdir(parents=True, exist_ok=True)
img.save(output_path)
print(f"\nBlue noise texture saved to: {output_path}")
print(f"Size: {args.width}x{args.height}")
print(f"Method: {args.method}")
fft = np.fft.fft2(noise)
power_spectrum = np.abs(np.fft.fftshift(fft)) ** 2
print(f"Power spectrum range: {power_spectrum.min():.2e} - {power_spectrum.max():.2e}")
if __name__ == '__main__':
main()

Binary file not shown.

BIN
assets/textures/terrain.exr Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 KiB