I tried doing a mix between YDP’s solution and the vector2rot script mentioned by Derek Wolfe.
Occasionally I was getting some very abrupt changes in aim direction when using the closestPointOnMesh node, especially on a deforming mesh.
So I tried comparing results with the nearestPointOnMesh command, and using the same input position here’s what I got, :
normal from closestPointOnMesh
// Result: -0.323307 0.709912 -0.625698 //
normal from nearestPointOnMesh
// Result: -0.33909 0.776836 -0.530607 //
Odd!
Anyway, using the command nearestPointOnMesh (remember to first load the plugin nearestPointOnMesh.mll) here’s a way to align particle instances to surface normals and having a random rotation around the alignment axis. In this case I’m aligning the instances X-axis, so the original instance object should be pointing along the X-axis on the grid (with transforms frozen) for this to look right.
add two custom per particle attr’s:
rotationPP (vector)
randomRotationX (float)
in the instancer section of the particleShape tab, go to Rotation Options and set Rotation to be rotationPP.
Creation expression:
// random start position
particleShape1.goalU = rand(0.1,0.9);
particleShape1.goalV = rand(0.1,0.9);
//random rotation for X axis
particleShape1.randomRotationX = rand(180);
Runtime expression:
// define a variable with the particle position
vector $p = particleShape1.position;
// get surface normal at particle position
vector $normal = `nearestPointOnMesh -ip ($p.x) ($p.y) ($p.z) -normal -q pPlane1`;
// define worldUp
vector $worldUp = <<0,1,0>>;
// calculate normalized directions by which to align the y and z axis of the instance object
vector $directionOfZaxis = unit(cross( $normal, $worldUp ));
vector $directionOfYaxis = unit(cross( $directionOfZaxis, $normal ));
// solve each angle, result in degrees
float $rotZ = rad_to_deg(( atan2( ($normal.y), ($normal.x) ) ));
float $rotY = rad_to_deg(( asin( -($normal.z) ) ));
// feed result into the rotationPP attribute
particleShape1.rotationPP = << particleShape1.randomRotationX, $rotY, $rotZ >>;
Optionally you can add the runtime expressions in the creation too.
Also, notice the “pPlane1”, which should be corrected to match the name your poly object.