use crate::features::mesh_adv::{MeshVertexFull, MeshVertexPosition};
use glam::{Vec2, Vec3};
use rafx::api::RafxIndexType;
use rafx::assets::PushBuffer;
pub(super) fn calculate_tangent_binormal(
p0: Vec3,
p1: Vec3,
p2: Vec3,
uv0: Vec2,
uv1: Vec2,
uv2: Vec2,
) -> (Vec3, Vec3) {
let dp1 = p1 - p0;
let dp2 = p2 - p0;
let duv1 = uv1 - uv0;
let duv2 = uv2 - uv0;
let denominator = duv1.x * duv2.y - duv1.y * duv2.x;
let (t, b) = if denominator.abs() > 0.0001 {
let r = 1.0 / denominator;
let t = (dp1 * duv2.y - dp2 * duv1.y) * r;
let b = (dp2 * duv1.x - dp1 * duv2.x) * r;
(t, b)
} else {
(glam::Vec3::ZERO, glam::Vec3::ZERO)
};
(t, b)
}
fn fix_tangent_binormal(
n: Vec3,
t: Vec3,
b: Vec3,
) -> (Vec3, Vec3) {
let mut t = if t.length_squared() > 0.0001 {
t.normalize()
} else {
n.any_orthogonal_vector()
};
let b = if b.length_squared() > 0.0001 {
let b = b.normalize();
if n.cross(t).dot(b) < 0.0 {
t = t * -1.0;
}
b
} else {
n.cross(t).normalize()
};
(t, b)
}
pub(crate) struct MeshPartData {
pub vertex_full_buffer_offset_in_bytes: u32,
pub vertex_full_buffer_size_in_bytes: u32,
pub vertex_position_buffer_offset_in_bytes: u32,
pub vertex_position_buffer_size_in_bytes: u32,
pub index_buffer_offset_in_bytes: u32,
pub index_buffer_size_in_bytes: u32,
pub index_type: RafxIndexType,
}
pub(crate) fn process_mesh_part(
part_indices: &[u32],
positions: &[[f32; 3]],
normals: &[[f32; 3]],
tex_coords: &[[f32; 2]],
all_vertices_full: &mut PushBuffer,
all_vertices_position: &mut PushBuffer,
all_indices: &mut PushBuffer,
) -> MeshPartData {
let mut tangents = Vec::<glam::Vec3>::new();
tangents.resize(positions.len(), glam::Vec3::default());
let mut binormals = Vec::<glam::Vec3>::new();
binormals.resize(positions.len(), glam::Vec3::default());
assert_eq!(part_indices.len() % 3, 0);
for i in 0..(part_indices.len() / 3) {
let i0 = part_indices[i * 3] as usize;
let i1 = part_indices[i * 3 + 1] as usize;
let i2 = part_indices[i * 3 + 2] as usize;
let p0 = glam::Vec3::from(positions[i0]);
let p1 = glam::Vec3::from(positions[i1]);
let p2 = glam::Vec3::from(positions[i2]);
let uv0 = glam::Vec2::from(tex_coords[i0]);
let uv1 = glam::Vec2::from(tex_coords[i1]);
let uv2 = glam::Vec2::from(tex_coords[i2]);
let (t, b) = super::mesh_util::calculate_tangent_binormal(p0, p1, p2, uv0, uv1, uv2);
tangents[i0] += t;
tangents[i1] += t;
tangents[i2] += t;
binormals[i0] += b;
binormals[i1] += b;
binormals[i2] += b;
}
let mut part_vertices_full = Vec::with_capacity(positions.len());
let mut part_vertices_position = Vec::with_capacity(positions.len());
for i in 0..positions.len() {
let (t, b) = fix_tangent_binormal(glam::Vec3::from(normals[i]), tangents[i], binormals[i]);
part_vertices_full.push(MeshVertexFull {
position: positions[i],
normal: normals[i],
tangent: t.into(),
binormal: b.into(),
tex_coord: tex_coords[i],
});
part_vertices_position.push(MeshVertexPosition {
position: positions[i],
});
}
#[cfg(feature = "meshopt")]
let (part_indices_data, part_vertices_full, part_vertices_position) = {
meshopt::optimize_vertex_cache_in_place(&part_indices, part_vertices_full.len());
let remap = meshopt::optimize_vertex_fetch_remap(&part_indices, part_vertices_full.len());
let part_indices =
meshopt::remap_index_buffer(Some(&part_indices), part_indices.len(), &remap);
let part_vertices_full =
meshopt::remap_vertex_buffer(&part_vertices_full, part_vertices_full.len(), &remap);
let part_vertices_position = meshopt::remap_vertex_buffer(
&part_vertices_position,
part_vertices_position.len(),
&remap,
);
(part_indices, part_vertices_full, part_vertices_position)
};
#[cfg(feature = "meshopt")]
let part_indices = &part_indices_data;
let vertex_full_offset = all_vertices_full.len();
all_vertices_full.push(&part_vertices_full, 1);
let vertex_full_size = all_vertices_full.len() - vertex_full_offset;
let vertex_position_offset = all_vertices_position.len();
all_vertices_position.push(&part_vertices_position, 1);
let vertex_position_size = all_vertices_position.len() - vertex_position_offset;
assert!(part_vertices_position.len() == part_vertices_full.len());
let index_type = if part_vertices_position.len() >= (u16::MAX as usize) {
RafxIndexType::Uint32
} else {
RafxIndexType::Uint16
};
let indices_offset = all_indices.len();
match index_type {
RafxIndexType::Uint32 => {
all_indices.push(&part_indices, 1);
}
RafxIndexType::Uint16 => {
for &index in part_indices {
all_indices.push(&[index as u16], 1);
}
}
}
let indices_size = all_indices.len() - indices_offset;
MeshPartData {
vertex_full_buffer_offset_in_bytes: vertex_full_offset as u32,
vertex_full_buffer_size_in_bytes: vertex_full_size as u32,
vertex_position_buffer_offset_in_bytes: vertex_position_offset as u32,
vertex_position_buffer_size_in_bytes: vertex_position_size as u32,
index_buffer_offset_in_bytes: indices_offset as u32,
index_buffer_size_in_bytes: indices_size as u32,
index_type,
}
}