Nodes/Avatar Graph/Transform Rotate Normal
ComfyUI Node

Transform Rotate Normal

Spinning custom shading normals by an angle

By avatechai·Created 3 years ago·Updated 2 years ago· 264
Transform Rotate Normal
  • BPY_OBJ
  • orient_type
  • orient_matrix
  • orient_matrix_type
  • constraint_axis
  • BPY_OBJ
value0.00
orient_axis
mirrorfalse
release_confirmfalse
use_accuratefalse

The companion move to Mesh Point Normals, and a different lever on the same idea: Transform Rotate Normal wraps bpy.ops.transform.rotate_normal, which rotates the custom shading normals of selected geometry by an angle around a chosen axis - instead of aiming them at a target point, you spin them. Same goal (controlling how a mesh catches light without moving any actual geometry), different control.

How it works

Custom split normals determine how a surface shades under light, independent of its real geometry. Where Point Normals snaps normals to face a specific location, this operator applies an angular rotation to whatever normals are already there - useful for nudging a shading result that's almost right, fixing a normals seam, or applying a consistent angular offset across a selection rather than a positional target. It's Blender's standard interactive rotate tool, retargeted at normals instead of geometry.

The inputs and outputs that matter

  • value - the rotation angle, in radians.
  • orient_axis - X, Y, or Z, the axis to rotate around.
  • mirror (default false) - mirrors the rotation, useful for symmetric geometry where you want matching-but-opposite normal rotation on both sides.
  • orient_type, orient_matrix, orient_matrix_type, constraint_axis - Blender's standard transform-orientation machinery (global/local/normal/view-space framing, and axis locking). These are the same low-level controls behind every interactive transform in Blender; unlike orient_axis above, the node's schema doesn't list friendly choices for these, so you'd need Blender's own orientation type identifiers (GLOBAL, LOCAL, NORMAL, VIEW, and so on) if you need to set them explicitly rather than leaving defaults.
  • use_accurate, release_confirm - interactive-tool leftovers (precision mode, confirm-on-release) from this being a modal transform tool originally; unlikely to matter in a headless graph.

Output is the same BPY_OBJ, normals rotated.

How to install it

Via ComfyUI Manager - search "Avatar Graph" - or manually: cd ComfyUI/custom_nodes && git clone https://github.com/avatechai/avatar-graph-comfyui, cd avatar-graph-comfyui && pip install -r requirements.txt, restart. The pack needs Python 3.10.x for bpy - a newer Python and the install fails, or the blender-category nodes don't show up. macOS/Linux: dedicated conda env at 3.10; Windows: Avatech's prebuilt Python-3.10 ComfyUI zip, pack installed via Manager.

Common issues & troubleshooting

No visible change. Like Point Normals, this edits shading, not geometry - the silhouette stays identical, so you need custom split normals already enabled and a smooth-shaded, lit view to see anything happen.

orient_type / orient_matrix_type fields don't behave like a dropdown. These are raw enum types without listed choices in the schema - if the node UI renders them as free text rather than a picker, you need Blender's exact orientation identifier strings, not a guess.

RuntimeError: ... poll() failed. This is an Edit Mode operator that needs a live selection - feed it a BPY_OBJ with nothing selected upstream and it'll refuse to run rather than silently doing nothing.

Not in the README - one of the pack's lower-level blender-category operator wrappers, auto-generated via generate_blender_types.py, not among the roughly seven higher-level nodes the README documents.

Categoryblender

Inputs (10)

NameTypeDefaultDescription
BPY_OBJoptBPY_OBJ
valueoptFLOAT0.00-3.402823466385289e+38–3.402823466385289e+38
orient_axisoptCOMBO3 options: X, Y, Z
orient_typeoptB_ENUM
orient_matrixoptB_VECTOR9
orient_matrix_typeoptB_ENUM
constraint_axisoptB_BOOLEAN3
mirroroptBOOLEANfalse
release_confirmoptBOOLEANfalse
use_accurateoptBOOLEANfalse

Outputs (1)

NameTypeDescription
BPY_OBJBPY_OBJ