The more generic/robust way the better. I.e. if this shader is copied to another project, it shouldn't be necessary to make other changes. But if this is not possible, then any other solution is nice too. (Mainly for Cycles, but for Eevee is well.)


2 Answers 2


Currently this solution relies on using an alpha version of the software (download 2.93 here) but it is pretty straightforward. Don't use for production until it is officially released.

Also, it seems it only works for Cycles if you are using a Windows OS.

Add a Geometry Nodes modifier to your object.

Plug an Attribute Fill node between the input and output. Change the Attribute name and remember it. Set the type to Color.

Plug the new Is Viewport node into the value. See the docs.

enter image description here

Add a material to your object, and add an Attribute node. See the docs.

Set the attribute name exactly as in the geometry node modifier. Plug the Color into your shader tree as you see fit. You may need to toggle between Material Preview and Render view to see the effect update.

This setup will render as White in the viewport, and as Black in the F12 rendered view :

enter image description here

Render Result :

enter image description here

  • $\begingroup$ Nice work, thank you! Still requires a change to the object (add a new modifier), but otherwise an elegant solution. If there will be no better answer, I will mark it as accepted. $\endgroup$ Feb 10, 2021 at 9:28
  • 1
    $\begingroup$ I hope this node gets ported to the shader editor too, that would be very useful and less cumbersome !! $\endgroup$
    – Gorgious
    Feb 10, 2021 at 9:31

I faced a similar challenge on a production this month; simulating a compositing setup in the viewport, while still outputting unmodified surface data in the final render. This is the solution I used:

  1. Create a python script that changes a custom scene property every time a final render is started, canceled, or completed
    1. In the Scripting tab (main window), create a new text asset
    2. Copy and paste the code below into the text editor
    3. Rename it to whatever you want, but include ".py" at the end
    4. Run the script by clicking the play button
    5. In the "Text" drop-down menu, check "Register" (that way it auto-runs when you open the scene again)
  2. Create a custom property at the scene level
    1. In the Scene Properties tab (Properties Panel), twirl open Custom Properties and click "Add"
    2. Rename the new property "RenderPreviewToggle" (this must match the name used in the script)
    3. Set the value to 1.0, and the minimum and maximum values to 0.0 and 1.0 (the limits probably aren't necessary, but can keep things cleaner when you manually override this)
    4. Right-click the property value field and choose "copy as new driver" (we'll use this in the next step)
  3. In the material editor, add a driver to switch between options
    1. In the "Shader Editor" wherever you need to switch between "render" and "preview" mode, paste the driver into the "Factor" of a mix node
      • 0.0 = render and 1.0 = preview so when using a "Shader Mix" node, you'll want your render shader connected to the first shader slot, and your preview shader connected to the second slot
    2. Enable "Viewport Shading" in the 3D view, and you should see the "1.0" results
    3. Render a still image or animation, and you should see the "0.0" results

This does not provide a simple solution that is easily transferred to another project, but it seems to work pretty reliably without having to modify any of your geometry (in my current production there are a lot of models and very few materials, so this was a particularly efficient solution). I've been using it with Eevee in Blender 2.93, but it should work just as well in Cycles, and in older and newer versions of Blender. And because it's based on drivers and Blender's handler system, it should also work reliably in other render engines such as Radeon ProRender or LuxCore.

If the engine prunes unused shader networks properly (a mix node set to 0.0 or 1.0 shouldn't be evaluating the "off" half of its inputs), this setup could be used to speed up preview rendering...but I haven't tested to see if that's the case.

I would certainly appreciate a solution that simply adds a "viewport" or similar output to the "Camera Data" node (back in the day, Lightwave included exactly that in a scene data node!)...hopefully that's a feature that will eventually be added. But for now, this works for me.

Here's the script:

import bpy

def render_preview_on(scene):
    bpy.data.scenes["Scene"]["RenderPreviewToggle"] = 1

def render_preview_off(scene):
    bpy.data.scenes["Scene"]["RenderPreviewToggle"] = 0


Note that using both render_cancel and render_complete is important so that the preview toggle is switched back on regardless of how the render proceeds.

Also note that running the script multiple times will add multiple instances in your handlers...so...don't do that. This is a super basic script and doesn't have any clearing/replacing features built in. If you need to modify the custom property name you can close and re-open the scene, or manually clear the handlers before re-running the script by entering the following lines (individually) in the Blender console:


...but this will also (temporarily) wipe out any plugins that added handlers, so it's not recommended if you're using something like the VF Auto Save Render add-on.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .