1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
use super::{streaminginfo::StreamingInfo, texture2d::TextureFormat};
use crate::object::{Value, parser::FromValue};
use anyhow::Result;
use glam::{UVec2, Vec3Swizzles, uvec2, vec2, vec3};
use image::{ImageBuffer, Rgba};
use serde::Serialize;
use std::f32::consts::PI;
#[derive(Debug, Serialize)]
pub struct Cubemap {
pub width: i32,
pub height: i32,
pub mip_count: i32,
pub name: String,
#[serde(skip)]
pub image_data: Vec<u8>,
pub format: TextureFormat,
pub texture_dimension: i32,
pub stream_data: StreamingInfo,
}
impl FromValue for Cubemap {
fn from_value(v: Value) -> Result<Self> {
let mut fields = v.as_class("Cubemap")?;
Ok(Cubemap {
width: fields.field("m_Width")?,
height: fields.field("m_Height")?,
mip_count: fields.field("m_MipCount")?,
texture_dimension: fields.field("m_TextureDimension")?,
format: fields.field("m_TextureFormat")?,
name: fields.field("m_Name")?,
stream_data: fields.field("m_StreamData")?,
image_data: fields.remove("image data").unwrap().as_typeless().unwrap(),
})
}
}
/// Face ordering is Left, Right, Back, Front, Down, Up
pub fn cubemap_to_equirectangular(
faces: &[ImageBuffer<Rgba<f32>, Vec<f32>>; 6],
output_width: u32,
output_height: u32,
) -> ImageBuffer<Rgba<f32>, Vec<f32>> {
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());
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 flip_face = [1., 1., -1., -1., 1., 1.];
let rotate_face = if face == 5 { -1. } else { 1. };
let face_texture = &faces[face];
let face_size = uvec2(face_texture.width(), face_texture.height());
let face_uv =
rotate_face * (other_comps / max_comp * vec2(flip_face[face], -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);
out.0 = face_texture.get_pixel(face_xy.x, face_xy.y).0;
}
output_image
}
|