Using the nuke.math Python module to do Vector and Matrix operations

Written by Ivan Busquets on .

2. Vector methods


Here's where the fun starts. I will go through some of the most useful methods available in the Vector and Matrix classes defined in nuke.math. This should give a basic idea of what can be done with them, as well as help understand how to use them.
Note: for a complete list of the methods available for each class, use "dir(nuke.math.className)" and "help(nuke.math.className)".

Vector2:

Vector2 is a Class that defines a bi-dimensional vector. That is, a vector that's defined by two coordinates, x and y. This is usually used to represent a point/vector in the plane. Here's a few useful methods available for Vector2 objects:


distanceBetween(...)

Syntax: Vector2.distanceBetween(Vector2) -> float :

Description: Returns the distance between two 2D points. This would also be the hypotenuse of the right triangle that can be described by those 2 points.

Example:

Finding the distance between two 2D points
1
2
3
4
5
6
pointA = nuke.math.Vector2(50,100)
pointB = nuke.math.Vector2(150, 175)
distance = pointA.distanceBetween(pointB)
print distance
 
# Result: 125.0

distanceSquared(...)

Syntax: Vector2.distanceSquared(Vector2) -> float :

Description: Returns the suare of the distance between points. If the equation for the distance between points is sqrt( (A.x-B.x)^2 + (A.y-B.y)^2), this function just avoids the square root, meaning it's faster to compute. This won't make any difference for a small number of operations, but this method can be faster if you're looping through a large number of vectors and don't need the exact distance. For example, when you only want to 'compare' the distance between many points and another point, to find out which one is the closest.


dot(...)

Syntax: Vector2.dot(Vector2) -> float :

Description: Returns the dot product of two vectors. This is a scalar value that represents how much the two vectors are looking in the same direction. This can be used for basic lighting operations (check how much a surface normal is facing a light source), or any kind of operation that involves checking the angle between two vectors.

Example:

Find the angle between vectors A and B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import math  # we'll need this for the arc cosine function, and to convert radians to degrees
 
vectorA = nuke.math.Vector2(50,100)
vectorB = nuke.math.Vector2(150, 175)

# We need both vectors to be 1-unit length so that the dot product between them
# equals the cosine of the angle between them, so we normalize A and B

vectorA.normalize()
vectorB.normalize()
dotProduct = vectorA.dot(vectorB)
angle = math.degrees(math.acos(dotProduct)) # 'A' dot 'B' = cos(angle), so angle = acos('A' dot 'B')
print angle
 
# Result: 14.0362473503

length(...)

Syntax: Vector2.length() -> float :

Description: Returns the magnitude of the Vector as a float. This is the same as the distance of the vector from the origin.

Example:

Length of a 2D vector
1
2
3
4
vectorA = nuke.math.Vector2(15,46)
print vectorA.length()
 
# Result: 48.3838806152

lengthSquared(...)

Syntax: Vector2.length() -> float :

Description: Returns the squared magnitude of the Vector as a float. Just like in the case of distanceSquared, this is just a faster method to compute, which may be useful if all you want to do is compare the lengths of many vectors to see which one has the biggest or smallest magnitude.


normalize(...)

Syntax: Vector2.normalize() -> float :

Description: Returns the magnitude of the Vector as a float, and converts the vector to a unit vector (by dividing each one of its components by the magnitude). So, this returns the same as Vector2.length(), and also divides the vector by the result. Note that this modifies the vector in-place, so running this method on a vector object actually modifies the object.

Example:

Length vs normalize methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vectorA = nuke.math.Vector2(15,46)
print vectorA.length()· # This should return the same as vectorA.normalize()
 
# Result: 48.3838806152
 
print vectorA/vectorA.length()· # This should the normalized version of vectorA
 
# Result: {0.310021, 0.95073}
 
print vectorA.normalize() # This is the same as .length(), but also modifies vectorA
 
# Result: 48.3838806152
 
print vectorA # This is the already normalized vector
 
# Result: {0.310021, 0.95073}

 

Vector3:


Vector3 is a Class that defines a 3-dimensional vector, with coordinates x, y and z. This is usually used to represent a point/vector in 3d space. The Vector3 Class has all the methods available in Vector2, plus a few additional ones:


cross(...)

Syntax: Vector3.cross(Vector3) -> Vector3 :

Description: Returns the a Vector3 object that's the cross product between two vectors. One of the definitions possible definitions for this is that the cross productof two vectors produces a third vector which is perpendicular to the plane in which the first two lie. If you imagine the standard viewer handles of an Axis, the Y vector would be the cross product of X and Z, X would be the cross product of Y and Z, etc. One of the most common uses of the cross product (in computer graphics) is to find the normal of a plane defined by two points

Example:

Using cross product to find the surface normal of a plane
1
2
3
4
5
6
vectorA = nuke.math.Vector3(1,0,0)  # Unit vector along the X axis
vectorB = nuke.math.Vector3(0,1,0) # Unit vector along the Y axis
vectorC = vectorA.cross(vectorB)
print vectorC
 
# Result: {0, 0, 1} # Unit vector along the Z axis -> normal vector of the XY plane

 


distanceFromPlane(...)

Syntax: Vector3.distanceFromPlane(float A, float B, float C, float D) -> Float :

