particleSamplerInfo smoke

david | mentalray | Monday, July 21st, 2008

In the past few years I have often been asked to create smoke for a variety of different visual effects. There are many ways to do it in maya using particles or fluids so I choose one that suits the job. Last week I needed to use particles and that led me to an interesting discovery - how to use the particleSamplerInfo node.

I had seen it before, in the hypershade Create menu, but I'd never tried to use it. But then I stumbled upon this archived post on cgtalk where Anders Egleus said

I've recently tested rendering particle clouds in mentalray instead of maya software and I'm very happy with how mentalray shades and motion blurs particle clouds.
It seems that turning on the local attribute in the 3d texture doesn't seem to have any effect when rendering with mental ray. No matter how I try, the particles seem to "swim" through the texture.

For years I've been rendering particle clouds (with the software renderer) and I didn't realise that I could turn on the local attribute in the effects tab of the texture node to stop the particles swimming through the texture. I've always done things like animating the place3dTexture node or the texture's time attribute to try and hide it, but was never totally satisfied with the results.

These days I use mentalray for most things and I also like the way it shaders particle clouds, so I wanted to fully understand the rest of Anders' post. Read on to see where it got me. (I'm very happy with the result).

I'll limit my explanation to one specific example and I'm going to assume you know a little about using particles in maya.


Anders Egleus figured the math behind maya's 3D Texture called Volume Noise. Knowing that math enables us to achieve the same result as what the local flag does when you use the software renderer. This means we can use Volume Noise as the blob map in the Particle Cloud shader, render it with mentalray, and the texture will move and scale with the particles completely negating the swimming effect.

Here is a movie that demonstrates the difference (mp4 h.264 or mov sorenson3)

The smoke on the left obviously swims though the texture, but the one on the right does not.

You can download an example scene file here (maya2008 sp1 .ma)

How to do it:

I started by creating a directional emitter which has an animated z rotation thanks to this expression

emitter1.rotateZ = 20*noise(frame/10);

The Particle Render Type is Cloud. Lifespan Mode is lifespanPP only.

I created a new Particle Cloud shader (Hypershade, Create Maya Nodes, Volumetric, Particle Cloud) and assigned it to the particles. I created a Volume Noise texture (Hypershade, Create Maya Nodes, 3D Textures, Volume Noise) and deleted the place3dTexture which is not needed in this example. Then I connected the outColor of the volumeNoise to the blobMap of the particleCloud.

Ok, now for the complicated part.

The particleSamplerInfo node does for particles what the more widely known samplerInfo node does for surfaces. It lets us extract data from the particles that we can use to control parts of our shader network. In this example I want to use each particle's position and radius to control what part of the volumeNoise texture is used and what the frequency should be.

Unfortunately not all the particleSamplerInfo outputs work in mentalray, so we need to use Anders' trick to get the data we need. We can use the expression editor to redirect the data we want to one of the supported outputs. In this example I will reroute the particle position (x,y,z) to the rgbPP, and the radiusPP will be sent out via the incandescencePP. (Wierd way of working, but it gets the job done!)

So particleShape needs these attributes to be added: radiusPP, incandescencePP, rgbPP.

The math that Anders figured out is this

origin = -1 * position * frequency / (scale * 16)

Using the particle position with this formula to set the volumeNoise origin attribute makes the texture follow and scale with the particle.

But I don't want every particle to get the same part of the texture, so I added a per particle offset to the equation. To implement this I had to add a custom particleShape attribute - a per particle vector called originOffset.

To make the scale of the volumeNoise follow the size of the particle we use

frequency = 1/radiusPP

But we also want to be able to control the overall frequency and animation speed so I added two extra attributes to the volumeNoise called frequencyMult and timeSpeed.

Hooking it all together.

First I wrote a creation expression for the particleShape.

// originOffset is a custom per-particle vector attribute
// that we use to store a random position offset
particleShape1.originOffset = sphrand(1);

// creation radiusPP
particleShape1.radiusPP = rand(0.1,0.3);

// lifespanPP
particleShape1.lifespanPP = rand(1,3);

// particleSamplerInfo:
//     use outIncandescencePP.r to output 1/radiusPP
particleShape1.incandescencePP = <<1/particleShape1.radiusPP,0,0>>;

// particleSamplerInfo:
//     use outColor to output position (including originOffset adjusted for radiusPP)
particleShape1.rgbPP = particleShape1.position + (particleShape1.originOffset * particleShape1.radiusPP);

And then a runtime expression


// increase radiusPP
particleShape1.radiusPP = 1.03 * particleShape1.radiusPP;

// particleSamplerInfo:
//     use outIncandescencePP.r to output 1/radiusPP
particleShape1.incandescencePP = <<1/particleShape1.radiusPP,0,0>>;

// particleSamplerInfo:
//     use outColor to output position (including originOffset adjusted for radiusPP)
particleShape1.rgbPP = particleShape1.position + (particleShape1.originOffset * particleShape1.radiusPP);

In the creation expression I set the radiusPP to be within a random range, and then in the runtime expression I added a multiplier of 1.03 to make the radius grow as the particle get older. My aim is to keep the particles overlapping as they move apart. Here's some pictures to show what I mean - first with constant radiusPP


and then with the 1.03 growth factor applied


This way the smoke will look like it is expanding to fill the volume, rather than just separating into little puffs.

The comments in the expressions indicate what each line is there for, so I will leave it at that. The expression sets the particleSamplerInfo.outColor to be the particle position (with a random offset for each particle) and the particleSamplerInfo.outIncandescence will be set to the inverse of the radiusPP (I use just the red component). These are the outputs that we hook up to the volumeNoise, but to achieve the correct math we also need a network of multiplyDivide nodes.

