ComfyUI Extension: NormalMapLightEstimator
A ComfyUI custom node for estimating light direction and quality from normal maps using luma masking. The system analyzes surface normals to infer lighting information for downstream tasks like adaptive relighting, directional masking, or stylized effects.
Custom Nodes (0)
README
NormalMapLightEstimator
A ComfyUI custom node for estimating light direction and quality from normal maps using luma masking. The system analyzes surface normals to infer lighting information for downstream tasks like adaptive relighting, directional masking, or stylized effects.
Features
- Categorical Directional Outputs: X direction (left/central/right), Y direction (top/central/bottom)
- Hard/Soft Classification: Continuous index from 0.0 (hard) to 1.0 (soft)
- Curves Strategy: Advanced luma processing with multiple curve types
- User-Controllable Thresholds: Fine-tune detection sensitivity
- Debug Visualization: Visual feedback for analysis results
- Confidence Scoring: Reliability indicators for all outputs
Installation
-
Copy this folder to your ComfyUI
custom_nodes
directory:ComfyUI/custom_nodes/NormalMapLightEstimator/
-
Restart ComfyUI
-
Dependencies will install automatically. If installation fails, see troubleshooting.
Usage
Basic Setup
- Connect a normal map to the
normal_map
input - Connect a luma/lighting image to the
luma_image
input - Adjust the
luma_threshold
to control which areas are considered lit - Run the workflow to get directional and quality outputs
Inputs
| Name | Type | Description | Default |
|------|------|-------------|---------|
| normal_map
| IMAGE | RGB normal map in tangent space (0–255) | - |
| luma_image
| IMAGE | Grayscale or RGB image to extract luminance | - |
| luma_threshold
| FLOAT | Threshold to mask out non-lit areas | 0.5 |
| curve_type
| COMBO | Luma processing curve | s_curve |
| x_threshold
| FLOAT | Sensitivity for left/right detection | 0.1 |
| y_threshold
| FLOAT | Sensitivity for top/bottom detection | 0.1 |
| central_threshold
| FLOAT | Threshold for central lighting detection | 0.3 |
| hard_light_threshold
| FLOAT | Below this = hard light | 0.15 |
| soft_light_threshold
| FLOAT | Above this = soft light | 0.35 |
| use_weighted
| BOOLEAN | Use weighted averaging | False |
| custom_curve_points
| STRING | Custom curve points (optional) | - |
Outputs
| Name | Type | Description |
|------|------|-------------|
| x_direction
| STRING | "left", "central", "right" |
| y_direction
| STRING | "top", "central", "bottom" |
| combined_direction
| STRING | "top-left", "top-central", etc. |
| hard_soft_index
| FLOAT | 0.0 (hard) to 1.0 (soft) |
| x_confidence
| FLOAT | Confidence in X direction classification |
| y_confidence
| FLOAT | Confidence in Y direction classification |
| overall_confidence
| FLOAT | Combined confidence score |
| spread_value
| FLOAT | Raw numerical spread value |
| debug_mask
| IMAGE | Binary mask showing which normals were used |
| directional_viz
| IMAGE | Color-coded visualization of results |
Algorithm
Core Concept
The system analyzes surface normals to infer lighting information:
- Normal Map (RGB) → Surface orientation (XYZ)
- Luma Mask → Which areas are actually lit
- Filtered Normals → Only consider lit surface orientations
- Statistical Analysis → Infer light direction and quality
Key Insight
Lit surface normals point TOWARD the light source. By averaging these directions, we get the light direction.
Processing Pipeline
- Normal Processing: Convert RGB to XYZ, apply axis inversions
- Luma Masking: Extract luminance, apply threshold with curves
- Directional Analysis: Quadrant-based normal distribution analysis
- Quality Classification: Spread analysis for hard/soft determination
Curve Types
Linear
Simple threshold-like behavior for basic masking.
S-curve
Enhance mid-tones, compress highlights/shadows. Good for balanced lighting.
Exponential
Emphasize bright areas. Useful for high-contrast scenes.
Logarithmic
Compress highlights, expand shadows. Good for low-light scenarios.
Custom
User-defined curve points for advanced control.
Threshold Controls
Directional Thresholds
- X Threshold: Controls left/right detection sensitivity
- Y Threshold: Controls top/bottom detection sensitivity
- Central Threshold: Detects central lighting patterns
Quality Thresholds
- Hard Light Threshold: Below this = hard light (index 0.0)
- Soft Light Threshold: Above this = soft light (index 1.0)
- Between: Linear interpolation from 0.0 to 1.0
Usage Examples
Basic Directional Detection
X Threshold: 0.1 (sensitive to left/right)
Y Threshold: 0.1 (sensitive to top/bottom)
Central Threshold: 0.3 (detect central lighting)
Hard Light Detection
Hard Threshold: 0.1 (very sensitive)
Soft Threshold: 0.2 (narrow range)
Result: Index 0.0-0.5 range
Soft Light Detection
Hard Threshold: 0.2 (less sensitive)
Soft Threshold: 0.5 (wider range)
Result: Index 0.5-1.0 range
Visualization System
Debug Mask
- White pixels: Lit areas used in analysis
- Black pixels: Masked out areas
Directional Visualization
- Red Channel: X direction (left=255, central=192, right=128)
- Green Channel: Y direction (top=255, central=192, bottom=128)
- Blue Channel: Hard/soft index (hard=255, soft=128)
- Confidence: Applied as transparency effect
Troubleshooting
Common Issues
"No light direction detected"
- Check if luma threshold is too high
- Verify normal map has proper lighting information
- Try adjusting directional thresholds
"Incorrect direction classification"
- Try inverting X or Y axes for different normal conventions
- Adjust central threshold for omnidirectional lighting
- Check confidence scores for reliability
"Poor quality classification"
- Adjust hard/soft thresholds based on your use case
- Try different curve types for luma processing
- Use weighted averaging for more accurate results
Manual Installation
If auto-installation fails:
cd ComfyUI/custom_nodes/NormalMapLightEstimator/
pip install -r requirements.txt
Technical Details
Dependencies
- torch>=1.9.0
- numpy>=1.21.0
- Pillow>=8.0.0
- scipy>=1.7.0
Performance
- Optimized for ComfyUI tensor operations
- Batch processing support
- Memory-efficient covariance calculations
- GPU acceleration where possible
Edge Cases Handled
- No lit areas: Returns default central direction
- Single normal: Uses that direction
- Collinear normals: Handles degenerate cases gracefully
- Low confidence: Provides reliability indicators
License
MIT License - see LICENSE for details.
Changelog
v1.0.0
- Initial release with categorical directional outputs
- Hard/soft classification with continuous index
- Curves strategy for luma processing
- User-controllable thresholds
- Debug visualization system
- Confidence scoring system
For support, open an issue on GitHub.