I am making a small block builder with physics in Bevy, just for fun and for learning purposes. I guess my issue boils down to basically a math problem. I am trying to rotate the block placement indicator to be flush with the side of the cube I am raycasting against, but as the cube rotates the indicator (gizmo) doesnt rotate with the cube properly (obviously).
When creating a Quaternion like this:
if let Ok(xf) = block_q.get(*entity) {
let face_center = xf.translation() + (hit.normal * 0.5);
gizmos.rect(
Transform::from_translation(face_center + hit.normal * 0.01)
.with_rotation(Quat::from_rotation_arc(Vec3::Z, hit.normal.normalize()))
.to_isometry(),
Vec2::new(1.0, 1.0),
Color::WHITE,
);
pos = Some(face_center);
}
It rotates and is pointing with the normal, but not with the block itself. Example 1
And if i just use the rotation from the block itself, it rotates properly with the cube, but isnt pointing to the normal (obviously).
if let Ok(xf) = block_q.get(*entity) {
let face_center = xf.translation() + (hit.normal * 0.5);
gizmos.rect(
Transform::from_translation(face_center + hit.normal * 0.01)
.with_rotation(xf.rotation())
.to_isometry(),
Vec2::new(1.0, 1.0),
Color::WHITE,
);
pos = Some(face_center);
}
So my question is, is it possible to mathematically combine these quaternions to achieve my desired result, or is there a better approach to my problem? Multiplying the quaternions together did not work...
I have to multiply the cubes rotation with the normal, but first repoint the starting direction of the gizmo (Z) with the cubes rotation by multiplying it:
if let Ok(xf) = block_q.get(*entity) {
let face_center = xf.translation() + (hit.normal * 0.5);
let block_rotation = xf.rotation();
let align_to_normal = Quat::from_rotation_arc(block_rotation * Vec3::Z, hit.normal.normalize());
let final_rotation = align_to_normal * block_rotation;
gizmos.rect(
Transform::from_translation(face_center + hit.normal * 0.01) // lil offset for style
.with_rotation(final_rotation)
.to_isometry(),
Vec2::new(1.0, 1.0),
Color::WHITE,
);
pos = Some(face_center);
}
The GlobalTransform
actually has a method that returns its own Z direction in global space called .back()
. So block_rotation * Vec3::Z
can be replaced with *xf.back()
.