Monday, May 12, 2008

texPPattrMapperNode

I made a Maya utility plug-in that maps normal and texture color of meshes to a particle.



This is a node plug-in that takes particle fieldData, ppFieldData,
texture(s), and mesh(es). It then calculates particle velocities,
gets closest intersection point on a mesh, outputs face/vertex normal, texture color, position etc. at the point.

It can search two ways (forward/backward particle moving direction) and can linear interpolate output values depending on the length from the particle to the hit points on the mesh.

In the above movie, The planes are meshes and the yellow lines are vertex normals. I mapped texture color to the particle color, and mesh vertex normal to particle normal.

























Another example.


These are the attribute descriptions.
























Long name (short name)
Type
Default
Description
getDirection (gd) enum
"fixed direction"
Valid values are "fixed direction", "velocity", "cameraCenter". If this is "fixed", it uses "direction" attribute to determine forward direction. If "velocity" it particle velocity is regarded as forward direction, and if "cameraCenter", its forward direction is radial to the position given by the camera center attribute.
cameraMatrix
matrix

Center point that is used to calculate each pariticle's forward direction. It is designed to connect camera transform's worldMatrix but any matrix attribute can be connected. This value is ignored when getDirection is not "cameraCenter".
direction (dir) double3
(1.0, 0.0, 0.0)
Fixed direction value. Used only if getDirection is "fixed". Per particle field attribute sensitive.
asearchRadiusF
float
1.0E8
Forward search radius to detect intersection. Any hits beyond this distance will not be considered.
asearchRadiusB
float1.0E8Backward search radius to detect intersection. Any hits beyond this distance will not be considered.
searchCol (sc) enum
"both"
Direction to execute mesh hit test for color. Valid values are "both", "forward", "backward". If "both" is set, it interpolates "forward" and "backward" values.
searchNorm (sn) enum
"both"
Direction to execute mesh hit test for normal. Valid values are "both", "forward", "backward". If "both" is set, it interpolates "forward" and "backward" values.
weight (w) double
1.0
Weight value that is multiplied to the output colors. Output normals are not affected. Per particle field attribute sensitive.
offset (o) double 0.0
Offset value that is multiplied to the output colors. Output normals are not affected. Per particle field attribute sensitive.
minValue (min) double 0.0
Min value that is multiplied to the output colors. Output normals are not affected. Per particle field attribute sensitive.
maxValue (max) double 1.0
Max value that is multiplied to the output colors. Output normals are not affected. Per particle field attribute sensitive.
inMesh (im) mesh
(array)
N/A
Input attribute for mesh geometry. Connect mesh.worldMesh here.
inColor (int) float3 (array)
N/A Input attribute for texture. Connect texture.outColor here. It must be correspondent to inMesh, i.e. the number of element must be the same as inMesh
defaultColor (dc) float3 (0.0, 0.0, 0.0)
Default color value. Used when no hit is found. Per particle field attribute sensitive.
defaultNormal (dn) double3
(0.0, 1.0, 0.0) Default normal value. Used when no hit is found. Per particle field attribute sensitive.
normalType (nt) enum
"vertex normal" The way to calculate normal. Valid values are "vertex normal", "face normal", "average face normal".




inputData (ind) compound
N/A
Input attribute for particle. Connect particle.fieldData here.
inputPPData (ppda) genericArray
N/A Input attribute for particle. Connect particle.ppFieldData here.




hitPointF (hpf) vectorarray
N/A
Forward hit point on mesh.
hitPointB (hpb) vectorarray N/A Backward hit point on mesh.
distanceToMeshF (dtmf) doublearray N/A Length between the particle position and the forward hitpoint, or minus value if no hit is found.
distanceToMeshB (dtmf) doublearray N/A Length between the particle position and the backward hitpoint, or minus value if no hit is found.
hitMeshIdsF (hmif) intarray N/A Array index of the mesh in the input attribute "inMesh" that is in front of the particle.
hitMeshIdsB (hmib) intarray N/A Array index of the mesh in the input attribute "inMesh" that is in back of the particle.
hitPolygonsF (hpgf) intarray N/A Polygon id of the forward mesh the ray hits.
hitPolygonsB (hpgb) intarray N/A Polygon id of the backward mesh the ray hits.




