This commit is contained in:
2026-09-05 15:39:19 +02:00
parent 7efb1a1404
commit f8cfb69b21
14 changed files with 495 additions and 960 deletions
+166 -25
View File
@@ -2,11 +2,12 @@ use std::fs::File;
use std::path::Path;
use glam::Vec3;
use indicatif::ProgressIterator;
use itertools::Itertools;
use crate::voxel::gpu::ExplicitNTreeNode;
use crate::voxel::gpu::StructurePointer;
use crate::voxel::sparse::Color;
use crate::voxel_cache::gpu::ExplicitNTreeNode;
use crate::voxel_cache::gpu::StructurePointer;
use crate::voxel_cache::sparse::Color;
pub struct BallGenerator<const N: usize>
{
@@ -15,7 +16,13 @@ pub struct BallGenerator<const N: usize>
pub fn map(x: f32, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> f32
{
((x - x_min) / (x_max - x_min)) * (y_max - y_min) + y_min
//((x - x_min) / (x_max - x_min)) * (y_max - y_min) + y_min
let input_range = x_max.algebraic_sub(x_min);
let output_range = y_max.algebraic_sub(y_min);
(x.algebraic_sub(x_min).algebraic_div(input_range))
.algebraic_mul(output_range)
.algebraic_add(y_min)
}
pub trait Producer<const N: usize>
@@ -240,6 +247,14 @@ where
heightmap: Vec<f32>,
colormap: Vec<u8>,
heightmap_low_width: usize,
heightmap_low_height: usize,
heightmap_low: Vec<(f32, f32)>,
colormap_low_width: usize,
colormap_low_height: usize,
colormap_mip: Vec<u8>,
pub chunk_width: usize,
pub chunk_height: usize,
pub chunk_alt: usize,
@@ -256,29 +271,50 @@ where
color_path: P,
) -> Self
{
println!("Starting terrain producer");
println!("Loading height map.");
let mut tiff_dec = tiff::decoder::Decoder::new(File::open(height_path).unwrap()).unwrap();
let (heightmap_width, heightmap_height) = tiff_dec.dimensions().unwrap();
let (heightmap_width, heightmap_height) =
(heightmap_width as usize, heightmap_height as usize);
let heightmap = match tiff_dec.read_image().unwrap()
let mut heightmap = match tiff_dec.read_image().unwrap()
{
tiff::decoder::DecodingResult::F32(vec) => vec,
_ => panic!("Unsupported format"),
};
println!("Loading color map.");
let mut color = image::ImageReader::open(color_path).unwrap();
color.no_limits();
let color = color.decode().unwrap();
let colormap = color.as_rgb8().unwrap().to_vec();
let mut colormap = color.as_rgb8().unwrap().to_vec();
println!("Converting color spaces");
colormap.iter_mut().for_each(|x| {
let normalized = map(*x as f32, 0., 255., 0., 1.);
let maped = normalized.powf(2.4);
*x = map(maped, 0., 1., 0., 255.) as u8;
});
let terrain_width = color.width() as usize;
let terrain_height = color.height() as usize;
let heightmap_min = heightmap.iter().copied().reduce(f32::min).unwrap();
println!("Computing heightmap min/max");
let heightmap_min = heightmap
.iter()
.copied()
.filter(|x| *x != -9999.)
.reduce(f32::min)
.unwrap();
let heightmap_max = heightmap.iter().copied().reduce(f32::max).unwrap();
heightmap
.iter_mut()
.filter(|x| **x == -9999.)
.for_each(|x| *x = heightmap_min);
// Decide size in chunks
let height_amplitude = heightmap_max - heightmap_min;
let chunk_size = N.pow(chunk_power as u32);
@@ -286,6 +322,65 @@ where
let chunk_height = terrain_height.div_ceil(chunk_size);
let chunk_alt = ((height_amplitude / height_factor) as usize).div_ceil(chunk_size);
// build the low heightmap
println!("Computing low res height/color maps");
let heightmap_low_width = heightmap_width / 8;
let heightmap_low_height = heightmap_height / 8;
let mut heightmap_low = vec![(0., 0.); heightmap_low_height * heightmap_low_width];
for y in 0..heightmap_low_height
{
for x in 0..heightmap_low_width
{
let mut min = heightmap_max;
let mut max = heightmap_min;
for sy in (y * 8)..(y * 8 + 8)
{
for sx in (x * 8)..(x * 8 + 8)
{
min = min.min(heightmap[sx + sy * heightmap_width]);
max = max.max(heightmap[sx + sy * heightmap_width]);
}
}
heightmap_low[x + y * heightmap_low_width] = (min, max);
}
}
// build the color map mip
let colormap_low_width = terrain_width / 8;
let colormap_low_height = terrain_height / 8;
let mut colormap_mip = vec![0u8; colormap_low_width * colormap_low_height * 3];
for y in 0..colormap_low_height
{
for x in 0..colormap_low_width
{
let mut r = 0u32;
let mut g = 0u32;
let mut b = 0u32;
for sy in (y * 8)..(y * 8 + 8)
{
for sx in (x * 8)..(x * 8 + 8)
{
r += colormap[(sx + sy * terrain_width) * 3] as u32;
g += colormap[(sx + sy * terrain_width) * 3 + 1] as u32;
b += colormap[(sx + sy * terrain_width) * 3 + 2] as u32;
}
}
colormap_mip[(x + y * colormap_low_width) * 3] =
((r as f32) / (8 * 8) as f32).clamp(0., 255.) as u8;
colormap_mip[(x + y * colormap_low_width) * 3 + 1] =
((g as f32) / (8 * 8) as f32).clamp(0., 255.) as u8;
colormap_mip[(x + y * colormap_low_width) * 3 + 2] =
((b as f32) / (8 * 8) as f32).clamp(0., 255.) as u8;
}
}
println!("Producer ready");
Self {
chunk_power,
heightmap_width,
@@ -297,6 +392,14 @@ where
heightmap,
colormap,
heightmap_low_width,
heightmap_low_height,
heightmap_low,
colormap_low_width,
colormap_low_height,
colormap_mip,
chunk_width,
chunk_height,
chunk_alt,
@@ -340,30 +443,68 @@ where
let mut sample_min = self.heightmap_max;
let mut color_avg = Color(0., 0., 0., 0.);
let mut count = 0;
for (x, z) in (0..child_size).cartesian_product(0..child_size)
if depth <= 2
{
let gvx = gcx + x;
let gvz = gcz + z;
if gvx < self.terrain_width && gvz < self.terrain_height
for (z, x) in (0..(child_size / 8)).cartesian_product(0..(child_size / 8))
{
// Height sample
let height_x = (gvx * self.heightmap_width) / self.terrain_width;
let height_z = (gvz * self.heightmap_height) / self.terrain_height;
let gvx = (gcx + x * 8) / 8;
let gvz = (gcz + z * 8) / 8;
if gvx < self.colormap_low_width && gvz < self.colormap_low_height
{
// Height sample
let height_x = (gvx * self.heightmap_low_width) / self.colormap_low_width;
let height_z = (gvz * self.heightmap_low_height) / self.colormap_low_height;
let sample = self.heightmap[height_x + height_z * self.heightmap_width];
sample_max = sample_max.max(sample);
sample_min = sample_min.min(sample);
let sample =
self.heightmap_low[height_x + height_z * self.heightmap_low_width];
sample_min = sample_min.min(sample.0);
sample_max = sample_max.max(sample.1);
let sample_color_r = self.colormap[(gvx + gvz * self.terrain_width) * 3];
let sample_color_g = self.colormap[(gvx + gvz * self.terrain_width) * 3 + 1];
let sample_color_b = self.colormap[(gvx + gvz * self.terrain_width) * 3 + 2];
let sample_color_r =
self.colormap_mip[(gvx + gvz * self.colormap_low_width) * 3];
let sample_color_g =
self.colormap_mip[(gvx + gvz * self.colormap_low_width) * 3 + 1];
let sample_color_b =
self.colormap_mip[(gvx + gvz * self.colormap_low_width) * 3 + 2];
color_avg.0 += map(sample_color_r as f32, 0., 256., 0., 1.);
color_avg.1 += map(sample_color_g as f32, 0., 256., 0., 1.);
color_avg.2 += map(sample_color_b as f32, 0., 256., 0., 1.);
count += 1;
color_avg.0 += map(sample_color_r as f32, 0., 256., 0., 1.);
color_avg.1 += map(sample_color_g as f32, 0., 256., 0., 1.);
color_avg.2 += map(sample_color_b as f32, 0., 256., 0., 1.);
count += 1;
}
//let gvy = gcy;
}
}
else
{
for (z, x) in (0..child_size).cartesian_product(0..child_size)
{
let gvx = gcx + x;
let gvz = gcz + z;
if gvx < self.terrain_width && gvz < self.terrain_height
{
// Height sample
let height_x = (gvx * self.heightmap_width) / self.terrain_width;
let height_z = (gvz * self.heightmap_height) / self.terrain_height;
let sample = self.heightmap[height_x + height_z * self.heightmap_width];
sample_max = sample_max.max(sample);
sample_min = sample_min.min(sample);
let sample_color_r = self.colormap[(gvx + gvz * self.terrain_width) * 3];
let sample_color_g =
self.colormap[(gvx + gvz * self.terrain_width) * 3 + 1];
let sample_color_b =
self.colormap[(gvx + gvz * self.terrain_width) * 3 + 2];
color_avg.0 += map(sample_color_r as f32, 0., 256., 0., 1.);
color_avg.1 += map(sample_color_g as f32, 0., 256., 0., 1.);
color_avg.2 += map(sample_color_b as f32, 0., 256., 0., 1.);
count += 1;
}
//let gvy = gcy;
}
//let gvy = gcy;
}
color_avg.0 /= count as f32;