Start a new topic

How to call Matrix44 in python script.

self.outputs.Transform[0][0].value = self.inputs.AxisZ.value

Can anyone fix this?


Just to be clear. Transform is the name of my Matrix and I want to be able to set the X,Y,Z and X,Y,Z rotations using python scripting.

Hi Logan,


First of all, if Transform is an output field in your script, you need to use .value before the bracket operator to assign values.

Like so:


    m_00 = self.outputs.Transform.value[0][0]


m_00 is then the element at row and column zero in your transformation matrix.

Note that ".value" will return the actual data element contained in the field (in this case the transformation matrix in your output).


To access element at (i,j) where i and j refer to the index of the desired row and column, you need to do


    m_ij =self.outputs.Transform.value[i][j]


We use column vectors in Vortex. So the first three columns of your transformation matrix represent the three axes of the reference frame which this transformation represents.


To set these three axes from your axes (I suppose that is what you want to do), you can simply copy them one by one into the transformation matrix.


I prepared a little script that you can add to a test scene which takes three input angles, creates a rotation matrix from them using the VxSim.createRotation function and then extracts the three columns that represent the three aces of the corresponding reference frame.

After, I copy these three axes (columns) into an output transformation matrix.

This should be all the operations you need.

  

from VxSim import *

def pre_step(self):
    """ Called before the collision detection and before the dynamic solver.
    Use this method to get inputs or set values to dynamics objects.""" 
    m = VxSim.createRotation(self.inputs.X.value, self.inputs.Y.value, self.inputs.Z.value)
    column0 = VxSim.VxVector3(m[0][0], m[1][0], m[2][0])
    column1 = VxSim.VxVector3(m[0][1], m[1][1], m[2][1])
    column2 = VxSim.VxVector3(m[0][2], m[1][2], m[2][2])

    print column0
    print column1
    print column2

    tm_out = self.outputs.tm.value
    tm_out[0][0] = column0[0]
    tm_out[1][0] = column0[1]
    tm_out[2][0] = column0[2]

    tm_out[0][1] = column1[0]
    tm_out[1][1] = column1[1]
    tm_out[2][1] = column1[2]

    tm_out[0][2] = column2[0]
    tm_out[1][2] = column2[1]
    tm_out[2][2] = column2[2]

    self.outputs.tm.value = tm_out
    pass 

  

To use this script, just create an empty scene, add a "Script" extension from the toolbox and add three inputs "X", "Y" and "Z" of type double and add one output "tm" of type "Matrix44".


Here is what this gives you when starting the simulation and playing with the input angles.


image


I hope this answers your question.


For a complete list of operations you can do with Matrix44, please look at the Transformation C++ API which is mostly exposed in python in the "VxSim" module (VxSim.createRotation is one of these functions).


https://www.cm-labs.com/vortexstudiodocumentation/Vortex_Technical_Documentation/namespace_vx_math_1_1_transformation.html


For you reference, here is an exhaustive list of functions accessible in the VxSim module (provided in C++ syntax though):


 

Matrix44 createScale(double sx, double sy, double sz);
Matrix44 createScale(const Vx::VxVector3& scale);
Matrix44 createRotation(double rx, double ry, double rz);
Matrix44 createRotation(const Vx::VxVector3& axis, double angle);
Matrix44 createRotation(Vx::VxQuaternion quat);
Matrix44 createRotationFromOuterProduct(const Vx::VxVector3& v, const Vx::VxVector3& w);
Matrix44 createTranslation(double tx, double ty, double tz);
Matrix44 createTranslation(const Vx::VxVector3& t);

Matrix44 createObjectLookAt(const Vx::VxVector3& eye, const Vx::VxVector3& center, const Vx::VxVector3& up);
Matrix44 createCameraLookAt(const Vx::VxVector3& eye, const Vx::VxVector3& center, const Vx::VxVector3& up);

Matrix44 createOrthographic(double left, double right, double bottom, double top, double zNear, double zFar);
Matrix44 createFrustum(double left, double right, double bottom, double top, double zNear, double zFar);
Matrix44 createPerspective(double fovy, double aspectRatio, double zNear, double zFar);

Vx::VxVector3 getScale(const Matrix44 & m);
Vx::VxVector3 getTranslation(const Matrix44 & m);
Vx::VxVector3 getRotation(const Matrix44 & m);
bool isPerspectiveProjection(const Matrix44 & m);

Matrix44 translateTo(const Matrix44 & m, const Vx::VxVector3& translation);
Matrix44 rotateTo(const Matrix44 & m, const Vx::VxVector3& rotation);
Matrix44 scaleTo(const Matrix44 & m, const Vx::VxVector3& scale);
Matrix44 compose(const Vx::VxVector3& scale, const Vx::VxVector3& rotation, const Vx::VxVector3& translation, double flip);

