Zuzu-Typ / PyGLM

Fast OpenGL Mathematics (GLM) for Python
zlib License
214 stars 29 forks source link

What is an `mvec4`? #226

Closed JC3 closed 1 year ago

JC3 commented 1 year ago

Extracting a column from a matrix seems to yield an mvec4:

>>> glm.mat4()[1]
mvec4(            0,            1,            0,            0 )

What is an mvec4? Is it different than a vec4?

I couldn't find anything about it in the wiki.

Zuzu-Typ commented 1 year ago

Hi @JC3 ,

I'm sorry about the confusion. mvec is indeed different to vec, because it has a different internal data structure. Specifically, it's a reference to a matrix column or another vector. I.e. if you modify its data, you actually modify the data it's referencing.

consider the following code:

import glm

v1 = glm.vec3(1, 2, 3)
v1_ref = glm.mvec3(v1)

v1_ref.x = 4

print(v1) # prints vec3(4, 2, 3)

mvecs were created to make this possible:

import glm

m = glm.mat4()
m[0][0] = 5 # changes the first item in the first column to 5

This works only because m[0] is a reference to the first column of m. If it was a normal vector, it would simply be a copy and would not allow modification of the original data. The name mvec is supposed to mean matrix_vector.

It's always a bit of a hassle with these, but there's no way around it, unless I make every type immutable (which was previously requested, and I consider doing).

Anyway, you can use them just like any normal vector. I believe there are some specific circumstances where mvecs cannot be used, but they should be compatible with basically any given glm function that works with vecs.

JC3 commented 1 year ago

Thanks for this, totally makes sense.

So, I have a question: Does an mvec always reflect the value of the matrix it was taken from? That is, if I do this:

   m = glm.mat4()
   v = m[0]

And then I modify m's contents in column 0, will v be modified as well?

In other words, should I be doing something like this instead if I don't want changes to the matrix to show up in the column vector?

    m = glm.mat4() 
    v = glm.vec4(m[0])

I guess I could just try it, heh, but I'm not near a machine with Python on it right now.

Thanks again!

Zuzu-Typ commented 1 year ago

Yes, accessing the column of a matrix always yields an mvec and mvecs are always an "alias" to the value of the matrix column in question.

Therefore if you modify the matrix column, the mvec (which acts as an alias to the data of the matrix) will also change. It even keeps a reference to the matrix, meaning if you delete m (or run out of scope), but keep the mvec v (e.g. as a global variable), the object m stays in memory until v is deleted or runs out of scope. Since an mvec is only an alias it would point nowhere if it was kept alive but the matrix was deleted.

You are entirely correct. If you want a copy of a matrix column that doesn't change if the matrix is modified (and vice versa), you need to create a copy of it using the appropriate vector constructor.

JC3 commented 1 year ago

Thank you very much!