I renamed each multiplyDivide node to indicate its function because even though the math is quite straight forward, it gets confusing when you try to keep track of all the nodes. Notice that one of these simply multiplies the particleSamplerInfo.outColor by -1/16 which is -0.0625, but attributes are displayed with only three decimal places so it looks like -0.063. As long as you type in the correct number it will still work properly.

Here is a diagram with connection details overlaid which shows the shader network I created. Click the picture to see a full size version in a new window.


I used the connection editor to make all the connections and now the texture will stick to each particle.

Next I wanted to have the particle become more transparent as it gets older, so that it will be invisible by the end of its life. You can do this easily by connecting a ramp to the transparency of the particleCloud. Maya will automatically hook up a new particleSamplerInfo to the ramp's uv coords, but I decided to use the one I already had and hooked it up manually as shown here.


Here are screen shots of the attributes I used to render the example movie.




The look of the particleCloud can be varied considerably by playing with combinations of attributes. Experimentation is required to really see how everything works together.


Each particle's radius will determine the volumeNoise frequency. Its position and offset will determin the volumeNoise origin. And it's age will determine the volumeNoise time, so the noise will evolve with the particle's life. There are two extra attributes on the volumeNoise which can be used to set a multiplier for the noise frequency and for the noise time. As a result the volume noise moves with the particles.


volumeNoise has several Noise Types but not all of them obey Anders' formula. These do: wispy, perlin, spaceTime. These don't: billow, volumeWave - although its not really a problem in practice. If you use billow, then the texture will not move exactly in sync with the particles, but it will still move and evolve and any texture swimming will probably not be noticeable.

While I'm on this subject, I think it is appropriate to link to Peter Shipkov's Over Burn (formely known as After Burn). He has taken an idea similar to this, but to a whole new level of complexity using maya fluids.

You can download an example scene file here (maya2008 sp1 .ma)


  1. cool stuff, thanks for sharing.

    on an unrelated note, how are you creating those hypershade snapshots with the connection overlays? maya trickery, or doing what I do and snapshotting each connection then comping in photoshop?

    Comment by matt — July 23, 2008 @ 7:24 pm

  2. Hi matt. The hypershade snapshots are composited in photoshop as you suspected. I wish there was an easier way though.

    Comment by david — July 23, 2008 @ 11:29 pm

  3. Hi dj, thanks for this great article.
    I've got a little problem, when i try to get in the mr render settings there is an error:
    ___ // Error: Cannot use data of type no type in a scalar operation. //
    And aftwerwards i cant see the rendersettings in the Rendersetting UI neither for Mental Ray nor for Maya software or hardware.
    can you help me on this?

    Comment by mmayrhoferr — September 27, 2008 @ 2:53 am

  4. Thanks martin. I appreciate your comment.
    I've seen that error a few times (before upgrading to maya 2008).
    Have you seen this cgtalk thread?

    Comment by david — September 27, 2008 @ 10:47 pm

  5. You are my hero :). Should have searched for myself, sry.
    Now its working fine again.
    have a nice day

    Comment by mmayrhoferr — September 27, 2008 @ 11:47 pm

  6. i have question!
    i serching solution about sprite particle with mental-ray render.
    this post about cloudshape connect fluidshape.

    in my case sprite particle opacityPP(or rgbPP) not working in mental-ray!

    how can i make sprite particle opacityPP in mental-ray?

    i really want to know!!

    here is my ORIGINAL MOV

    thx you and sorry about my english

    Comment by Noah — February 5, 2009 @ 7:48 pm

  7. Hey David!

    Im currently trying to some smoke and render it with mental ray. So with a quick google search I found your blog and this post. Awesome! Will definitely follow it :)

    Now to my question. I managed to follow this guide all the way up to where Im about to connect the "volumeNoise1.timeSpeed" -> "mulTimeByTimeSpeed.input2X", the timeSpeed attribute isnt in the list! But when I open up your file is sure is there. I've only used Maya for 6 or so months and could really use some enlightenment on why its not there..
    Im using Maya 2011 by the way!

    Cheers on a great blog!

    Comment by Johan — January 21, 2011 @ 8:45 pm

  8. Hi Johan. I'm glad you found something useful in my blog. The attribute "timeSpeed" does not exist by default. I created "timeSpeed" and "frequencyMult" as extra attributes that I could use to control other parts of the shader network (a bit like adding variables to an expression). I often do this so that all the attributes that I want to be able to tweak are in one place.

    I mentioned it very briefly in the line before the section titled "Hooking it all together". I can see how you might have missed that, especially if you have only been using maya for a short while. You can add extra attributes using the attribute editor in the menu "Attributes|Add Attributes..." and in this case they are both floats.

    I have not tried the example scene in 2011. Let me know if you cant get it to work and I'll take a look.

    Comment by david — January 23, 2011 @ 5:11 pm

  9. Hi and thanks for the fast reply!

    I see now that you mention it just before that section :D Missed it completely, or maybe I didnt understand that I should do it then :) Now I might be able to do some smoke for my airplane crash :) Going to comp it in live footage for a school project so we needed the particles to render with mr for the fg-pass :) Cheers for a great tutorial! Will be sure to follow your future posts and dig around in the old ones!:)

    Comment by Johan — January 23, 2011 @ 11:10 pm

RSS feed for comments on this post.

Leave a comment

You must be logged in to post a comment.

Powered by WordPress | Based on a theme by Roy Tanck