del_canvas_core/
raycast_trimesh3.rs

1use num_traits::AsPrimitive;
2use rayon::iter::IntoParallelIterator;
3use rayon::iter::ParallelIterator;
4
5pub fn pix2tri<Index>(
6    tri2vtx: &[Index],
7    vtx2xyz: &[f32],
8    bvhnodes: &[Index],
9    aabbs: &[f32],
10    img_shape: &(usize, usize), // (width, height)
11    transform_ndc2world: &[f32; 16],
12) -> Vec<Index>
13where
14    Index: num_traits::PrimInt + AsPrimitive<usize> + Sync + Send,
15    usize: AsPrimitive<Index>,
16{
17    let tri_for_pix = |i_pix: usize| {
18        let i_h = i_pix / img_shape.0;
19        let i_w = i_pix - i_h * img_shape.0;
20        //
21        let (ray_org, ray_dir) =
22            crate::cam3::ray3_homogeneous((i_w, i_h), img_shape, transform_ndc2world);
23        let mut hits: Vec<(f32, usize)> = vec![];
24        del_msh_core::bvh3::search_intersection_ray::<Index>(
25            &mut hits,
26            &ray_org,
27            &ray_dir,
28            &del_msh_core::bvh3::TriMeshWithBvh {
29                tri2vtx,
30                vtx2xyz,
31                bvhnodes,
32                aabbs,
33            },
34            0,
35        );
36        hits.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
37        let Some(&(_depth, i_tri)) = hits.first() else {
38            return Index::max_value();
39        };
40        i_tri.as_()
41    };
42    let img: Vec<Index> = (0..img_shape.0 * img_shape.1)
43        .into_par_iter()
44        .map(tri_for_pix)
45        .collect();
46    img
47}
48
49pub fn render_depth_bvh(
50    image_size: (usize, usize),
51    img_data: &mut [f32],
52    transform_ndc2world: &[f32; 16],
53    tri2vtx: &[usize],
54    vtx2xyz: &[f32],
55    bvhnodes: &[usize],
56    aabbs: &[f32],
57) {
58    let transform_world2ndc: [f32; 16] =
59        nalgebra::Matrix4::<f32>::from_column_slice(transform_ndc2world)
60            .try_inverse()
61            .unwrap()
62            .as_slice()
63            .try_into()
64            .unwrap();
65    let (width, height) = image_size;
66    for ih in 0..height {
67        for iw in 0..width {
68            let (ray_org, ray_dir) =
69                crate::cam3::ray3_homogeneous((iw, ih), &image_size, transform_ndc2world);
70            let mut hits: Vec<(f32, usize)> = vec![];
71            del_msh_core::bvh3::search_intersection_ray(
72                &mut hits,
73                &ray_org,
74                &ray_dir,
75                &del_msh_core::bvh3::TriMeshWithBvh {
76                    tri2vtx,
77                    vtx2xyz,
78                    bvhnodes,
79                    aabbs,
80                },
81                0,
82            );
83            hits.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
84            let Some(&(depth, _i_tri)) = hits.first() else {
85                continue;
86            };
87            let pos = del_geo_core::vec3::axpy(depth, &ray_dir, &ray_org);
88            let ndc =
89                del_geo_core::mat4_col_major::transform_homogeneous(&transform_world2ndc, &pos)
90                    .unwrap();
91            let depth_ndc = (ndc[2] + 1f32) * 0.5f32;
92            img_data[ih * width + iw] = depth_ndc;
93        }
94    }
95}
96
97pub fn render_normalmap_from_pix2tri(
98    image_size: (usize, usize),
99    cam_modelviewd: &[f32; 16],
100    tri2vtx: &[usize],
101    vtx2xyz: &[f32],
102    pix2tri: &[usize],
103) -> Vec<f32> {
104    let (width, height) = image_size;
105    let mut img = vec![0f32; height * width * 3];
106    for ih in 0..height {
107        for iw in 0..width {
108            let i_tri = pix2tri[ih * width + iw];
109            if i_tri == usize::MAX {
110                continue;
111            }
112            let tri = del_msh_core::trimesh3::to_tri3(i_tri, tri2vtx, vtx2xyz);
113            let nrm = tri.normal();
114            let nrm = del_geo_core::mat4_col_major::transform_vector(cam_modelviewd, &nrm);
115            let unrm = del_geo_core::vec3::normalized(&nrm);
116            img[(ih * width + iw) * 3] = unrm[0] * 0.5 + 0.5;
117            img[(ih * width + iw) * 3 + 1] = unrm[1] * 0.5 + 0.5;
118            img[(ih * width + iw) * 3 + 2] = unrm[2] * 0.5 + 0.5;
119        }
120    }
121    img
122}
123
124pub fn render_texture_from_pix2tri(
125    img_shape: (usize, usize),
126    transform_ndc2world: &[f32; 16],
127    tri2vtx: &[usize],
128    vtx2xyz: &[f32],
129    vtx2uv: &[f32],
130    pix2tri: &[usize],
131    tex_shape: (usize, usize),
132    tex_data: &[f32],
133    interpolation: &crate::texture::Interpolation,
134) -> Vec<f32> {
135    let (width, height) = img_shape;
136    let mut img = vec![0f32; height * width * 3];
137    for ih in 0..height {
138        for iw in 0..width {
139            let (ray_org, ray_dir) =
140                crate::cam3::ray3_homogeneous((iw, ih), &img_shape, transform_ndc2world);
141            let i_tri = pix2tri[ih * width + iw];
142            if i_tri == usize::MAX {
143                continue;
144            }
145            let tri = del_msh_core::trimesh3::to_tri3(i_tri, tri2vtx, vtx2xyz);
146            let a = tri.intersection_against_ray(&ray_org, &ray_dir).unwrap();
147            let q = del_geo_core::vec3::axpy(a, &ray_dir, &ray_org);
148            let bc = del_geo_core::tri3::barycentric_coords(tri.p0, tri.p1, tri.p2, &q);
149            let uv0 = arrayref::array_ref!(vtx2uv, tri2vtx[i_tri * 3 + 0] * 2, 2);
150            let uv1 = arrayref::array_ref!(vtx2uv, tri2vtx[i_tri * 3 + 1] * 2, 2);
151            let uv2 = arrayref::array_ref!(vtx2uv, tri2vtx[i_tri * 3 + 2] * 2, 2);
152            let uv = [
153                uv0[0] * bc[0] + uv1[0] * bc[1] + uv2[0] * bc[2],
154                uv0[1] * bc[0] + uv1[1] * bc[1] + uv2[1] * bc[2],
155            ];
156            /*
157            let iu = (uv[0] * tex_shape.0 as f32).round() as usize;
158            let iv = ((1. - uv[1]) * tex_shape.1 as f32).round() as usize;
159            let itex = iv * tex_shape.0 + iu;
160            img[(ih * width + iw) * 3] = tex_data[itex * 3 + 0];
161            img[(ih * width + iw) * 3 + 1] = tex_data[itex * 3 + 1];
162            img[(ih * width + iw) * 3 + 2] = tex_data[itex * 3 + 2];
163             */
164            let pix = [
165                uv[0] * tex_shape.0 as f32,
166                (1. - uv[1]) * tex_shape.1 as f32,
167            ];
168            let res = match interpolation {
169                crate::texture::Interpolation::Nearest => {
170                    crate::texture::nearest::<3>(&pix, &tex_shape, tex_data)
171                }
172                crate::texture::Interpolation::Bilinear => {
173                    crate::texture::bilinear::<3>(&pix, &tex_shape, tex_data)
174                }
175            };
176            img[(ih * width + iw) * 3] = res[0];
177            img[(ih * width + iw) * 3 + 1] = res[1];
178            img[(ih * width + iw) * 3 + 2] = res[2];
179        }
180    }
181    img
182}