While there's no native FUZE function to directly set an object's rotation to an arbitrary state starting from any other rotation state, it's possible to write a function that does this by building off of objectPointAt(). objectPointAt() follows consistent rules about how it orients an object, and once we know these rules, we can use them as a starting point for our function.
objectPointAt() will always set the forward vector (the object's local z-axis) to the requested direction.
objectPointAt() will always set the right vector (the object's local x-axis) orthogonal to the global y-axis (that is, the right vector will always point along the floor).
objectPointAt() will always give the up vector (the object's local y-axis) a positive y value (that is, the up vector will always point upward and never downward).
objectPointAt() has a bug that will cause the object to disappear if you point it directly up or directly down.
In practical terms, this means we can set the object's forward vector with objectPointAt(), and then, because we know based on the four rules above how the up and right vectors must now be oriented, we can calculate how much we need to rotate the object around its local z-axis to reach our desired orientation.
The code below does that and also provides some safeguards against the disappearing object bug and potential floating point errors. My implementation uses direction vectors as the inputs to represent a rotation state because that's generally how I prefer to work, but it would also be possible to use the same principles to create a function that takes, for example, pitch/yaw/roll as its rotation input (or you can convert with eulerToDirVec()/axisAngleToDirVec(), included below).
Once the share is approved, this code can be downloaded with 5LH73MNDDT.
(The vectors passed to setObjRot() as _fwd and _up should be normalized.)
// Sets rotation for an object.
function setObjRot(_obj, _pos, _fwd, _up)
// A straight up or down forward wrecks the algorithm, so fudge the
// vectors if necessary.
if equals(abs(_fwd.y ), 1, 0.000001) then
_fwd = axisRotVecBy(_fwd, _up, 0.015)
endif
// When called from any orientation, objectPointAt() will always
// result in a positive-y up vector and a 0-y right vector, so it's
// predictable enough that we can infer the object's up/right vectors
// even without specific data about how they've been modified.
objectPointAt(_obj, _pos + _fwd)
var unrolledR = axisRotVecBy(normalize({_fwd.x, 0, _fwd.z}), {0, 1, 0}, -90)
var unrolledUp = cross(unrolledR, _fwd)
var roll = getAngleBetweenVecs(unrolledUp, _up)
if roundVec(axisRotVecBy(unrolledUp, _fwd, roll), 2) != roundVec(_up, 2) then
roll *= -1
endif
rotateObject(_obj, {0, 0, 1}, roll)
return void
// Equality check with tolerance value.
function equals(_num1, _num2, _tolerance)
var isEqual = true
if strBeginsWith(str(_num1), \''{\'') then // If a vector
var i
for i = 0 to 4 loop
if abs(_num1[i] - _num2[i]) > abs(_tolerance) then
isEqual = false
break
endif
repeat
else if abs(_num1 - _num2) > abs(_tolerance) then
isEqual = false
endif endif
return isEqual
// Rotates 3D vector _v around 3D vector _axis by _deg degrees.
function axisRotVecBy(_v, _axis, _deg)
// Euler-Rodrigues rotation formula
var halfDeg = _deg / 2
var w = _axis * sin(halfDeg)
var crossWV = cross(w, _v)
return _v + 2 * cos(halfDeg) * crossWV + 2 * cross(w, crossWV)
// Returns angle in degrees between two vectors.
function getAngleBetweenVecs(_v1, _v2)
angle = 0
if equals(_v1, _v2 * -1, 0.001) then
angle = 180
else if !equals(_v1, _v2, 0.001)
and !equals(_v1, {0, 0, 0}, 0.001)
and !equals(_v2, {0, 0, 0}, 0.001) then
angle = acos(dot(_v1, _v2) / (length(_v1) * length(_v2)))
endif endif
return angle
// Round a float to a given number of decimal places.
function roundDec(_num, _decimals)
var factor = pow(10, _decimals)
if _decimals <= 0 then
factor = 1
endif
_num = _num * factor
_num = round(_num)
return _num / factor
// Rounds a vector to the given number of decimal places.
function roundVec(_v, _decimals)
_v[0] = roundDec(_v[0], _decimals)
_v[1] = roundDec(_v[1], _decimals)
_v[2] = roundDec(_v[2], _decimals)
if _v[3] != 0 then
_v[3] = roundDec(_v[3], _decimals)
endif
return _v
// Converts an Euler angle to direction vectors.
function eulerToDirVec(_yaw, _pitch, _roll)
var up = axisRotVecBy({0, 1, 0}, {0, 0, 1}, _roll)
var fwd = axisRotVecBy({0, 0, 1}, {-1, 0, 0}, _pitch)
up = axisRotVecBy(up, {-1, 0, 0}, _pitch)
fwd = axisRotVecBy(fwd, {0, 1, 0}, _yaw)
up = axisRotVecBy(up, {0, 1, 0}, _yaw)
var result = [
.fwd = fwd,
.up = up
]
return result
// Converts degrees of rotation around an axis to direction vectors.
function axisAngleToDirVec(_axis, _deg)
if axis != {0, 0, 0} then
_axis = normalize(_axis)
endif
var result = [
.fwd = axisRotVecBy({0, 0, 1}, _axis, _deg),
.up = axisRotVecBy({0, 1, 0}, _axis, _deg)
]
return result