0
$\begingroup$

For an explanation video about my company's products, I have an animated scene in Blender 2.8 with a large number of mechanical parts of which I'd like to highlight a specific collection of parts, for example by making them flash in red.

The closest option would be to animate the material of these parts with a second shader that makes the objects stand out and keyframing the ratio between the regular and the highlight shader from 0 to 1 with a mix shader node. However, since I have 50+ parts with 50+ unique materials, that would be a lot of manual work to set up and keyframe for every individual material used, not to mention that every material would have a set of nodes that is only used once in the animation which makes the already big scene even messier.

What other ways outside of material editing would exist to highlight a large set of objects at the same time?

$\endgroup$
2
$\begingroup$

You could duplicate all the objects (perhaps scale them up a percent, and maybe put them all in a separate collection), and give the all duplicates the same material with Make Links (Ctrl + L) > Material. Then do something like make this material have a Mix Shader, with a Transparent BSDF and red Diffuse BSDF plugged into it. Then Animate the Fac value of the Mix Shader.

enter image description here

EDIT:

You could do the work but copy-paste the extra nodes and copy-paste a driver in the Mix Shader to decrease the amount of manual work.

Add an empty, add a custom property (Object Properties > Custom Properties), give it a nice name (optional), right click the value field and choose Copy Data Path.

enter image description here

Create a node setup with a Mix Shader as an alternative output for a material. Give it a nice frame (optional). Right click the Fac value and choose Add Driver.

enter image description here

Edit the driver right away when it pop up, or with the Mix Shader selected go to the Drivers window. Type: Scripted Expression, Expression: "var", for Prop target the empty object, and hoover over Path: with the mouse and press Ctrl+V to paste the custom property data path.

enter image description here

Sadly when you copy-paste the highlight nodes to another material the driver isn't copied with it, but you can easily copy paste a driver by right clicking the field where the driver is applied. Connect it to the other nodes, and no need to delete anything; the last selected Material Output becomes the active one. (Once i had the nodes and driver set up, it took me only a few seconds to paste an connect them in to each material.)

enter image description here

Since all drivers share the data path they are all driven by the same custom property. And it can be animated.

enter image description here

$\endgroup$
2
  • $\begingroup$ This is not a bad method, the material linking works flawlessly. However, scaling up the duplicated object and making it overlay the smaller one has proven to be a small challenge. The downside to this method is that it basically doubled my active poly count, which makes the rendering quite slow. $\endgroup$
    – Croomar
    Jul 17 '20 at 10:32
  • $\begingroup$ Edited my answer. Maybe it can help : ) $\endgroup$ Jul 17 '20 at 13:00
2
$\begingroup$

Swap out materials with a frame change handler

As a proof of concept, here is a handler that simply swaps out all of the materials of an object when frame is withing a range defined by a custom property

A dictionary of each scene objects name to material names is created and printed (xxx)

materials = {o.name : [
    s.material.name if s.material else "None"
    
    for s in o.material_slots
    ] for o in scene.objects
    }
    
print(materials)

for my very simple example scene has 3 objects, the lamp and cam have no materials, the cube has 3 slots set to, in order, "Material", "Red" and "Red". If slot is empty it is given the name "None".

{'Cube': ['Material', 'Red', 'Red'], 'Lamp': [], 'Camera': []}

so instead could replace the generation (xxx) with (for my example)

materials = {'Cube': ['Material', 'Red', 'Red'], 'Lamp': [], 'Camera': []}

The handler script. Creates the dict and on a frame change if any object in scene has custom property "highlight" and the frame is in the range defined by property a highlight material is used for all materials of that object.

The script only need be run once. As with all scripts make sure you save your file first.

import bpy

context = bpy.context
scene = context.scene
scene.frame_set(0)

highlightmat = "Red"

materials = {o.name : [
    s.material.name if s.material else "None"
    
    for s in o.material_slots
    ] for o in scene.objects
    }
    
print(materials)

def frame_change(scene, depsgraph):
    iframe = int(scene.frame_current)
    for ob in scene.objects:
        highlight = ob.get("highlight")
        if highlight and iframe in range(*highlight):
            for s in ob.material_slots:
                s.material = bpy.data.materials.get(highlightmat)
        elif highlight or not iframe:
            for key, s in zip(materials[ob.name], ob.material_slots):
                if s and key:
                    s.material =  bpy.data.materials.get(key)
                

bpy.app.handlers.frame_change_post.clear()                 
bpy.app.handlers.frame_change_post.append(frame_change)   

Frame 0 is used as a default reset. Suggest don't include 0 when defining object highlight ranges.

Set the object highlight range

To highlight the current context object from frame 2 to 30, go to python console and type in

C.object["highlight"] = [2, 30]

(Not sure how to do the list with UI)

If you know the names of all your objects, could also hard code this into the script above. Eg to have "Elvis" highlighted frames 20 to 444

bpy.data.objects["Elvis"]["highlight"] = [20, 444]

then with the handler active playing animation will cause all materials to swap to highlightmat which I have set to use the material named "Red", change to suit

highlightmat = "Red"

EDIT

In as much as can swap the materials as shown above, consider setup materials to use the object info node utilizing the pass index or object color to flag and animate a highlight.

Control object emission strength (not material)

Same Material with different key frames

$\endgroup$
3
  • $\begingroup$ Very nice : ). I'm still relatively inexperienced with coding. Could the line affecting the Elvis object be changed into something that would affect the "highlight"property of all objects in a certain collection? Something with bpy.data.collections.all_objects perhaps ? (I think that would make it easier to manually create the distinction between objects that need to be highlighted and objects that don't) $\endgroup$ Jul 18 '20 at 19:18
  • $\begingroup$ Yes. Something like for ob in bpy.data.collections["Foo"].objects: to iterate thru all objects in a collection. $\endgroup$
    – batFINGER
    Jul 18 '20 at 19:24
  • $\begingroup$ I got it to work. Thanks : ) I think it would benefit your answer and any anyone who wanted to use it and who isn't that familiar with coding. (I considered editing it but i wasn't sure if that was polite or appropriate, since there isn't anything wrong with your answer) $\endgroup$ Jul 18 '20 at 20:21

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.