# Creating knob/dial with indicator strip

I've modelled a few knobs/dials which I've animated over 100 frames or so. They rotate from -135 degrees to +135 over 100 or so frames.

However, now I need to add an indicator strip so as the knob turns, the strip lights up dependent on the pointer position of the dial.

i.e:

I feel I either need some sort of masking layer, or some way of tying in the current rotation value of the main dial to the position of the emission strip.

This one is driven by the knob rotation, so you animate the knob and the lights are good.

Let's assume you are looking at your knob from top view.

For convenience, you model a led and you parent led and knob to an empty. Knob must have first rotation applied and rotation mode must be set to xyz euler, if you set it in quaternion or axis angle it will lit only on 180°. Add a material to the led, a simple diffuse one, it will be modified later. Then you switch to 3D cursor pivot mode and you snap the cursor to the center of your knob. The idea is to duplicate linked the led, then rotate to a determined amount around the 3D cursor, then add a custom property or as I have done here, use the pass index in the object tab and increment it for each duplicata. I am not a great coder, you will find the script (poor one) I did in the blend file.

import bpy

# range covered (in degrees)
rangecovering = 270

# number of leds
leds = 20

##############################"
# step calculated

#the override comes from http://blender.stackexchange.com/questions/6969/rotate-object-around-cursor-with-python

def get_override(area_type, region_type):
for area in bpy.context.screen.areas:
if area.type == area_type:
for region in area.regions:
if region.type == region_type:
override = {'area': area, 'region': region}
return override
#error message if the area or region wasn't found
raise RuntimeError("Wasn't able to find", region_type," in area ", area_type,
"\n Make sure it's open while executing script.")

#we need to override the context of our operator
override = get_override( 'VIEW_3D', 'WINDOW' )

for N in range(0,leds) :

# rotation of the duplicate
bpy.ops.transform.rotate(override, value=steprad, axis=(-0, -0, -1), constraint_axis=(False, False, False), constraint_orientation='GLOBAL')

# change pass index obj
bpy.context.object.pass_index = N+1


You just have to change the range in degree, the number of leds you want, and it will create the strip with the correct number of leds around the 3D cursor. If you want to change the shape of the leds (in edit mode), you can and they will be all modified at the same time as they are linked duplicate. You can also modify the mesh data of one led and link the object data to the others quickly.

Then you create a material with a value driven by the rotation of the knob

When you create the driver, use the name var in Scripted Expression, and local z axis in order to rotate the whole thing using the empty without breaking the driver.

I chose to keep the default driver curve and to manage the values directly in the material, so you have a few parameters to adjust to make it work there : range of strip leds, and number of leds as in the script.

If you want to rotate the knob, use the empty so that you will be able to center it at your taste.

If you use the same led material for the knob, and you put an indexpass = 0 it will light up at the same time than the first led.

• This is awesome; however, I can't get the LEDs to trigger past 180 degrees when rotating - did you find the same thing? – Neokoenig Jun 13 '16 at 10:28
• With the blend supplied ? Did you modify some values ? Are the strip leds triggering exactly when the knob led is coming in front of them ? Did you modified the driver curve ? I can have a look at your blend if you want to... Edit : I just found why, you need to set the rotation mode of the knob in xyz euler. If you set it in Quaternion or axis angle it's giving you this behavior. – tynaud Jun 14 '16 at 19:22
• AGH! Yes, it was that simple. Legend. Thank you so much! – Neokoenig Jun 14 '16 at 20:10

Here is a solution to light up the individual LED's one at a time without any type of unwanted gradient effect.

The basis of the effect is based on 36 equally spaced LED rectangles created by extruding a 36 point circle, bevelling the edges and then deleting the separating faces.

The texture mask that turns on the LED shader is made up of a number of Radial textures which are turned using a Custom Vector Rotate node (Credit for node: Stan Pancakes on BA). This is necessary because the standard Mapping node does not allow inputs for the rotation values.

A More In Depth Description:

Note: in order to see the radial texture during testing I add a centred plane to the LED mesh. This allows for easier visualization of the mask texture.

