Organize HalfSpace, create 2d and 3d HalfSpace primitives#23416
Organize HalfSpace, create 2d and 3d HalfSpace primitives#23416jackxpeng wants to merge 8 commits intobevyengine:mainfrom
Conversation
|
Welcome, new contributor! Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨ |
3b3fbb8 to
368fe77
Compare
a51b70f to
793e275
Compare
| let half_depth = if facing_z { 0.0 } else { f32::MAX / 2.0 }; | ||
| let half_size = Vec3A::new(half_width, half_height, half_depth); | ||
|
|
||
| Aabb3d::new(isometry.translation, half_size) |
There was a problem hiding this comment.
I believe this doesn't account for the translation of the plane by the signed offset. Not really relevant in the general case, but in the special cases that the plane aligns with an axis, this provides a wrong AABB.
| let translation = Vec3::new(2.0, 1.0, 0.0); | ||
|
|
||
| let aabb1 = InfinitePlane3d::new(Vec3::X).aabb_3d(translation); | ||
| let aabb1 = InfinitePlane3d::new(Dir3A::X, 0.0).aabb_3d(translation); |
There was a problem hiding this comment.
These need testcases where the offset is some arbitrary nonzero value.
| pub fn new(normal: Vec2) -> Self { | ||
| pub fn from_coefficients(a: f32, b: f32, c: f32) -> Self { | ||
| debug_assert!( | ||
| ops::abs(a * a + b * b - 1.0) < 1e-6, |
There was a problem hiding this comment.
Does this epsilon (1e-6) match the usual values we use?
- Update `Plane2d` and `InfinitePlane3d` initializations in examples to account for the new `offset` field.
- Transition to using explicit direction types (`Dir2`, `Dir3A`) for plane normals instead of raw vectors.
- Replace `signed_distance` with `signed_distance_to_point` in the 3D mirror example.
- Collapse an `else { if }` block into `else if` in `bevy_winit`.
- Mark the `HalfSpace` type alias as deprecated for the 0.19.0 release.
793e275 to
3b2d1a3
Compare
|
|
||
| /// Creates a new [`Plane2d`] from the coefficients of the plane equation `ax + by + c = 0`. | ||
| /// | ||
| /// The normal vector `(a, b)` must be of unit length. |
There was a problem hiding this comment.
This is a subtle breaking change. The method used to do the normalisation and failed only if the normalisation couldn't be done. Now it doesn't panic without assertions (good), but it also doesn't handle the same cases as before correctly.
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if the normal vector `(a, b)` is not of unit length. |
There was a problem hiding this comment.
This is misleading, the error is returned if the vector (a,b) could not be normalised.
| /// Returns an error if the normal vector `(a, b)` is not of unit length. | ||
| #[inline] | ||
| pub fn try_from_coefficients(a: f32, b: f32, c: f32) -> Result<Self, InvalidDirectionError> { | ||
| let normal = Dir2::new(Vec2::new(a, b))?; |
There was a problem hiding this comment.
| let normal = Dir2::new(Vec2::new(a, b))?; | |
| let normal = Dir2::from_xy(a, b)?; |
| d: f32, | ||
| ) -> Result<Self, UnnormalizedNormalError> { | ||
| let len_sq = a * a + b * b + c * c; | ||
| if ops::abs(len_sq - 1.0) >= 1e-6 { |
There was a problem hiding this comment.
The condition as it's written doesn't handle NAN numbers. This is because Nan fails to compare with anything, so std::f32::NAN >= 1e-6 gives false, avoiding the error handler.
| let an = a.normal(); | ||
| let bn = b.normal(); | ||
| let cn = c.normal(); | ||
|
|
||
| let x = Vec3A::new(an.x, bn.x, cn.x); | ||
| let y = Vec3A::new(an.y, bn.y, cn.y); | ||
| let z = Vec3A::new(an.z, bn.z, cn.z); | ||
|
|
||
| let d = -Vec3A::new(a.d(), b.d(), c.d()); | ||
|
|
||
| let u = y.cross(z); | ||
| let v = x.cross(d); | ||
|
|
||
| let denom = x.dot(u); | ||
|
|
||
| if ops::abs(denom) < f32::EPSILON { | ||
| return None; | ||
| } | ||
|
|
||
| Some(Vec3::new(d.dot(u), z.dot(v), -y.dot(v)) / denom) |
There was a problem hiding this comment.
I believe this entire thing would be better done by constructing a 3x3 matrix from the normal vectors and using https://docs.rs/glam/latest/glam/f32/struct.Mat3.html#method.try_inverse to compute an inverse matrix, then multiply by it the vector of offsets.
Effetively one is solving the set of 3 linear equations:
Vec3::dot(n_i, x) = -offset_i
So the n vectors assemble as rows into a matrix, and the offsets into the right hand side.
That's effectively what this code is doing (I hope), but in a rather confusing way.
|
It looks like your PR is a breaking change, but you didn't provide a migration guide. Please review the instructions for writing migration guides, then expand or revise the content in the migration guides directory to reflect your changes. |
Objective
bevy_math: OrganizeHalfSpace, create 2d and 3dHalfSpaceprimitives #22784Solution
Vec4internally (packing the normal and offset for SIMD efficiency).pub type HalfSpace = HalfSpace3dto maintain backward compatibility with existing usages inbevy_cameraandbevy_pbr.Testing
bevy_mathlocally.bevy_cameraandbevy_pbrcompile cleanly with the changes via the HalfSpace type alias.Migration Guide
The Plane2d primitive has been updated to include an offset. If you were creating planes previously, the constructor signature has changed.
Plane2d::new(Vec2::X)should be updated toPlane2d::new(Dir2::X, 0.0).offset: f32field.HalfSpace2d.