-
-
Notifications
You must be signed in to change notification settings - Fork 228
Reimplements Many Projection
Methods in Rust
#179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This looks largely good! I'm not too familiar with the actual math here (thus why i didn't do this initially) but overall seems good. I did notice that some of the code looks very similar to the c++ code, is this just a consequence of there being fairly standard algorithms for this stuff, or did you look at and copy some code? It's not an issue either way, it's just good to know if you did copy and to what degree, for copyright reasons. (we can copy code from godot but doing so to a substantial degree would require us to properly add MIT license attribution). There are still some functions not fully reimplemented in rust, so this wouldn't fully close #143, but it's a very good start on getting that done. You are missing tests, could you add some unit-tests for code we can run entirely from rust, as well as integration tests to at least confirm our implementation works approximately the same as godot's? (feel free to add other integration tests that make sense too, but keep in mind that we can't really catch errors from godot at the moment) Look at basis.rs for an example of some unit tests, and basis_test.rs. In particular you can use
|
I mostly use OpenGL's description of perspective and orthogonal matrix. It's pretty standard anyways. Sometimes there is equivalent function in As for I might make unittests tomorrow. |
Projection
in RustProjection
Methods in Rust
I think it's ready for review for now. The only missing tests are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! 👍
The PR looks mostly good, if you could squash your comments and answer the minor comments, that would be nice!
Regarding fuzzing, I agree it's something we should consider, I brought up the idea of property-based testing in the past. Do you have experience with propetest
in particular?
godot-core/src/builtin/projection.rs
Outdated
self.cols[3].w == 1.0 | ||
|
||
// XXX: Test the entire last row? | ||
// The argument is that W should not mixed with any other dimensions. | ||
// But if the only operation is projection and affine, it suffice | ||
// to check if input W is nullified (v33 is zero). | ||
// (self.cols[0].w == 0.0) && (self.cols[1].w == 0.0) && (self.cols[2] == 0.0) && (self.cols[3].w == 1.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does Godot handle this?
In case of doubt, I'd probably adopt its behavior, or what do you think? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's currently identical to Godot's. I just proposing for maybe a more thorough test (?) But it risk diverging with Godot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Could you maybe change "XXX" to "TODO" and mention what you just replied (that the current impl matches Godot's)?
godot-core/src/builtin/projection.rs
Outdated
let left = (left_i as real) * 0.5 - 5.0; | ||
let right = (right_i as real) * 0.5 - 5.0; | ||
let bottom = (bottom_i as real) * 0.5 - 5.0; | ||
let top = (top_i as real) * 0.5 - 5.0; | ||
let near = (near_i as real) * 0.5 - 5.0; | ||
let far = (far_i as real) * 0.5 - 5.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you could extract the (x as real) * 0.5 - 5.0
into a small closure or function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably, but better solution would be proper fuzzing. I'll refactor it.
bors try |
tryBuild succeeded: |
I haven't tried fuzz testing yet. Looking up potential libraries, it seem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good. Few comments left, and could you squash commits to 1?
godot-core/src/builtin/projection.rs
Outdated
self.cols[3].w == 1.0 | ||
|
||
// XXX: Test the entire last row? | ||
// The argument is that W should not mixed with any other dimensions. | ||
// But if the only operation is projection and affine, it suffice | ||
// to check if input W is nullified (v33 is zero). | ||
// (self.cols[0].w == 0.0) && (self.cols[1].w == 0.0) && (self.cols[2] == 0.0) && (self.cols[3].w == 1.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Could you maybe change "XXX" to "TODO" and mention what you just replied (that the current impl matches Godot's)?
godot-core/src/builtin/projection.rs
Outdated
RMat4::from_cols_array(&[ | ||
1.0 / x, | ||
0.0, | ||
0.0, | ||
0.0, | ||
0.0, | ||
1.0 / y, | ||
0.0, | ||
0.0, | ||
0.0, | ||
0.0, | ||
1.0 / z, | ||
0.0, | ||
0.0, | ||
0.0, | ||
0.0, | ||
1.0 / w, | ||
]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe that's a case for #[rustfmt::skip]
and 4-by-4 matrix notation for readability. I think this has been done elsewhere already.
Maybe use a separate variable:
if det.abs() > 1e-6 {
#[rustfmt::skip]
let expected = RMat4::from_cols_array(&[
// 4 rows, 4 columns
]);
assert_eq_approx!(proj.inverse(), expected);
godot-core/src/builtin/projection.rs
Outdated
/// Test `create_orthogonal_aspect` method. | ||
#[test] | ||
fn test_ortho_aspect() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no reason to abbreviate here, it just makes it harder to associate with the method.
/// Test `create_orthogonal_aspect` method. | |
#[test] | |
fn test_ortho_aspect() { | |
/// Test `create_orthogonal_aspect` method. | |
#[test] | |
fn test_orthogonal_aspect() { |
godot-core/src/builtin/projection.rs
Outdated
|
||
assert!( | ||
Projection::create_orthogonal(left, right, bottom, top, near, far).is_orthogonal(), | ||
"Projection should be orthogonal! (left={left} right={right} bottom={bottom} top={top} near={near} far={far})", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nitpick, the screaming !
in the message is not needed 😉
a4cbe9c
to
13d4611
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates, and the great work in this PR!
Using RMat4::from_cols_array_2d
for square matrix literals is even better than my #[rustfmt::skip]
suggestion! 👍
bors r+
Build succeeded:
|
Closes #143
Note:
create_fit_aabb
is not yet exists, should it be a stub function?