A reusable apple material in Blender 2.79b

Introduction

The Facebook group Blender Procedural Textures holds biweekly contest to construct procedural textures. A recent challenge was

You will try to come as close as possible to an apple, BUT I would like the nodes to be structured, grouped and user friendly, so that you can dynamically change your apple to green or red, mix colors or decide how many lines and spots the peel should have. In short… a perfect “apple peel material” that you can set in the hand of a non node expert user and they should be able to use it .

My entry renders as

apples

A render of two apples created with the same apple node group.

This is a brief discussion of how I created the materials. I created this with Blender 2.79b.  It should work for any version of Blender that has the node groups I used. It can be improved in later versions of Blender by using microdisplacement.

Preliminaries

What color is an apple?

The first rule of creating objects or materials for 3D rendering is to look at examples. The US Apple Association has a nice collection of large images of apple types and a Google search will turn up many images as well, although it will also turn up a lot of copies of Apple’s logo.

It appears to me that an apple peel may have

  • A basic color
  • Variations on that color
  • Vertical blemishes
  • small dots

There are other aspects as well, but providing these four things will produce a pretty good apple (material).

Modeling an apple.

I am taking Stephen Wood’s Complete 3D Artist course on Udemy. In one lesson, he creates an apple.  Using that technique, I created an apple for the contest. It’s simply a modified sphere, sculpted to have the form of an apple, with a stem extending from the top.

apple

apple

You can search YouTube and discover Apple How-To Tutorials

Lighting

Changing the lighting in a scene will change the way materials in scene will appear. Gleb Alexandrov has a nice series of lighting tutorials on YouTube.  You can also look for tutorials on photographic lighting, as the principles are the same.

That said, I decided to be lazy and use an existing lighting set up. I grabbed the Modified_b.m.p.s.ByRobinMarin.blend file and stripped it down to its basic lighting.

Building the material

The contest instructions suggest that the nodes to be structured, grouped and user friendly. I decided to make an apple node group that generated the apple color, but did not include the shader to be used. Here are two examples of using the node group to create a red and green (really yellow) apple material.

A limitation of using a node group like this is that there is no way to control the handles of a color ramp that is embedded in a node group, unless you want to change every material that uses that group. This greatly influences the design of the node group.

Basic skin color

The skin of an apple isn’t a single color, but rather runs a gamut of shades of the same color. An easy way to produce this effect is to use a Musgrave texture to control a mix factor.

Commonly, a color ramp is used to tune the pattern provided by the Musgrave texture. But color ramps won’t work within a node group, so a MixRGB node is used instead.  This provides an acceptable approximation of the basic color.

Dots

A Voronoi texture can be used to produce random dots. A Voronoi texture creates cells. Each cell has an intensity that varies from one at the center to 0 at the edges in a circular pattern. We can use the Voronoi to control the mix.

A simple Voronoi mix

A less than node creates circles from the Voronoi  This works well if you want precise circular dots, but the dots on the apple aren’t that precise.  A workaround is to use a color ramp rather than the less than node.

But we want to control the size of the dots as a parameter of the node group, so a color ramp won’t work. I have a node group that will do this.  It is described in Faking a color ramp in Blender 2.79.

Stripes

There are a few ways to go about adding random stripes. Since these stripes tend to run in a vertical direction, it makes sense to use a noise texture scaled in X and Y as the factor for a mix RGB node.

Putting it all together.

So far I’ve shown each aspect separately.  It’s easy to put them together with mixRGB nodes.

Bumps

Two factors contribute to the bump map.  The skin has an overall bumpiness.  This is easy enough to represent with a noise texture.The dots also contribute additional bumpiness. We need to balance these out, so we multiply the noise texture by a factor before adding it to the bump data from the dots.

The multiply balances the relative strength of the bumps from overall bumpiness and the bumps from the dots. The strength parameter of the bump map controls the overall strength of the bumps.

Making the node group

There are no color ramps in the material, but it does use a vector mapping node.  Vector mapping is another node that doesn’t fit well into node groups, so we perform our own equivalent.  In this case, we only need to scale the vectors, not translate or rotate them. Scaling a vector is accomplished by separating the X, Y, and Z values, multiplying each by its scale factor and recombining them to make a new vector
This is useful enough to make into its own node group

The finished material

Converting to a node group

