# [Bf-committers] Proposal to Change Mathutils Vectors

Andrew Hale trumanblending at gmail.com
Wed Dec 7 16:50:10 CET 2011

Well Blender already contains class methods to create rotation, scaling and
other matrices, see here
http://www.blender.org/documentation/blender_python_api_2_60a_release/mathutils.html#mathutils.Matrix.Rotationwhich
is somewhat similar to the above discussion.

I'm not sure how worthwhile it is to subclass vectors for position
positions vs normals. Couldn't this be handled by the user explicitly? It
would basically amount to generating a storing a second matrix. If new
vector sub classes are added then there is a risk of creating more
confusion with users. If you want it handled automatically then you could
subclass vectors from within python.

Thanks,
Andrew

PS Something like vec = Vector((1,2,3), is_position=True) might be possible.

2011/12/8 José Romero <jose.cyborg at gmail.com>

> On Wed, 07 Dec 2011 13:45:36 +0100
> Paul Melis <paul.melis at sara.nl> wrote:
>
> > Hi Andrew,
> >
> > On 12/07/2011 11:33 AM, Andrew Hale wrote:
> > > Correct me if I'm wrong, but do you propose to have 3D vectors with
> > > matrix multiplication just work (i.e. making assumptions about the w
> > > coordinate and renormalising if necessary) but retain 4D vectors
> > > which compute the product without modification of the w component?
> > > This sounds quite logical, however, these transformations deal with
> > > points so I'm not sure I understand what you mean by
> > > differentiating between vectors and normals.
> >
> > Regarding the last point: suppose you have a 3D model consisting of a
> > set of points with associated normals. If you want to transform the
> > model using some transformation matrix M then you can simply update
> > each point by matrix mulplication with M and normalizing the result.
> > I.e. you would represent each 3D point coordinate as (x, y, z, 1),
> > multiply with M to get (x', y', z', w') and divide by w' to get the
> > final transformed coordinates. The normal vectors of the model
> > however need to be transformed by multiplying with (M^-1)^T, i.e. the
> > transpose of the inverse of M. So you would first compute Mn =
> > transpose(inverse(M)) and then compute each transformed normal vector
> > using (nx', ny', nz', 0) = Mn * (nx, ny, nz, 0).
> >
> > This is the type of situation where a good API can hide lots of
> > details the user might not be interested in. The key here I think is
> > not to have users use mathematical operations like multiplication,
> > but to make them use methods that handle and hide the above
> > complexities. For example (obviously pseudocode not based on current
> > Blender Python API :)):
> >
> > # Load wavefront model
> >
> > # Create transformation
> > S = Matrix.scale(2, 2, 2)
> > R = Matrix.rotate_x(90)
> > T = Matrix.translate(1, -4, 3)
> > # Combined transformation: 1) scale, 2) rotate, 3) translate
> > M = S * R * T
> >
> > # Transform model
> > for v in model.vertices:
> >     new_position = M.transform_point(v.position)
> >     new_normal = M.transform_normal(v.normal)
> >     ....
> >
> > Here, the transform_normal() method could take care of computing
> > (M^-1)^T and caching it in the M instance, so it only needs to be
> > computed once. The user only works with 3-tuples for points, vectors
> > and normals without having to worry about normalization after
> > multiplication and such. In fact, the user could be completely
> > unaware that M*v multiplication is being doing. Furthermore,
> > transform_point() would take care of normalization after
> > multiplication, while transform_vector() wouldn't perform that step
> > as it isn't necessary for vectors.
> >
> > Interestingly I now seem to be arguing that for doing general
> > transformation stuff like above you never have to work with 4-tuples
> > or homogenous coordinates, more or less supporting your original
> > proposal :) I just looked at the RenderMan specification, as existing
> > references might provide some insights. The spec defines different
> > data types for points, vectors and normals, all being simple float[3]
> > arrays. So the type of a value defines the interpretation of the
> > value. Interestingly, there's also a "float RtHPoint[4]", which
> > probably represents a value in homogenous coordinates, but it's used
> > nowhere in the API :)
> >
> > I guess the bottom line is whether exposing the 4-tuple Blender vector
> > internals has any use when writing Python scripts. On the one hand
> > having access to the real underlying data provides great power. But in
> > the current Python API there are no high-level methods available and
> > users need to use low-level matrix-vector multiplications that forces
> > them to having to understand what they're doing. Perhaps adding a
> > higher-level API like something above is a good way forward, while
> > leaving the low-level stuff in place....
> >
> > Regards,
> > Paul
> >
> matrix object you could have a "transformation" object that abstracts
> away the linear algebra (actually, implements the concept of linear
> transformation, that is easier to grasp than the nitty gritty details
> of matrix representation and change of coordinates) and just does what
> the user tells it to, an API idea:
>
> Method chaining (each function returns a transformation object
> modified by the method)
>
>  T = Transformation.scale(2,2,2).rotate(x=90).translate(1,-4,3)
>
> Callable, having different types for points, vectors and normals a
> transform operation could be just:
>
>  for v in model.vertices:
>      new_position = T(v.position)
>      new_normal = T(v.normal)
>
> Having a different type for normals would also allow for every
> operation on them to renormalize and prevent mistakes like multiplying
> a normal by zero, but i digress.
>
> The callable protocol could also be used for transformations
> themselves, to combine them:
>
>  T1 = Transformation.rotate(x=54, z=45).scale(y=2)
>  T2 = Transformation.translate(1,2,3)
>  T3 = T1(T2) # The notation even still looks math-y
>  T4 = T2(T1) # Note that the order of operations is important.
>
> If that's not practical, you could use one method per type of operation
> like Paul proposed.
>
> It could also be useful to interact with matrices, for example, to get
> the matrix representation of that linear transformation it could be
> something like T.to_matrix(), maybe a convenience like
> T.to_rotation_matrix() to get a 3x3 and a T.from_matrix(M) to convert
> from a 3x3 or a 4x4 matrix.
>
> Just my two cents, I'd rather see it abstracted away than promoting
> cargo cult linear algebra.
>
> > _______________________________________________
> > Bf-committers mailing list
> > Bf-committers at blender.org
> > http://lists.blender.org/mailman/listinfo/bf-committers
>
> _______________________________________________
> Bf-committers mailing list
> Bf-committers at blender.org
> http://lists.blender.org/mailman/listinfo/bf-committers
>