Photorealistic ray-traced PCB renderings (with raytraced solder meniscus refractions, rough FR4 fiberglass weaves, and brushed aluminum capacitor cans) look impressive in datasheets. However, for project documentation, social announcements, and technical blogs, hyper-realism often obscures the circuit architecture beneath glossy reflections and specular glare.

Inspired by the visual design of Nintendo’s The Legend of Zelda: The Wind Waker, we built an automated Non-Photorealistic Rendering (NPR) cel shader pipeline for Blender EEVEE.

Using the pcb2blender bridge and a procedural Python shader builder, raw KiCad layouts are converted into high-contrast, cel-shaded anime illustrations with bold ink contours.


1. Pipeline Overview: From KiCad to Inked Cel

KiCad Layout (.kicad_pcb)
          │
          ▼
 pcb2blender Addon ──► Blender Scene (Multi-layer mesh: Substrate, Copper, Mask, Silk)
                             │
                             ▼
 toon_shader_library.py ──► Replaces PBR materials with WW_Cel_Core shader graphs
                             │
                             ▼
 Grease Pencil LineArt ──► Inks silhouette edges, component creases, and pad perimeters
                             │
                             ▼
 Real-Time EEVEE Next Cel Render

2. Core Cel Shader Architecture (WW_Cel_Core)

Standard PBR shaders compute continuous Lambertian diffuse falloff:

$$I_{\text{diffuse}} = \mathbf{N} \cdot \mathbf{L}$$

In The Wind Waker, lighting is quantized into flat, discrete color bands with zero muddy transitional gradients.

In Blender EEVEE, we convert real-time light evaluations into color data using the Shader to RGB node, followed by mathematical thresholding:

[Scene Directional Sun Light]
               │
               ▼
         Diffuse BSDF
               │
               ▼
         Shader to RGB
               │
               ├─► Math (Greater Than: 0.28) ──► Mix (Shadow Color, Base Color)
               │                                            │
               └─► Math (Greater Than: 0.72) ──► Mix (..., Highlight Color)
                                                            │
         Glossy BSDF ──► Shader to RGB ──► Greater Than 0.85 ──┼─► Add (Specular)
                                                            │
         Layer Weight ──► Facing > 0.65 ────────────────────┴─► Add (Rim Light)
                                                                    │
                                                                    ▼
                                                            Emission (1.0)
def build_cel_core_group():
    """Constructs reusable node group for quantized stepped diffuse lighting."""
    group = bpy.data.node_groups.new(name="WW_Cel_Core", type='ShaderNodeTree')
    
    # Diffuse evaluation
    diffuse = group.nodes.new('ShaderNodeBsdfDiffuse')
    s2rgb = group.nodes.new('ShaderNodeShaderToRGB')
    group.links.new(diffuse.outputs['BSDF'], s2rgb.inputs['Shader'])
    
    # Step 1: Shadow vs Base threshold
    step_shadow = group.nodes.new('ShaderNodeMath')
    step_shadow.operation = 'GREATER_THAN'
    step_shadow.inputs[1].default_value = 0.32
    
    # Step 2: Highlight band
    step_hi = group.nodes.new('ShaderNodeMath')
    step_hi.operation = 'GREATER_THAN'
    step_hi.inputs[1].default_value = 0.78
    
    # Output to Emission to bypass second-bounce indirect muddying
    return group

Bypassing standard surface shaders and routing the quantized result into an Emission BSDF ensures that ambient scene bounce light does not pollute the sharp 2-tone cel boundaries.


3. The Great Sea Color Palette

Rather than generic green PCB masks, the palette adopts the nautical hues of The Wind Waker:

Board Layer Base Cel Color Shadow Tone Highlight / Specular
Soldermask Great Sea Turquoise (#00A896) Deep Navy Trench (#001030) Aqua Shimmer (#02C39A)
Copper Traces Subsurface Gold (#F4A261) Dark Bronze (#7A4B1A) Shines through thin mask
ENIG Pads / Gold Anime Gold (#FFD166) Ochre Umber (#B87333) Sharp 1-bit White Specular
Silkscreen Parchment Cream (#FDFCDC) Soft Tan (#D4A373) Self-illuminated
SMD Resistors/ICs Matte Charcoal (#1F2421) Midnight Black (#0B0C10) Edge specular glint

4. Real-Time Inking via Grease Pencil LineArt

A cel render is incomplete without crisp outline inking. Traditional inverse-hull modifiers (inverted normals with backface culling) fail on open PCB trace polylines and component pin headers.

We configured Blender’s Grease Pencil LineArt modifier:

  1. Silhouette Inking: Traces the external perimeter of the PCB substrate and tall components (switches, rotary encoders, USB-C ports) with a $3.0\text{ px}$ black stroke.
  2. Crease Inking: Detects sharp surface angle changes ($> 70^\circ$) to ink component pin shoulders and mechanical housings.
  3. Material Borders: Inks the boundary lines where the exposed ENIG gold pads transition into the soldermask.

5. Automated Batch Processing

To run the shader on any newly imported board without manual node wiring, toon_shader_library.py scans the scene collections generated by pcb2blender, identifies layers by name prefix (F_Cu, F_Mask, F_SilkS), and swaps their material graphs automatically:

& "C:\Program Files\Blender Foundation\Blender 5.1\blender.exe" `
    "pcb.blend" `
    --python "toon_shader_library.py"

The resulting render combines the architectural clarity of a technical block diagram with the expressive visual personality of classic video game cel art.