I like to create a node group in stages.  First I determine a parameters I want to expose. Next I add an input node to hold the value of that parameter. Then I give the input node a label that represents what I think will be a good name for the parameter in the node group. I repeat this until I have all of the parameters.  Then I select the nodes that will make up the node group and make the node group.

There are twenty nine input sockets in the finished material. It would be possible to expose all of them, but the node group would become unintuitive and unwieldy. Here are the choices I made

  • Base colorIn an fBM Musgrave, offset and gain have no value. Because the basic shape using the default detail, dimension and lacunarity are sufficient, controlling only the scale seems sufficient.  Of course, the two colors used by the mix RGB node have to be parameters.
  • Dots the X0, Y0, and Y1 values of the linear equation are specified by the problem design.  Likewise the clamping parameters are specified.  This leaves only the dot size, which is the position of the White pos in the equivalent color ramp, and the scale, which sets the density.
  • StripesThere is no advantage to changing the Z scale, nor is there any real value in setting the X and Y scales to different values. The noise texture default detail and distortion are sufficient, so the only parameter for it is the scale.
  • Bumps The default detail and distortion serve well enough. The multiplier value was explained above.
  • Now we’ve set the input parameters, we choose the output parameters, in this case the final color mix and the height map.  If we leave out all of the input parameters, the bump map, shader, and material output nodes, we can create a node group

Cleaning up the node group

Creating the node group has a couple of problems.

Externally, the parameters don’t have good names or default values. This is resolved by the tedious task of editing each parameter interface slot, setting its name and giving it reasonable defaults. Eventually you end up with a node group with its own name, and with (hopefully) meaningful names for its parameters

Internally,routing can make a spaghetti mess of the node group layout

Everyone has their own way of organizing node groups so that they are readable.  I like to use frames to group functionality, to use reroutes to clarify routing and to use reroute labels to help tracing the routing.

The entire node group

Procedural Archimedean Spirals in Blender – Part 2: Creating a node group

Introduction

In a previous post I developed a material that has a spiral pattern. In this post, I convert that material’s spiral nodes into a node group. The tutorial was prepared using 2.79b but the texture will work in any version of Blender that supports the math node and node groups.

We’ll clean up the material, making it more suitable for creating a node group. We’ll create the node group. We’ll incrementally improve the interface and layout of the group. In the end we’ll have a node group that provides a wide range of control over a spiral texture.

Clean up

Magic Constants

There are math nodes that have constants as one of their arguments. It is not apparent why they have the values they do or if they are related in any way.  Programmers call such numbers magic constants. We finished part 1 with this material.

The new Math nodes as well as the multiply Math node to the left of the top added Math node all have constant values as arguments, as does the the divide Math node below the gradient Texture node. These numbers are related to each other. Changing one without changing the others will break the spiral pattern. This addition corrects that.

Now we have a single Value node that is the source of the other constants.

Bad parameter values

If we set the new density parameter to anything that is not an integer value, the spiral will stutter Here is a render with density set to 1.5 Similarly, setting the number of arms to anything but an integer will break the spiral.

We can’t fix this, because Blender has no integer only input value, but we can work around it using the round Math node.

The node ignores its second argument, so we haven’t introduced new magic constants.  Now, any value between N-.5 and N+.5 will be rounded to the integer value N.

Separating Parameters

We can make it easier to see which nodes belong in the texture node group by moving the nodes that act as values away from the nodes that will be part of the node group. Clearly this contains all of the Value nodes. The vector that it uses to calculate should also be a parameter. Moving nodes gives us

What nodes go into the node group?

We’re creating a texture, not a shader, so the Diffuse and Material nodes are clearly not to be included. Everything else that is not a parameter, except the color ramp is required to create the texture.

Do we include the color ramp?  Normally I would not, because there is no way to control a color ramp that is in a node group, except by opening the group and modifying it.  Doing that will modify every material that uses the node group.

In this case, I’ll make an exception. The color ramp has a very specific purpose that’s unlikely to change, and there is a parameter that can be used to tweak it. The node group starts out as

and our material now looks like

This is a good time to give the node group its own unique name.

Merging parameters

Creating a node group this way has the annoying feature that parameters, in this case the Vector and spacing parameters are duplicated.  Merging those gives us

Naming parameters

The node group has several “value” labels for its parameters.  Better names will make it easier to remember what each input does.

Assigning defaults and limits

Each input parameter of a node group has default values and limits. If there are specific values that make sense, use them. Here are those for the spiral node group

Spiral parameters

