Skip to content
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

[3.x] Fix scale sensitivity for 3D objects. #52665

Merged
merged 1 commit into from
Sep 15, 2021

Conversation

lentsius-bark
Copy link
Contributor

Scaling 3D objects has been broken for a long time, it works well only when scale values stay around their original ones. Meaning that if you try scaling an objects that already at scale 30, the scaling function becomes unusable. Simple as that.

Current godot implementation vs. this PR:

GodotScaleFix2.mp4

This PR also divides the scale factor by the distance of the mouse click from the object. This is neat as it gives users the ability to choose scaling sensitivity in a very simple way: "The further from the object's center you mouse is, the slower it scales and vice versa"

A video showing the variable scaling sensitivity:

VariableScale.mp4

I'm new to contributing and a novice at C++, I welcome all feedback. I heard the codebase for specifically this has changed loads for 4.0, chances are it's already fixed if not I could try my hand at porting it?

@akien-mga akien-mga added this to the 3.4 milestone Sep 14, 2021
@akien-mga akien-mga requested a review from a team September 14, 2021 12:44
Copy link
Contributor

@JFonS JFonS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense usability-wise. The way the scaling factor is computed is a bit convoluted, I left a change suggestion in a comment.

This also needs to be changed in master. Simply applying the same scaling factor to motion right before this piece of code should do it:

if (se->gizmo.is_valid()) {
for (Map<int, Transform3D>::Element *GE = se->subgizmos.front(); GE; GE = GE->next()) {
Transform3D xform = GE->get();
Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords);
if (!local_coords) {
new_xform = se->original.affine_inverse() * new_xform;
}
se->gizmo->set_subgizmo_transform(GE->key(), new_xform);
}
} else {
Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords);
_transform_gizmo_apply(se->sp, new_xform, local_coords);
}

Comment on lines 1650 to 1651
float click_distance = click.distance_to(_edit.center);
motion = ((motion / original.basis.get_scale()) / (Vector3(click_distance, click_distance, click_distance) / original.basis.get_scale()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The divisions by original.basis.get_scale() are redundant since they happen on both sides of the larger division. The code can be simplified down to this:

Suggested change
float click_distance = click.distance_to(_edit.center);
motion = ((motion / original.basis.get_scale()) / (Vector3(click_distance, click_distance, click_distance) / original.basis.get_scale()));
motion /= click.distance_to(_edit.center);

@lentsius-bark
Copy link
Contributor Author

I'll be online later this evening and work the changes in then, thanks for the suggestions! Loving the simplicity.

@akien-mga
Copy link
Member

akien-mga commented Sep 14, 2021

Aside from the code simplification, three more things worth considering (I didn't assess them myself):

  • Is this the "best" location to perform this operation? motion is calculated further up.
  • Related, we're in a for loop for all the selection - was this tested with multiple scaled objects selected, with different scales? It looks like it will mutate the same motion each time so I suspect you'll see problems.
  • Related, further up some calculations are done for when snapping is enabled. Was this tested with snapping on, and if so does it work as expected?

@lentsius-bark
Copy link
Contributor Author

@JFonS I implemented your suggestions. Thanks for pointing this out, really good stuff.
@akien-mga I moved the code higher, right after where motion is first defined so that it'd work robustly.
I tried scaling multiple objects as well as scale snap and it worked as expected.

I'll rebase and squash commits when this is all resolved :)

@lentsius-bark
Copy link
Contributor Author

a video with the scaling of a group as well as snap scale

groupScale.mp4

Copy link
Contributor

@JFonS JFonS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I approve the PR, but it would need a master version before being merged :)

@lentsius-bark
Copy link
Contributor Author

@JFonS #52685

Should I rebase and squash commits on this one?

@JFonS
Copy link
Contributor

JFonS commented Sep 14, 2021

@lentsius-bark yup, this one needs the commits squashed.

@lentsius-bark
Copy link
Contributor Author

@JFonS will do, thanks!

When scaling 3D objects the distance form them is not considered. Allowing for finer contorl. Overscaled objects no longer break the gizmo.
@lentsius-bark
Copy link
Contributor Author

@JFonS done.

@akien-mga akien-mga merged commit 29eefc4 into godotengine:3.x Sep 15, 2021
@akien-mga
Copy link
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants