In Cycles, I'd like to create a misty torus. Create torus, Volume Scatter note into the Volume Material Output node. Done.

But I'd like to be able to adjust the density of the scatter with respect to surface proximity. So the closer the scatter effect gets to the surface of the object, the more transparent or "less dense' it becomes.

Any suggestions? I'd like this to be material-specific. I could do this in the compositor, but blurring introduces other problems.

  • $\begingroup$ Im thinking you start with a cube, then add a gradient texture node in combination with the volumetrics so it starts dense on one side, then clear on the other. Then subdivide the cube and use a deform modifier to bend it into a cylinder, then use another modifier to bend the cylinder into a torus. $\endgroup$ – eromod Jan 1 '17 at 22:45

An alternative solution to the 'pure' mathematical solution (https://blender.stackexchange.com/a/70340/29586) is to use the Point Density texture node to convert a circular mesh into a density as follows (using a mesh created from a BezierCircle) :

circular point cloud

The Multiply and Power nodes can again be used to manipulate the scale and fuzziness of the generated torus.

This has the added advantage that you can manipulate the source mesh as desired :

distorted torus

Note, this method may be less efficient than the pure mathematical approach described in the previous answer due to the use of the Point Density node. It will also be dependent on the number of vertices in the source mesh and the resolution of the Point Density (lower values will produce less accurate results). However, it is more versatile since the source mesh can be easily manipulated.

Blend file attached.

  • $\begingroup$ OMFG! Depending on render times, this might do the trick too, but again, this is black magic beyond mere mortal ken. Cheers Rich! $\endgroup$ – OroNZ Jan 3 '17 at 4:19
  • $\begingroup$ :-) Glad to help. Render performance shouldn't be bad providing you don't go too mad with the number of vertices. This method would be preferble to the pure maths solution simply because it gives you much more control to manipulate the shape. Also, keep the 'domain' mesh as small as you can without clipping the volumetrics - any rays passing through the volumetric material will have a high cost - and don't forget to 'apply scale' if you resize it. Play around with the Multiply and Power values - or replace the Power node with a Color Ramp if you prefer to vary it that way. $\endgroup$ – Rich Sedman Jan 3 '17 at 12:03

There seems to be an error in my calculations. I think I will manage to review them later.

As Ibalazscs pointed out, you can control volume with the existing math nodes and procedural textures.

I will setup a mathematic procedural torus to use as density. This will not be affected by the geometry, sadly, but will work as a substitute solution.

enter image description here

To control the density of a volume, we can connect a texture or other value node to the density input of the Volume Scatter Node.

enter image description here

Starting with a two dimensional equation, let's control the volume of a cylinder with a colorramp or RGBcurve.

enter image description here

Here is the relatively simple mathematical basis. We need the equation of a circle.

x**2 + y**2 = radius**2
radius = (x**2 + y**2)**0.5

enter image description here

This will result in values from 0 to 1, starting from the center of the XY circle to any point on the circle.

Translated into a node setup, we have to use the Converter>Math nodes.

enter image description here

Connect the last node to a colorramp and we can see the effect on a 3D object in material or rendered mode.

enter image description here

The complete node setup looks like this.

enter image description here

I use a multiply node before the RGB curves to "scale" the circle. The RGB curves modify the density from the center of the circle to the rim. I have set them to the various examples in the beginning. The multiply node after the RGB curves raise the upper density limit. Close to zero (transparent) values will stay relatively unaffected, values close to 1 or higher will become more dense.
The position attribute of the Geometry node holds the XYZ coordinates. The separate RGB node extracts the three channels.
Important: The position attribute is in world coordinates. Use the Object Info > Location attribute if you move your object.

Creating the torus

  1. Add a cube. This will function as the volume domain of the torus.
  2. Use the existing node tree of the circle calculation nodes.
  3. Add a subtract node to the chain. This will shift the value of zero along circles of different size. We will connect the Major Radius of the torus to the subtrahend. The add an absolute node. We want the values around 0 (our major radius) to fade out towards the center and towards infinity.
    enter image description here

