aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-03-26 19:16:09 +0100
committermetamuffin <metamuffin@disroot.org>2025-03-26 19:16:09 +0100
commit0a0a026bc30055933958dee11691a87a3b1ec622 (patch)
treee5759a712fe4b4cce2ae2e22790b2817a05d2a3e /src
parentab8ecf890fc51fcaf8b85ae594bf41db8aa6bc8a (diff)
downloadunity-tools-0a0a026bc30055933958dee11691a87a3b1ec622.tar
unity-tools-0a0a026bc30055933958dee11691a87a3b1ec622.tar.bz2
unity-tools-0a0a026bc30055933958dee11691a87a3b1ec622.tar.zst
fix equirectangular projection
Diffstat (limited to 'src')
-rw-r--r--src/classes/cubemap.rs57
1 files changed, 31 insertions, 26 deletions
diff --git a/src/classes/cubemap.rs b/src/classes/cubemap.rs
index 0355a05..58e77d6 100644
--- a/src/classes/cubemap.rs
+++ b/src/classes/cubemap.rs
@@ -4,6 +4,7 @@ use anyhow::Result;
use glam::{UVec2, Vec3Swizzles, uvec2, vec2, vec3};
use image::{DynamicImage, ImageBuffer, Rgba};
use log::info;
+use rayon::iter::ParallelIterator;
use serde::Serialize;
use std::f32::consts::PI;
@@ -38,35 +39,39 @@ pub fn cubemap_to_equirectangular(
faces[0].height()
);
let mut output_image = ImageBuffer::<Rgba<f32>, Vec<f32>>::new(output_width, output_height);
- for (er_x, er_y, out) in output_image.enumerate_pixels_mut() {
- let xy_angle = er_x as f32 / output_width as f32 * PI * 2.;
- let cyl_z = er_y as f32 / output_height as f32 * 2. - 1.;
- let sphere_azimuth = cyl_z.asin();
- let r = sphere_azimuth.cos();
- let normal = vec3(xy_angle.sin() * r, xy_angle.cos() * r, cyl_z);
- assert!(normal.is_normalized());
+ output_image
+ .par_enumerate_pixels_mut()
+ .for_each(|(er_x, er_y, out)| {
+ let phi = er_x as f32 / output_width as f32 * PI * 2.;
+ let theta = (1. - er_y as f32 / output_height as f32) * PI;
+ let normal = vec3(
+ phi.sin() * theta.sin(),
+ phi.cos() * theta.sin(),
+ theta.cos(),
+ );
+ assert!(normal.is_normalized());
- let normal_abs = normal.abs();
- let (axis, max_comp, other_comps) = if normal_abs.x > normal_abs.y.max(normal_abs.z) {
- (0, normal.x, normal.yz())
- } else if normal_abs.y > normal_abs.z {
- (1, normal.y, normal.xz())
- } else {
- (2, normal.z, normal.xy())
- };
+ let normal_abs = normal.abs();
+ let (axis, max_comp, other_comps) = if normal_abs.x > normal_abs.y.max(normal_abs.z) {
+ (0, normal.x, normal.yz())
+ } else if normal_abs.y > normal_abs.z {
+ (1, normal.y, normal.xz())
+ } else {
+ (2, normal.z, normal.xy())
+ };
- let face = axis as usize * 2 + if max_comp < 0. { 1 } else { 0 };
- let face_texture = &faces[face];
- let face_size = uvec2(face_texture.width(), face_texture.height());
- let face_uv = other_comps / max_comp * vec2(1., -max_comp.signum());
- let face_uv = face_uv / 2. + 0.5;
+ let face = axis as usize * 2 + if max_comp < 0. { 1 } else { 0 };
+ let face_texture = &faces[face];
+ let face_size = uvec2(face_texture.width(), face_texture.height());
+ let face_uv = other_comps / max_comp * vec2(1., -max_comp.signum());
+ let face_uv = face_uv / 2. + 0.5;
- let face_xy = (face_uv * face_size.as_vec2())
- .floor()
- .as_uvec2()
- .clamp(UVec2::MIN, face_size - UVec2::ONE);
+ let face_xy = (face_uv * face_size.as_vec2())
+ .floor()
+ .as_uvec2()
+ .clamp(UVec2::MIN, face_size - UVec2::ONE);
- out.0 = face_texture.get_pixel(face_xy.x, face_xy.y).0;
- }
+ out.0 = face_texture.get_pixel(face_xy.x, face_xy.y).0;
+ });
output_image
}