1. A radial gradient texture is inverted, multiplied by 2, and then passed through a Color Ramp set to Constant. This give us a solid black+white divided texture that we can rotate around the Z axis of the object. (Please note the radial gradient has banding in the GIF file below)

1. By doubling the BW texture, and only rotating one, we can subtract one from the other to get a black area that grows by 10 degrees at a time.

1. However once we past the 180 degree mark, the colour subtracting starts over whereby we only get a single 10 degree segment at the 190 degree mark. This means we have to add a third texture that remains stationary (180 + 10 = 190) and add some conditional logic to only add this texture when the main angle is greater than 180 degrees.

Here's a closer look at the logic nodes to add the third texture.

1. I created 2 Value nodes, one to drive the starting LED position, and one to drive the amount of visible LED's. Then I keyframed the Segments On node value per frame for 36 frames (one frame per LED). You could probably spread out the keyframes to show more slowly in your animation if necessary.

Also, note that I had to change the interpolation for the animated value to Constant so each frame would equal 1 LED being turned on.

1. Once the mask texture is working, it's simply a matter of using it drive the Mix factor between an ON and OFF shader in the material.

Here is the blend file for you to inspect:

• Wow, that's exactly what I'm after. amazing! The cycles nodes for that are insane - lots to learn. Thank you! – Neokoenig Jun 12 '16 at 7:42

Another approach using UV Warp modifier (to avoid the non linear aspect of the previous solution I gave, which does not directly avoid the gradient effect -see the note at the end-, but very quick to setup).

Create your object and set its UV map like this (project from view) on a black and white (or blended if you prefer) texture :

Then add a UV Warp modifier using two control objects (here two cubes) :

Setup your material nodes so that the black and white texture controls the swith of lighted/unlighted knobs/dials indicators.

Now simply play with the position of the "to" cube you set in the UV Warp modifier previously :

Note : to avoid the gradient effect, you can insert keyframes degre by degre and after that set the interpolation mode to constant in the graph editor, but this is a bit long and (i think) not very elegant approach.

You can simply do it with driver expression on Array Modifier.
Please take a look at the blend file.
Short explanation:

1. Create a Plane object (Indicator_Light) and add Array modifier with Count 36 and Relative Offset of 1.5. Also add Subdivision Surface modifier with Simple type of subdivision.

2. Create a Bezier Circle and use it as Curve modifier for Indicator_Light. Scale the latter until all 36 copies are distributed evenly on the circle.

3. Create Knob object (the shape is optional). Add Driver to the Count parameter of the Array modifier of the Indicator_Light object. The Driver should be linked to the Transform Chanel and Y Rotation of the Knob object. Use the default variable name "var" and enter the expression in Expr. field: ((var*(180/pi))//10). Now when you rotate the Knob around the Y axis it will control the number of copies of Indicator_Light.

4. Finally if you need to display part of the copies, you can "cut out" those you don't need by adding an object with appropriate shape as Boolean modifier

• Please expand a bit on the process to make this answer reach a wieder audience. Keep in mind that just by looking at a blend flies, the proposed solution might not be obvious to those who do not know the steps you used to implement it. – cegaton Jun 16 '16 at 16:36
• Thank you for the note, cegaton. Additional explanation added. – Rumen Belev Jun 17 '16 at 14:20

You can use this kind of principle :

With a texture like that (setting a blending on it) :

A closer view to the nodes :

• It takes the texture as entry
• Then separate one color component.
• That the color is tested against a limit ("Less than" node)
• And this limit is the animated value
• The output of the "less than" node is the factor for a "Mix shader"

Note : i did not succeed to make it completely linear

• Thank you very much; very close to what I was after, but not quite! – Neokoenig Jun 12 '16 at 7:42

I think you can simplify the code by using internal Blender Game Engine. By using the logic block, animate the movements of the the knob and insert the frame for the LED for Off to On by hovering the mouse cursor over the "amount of light to emit" box and press I (Insert a frame). In the actuator sections, insert an action and use the properties variable.s