We want to control the density using values from 0 to 1 ranging from the major radius to the (major + minor) radius.
The value of the major radius in XY is currently 0.

enter image description here

  1. We are going to use the circle node setup again with the existing XY circle output and the Z axis. After the last subtract node, paste the circle nodes (pow2, pow2, add, sqare root) and connect the subtract node to the first pow2. Connect the extracted Z value (B output of the separate RGB node) to the second pow2. The result is a circle with a major radius of 1. The values at the major radius are at 0. Values moving away from the major radius range to infinity, the distance from the major radius. We need it the other way around.
  2. Negate the value (multiply with -1), now we have values from 0 to -infinity. Add a value with an add node. The second input of the add node is the minor radius. Clamp this value. We now have a range of 0 to 1 from the outer rim of the torus to the inner circle.
  3. Connect this to the RGB curves.

enter image description here

Make sure your domain object is large enough.
If you want to add a shader to the outer surface, add a torus with correspoing major and minor radius. In my case

  • $\begingroup$ A lot of interesting ideas, altough - so far - the end result does not look as "volumetric" as in Rich's answer, the edges are too visible. But definitely worth an upvote. $\endgroup$ – lbalazscs Jan 3 '17 at 0:51
  • $\begingroup$ I added a surface shader to demonstrate that the volumetric torus is easily recreated as a surface. His answer is better, mine just has some maths. $\endgroup$ – Leander Jan 3 '17 at 1:02
  • $\begingroup$ Oh, I see. I wondered why some intermediate results are better than the final one :) $\endgroup$ – lbalazscs Jan 3 '17 at 1:07
  • $\begingroup$ Thanks Leander. A lot of very good node-fu information on this response page. Thanks for helping out! $\endgroup$ – OroNZ Jan 3 '17 at 4:22

Varying the density based on the proximity to the surface of the mesh is tricky - and requires use of complicated OSL shaders to probe out the nearby surface of the mesh. A much simpler method is to generate the torus mathematically as a procedural volumetric material. This means that we can more easily vary how the density of the torus varies as it moves away from the center.

Firstly, we need to create a volumetric material that varies based on distance. This can be achieved with the following material :

Fuzzy single point material

This takes the 'object' coordinates and feeds this into both sockets of a Dot Product vector math node. The Dot Product returns a scalar value based on the magnitudes and relative directions of the input vectors. By using the same vector for both inputs the node returns a value based purely on the distance of the vector (actually distance squared) - this returns a value base on the distance from (0,0,0) - ie, the distance from the center of the mesh. This is passed through a Multiply node to allow the final result to be scaled, subtracted from 1 (clamped) so the result varies from 1 at the center to 0 at its edge, passed through a Power node to allow the falloff to be varied (to make it either more sharp or more fuzzy) and, finally, a Mulltiply node to allow it to be made overall more or less dense. This is then used as the Density of both a Scatter and an Absorption shader node - which are then combined for the final material output.

By creating a mesh (eg, a cube) to act as a 'domain' for the material and varying the Multiply and Power nodes, this can produce an effect similar to the following :

single blurry point rendered

Small 'Power' (eg, 0.1) will produce a very sharp edge to the sphere while large values (eg, 10) will produce a more fuzzy edge. Reducing the first Multiply will increase the sphere's size while increasing it reduces its size.

To turn this into a Torus, we simply need to add some nodes to position the reference point (in the above case, this was the Origin) at various points along a circle - in particular, at the closest point along the circular path. The size of the circle will then dictate the size of the torus and the above Multiply and Power nodes will determine its fuzziness and thickness.

This can be achieved as shown below :

torus material