ParameterDefaultMinimumMaximum
Vectordefault for typeminimum for typemaximum for type
Spacing.50maximum for type
Lower Bound00maximum for type
Upper Bound10maximum for type
Groove Width.50maximum for type
Density10maximum for type
Arms11maximum for type
The default and limit values of the parameters to the spiral node group

The wording “… for type” means that that parameter is set to the value it has by default when you make the input parameter.

The default value for the Vector input is a problem.  Because it is 0, if you don’t connect a Texture Coordinate node output to this input, the node group will not produce a useful result. It would be nice to use the Object output as a default, but doing so is very difficult.

All of the parameters have maximum values of “maximum” for type. This is because there is no easy to describe upper bounds for most of these values.

The default and minimum values for all except the Vector input can be selected in ways that make sense, so they are set.

Rerouting

It’s a bit difficult to figure out where each connecting line goes. There are various ways to make it easier to read a node group and there as many opinions about them as there are node group developers. The one that’s right is the one that makes the group most readable to you. I like the way printed circuit diagrams look so my node groups tend to end up looking like that.

Recently I started adding labels to the reroute nodes, so my final version of the node group looks like this.

Here’s a closeup of part of the reroute

 

Layout

Sticking to a handful of rules about how you lay out node groups in the node editor will make it easier for you to read your own node groups later when you’ve forgotten what they do. Here is a set of rules that work for me.

  • Give the node group a meaningful name.
  • Give the input and output parameters meaningful names.
  • Set the defaults and limits on parameters.
  • Center the node group.
  • Align the nodes into evenly spaced rows and columns.
    • Use the rows to indicate flow through a section of the group.
    • Use the columns to group similar operations.
  • Use frames to visually group sets of nodes that act together to perform a function.  This tutorial describes the function step by step, so doing so is left as an exercise for the reader.
  • Use reroutes to clarify the flow.
    • Minimize connectors crossing each other.
    • Minimize connectors crossing nodes.
  • Label reroutes.
  • Use a frame containing a text to document the node group. Also left as an exercise for the reader.

Conclusion

I have described my usual workflow for converting a group of nodes into a reusable node group. It is only one of many. It may not be the best for you, but it can serve as a starting point.

  • Fix “magic” constants.
  • Filter parameters.
  • Separate parameters from node group.
  • Determine what nodes belong to the group and create it.
  • Merge parameters.
  • Name the node group and the parameters.
  • Give the input parameters reasonable default, minimum and maximum values.
  • Lay out the nodes within the group to make it more readable.
  • Add frames to visually group nodes within the node group.
  • Add a frame with text to document the input and output parameters

I have not described how to collect node groups into files so that you can easily add them to blend files as needed. I have a method, but it doesn’t work very well. Please comment if you have one that works well for you.

Procedural Archimedean Spirals in Blender – Part 1: creating the node group

Introduction

This is one of my favorite procedural textures, although I rarely use it. Here is a step by step tutorial describing the technique. The tutorial was prepared using 2.79b but the texture will work in any version of Blender that supports the math node.

The Archimedean Spiral

There are several kinds of spirals, each defined by its own equation. The equation for the Archimedean Spiral, in polar form is

r = a + b * theta

which makes perfect sense to a mathematician but is probably Greek to an artist. Ignore it for now.

Wikipedia describes this as

the locus of points corresponding to the locations over time of a point moving away from a fixed point with a constant speed along a line which rotates with constant angular velocity

a description that I suppose would seem natural to a physics student but is just more Greek to anyone else.

Another way of saying the Wikipedia description is to consider a record player. The locus of points is simply the groove that runs from the inside to the outside of the record. Constant angular velocity means the turntable rotates at a constant speed. For an old LP this is 33 1/3 rotations per minute. If you look straight down on the turntable you will see that the needle moves in a straight line from the edge towards the center. No matter where it is along that line, it is moving at the same speed. This is the constant speed along a line.

Preliminaries

There are two useful helper node groups. The first is a bit of coordinate geometry, the second a bit of logic. The next two subsections describe them, but you can safely skip the description and move to the following section.

Measuring Distance

Blender uses a Cartesian coordinate system to describe where points are on a surface. It takes three numbers to describe where a point is in space, but we’ll be working with a plane, so we only need two.

The distance between the origin and a point is described by the equation

D = square root(x*x + y*y)

we can express this as a procedural material using this node group

From left to right

  • Extracting X and Y:
    • The Object output of a Texture Coordinate node. This will provide the 3d coordinate of each point on the object, in arbitrary blender units. The origin of this coordinate system is the Blender origin of the object.
    • The Vector output of a Mapping node.  For this texture, the mapping node is not used and can be ignored.
    • The X and Y outputs of a Separate XYZ node
  • Calculating the distance
    • Two multiply Math nodes. These compute X*X and Y*Y
    • One add Math node. This adds the two previous results together, giving X*X + Y*Y
    • One power Math node. This extracts the square root, providing the distance.
  • Displaying the result
    • A Diffuse node. This converts the distance value into a gray level.
    • A Material node. Output the result.

Since Blender represents gray values with a number that varies from zero to one, this material will provide an output that is darker near the origin of the plane and becomes lighter the farther away from the plane the point is.

Determining if a number lies between two other numbers

Suppose we want to create a ring using the distance.  A ring would include every point that is farther away from the center than a certain distance, but no farther away than another. The math for this is

d < outer radius AND d > inner radius

We can express this as

The distance formula is now calculated using a node group and we’ve added three more columns of nodes. From left to right, the new nodes are

  • Two Value nodes. These are not strictly necessary because the values can be input directly to the next two nodes.
  • a greater than Math node and a less than Math node.  These give one if their condition is true for their inputs or zero if it is not.
  • A minimum Math node. Blender doesn’t have logic nodes and this is one of several ways to provide the AND logic. If either of its inputs are 0, then the node will give 0.  If both are 1, then the node will give 1. This is the truth table for AND.

Since 0 will display as black and 1 as white, rendering this gives a ring.

Creating a spiral

There are two ways to go about this.  One is to do more complicated math to convert the equation from polar to Cartesian form.  Another is to use a few tricks to accomplish the same thing.  We’ll take the tricky path. How this path works is left as an exercise for the mathematically inclined.

First Trick: Add a radial gradient.

We know what r is: The distance from the center. But what is theta that we use it to know which distance matters? The first thing is to add a radial gradient texture.

The radial gradient, by itself renders as

Adding it to the distance modifies this.

 It is difficult to see what this happens.  Temporarily add the nodes to determine what part of the image is in the range zero to one

The edge of the white area turns out to be a spiral, but only one complete rotation.

Second Trick: add a modulo

The second trick comes from Modular Arithmetic.  Consider time keeping.  The next hour after 12 on a 12 hour clock is not 13 but 1. Without describing the math let’s add a modulo math node

which renders as

giving us a two armed spiral.

Setting the number of arms

Add a multiply before the modulo operator. Now the texture will produce twice as many arms as that number

A value of 2 results in 4 arms

It’s inconvenient to remember to divide the number of arms we want by 2. Here’s a node group that allows us to set the number by changing the value in the value node

With the value set to 1 we get a single arm

Controlling the spacing

So far we’ve accomplished the equivalent of R = theta.  Let’s add in the constant b.  B controls how far apart the turns of the spiral are. A simple trick for doing this is to divide the X and Y coordinates by a constant.

for the value .5 this renders as

Adding limits

Suppose we wanted this pattern to fit in a ring, the way the grooves on a record do.  This is where the range calculation comes into play

There is a subtly here.  We compute the distance twice, once with the division and once without. If we used the output of the division in both cases, the limits would depend on the divisor for the ring.  This keeps them independent.  It now renders as

Setting the “width” of the groove

We have a complete node group that will generate a spiral within a ring. We control the spacing of the spiral and we can control the number of arms.  This is a complete procedural spiral.  There’s one more feature that I’ve found useful.

Look closely at the grooves.  There is a repeated pattern moving outward. The spiral itself is black, but moving outward, it ramps up to white. We can control the way that ramp happens.  We use a color ramp to do this.  In this example, a color ramp that changes the saw tooth pattern into a more symmetric one with a more gentle gradient.

This renders as 

We can add another node group that controls the falloff

rendering as

This doesn’t look any different, but if you adjust the width parameter you can change the curve. The higher the width value, the sharper the falloff, giving greater contrast.

width = .1, you can barely detect the spiral

width = 4, the fall off is much sharper.

Conclusion

We’ve created a procedural material that will generate a spiral. We refined the material, allowing us to

  • control the number of arms generated
  • control the distance covered in one rotation — the spacing
  • limit the range of the spiral to a ring of a given size
  • control the ‘falloff’ from black to white as you move a long a radius — the width

This is a useful enough material that we might turn it into a node group. Part 2 discusses one way to do that.