Packed Geometry and Transformation Matrix on individual elem

   7496   7   4
User Avatar
Member
46 posts
Joined: Oct. 2019
Offline
Hi,
I am trying to rotate packed geometry individually. But can find a way to make it.
I have geometries (the flags) that I first copy and orient to a cube. Then I want to randomly rotate the flag individually around their “mat” axis.

I was able to get a transform matrice for each prim of the cube but then I am stuck.
Not sure if I should transform the matrice before or after the copyToPoints Node, plus I can't find a way to rotate the flags individually around their “mat”.

Any help will be very appreciated thanks.

//get X Y Z Vector per prim


int primpts[] = primpoints(0,@primnum);

//get prim edge
int edgeA = primhedge(0, @primnum);
int edgeB = hedge_next(0, edgeA);

//get prim edge points id
int edgeA_p1 = hedge_srcpoint(0, edgeA);
int edgeA_p2 = hedge_dstpoint(0, edgeA);
int edgeB_p1 = hedge_srcpoint(0, edgeB);
int edgeB_p2 = hedge_dstpoint(0, edgeB);

//get prim edge points poistion
vector a1 = point(0, "P", edgeA_p1);
vector a2 = point(0, "P", edgeA_p2);
vector b1 = point(0, "P", edgeB_p1);
vector b2 = point(0, "P", edgeB_p2);

vector x = normalize(a2-a1);
vector t = normalize(b2-b1);
vector y = cross(x, t);
vector z = cross(x, y);

v@vX = x;
v@vY = y;
v@vZ = z;

/*
vector center = getbbox_center(0);

matrix m = set(x,y,z, center);
setcomp(m, 0, 0, 3);
setcomp(m, 0, 1, 3);
setcomp(m, 0, 2, 3);

4@xform = m;
*/

v@N = set(v@vZ[0], v@vZ[1], v@vZ[2]);

float t = chf("t");

// matrix to transform by
matrix tf = ident();
rotate(tf, radians(t), {0,1,0});
//rotate(tf, radians(t), @N);


// prim existing matrice
matrix transform = getpackedtransform(0, @primnum);
setpackedtransform(0, @primnum, transform * tf);

Attachments:
200604_packprimitive matrix transformation.hiplc (211.3 KB)
200604_packprimitive matrix transformation_001.PNG (671.1 KB)

User Avatar
Member
405 posts
Joined: April 2017
Offline
Here, try this file.

Basically you were trying to rotate around a world axis, but you need to transform that axis into the local space of each packed transform in order to get a local rotation. For example, if you want to rotate something around local Z, you have to take world Z and multiply it by the packed transform before you then rotate the transform matrix around that new local Z axis.

The other problem is that getpackedtransform() and setpackedtransform() are meant to work with 4x4 transform matrices, which includes the position of your flags. If you rotate those matrices without first translating each matrix to the origin, you will effectively be rotating each flag around the world origin. If you're just trying to change rotation or scale without changing the position of each copy, it's easier to use primintrinsic() and setprimintrinsic() to fetch the “transform” intrinsic, which is a 3x3 and will not affect position.
Edited by toadstorm - June 5, 2020 15:06:58

Attachments:
200604_packprimitive matrix transformation_toadstorm.hiplc (210.3 KB)

MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
46 posts
Joined: Oct. 2019
Offline
Great. Thanks!
User Avatar
Member
46 posts
Joined: Oct. 2019
Offline
It sounds clear when it comes to rotation with local axis. However now i am trying to scale and translate the flags as I would like them to have various size keeping their base stick to the box.

I understand that matrix3 type is only for rotation and scale. So I transformed the 3x3 matrix to 4x4 then applied scale and rotate to finaly set it back using setprimintrinsic. But no transformation happens.

After checking my prim intrinsic I can see that the transform matrix is still 3x3.
I am very confused with transformation matrix and althought there are some interresting tutorial I still struggle a lot.
Should I use a 4x4 matrix at first instead of a 3x3 that later transform to 4x4?
Any help will be very appreciated.

Thanks in advance.

// we can't rotate locally around a world axis, we need to rotate around a local axis. 
// the "spin" axis for this flag is Z if you look at the original instance.
// to find local Z, we can multiply world Z by our transform matrix.

// we don't want to affect @P, so rather than using getpackedtransform and setpackedtransform,
// we'll use primintrinsic() and setprimintrinsic() to set the "transform" intrinsic, which
// does not modify @P.

matrix3 transform = primintrinsic(0, "transform", @ptnum);
vector axis = transform * {0,0,1};


// the rotate VEX function applies to matrix3 transform "in-place" (that's what the "&" means in the documentation)
rotate(transform, radians(i@randRot), axis);
// now set the packed transform intrinsic to this transform we rotated
//setprimintrinsic(0, "transform", @ptnum, transform, "set");

vector vScale = {0.5, 0.5,0.5};
vector vTrans = {0,0,-0.25};

matrix transform2 = set(transform);
scale(transform2, vScale);
translate(transform2, vTrans);

setprimintrinsic(0, "transform", @ptnum, transform2, "set");
User Avatar
Member
405 posts
Joined: April 2017
Offline
If you want the base to stick to the box while still having various different scales and rotations, then you're not editing the position, and you should still be using a 3x3 matrix.

There's two ways you can approach this. You can either set template point attributes before the Copy SOP and forget about all this primitive intrinsic business, or you can continue with the method that you're using now, though it will get a little bit more complicated now that you're scaling as well. This is because the scaling operation also needs to happen in the local space of each copy. With template point attributes, this is done for you… just define an orientation (using p@orient or v@N and v@up) and a v@scale or f@pscale attribute and Copy handles the rest.

I'm attaching a file that compares both approaches. There's unfortunately still a bit of math involved no matter what… with the template point attribute approach, you have to first compute an up vector from your N vector in the same general way that the Copy SOP does internally if up is missing (the VEX dihedral() function) and then rotate this vector randomly around your N vector to get your final up.

The easy way out is to use MOPs Transform or MOPs Randomize to handle these transformations for you, though it's a good idea to learn how this math works either way.

Attachments:
transform_comparison_toadstorm.hiplc (175.7 KB)

MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
46 posts
Joined: Oct. 2019
Offline
Thanks! Really appreciated your detailed explanation. It helped a lot.
User Avatar
Member
281 posts
Joined: Sept. 2012
Offline
I did that one a while ago, but in VEX , was giving another try with Kinefx, and cluster piece from a split instead of polygons, use a base of your method, now how block to transfer the rotation of the packed pieces?
Im a method to unfold from moritz.. Maybe I should not packed ? BEfore I used another squeleton, it was worse, now looks like only the rotation need to be corrected at least to get a base... See

Image Not Found

Attachments:
unfold.jpg (152.7 KB)

Vincent Thomas   (VFX and Art since 1998)
Senior Env and Lighting  artist & Houdini generalist & Creative Concepts
http://fr.linkedin.com/in/vincentthomas [fr.linkedin.com]
User Avatar
Member
281 posts
Joined: Sept. 2012
Offline
What i did before in vex

Attachments:
unfoldgems_test_houdini_vincentsm4.gif.gif (15.0 MB)

Vincent Thomas   (VFX and Art since 1998)
Senior Env and Lighting  artist & Houdini generalist & Creative Concepts
http://fr.linkedin.com/in/vincentthomas [fr.linkedin.com]
  • Quick Links