The center of the circle is at the Origin (0,0,0). The orientation of the circle is determined by a Normal vector - in the same way as for the Normal of a surface. Varying the Normal will change the orientation of the torus. The radius of the circle is controlled via an input Value (Radius).

The Cross Product vector math node is used to determine the direction of the closest point of the circle. The Cross Product always returns a vector which is perpendicular to both of the input vectors. By passing in the Normal to the first Cross Product, this will produce a vector that is along the plane of the circle - but at 90 degrees to the direction of the point being sampled. The second Cross Product takes that vector and produces one at -90 degrees to that - this will be along the plane of the circle and in the direction of the point being sampled (which will be the point on the circle that is closest to the point being sampled). This vector is Normalized (so it's magnitude is '1') and then multiplied by the desired Radius. The result of this can then be used to find the actual reference point on the circle that can be measured against the sample point to determine how close that point is to the circle.

We then have the Multiply and Power nodes used to control the falloff of the edge of the torus as in the previous example (but fed from Value nodes and given appropriate names).

This can then produce the following result :

enter image description here

Blend file attached.

  • $\begingroup$ You actually took the time to do the math! Cool! $\endgroup$ – lbalazscs Jan 3 '17 at 0:47
  • $\begingroup$ Holy Brainmelt, Batman! I'm glad I asked first - there's no way in hell I could've worked all that out. hanks Rich, that'll probably work for me :) $\endgroup$ – OroNZ Jan 3 '17 at 4:18

An absorption volume shader is automatically darker around the thicker areas, maybe all you need is to use it instead of scatter, like here: Volumetric gradient based on density?

To be physically correct, you need both of them, mixed with an Add Shader. If you really want to control the scatter density, then continue reading...

If a (slightly random) cloud-like appearance is OK, then see this question: Is there an easy way to make volumetric clouds for Cycles? (you would start with a torus instead of a cube)

If you need precision, you can start with this one: Controlling volume density

Here (in the second example) the density is based on the X location. Now for a torus, the math becomes somewhat more complicated: the density depends on the distance from the center, and on the Z location. I trust you that you can figure out the details :)

EDIT Just for fun, here are three torus-clouds (of type stratus, cirrus and cumulous) created with the cloud generator addon:

enter image description here

The cloud generator uses a particle system internally to set up the point density, so theoretically its source code could be modified so that the points are less randomly positioned.

  • $\begingroup$ @Ibalazcs: Thanks, but these suggestions address overall density variation, but not density with respect to proximity to geometry. A cloud sim is possibly the closest, but to configure and render the way I want it'll cost days for me to render. The paradox I have is I want an object to contain a 'mist', but I don't want the mist to get close to the geometry defining the mist container's shape. I want a far softer 'edge' to the mist (actually, NO edge), without having to blur it in the compositor. $\endgroup$ – OroNZ Jan 2 '17 at 3:50
  • $\begingroup$ Following the last suggestion you can control precisely the density with respect to proximity to geometry - you just have to set up the overall density variation so that it corresponds to the geometry. I didn't say it's easy... $\endgroup$ – lbalazscs Jan 2 '17 at 9:39
  • $\begingroup$ Alternatively you can create a script that places vertices inside for a point density texture - similar to the cloud add-on, but then you have more control. Or add a particle emitter inside for particle-based point density, and set up the lifetime so that some particles die immediately, and all of them die before reaching the surface. $\endgroup$ – lbalazscs Jan 2 '17 at 9:42
  • $\begingroup$ The last solution just replaces problems. You're asking me to swap out something I have trouble doing (advanced volumetric calculations) with something else I don't know how to do (scripting) :) Don't get me wrong - I appreciate your time - I'm just stuck. The manual says only the Position and Incoming outs of the Geometry node are workable for volumetrics. So I'm in a corner here. $\endgroup$ – OroNZ Jan 2 '17 at 10:32
  • $\begingroup$ So what about the particle system? $\endgroup$ – lbalazscs Jan 2 '17 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.