bevy/crates/bevy_mikktspace/src/lib.rs

99 lines
3.1 KiB
Rust
Raw Normal View History

#![allow(
unsafe_op_in_unsafe_fn,
clippy::all,
clippy::undocumented_unsafe_blocks,
clippy::ptr_cast_constness,
// FIXME(15321): solve CI failures, then replace with `#![expect()]`.
missing_docs
)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(
html_logo_url = "https://bevyengine.org/assets/icon.png",
html_favicon_url = "https://bevyengine.org/assets/icon.png"
)]
Generate vertex tangents using mikktspace (#3872) # Objective Models can be produced that do not have vertex tangents but do have normal map textures. The tangents can be generated. There is a way that the vertex tangents can be generated to be exactly invertible to avoid introducing error when recreating the normals in the fragment shader. ## Solution - After attempts to get https://github.com/gltf-rs/mikktspace to integrate simple glam changes and version bumps, and releases of that crate taking weeks / not being made (no offense intended to the authors/maintainers, bevy just has its own timelines and needs to take care of) it was decided to fork that repository. The following steps were taken: - mikktspace was forked to https://github.com/bevyengine/mikktspace in order to preserve the repository's history in case the original is ever taken down - The README in that repo was edited to add a note stating from where the repository was forked and explaining why - The repo was locked for changes as its only purpose is historical - The repo was integrated into the bevy repo using `git subtree add --prefix crates/bevy_mikktspace git@github.com:bevyengine/mikktspace.git master` - In `bevy_mikktspace`: - The travis configuration was removed - `cargo fmt` was run - The `Cargo.toml` was conformed to bevy's (just adding bevy to the keywords, changing the homepage and repository, changing the version to 0.7.0-dev - importantly the license is exactly the same) - Remove the features, remove `nalgebra` entirely, only use `glam`, suppress clippy. - This was necessary because our CI runs clippy with `--all-features` and the `nalgebra` and `glam` features are mutually exclusive, plus I don't want to modify this highly numerically-sensitive code just to appease clippy and diverge even more from upstream. - Rebase https://github.com/bevyengine/bevy/pull/1795 - @jakobhellermann said it was fine to copy and paste but it ended up being almost exactly the same with just a couple of adjustments when validating correctness so I decided to actually rebase it and then build on top of it. - Use the exact same fragment shader code to ensure correct normal mapping. - Tested with both https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/NormalTangentMirrorTest which has vertex tangents and https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/NormalTangentTest which requires vertex tangent generation Co-authored-by: alteous <alteous@outlook.com>
2022-05-31 22:53:54 +00:00
use glam::{Vec2, Vec3};
mod generated;
/// The interface by which mikktspace interacts with your geometry.
pub trait Geometry {
/// Returns the number of faces.
fn num_faces(&self) -> usize;
/// Returns the number of vertices of a face.
fn num_vertices_of_face(&self, face: usize) -> usize;
/// Returns the position of a vertex.
fn position(&self, face: usize, vert: usize) -> [f32; 3];
/// Returns the normal of a vertex.
fn normal(&self, face: usize, vert: usize) -> [f32; 3];
/// Returns the texture coordinate of a vertex.
fn tex_coord(&self, face: usize, vert: usize) -> [f32; 2];
/// Sets the generated tangent for a vertex.
/// Leave this function unimplemented if you are implementing
/// `set_tangent_encoded`.
fn set_tangent(
&mut self,
tangent: [f32; 3],
_bi_tangent: [f32; 3],
_f_mag_s: f32,
_f_mag_t: f32,
bi_tangent_preserves_orientation: bool,
face: usize,
vert: usize,
) {
let sign = if bi_tangent_preserves_orientation {
1.0
} else {
-1.0
};
self.set_tangent_encoded([tangent[0], tangent[1], tangent[2], sign], face, vert);
}
/// Sets the generated tangent for a vertex with its bi-tangent encoded as the 'W' (4th)
/// component in the tangent. The 'W' component marks if the bi-tangent is flipped. This
/// is called by the default implementation of `set_tangent`; therefore, this function will
/// not be called by the crate unless `set_tangent` is unimplemented.
fn set_tangent_encoded(&mut self, _tangent: [f32; 4], _face: usize, _vert: usize) {}
}
/// Generates tangents for the input geometry.
///
/// # Errors
///
/// Returns `false` if the geometry is unsuitable for tangent generation including,
/// but not limited to, lack of vertices.
Forbid unsafe in most crates in the engine (#12684) # Objective Resolves #3824. `unsafe` code should be the exception, not the norm in Rust. It's obviously needed for various use cases as it's interfacing with platforms and essentially running the borrow checker at runtime in the ECS, but the touted benefits of Bevy is that we are able to heavily leverage Rust's safety, and we should be holding ourselves accountable to that by minimizing our unsafe footprint. ## Solution Deny `unsafe_code` workspace wide. Add explicit exceptions for the following crates, and forbid it in almost all of the others. * bevy_ecs - Obvious given how much unsafe is needed to achieve performant results * bevy_ptr - Works with raw pointers, even more low level than bevy_ecs. * bevy_render - due to needing to integrate with wgpu * bevy_window - due to needing to integrate with raw_window_handle * bevy_utils - Several unsafe utilities used by bevy_ecs. Ideally moved into bevy_ecs instead of made publicly usable. * bevy_reflect - Required for the unsafe type casting it's doing. * bevy_transform - for the parallel transform propagation * bevy_gizmos - For the SystemParam impls it has. * bevy_assets - To support reflection. Might not be required, not 100% sure yet. * bevy_mikktspace - due to being a conversion from a C library. Pending safe rewrite. * bevy_dynamic_plugin - Inherently unsafe due to the dynamic loading nature. Several uses of unsafe were rewritten, as they did not need to be using them: * bevy_text - a case of `Option::unchecked` could be rewritten as a normal for loop and match instead of an iterator. * bevy_color - the Pod/Zeroable implementations were replaceable with bytemuck's derive macros.
2024-03-27 03:30:08 +00:00
#[allow(unsafe_code)]
Generate vertex tangents using mikktspace (#3872) # Objective Models can be produced that do not have vertex tangents but do have normal map textures. The tangents can be generated. There is a way that the vertex tangents can be generated to be exactly invertible to avoid introducing error when recreating the normals in the fragment shader. ## Solution - After attempts to get https://github.com/gltf-rs/mikktspace to integrate simple glam changes and version bumps, and releases of that crate taking weeks / not being made (no offense intended to the authors/maintainers, bevy just has its own timelines and needs to take care of) it was decided to fork that repository. The following steps were taken: - mikktspace was forked to https://github.com/bevyengine/mikktspace in order to preserve the repository's history in case the original is ever taken down - The README in that repo was edited to add a note stating from where the repository was forked and explaining why - The repo was locked for changes as its only purpose is historical - The repo was integrated into the bevy repo using `git subtree add --prefix crates/bevy_mikktspace git@github.com:bevyengine/mikktspace.git master` - In `bevy_mikktspace`: - The travis configuration was removed - `cargo fmt` was run - The `Cargo.toml` was conformed to bevy's (just adding bevy to the keywords, changing the homepage and repository, changing the version to 0.7.0-dev - importantly the license is exactly the same) - Remove the features, remove `nalgebra` entirely, only use `glam`, suppress clippy. - This was necessary because our CI runs clippy with `--all-features` and the `nalgebra` and `glam` features are mutually exclusive, plus I don't want to modify this highly numerically-sensitive code just to appease clippy and diverge even more from upstream. - Rebase https://github.com/bevyengine/bevy/pull/1795 - @jakobhellermann said it was fine to copy and paste but it ended up being almost exactly the same with just a couple of adjustments when validating correctness so I decided to actually rebase it and then build on top of it. - Use the exact same fragment shader code to ensure correct normal mapping. - Tested with both https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/NormalTangentMirrorTest which has vertex tangents and https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/NormalTangentTest which requires vertex tangent generation Co-authored-by: alteous <alteous@outlook.com>
2022-05-31 22:53:54 +00:00
pub fn generate_tangents<I: Geometry>(geometry: &mut I) -> bool {
unsafe { generated::genTangSpace(geometry, 180.0) }
}
fn get_position<I: Geometry>(geometry: &mut I, index: usize) -> Vec3 {
let (face, vert) = index_to_face_vert(index);
geometry.position(face, vert).into()
}
fn get_tex_coord<I: Geometry>(geometry: &mut I, index: usize) -> Vec3 {
let (face, vert) = index_to_face_vert(index);
let tex_coord: Vec2 = geometry.tex_coord(face, vert).into();
let val = tex_coord.extend(1.0);
val
}
fn get_normal<I: Geometry>(geometry: &mut I, index: usize) -> Vec3 {
let (face, vert) = index_to_face_vert(index);
geometry.normal(face, vert).into()
}
fn index_to_face_vert(index: usize) -> (usize, usize) {
(index >> 2, index & 0x3)
}
fn face_vert_to_index(face: usize, vert: usize) -> usize {
face << 2 | vert & 0x3
}