I’m at present implementing gizmos in my engine (or reasonably persevering with the implementation I made a yr in the past). I had carried out a method to decide on whether or not transformations are utilized based mostly on native area or world area, which is fairly simple for translation and rotation, however not a lot for scale.
What I want to do is apply world area scaling with out skewing the axes, ideally with out utilizing matrices as extracting scale from a matrix is tough to do proper. My resolution at present (which doesn’t work) is to “undertaking” the dimensions alongside every native axis onto all the worldwide axes.
At present to undertaking scale onto an axis I take the sum of the projection of X, Y and Z onto the axis (absolute worth for now as I do not wish to care about unfavorable scale but). The method then is mainly the next: 1- when dragging begins, undertaking the item scale alongside its reworked axes onto the worldwide axes, 2- modify scale on the worldwide axes, 3- undertaking again. It doesn’t work as my resolution doesn’t round-trip (i.e. undertaking A onto B then the outcome again onto A doesn’t yield the unique worth), which is a essential constraint as a result of when no modification is completed the outcome wants to remain the identical. I’ve one thing like this:
ThreeAxes :: struct {
x, y, z : Vec3f;
}
operator * :: (axes : ThreeAxes, vec : Vec3f) -> ThreeAxes {
return .{axes.x * vec.x, axes.y * vec.y, axes.z * vec.z};
}
GetScaleOnAxis :: (scale : ThreeAxes, axis : Vec3f) -> float {
return Abs(Dot(scale.x, axis)) + Abs(Dot(scale.y, axis)) + Abs(Dot(scale.z, axis));
}
ProjectScale :: (scale : ThreeAxes, onto : ThreeAxes) -> Vec3f {
return .{
GetScaleOnAxis(scale, onto.x),
GetScaleOnAxis(scale, onto.y),
GetScaleOnAxis(scale, onto.z),
};
}
GizmoScale :: (/*...*/) {
global_axes_vectors := Vec3f.[
.{1,0,0},
.{0,1,0},
.{0,0,1},
];
local_axes_vectors := Vec3f.[
Normalized(TransformVector(transform, .{1,0,0})),
Normalized(TransformVector(transform, .{0,1,0})),
Normalized(TransformVector(transform, .{0,0,1})),
];
// ...
i := index_of_axis_being_dragged;
if drag_started {
ctx.drag_start_scale = ProjectScale(scale=local_axes_vectors * scale, onto=global_axes_vectors);
}
if dragging {
scale_axes := ThreeAxes.{
global_axes_vectors[0] * ctx.drag_start_scale.x,
global_axes_vectors[1] * ctx.drag_start_scale.y,
global_axes_vectors[2] * ctx.drag_start_scale.z,
};
scale_axes.axes[i] += global_axes_vectors[i] * additional_scale;
outcome = ProjectScale(scale=scale_axes, onto=local_axes_vectors});
}
}
What I’m on the lookout for is to undertaking not directly scaling from a coordinate system to a different, and I feel for it to work it must respect the standards: 1- identification projection works as anticipated (i.e. undertaking A * scaleXYZ onto A provides scaleXYZ), 2- the calculation spherical journeys (i.e. undertaking A * scaleXYZ onto B -> newScaleXYZ, then undertaking B * newScaleXYZ onto A provides scaleXYZ).
Both that or my method is fallacious and I would like a very completely different resolution.