adamlwgriffiths / Pyrr

3D mathematical functions using NumPy
Other
403 stars 57 forks source link

confused about matrix and @ operator in numpy #103

Open Yves33 opened 3 years ago

Yves33 commented 3 years ago

Hi,

I'm confused about matrix multiplication. I used to use "*" operator to perform my matrix multiplications, coming from a first C++/glm experience. it seems that in python 3.5+, numpy matrix multiplication should use @ operator.

However:

rot_y = pyrr.Matrix44.from_z_rotation(time.perf_counter() * 2)
translate = pyrr.Matrix44.from_translation([0.5,0.5,0])
scale=pyrr.Matrix44.from_scale([0.5,0.5,0.5])
model=scale @ translate @ rot_y                                   # line 1 first rotate, then translate, then scale
model=rot_y * translate * scale                                       # line 2 first rotate, then translate, then scale
model=rot_y @ translate @ scale                                   # line 3 first scale, then translates, then rotates
model=scale * translate * rot_y                                       # line 4 first scale, then translates, then rotates

it seems that "*" is performing matrix multiplication in the "reverse order"? wasn't it supposed to perform element wise multiplication? what is the correct notation?

I used to have perfectly decent results with

projM=pyrr.Matrix44.look_at(eye,target, up)
viewM=pyrr.Matrix44.perspective_projection(fovy, aspect, near, far)
modelM=(whatever)
ModelViewProjection=projM*viewM*modelM

but using the @ operator, i have to reverse the order of matrices to get the same results

ModelViewProjection=modelM@viewM@projM

what is the correct way to proceed? (in shader, obviously, gl_Position=ModelViewProjection*vec4(position, 1.0) )

adamlwgriffiths commented 3 years ago

Looks like the object interface m1 * m2 expands to multiply(m2, m1) which then expands to np.dot(m2, m1)

I'm not sure what the reasoning for it was, it's obviously inappropriate.

RitChan commented 3 years ago

I also found this confusing. Matrix44.from_translation((x, y, z)) returns a matrix, say A. A stores (x, y, z) in A[3, 0:3], which I didn't know at first. I performed A @ another_matrix44 (to transform every column of another_matrix44) as did with numpy array, which leads to the wrong answer. After I read the documentation, I realized that pyrr does this by "" operator. Simultaneously, I found A[3, 0:3] actually stores translation. So I wrote `another_matrix44.transpose() A`, which is wrong again. It took me a few hours to figure out how to do it right. I didn't fully recognize what I am doing until I cloned and read the source code. Sad story 😥

adamlwgriffiths commented 3 years ago

PRs are welcome