I'm trying to get a normal pass without normal maps in it in Eevee: only geo normals. Currently my normal pass looks like the left image and I want a right image (the same scene rendered without materials)

enter image description here

I'm thinking of writing a script that'd be used only to render this pass: the script would basically disable bump nodes, disable lights (to render faster), disable other passes (to not overwrite them) render the pass, re-enables everything back. But I wonder if I'm missing something and there's an easier way?

p.s. rendering a Normals Matcap from workbench won't work with perspective cameras, I need true normals.


1 Answer 1


I didn't find a solution so decided to write a script. It uses my scene setup so there's no point of pasting the whole thing but I'll paste a pseudo code that explains my approach

import bpy
import time

# disabling things
def get_color_management_settings():
  # returns some current values from scene.display_settings and view_settings: 
  # look, exposure, gamma, etc

def set_default_color_management_settings():
  # sets various display settings to a zeroed state 
  # so that the render wouldn't be affected by custom gamma/exposure/color profile settings

def set_color_management_settings(values):
  # sets various display settings to previously saved settigns

def disable_passes():
  # disables all the render passes but normal: breaks connections in compositing tab
  # renames 'normal' pass to 'geo_normal'
  # returns everything to restore to defaults:
  # file_output_node
  # render_output_node
  # outputs_arr: array of sockets that were connected

def disable_materials():
  # for each material
  # disconnects Material Output from the shader node
  # creates a blank Diffuse node and connects Material Output with it
  # creates and returns a dict with mat_name: [original_input_node, original_input_socket]

def disable_lights():
  # gets and returns all the lights that aren't disabled in render
  # also disables them in render

def disable_volumes():
  # gets and returns all the objects with Volumetric materials
  # also disables them

# enabling things
def enable_passes(file_output_node, render_output_node, outputs_arr):
  # re-enables original nodes connections in the compositing tab
  # renames 'geo_normal' pass back to 'normal' pass

def enable_lights(lights):
  # re-enables all the lights that were disabled

def enable_materials(materials):
  # removes temporary Diffuse nodes
  # and reconnects original shader nodes with Material Output node

def enable_volumes(volumes):
  # re-enables objects with volumetric materials

def main():
  timeStart = time.perf_counter()

  # getting active color management settigs
  color_management_settings = get_color_management_settings()

  # setting default color management settings

  # disable links in compositing
  file_output_node, render_output_node, outputs_arr = disable_passes()

  # disable objects with volumentric materials: saves around 30% of render time
  volumes = disable_volumes()

  # changes all materials to use a black diffuse node
  materials = disable_materials()

  # disable all the lights: saves render time
  lights = disable_lights()

  # render

  # re-enable everything back
  enable_passes(file_output_node, render_output_node, outputs_arr)
  timeEnd = time.perf_counter()
  # render takes about 1 second for simple scene, about 7-8 seconds for complex ones on 2070s
  print(f"time: {timeEnd - timeStart:0.4f} seconds")


The result: normals_geo.png with geo normals and correct gamma, normals.png that comes from default render setup:

enter image description here


You must log in to answer this question.

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