void decompose(const Matrix44 & m, Vx::VxVector3& scale, Vx::VxVector3& rotation, Vx::VxVector3& translation, double& flip);

Vx::VxVector3 linearVelocity(const Matrix44 & from, const Matrix44 & to, double dt);
Vx::VxVector3 angularVelocity(const Matrix44 & from, const Matrix44 & to, double dt);

 

Hope this helps,

Daniel

Your last message helped a bit, but now I seem to be more lost than ever. The matrix system seems to be completely random. I can change m[0][0] and it changes the scale and the rotation at the same time, but [3][0] also changes a different scale and rotation. Can you please let me know how your matrix is made. What is the X Rotation, Y Rotation and Z Rotation on the matrix.

[0][3] = X
[1][3] = Y
[2][3] = Z

That is all I can figure out by randomly putting numbers in. When I use the createRotation, it also changes my scale for some reason.

Any help would be appreciated.

Hi Logan,


In Vortex, for representing poses (positions and orientations) we are using affine transformations represented using homogeneous coordinates (see here: https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations). In this representation, 3-dimensional positions (x,y,z) and direction vectors (i,j,k) are represented via 4-dimensional vectors (x,y,z,1) and (i,j,k,0) respectively. The fourth component is used to indicate whether we have a position or a direction vector. The transformation matrices for rotating, scaling or translating are therefore 4x4 matrices where the top-left 3x3 sub-matrix models the rotation and scaling, and the last 4x1 column in the matrix models the translational part.


The last column will only have an effect on positions (x,y,z,1) due to the fourth component value 1 in the position vector. This makes sense, since direction vectors (i,j,k) can by definition not be translated. the fourth component being 0 for these vectors has this effect.


So, if you are looking at the entries [0][3], [1][3], [2][3] in the matrix, you are effectively accessing the last column in the matrix which contains the translational part.


Here is an explanation of the explained concept:

http://www.it.hiof.no/~borres/j3d/math/threed/p-threed.html


For compositing rotations, translations and scaling you will need to create individual 4x4 transformation matrices using the API functions I mentioned in my previous post (e.g., VxSim.createTranslation, VxSim.createRotation and VxSim.createScale) and multiyply the resultant matrices with each other.


For example, to produce a combined translation and rotation you could do the following:


T = VxSim.createTranslation(...)

R = VxSim.createRotation(...)


M = T * R


Hope this helps,

Daniel

If I use createTranslation and createRotation, it does not do what I need it to do, I don't want the camera to reset. I want it to rotate with the joystick, not to be trapped and reset when I let go of the thumbstick.

Z = self.inputs.AxisZ.value / 5

Y = self.inputs.AxisY.value / 5

X = self.inputs.AxisX.value / 5


tm_out = self.outputs.Transform.value

tm_out[0][3] += X

tm_out[1][3] += Y

tm_out[2][3] += Z


self.outputs.Transform.value = tm_out

This block of code, for example, translates the camera perfectly, exactly how I need it to, at the speed I need it to.

Is there any easy way to do that with the rotation, simply adding a value to the matrix in order to rotate?

To add to my last comment, doing something like this, as you suggested, only temporarily moves the camera, but it then resets back to its origin.

    Z = self.inputs.AxisZ.value / 5

    Y = self.inputs.AxisY.value / 5

    X = self.inputs.AxisX.value / 5

 

    new_rotation = VxSim.VxVector3(self.inputs.AxisXRot.value, self.inputs.AxisYRot.value, self.inputs.AxisZRot.value)

 

    tm_out = self.outputs.Transform.value

 

    r = VxSim.createRotation(new_rotation, +1)

    t = VxSim.createTranslation(X,Y,Z)

 

    tm_out = t * r

 

    self.outputs.Transform.value = tm_out

    pass

Hi Logan,


In your code, "t * r" results in the change, and not the absolute value that you want in the end. In other words something like "rotate by 1 radian on this axis". But you're not giving it a starting point, so it thinks it's starting from 0 every time. That's why it seems to reset.


To get the effect that you want, you have to apply that difference to the previous state. Remember that matrices are combined via multiplication, so you could do this:


Change   

t * r

 to     

t * r * self.outputs.Transform.value

That will take the previous value that your script had output and apply your changes to it every frame.


Apart from that, watch out about your "+1" in your createRotation. In Vortex, rotation is computed in radians, and 1 radian per frame is going to spin really fast!


2 people like this
Login to post a comment