Description: Returns the distance of a Vector3 to a plane defined by 4 float values, where each value corresponds to A, B, C and D from the plane equation Ax +By + Cz +D = 0. You can easily derive the values of that equation if you only know a point in the plane and its surface normal (like you would get from a card's translate and rotate values).

The example below assumes you already know A,B,C and D values that define the plane, but you can check one of the examples at the end of this tutorial to see how to get A, B, C and D to describe a plane knowing a point in the plane and the surface normal.
Note that this function can return negative values. If you want purely the distance, you'll have to take the absolute value from this. However, it can be useful to know whether a point is facing the normal of the plane (positive result) or is on the other side of the plane (negative result).

Example:

 

Distance from point to plane ABCD
1
2
3
4
5
6
#Assuming we already know the A,B,C and D values that define a plane
A,B,C,D = -0.146446615458, 0.499999970198, 0.853553295135, -1.7677667737
P = nuke.math.Vector3(5,6,7)
print P.distanceFromPlane(A,B,C,D)
 
# Result: 6.47487258911

 


maximum(...) and minimum(...)

Syntax: Vector3.maximum(Vector3) -> Vector3
 :
              Vector3.minimum(Vector3) -> Vector3 :

Description: Returns a Vector3 object whose x, y and z coordinates take the maximum or minimum value out of the two input vectors. This would be the same as (using the maximum example) manually doing "x3 = max(x1,x2); y3 = max(y1,y2); z3 = max(z1,z2)".


reflect(...)

Syntax: Vector3.reflect(Vector3) -> Vector3 :

Description: Returns a the reflection of a Vector3 onto another Vector3 (usually a vector and a surface normal). This will result in a reflected vector

Example:

Finding the reflection of a vector on a given surface
1
2
3
4
5
6
vector = nuke.math.Vector3(10,5,2)
surface = nuke.math.Vector3(0,1,0) # Flat surface pointing up, like a ground plane
reflection = vector.reflect(surface)
print reflection
 
# Result: {-10, 5, -2}


Vector4:

The Vector4 Class defines a 4-component vector (x, y, z, w). This is used to represent a point in 3D homogenous (perspective) space, and is also useful to represent an rgb color with alpha. Homogeneous coordinates are commonly used in computer graphics so we can use 4x4 matrices (Matrix4) to do affine transformations and perspective projections to an arbitrary point (Vector4).
Nuke.math defines no specific methods for the Vector4 Class, but Vector4 instances can be used in some Matrix methods, as you'll see in the next section.

 

Comments   

 
+1 # Frank Rueter 2010-09-14 15:09
awesome tutorial! Thanks so much for sharing and putting in that much effort!
 
 
0 # Carlos Trijueque 2010-09-16 00:55
Ivan, thanks for sharing this terrific piece of info.Very helpful and, as your other tutorials, very well written and explainied.
 
 
0 # Michael Garrett 2010-09-17 11:29
Brilliant! Good info on nuke.math is long overdue!
 
 
+1 # Ivan Busquets 2010-09-17 12:06
Thanks for all the comments, guys!

Yes, Michael, completely agree. It's one of those I had to learn the hard way, so I figured it would be useful to share. Plus, I learnt a bit more while writing it. Glad you liked it. ;-)
 
 
0 # Pete O'Connell 2010-09-20 19:33
Thanks Ivan, that is one of the most awesome tutorials I have ever read!
 
 
0 # Zach Lewis 2011-08-06 10:12
Wanted to chime in and say that this is awesome. A lot of care went into preparing this, and it's much appreciated.
 
 
0 # Diego Piccinato 2011-09-08 10:53
Awesome stuff, thanks Ivan!
 
 
0 # Marco Leone 2013-08-24 00:25
Hey Ivan, thanks a lot for the tutorial, it opened my mind!!!

one quick question thou, I was testing out some of those function on Matrix and I found a little problem.

What I am trying to do is to get the XYZ rotation( in degrees ) from the world matrix of a Camera.

Following you tutorial everythign works fine but the final result of the rotation is a bit different from the original rotation.

what I am doing is really simple :

########################################

import math

matrix = nuke.math.Matri x4() #creating a matrix

matrixValues = nuke.toNode('Ca mera1')['world_ matrix'].getVal ue() # getting the value from the camera world matrix

print "matrixValues :", matrixValues

### adding the value from the camera to the matrix just created ###

for VAL in matrixValues :
print "VAL",VAL
matrix[matrixVa lues.index(VAL) ] = VAL



matrix.rotationOnly() #getting sure I have only the rotation values

print math.degrees(ma trix.rotationsZ XY()[0])
print math.degrees(matrix.rotationsZXY()[1])
print math.degrees(matrix.rotationsZXY()[2])

### check if values r the same

if nuke.toNode('Ca mera1')['rotate '].value(0) == math.degrees(ma trix.rotationsZ XY()[0]) : print True
else: print False


########################################


as u may see it seems that there is an approximation and we loose the last 5 digits on every value when we are adding the worldMatrix of the camera to our Matrix4, and that may be causing the little difference in the result.

Do you know by chance if that is something I did wrong or maybe if there is a work around it ?
thanks for your time
 

You have no rights to post comments

We have 3602 guests and 163 members online