colorF (clf) vectorarray N/A Texture color at the forward hit point. Min, max, offset, weight are not applied.
colorB (clb) vectorarray N/A Texture color at the backward hit point. Min, max, offset, weight are not applied.
normalF (nmf) vectorarray N/A Normal at the forward hit point.
normalB (nmb) vectorarray N/A Normal at the backward hit point.
outColor (oc) vectorarray N/A Output texture color. Min, max, offset, weight are applied and it may be interpolated.
outColorR (ocr) doublearray N/A R component of the outColor. Note that this is not a child attribute of outColor.
outColorG (ocg) doublearray N/A G component of the outColor. Note that this is not a child attribute of outColor.
outColorB (ocb)n doublearray N/A B component of the outColor. Note that this is not a child attribute of outColor.
outColorV (ocv) doublearray N/A V component of the outColor in HSV color space. Note that this is not a child attribute of outColor.
outNormal (on) vectorarray N/A Output normal value. Always a unit vector.
outNormalX (onx) doublearray N/A X component of outNormal.
outNormalY (ony) doublearray N/A Y component of outNormal.
outNormalZ (onz) doublearray N/A Z component of outNormal.

Here a per particle field attribute sensitive attribute is an attribute you can customize the value just like you can do it for a field node attribute, i.e. you can create a per particle attribute which name is (texPPattrMapperNode)_(attribute name) and set per particle value for the attribute to customize the value.


... another example


... and two more examples
You can control particle movement with mesh face normals. (you can also use vertex normals)


10 comments:

mihai said...

this one is pretty awesome... i like the 2nd example where you probably set lifespanPP or opacityPP based on the texture?

Koichi Tamura said...

thanks, yeah i set lifespanPP.
The expression I used is like this.
if (texPPattrMapperNode1.distanceToMeshF > 0)
{
particleShape2.lifespanPP = (texPPattrMapperNode1.outColorV > 0.5)? 1000 : 0;
}

mihai said...

thank you for the expressions.

also i'm curious: it seems it is not a field: how did you connect the outputs of your node to the particle's pp attrs? or what kind of connections are you making?

Koichi Tamura said...

it's just a plain MPxNode. to connect the result of my node to pp attrs, i had to use an expression. above expression makes the two nodes get connected. Because the number and index of the output array attributes of the plugin node are exactly the same as those in the particle array attrs, you can use the result in an pp expression.

mihai said...

uuum...

you mean that if you say

particleShape.attrPP = texPPattrMapperNode1.outColorV

then this is executes for every index of the 2 atrributes?:

particleShape.attrPP for pid 0 = texPPattrMapperNode1.outColorV[0]


particleShape.attrPP for pid 1 = texPPattrMapperNode1.outColorV[1]

...

??

Koichi Tamura said...

Exactly!

When Maya executes pp expression for perticle i (index in array attributes, not particle id),

Maya takes

particleShape.attrPP = texPPattrMapperNode1.outColorV

as

particleShape.attrPP[i] = texPPattrMapperNode1.outColorV[i]

Internally (hidden to the user) Maya may be doing some optimization when executing pp expression by executing one assinment for multiple particles (i.e. array elements) at a time to use CPU's L2 cache effectively, so if there's two assignment in one pp expression,

particleShape.attrPP_a = texPPattrMapperNode1.attrPP_x;
particleShape.attrPP_b = texPPattrMapperNode1.attrPP_y;

Maya may be executing

particleShape.attrPP_a[0] = texPPattrMapperNode1.attrPP_x[0];
particleShape.attrPP_a[1] = texPPattrMapperNode1.attrPP_x[1];
...
particleShape.attrPP_b[0] = texPPattrMapperNode1.attrPP_y[0];
particleShape.attrPP_b[1] = texPPattrMapperNode1.attrPP_y[1];
...

instead of executing assignments in this order

particleShape.attrPP_a[0] = texPPattrMapperNode1.attrPP_x[0];
particleShape.attrPP_b[0] = texPPattrMapperNode1.attrPP_y[0];
particleShape.attrPP_a[1] = texPPattrMapperNode1.attrPP_x[1];
particleShape.attrPP_b[1] = texPPattrMapperNode1.attrPP_y[1];
...

but I doubt it.

mihai said...

ah wow! i didn't know this trick! thank you very very much!
very useful for me! :)

how did you figure this one out? (that attrPP[i] = yourOutAttr[i])

what kind of tests did you make to figure that one out?

Koichi Tamura said...

I didn't do any test. I can't remember what made me think so but since I got the idea everyting has been fine with the idea.

Value in the nth index of every array attr needs to be the one for the same particle (ie index i should be the value for particle id i', for all the array attrs), otherwise Maya would need another array attrs that maps ids to indices.

If so,
particleShape.attrPP = texPPattrMapperNode1.outColorV
can be taken as
particleShape.attrPP[i] = texPPattrMapperNode1.outColorV[i]

And in Maya there's no connection to send id-index mapping information around particle. I think that's what made me think so.

mihai said...

great job! :)
if you post the plugin and/or source here on the blog i'd love to take a look at it :D

keep up the good work!

Koichi Tamura said...

Thank you :)
I'll send you the source via email.