Skip to content

My math skills are weaksauce

Now that I'm finally getting the hang of using the new ObjectVisualTransform functions I've run into another problem. I would like to make a wall object (torch, painting, shield, sword, etc) rotate a certain number of degrees to use as as a switch for a secret/trapdoor or what not. The problem is that OBJECT_VISUAL_TRANSFORM_ROTATE_
rotates at the base of the object and not at its center point. In addition to rotating you also need to translate up or down and to either side based on which way you are rotating. So I was wondering if anyone with some math skill might have made a home brew function using the new Transform function to rotate the object at it's center.

Comments

  • NeverwinterWightsNeverwinterWights Member Posts: 339
    edited May 2018
    Upon further testing is seems that some objects do in fact rotate from the center. Hmm. Ugh. This has me confused.
    Ok so it's the base of every object. Horizontal objects seemed different at first.
    Post edited by NeverwinterWights on
  • OldFriendlyFireOldFriendlyFire Member Posts: 4
    I had a look at this and there seem to be a few issues.

    Given a coordinate system where:
    x - West to East
    y - South to North
    z - Down to Up

    It seems the SetObjectVisualTransform function is using:
    OBJECT_VISUAL_TRANSFORM_ROTATE_X rotates about global z
    OBJECT_VISUAL_TRANSFORM_ROTATE_Y rotates about global x
    OBJECT_VISUAL_TRANSFORM_ROTATE_Z rotates about global y

    Although the TRANSLATE parts do work in the global system as expected.

    You can work out the new coordinates of a rotated point:
    fXNew = fXOld * cos(fAngle) + fYOld * sin(fAngle); fYNew = -fXOld * sin(fAngle) + fYOld * cos(fAngle);

    If you subtract those from the original offset values (e.g. the original coordinates of the centroid of the object) you should be able to apply that as a correction using OBJECT_VISUAL_TRANSFORM_TRANSLATE_*

    Well here is some sample code that I wrote
    void main() { // the object to be rotated object oObject = OBJECT_SELF; // the global axis system equates to: // x - West to East // y - South to North // z - Down to Up // the required rotation (degrees) about the global axis (as used for object location) float fXGlobalRot = 0.0; float fYGlobalRot = 0.0; float fZGlobalRot = 45.0; // the distance from the rotation centre to the centre of the object in the global axis // you have to figure this out for each object by experimentation and guesswork. // for generic code solutions I suggest you add these values to local variables on the objects. // these values will be different for every object float fXGlobalOffset = 0.0; float fYGlobalOffset = 0.0; float fZGlobalOffset = 1.65; //================================================ // Do not edit below this line //================================================ // object rotation system // for reasons unknown the object rotational system is not the same as the translational system // OBJECT_VISUAL_TRANSFORM_ROTATE_X rotates about global z // OBJECT_VISUAL_TRANSFORM_ROTATE_Y rotates about global x // OBJECT_VISUAL_TRANSFORM_ROTATE_Z rotates about global y // switch global rotations to local rotations float fXLocalRot = fZGlobalRot; float fYLocalRot = fXGlobalRot; float fZLocalRot = fYGlobalRot; float fXNew, fYNew, fZNew; if(fXGlobalRot > 0.0){ // make a global x rotation SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_ROTATE_Y, fYLocalRot); // correct for global yz displacements fYNew = fYGlobalOffset * cos(fXGlobalRot) + fZGlobalOffset * sin(fXGlobalRot); fZNew = -fYGlobalOffset * sin(fXGlobalRot) + fZGlobalOffset * cos(fXGlobalRot); if(fXGlobalRot < 180.0) fYNew = -fYNew; if(fXGlobalRot > 90.0 && fXGlobalRot < 270.0) fZNew = -fZNew; SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y, fYGlobalOffset - fYNew); SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z, fZGlobalOffset - fZNew); }else if(fYGlobalRot > 0.0){ // make a global y rotation SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_ROTATE_Z, fZLocalRot); // correct for global xz displacements fXNew = fXGlobalOffset * cos(fYGlobalRot) + fZGlobalOffset * sin(fYGlobalRot); fZNew = -fXGlobalOffset * sin(fYGlobalRot) + fZGlobalOffset * cos(fYGlobalRot); SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_TRANSLATE_X, fXGlobalOffset - fXNew); SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z, fZGlobalOffset - fZNew); }else if(fZGlobalRot > 0.0){ // make a global z rotation SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_ROTATE_X, fXLocalRot); // correct for global xy displacements fXNew = fXGlobalOffset * cos(fZGlobalRot) + fYGlobalOffset * sin(fZGlobalRot); fYNew = -fXGlobalOffset * sin(fZGlobalRot) + fYGlobalOffset * cos(fZGlobalRot); SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_TRANSLATE_X, fXGlobalOffset - fXNew); SetObjectVisualTransform(oObject, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y, fYGlobalOffset - fYNew); } }

    You can see in this example I have a line: float fZGlobalOffset = 1.65; at line 22. This is setting the z offset for a torch placeable (x3_plc_torch) to give it a position to rotate about near the visual centre of the torch when it is placed with a z location of 0.0. You can add this script as an OnClick event for a torch if you want to play with it.

    The script does not handle compound rotations as that is significantly more involved (beware the gimble lock!). I find the conditional to mess with the sign convention annoying, perhaps someone can explain my error that is causing it to be needed? Hope that gives you a starter anyway.
    DerpCity
  • NeverwinterWightsNeverwinterWights Member Posts: 339
    @OldFriendlyFire Holy cow. Yeah I haven't taken a math class since 94'. Failed geometry (twice) and never took trig, so I suffer a little in scripting because of it. I appreciate this and will play around with it. Thank you.
Sign In or Register to comment.