Files
tinyusdz/tools/hdrgen/README.md
Syoyo Fujita 274e6826e4 Add OpenPBR parameters reference and HDRGen environment map generator tool
This commit adds comprehensive OpenPBR documentation and a powerful synthetic
environment map generation tool for testing and visualization workflows.

## OpenPBR Parameters Reference (doc/openpbr-parameters-reference.md)

- Complete mapping of all 38 OpenPBR parameters
- Blender v4.5+ MaterialX export parameter names
- Three.js MeshPhysicalMaterial support status with detailed notes
- Parameter categories: base, specular, transmission, subsurface, sheen, coat,
  emission, and geometry
- Support summary: 15 fully supported (39%), 7 partial (18%), 16 not supported (42%)
- Critical limitations clearly marked (subsurface, transmission effects, advanced coat)
- Conversion recommendations for Three.js WebGL target
- Blender MaterialX and USD format examples
- 8KB comprehensive reference with all technical details

## HDRGen Tool (tools/hdrgen/)

Pure Node.js synthetic HDR/EXR/LDR environment map generator with zero dependencies.

### Version 1.0.0 Features:
- Three presets: white-furnace (testing), sun-sky (outdoor), studio (3-point lighting)
- Dual projections: lat-long and cubemap (6 faces)
- HDR output: Radiance RGBE format with proper encoding
- Procedural generation: Hosek-Wilkie sky approximation, studio lighting model
- Comprehensive CLI with preset-specific options
- Full test suite: 8 unit tests, all passing
- Documentation: 15KB README, quick start guide, examples

### Version 1.1.0 Features (added in this commit):
- Image rotation: rotate environment maps around Y axis with bilinear filtering
- Intensity scaling: global brightness multiplier for testing and adjustment
- LDR output formats: PNG (8-bit RGB), BMP (24-bit), JPEG placeholder
- Tone mapping: three operators (simple, Reinhard, ACES filmic)
- Exposure control: EV-based exposure adjustment
- Gamma correction: configurable gamma for different displays

### Code Statistics:
- Total: ~1,500 lines of pure JavaScript
- Core library: 913 lines (hdrgen.js)
- CLI: 254 lines (cli.js)
- Tests: 194 lines
- Zero external dependencies

### Technical Implementation:
- HDR: Proper RGBE encoding with 8-bit mantissa + shared exponent
- PNG: Uncompressed RGB with CRC32 validation
- BMP: 24-bit RGB with proper padding
- Tone mapping: Reinhard, ACES filmic, simple clamp operators
- Image transforms: Bilinear filtering for rotation
- Math utilities: Vec3, coordinate conversions, color space operations

### Output Examples Included:
- test_furnace.hdr (white furnace for energy conservation testing)
- test_sunsky.hdr (procedural sky with sun disk)
- test_studio.hdr (3-point studio lighting)
- test_cube_*.hdr (cubemap faces, 6 files)
- studio_test.png (LDR preview with tone mapping)
- sky_test.bmp (BMP format example)

### Use Cases:
- Material energy conservation validation (white furnace)
- IBL testing and debugging
- Web-friendly environment map previews (LDR output)
- Lighting direction adjustment (rotation)
- Brightness testing (intensity scaling)
- DCC integration (Blender, Houdini, Maya, Unreal, Unity)

## Documentation Updates (doc/materialx.md)

- Added "Related Documentation" section linking to OpenPBR parameters reference
- Cross-reference for developers working with OpenPBR materials
- Better discoverability of comprehensive parameter mappings

## Testing

All functionality tested and verified:
- HDR output: Valid Radiance RGBE format
- PNG output: Valid PNG with correct CRC32
- BMP output: Valid 24-bit bitmap
- Rotation: Smooth 90° rotation with bilinear filtering
- Intensity scaling: Correct 0.5x and 2.0x multipliers
- Tone mapping: All three methods produce correct output

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 02:18:48 +09:00

554 lines
15 KiB
Markdown

# HDRGen - Synthetic HDR/EXR Environment Map Generator
A pure Node.js tool for generating synthetic HDR environment maps for testing, debugging, and prototyping PBR materials and IBL (Image-Based Lighting) setups.
## Features
- **Pure JavaScript/Node.js** - No external dependencies, no native bindings
- **Multiple Presets** - White furnace, sun & sky, studio lighting
- **Flexible Output** - HDR (Radiance RGBE) and EXR (OpenEXR) formats
- **Dual Projections** - Equirectangular (lat-long) and cubemap
- **Physically-Based** - Linear color space, HDR values, proper intensity scaling
- **Customizable** - Extensive options for each preset
- **CLI & API** - Use from command line or import as library
## Installation
```bash
cd tools/hdrgen
npm install
```
Make CLI globally available:
```bash
npm link
```
## Quick Start
### Generate White Furnace (Energy Conservation Test)
```bash
node src/cli.js --preset white-furnace -o output/furnace.hdr
```
### Generate Sun & Sky Environment
```bash
node src/cli.js --preset sun-sky --sun-elevation 45 -o output/sky.hdr
```
### Generate Studio Lighting
```bash
node src/cli.js --preset studio -o output/studio.hdr
```
### Generate Cubemap
```bash
node src/cli.js --preset studio --projection cubemap --width 512 -o output/studio_cube
```
### Generate All Examples
```bash
npm run example
```
## CLI Usage
```bash
hdrgen [OPTIONS]
```
### General Options
| Option | Description | Default |
|--------|-------------|---------|
| `-h, --help` | Show help message | - |
| `-p, --preset <name>` | Preset name (white-furnace, sun-sky, studio) | `white-furnace` |
| `-w, --width <px>` | Width in pixels | `2048` |
| `--height <px>` | Height in pixels | `1024` |
| `--projection <type>` | Projection type (latlong, cubemap) | `latlong` |
| `-f, --format <fmt>` | Output format (hdr, exr) | `hdr` |
| `-o, --output <path>` | Output file path | `output/<preset>_<proj>.<fmt>` |
### White Furnace Options
| Option | Description | Default |
|--------|-------------|---------|
| `--intensity <val>` | Furnace intensity | `1.0` |
**Purpose:** Uniform white environment for testing energy conservation. A perfect diffuse BRDF should integrate to exactly the furnace intensity.
### Sun & Sky Options
| Option | Description | Default |
|--------|-------------|---------|
| `--sun-elevation <deg>` | Sun elevation angle (0=horizon, 90=zenith) | `45` |
| `--sun-azimuth <deg>` | Sun azimuth angle (0=north, 90=east) | `135` |
| `--sun-intensity <val>` | Sun disk intensity | `100.0` |
| `--sky-intensity <val>` | Base sky intensity | `0.5` |
**Purpose:** Procedural outdoor environment with directional sun and atmospheric sky gradient.
### Studio Lighting Options
| Option | Description | Default |
|--------|-------------|---------|
| `--key-intensity <val>` | Key light intensity (main light) | `50.0` |
| `--fill-intensity <val>` | Fill light intensity (shadow fill) | `10.0` |
| `--rim-intensity <val>` | Rim light intensity (back highlight) | `20.0` |
| `--ambient-intensity <val>` | Ambient light intensity | `0.5` |
**Purpose:** Professional 3-point lighting setup for product visualization and character lighting.
## Presets
### 1. White Furnace
Uniform white environment at specified intensity. Essential for validating PBR material energy conservation.
**Use Cases:**
- Energy conservation testing
- BRDF validation
- Exposure calibration
- Albedo verification
**Example:**
```bash
# Standard furnace test
hdrgen -p white-furnace --intensity 1.0 -o output/furnace.hdr
# High intensity test
hdrgen -p white-furnace --intensity 10.0 -o output/furnace_10x.hdr
```
**Expected Results:**
- Perfectly diffuse white material should appear with albedo = intensity
- Metals should appear dark (no diffuse reflection)
- Specular reflections should be uniform in all directions
### 2. Sun & Sky
Procedural sky with sun disk and atmospheric gradient. Simplified Hosek-Wilkie sky model approximation.
**Use Cases:**
- Outdoor scene lighting
- Architecture visualization
- Product photography (outdoor)
- Time-of-day studies
**Parameters:**
- **Sun Elevation:** Height of sun above horizon (0°-90°)
- `0°-10°`: Sunrise/sunset (warm, long shadows)
- `30°-60°`: Mid-day (balanced, natural)
- `80°-90°`: Noon (overhead, harsh)
- **Sun Azimuth:** Compass direction of sun (0°-360°)
- `0°`: North
- `90°`: East
- `180°`: South
- `270°`: West
**Examples:**
```bash
# Afternoon sun (front-right)
hdrgen -p sun-sky --sun-elevation 45 --sun-azimuth 135 -o output/afternoon.hdr
# Sunset (low sun, west)
hdrgen -p sun-sky --sun-elevation 5 --sun-azimuth 270 --sun-intensity 150 -o output/sunset.hdr
# Noon (overhead)
hdrgen -p sun-sky --sun-elevation 85 --sun-azimuth 0 --sun-intensity 200 -o output/noon.hdr
# Sunrise (low sun, east)
hdrgen -p sun-sky --sun-elevation 10 --sun-azimuth 90 --sun-intensity 120 -o output/sunrise.hdr
```
### 3. Studio Lighting
3-point lighting setup with key, fill, and rim lights. Classic photography and cinematography lighting pattern.
**Use Cases:**
- Product rendering
- Character lighting
- Controlled lighting studies
- Material comparison
**Light Configuration:**
- **Key Light:** Main light source (front-right, elevated)
- Position: 45° right, 30° up
- Color: Warm (slightly yellow)
- **Fill Light:** Shadow fill (front-left, lower)
- Position: 30° left, 20° up
- Color: Cool (slightly blue)
- **Rim Light:** Edge/separation light (back, elevated)
- Position: Behind subject, 25° up
- Color: Neutral white
**Examples:**
```bash
# Standard studio setup
hdrgen -p studio -o output/studio.hdr
# High-key lighting (bright, low contrast)
hdrgen -p studio --key-intensity 80 --fill-intensity 30 --ambient-intensity 1.0 -o output/highkey.hdr
# Low-key lighting (dramatic, high contrast)
hdrgen -p studio --key-intensity 30 --fill-intensity 5 --rim-intensity 40 --ambient-intensity 0.1 -o output/lowkey.hdr
# Product lighting (strong rim for edge definition)
hdrgen -p studio --key-intensity 60 --fill-intensity 15 --rim-intensity 50 -o output/product.hdr
```
## Projection Types
### Equirectangular (Lat-Long)
Single image with 2:1 aspect ratio (e.g., 2048x1024). Standard format for environment maps.
**Characteristics:**
- Full 360° horizontal, 180° vertical coverage
- Distortion at poles (top and bottom stretched)
- Most compact format (single file)
- Widely supported by renderers and DCCs
**Output:** Single `.hdr` or `.exr` file
```bash
hdrgen -p sun-sky --projection latlong -w 2048 --height 1024 -o output/sky.hdr
```
### Cubemap
Six square images representing faces of a cube. No distortion, but requires 6 separate files.
**Face Order (OpenGL Convention):**
- `+X`: Right
- `-X`: Left
- `+Y`: Top (up)
- `-Y`: Bottom (down)
- `+Z`: Front
- `-Z`: Back
**Characteristics:**
- No polar distortion
- Uniform sampling across all directions
- Larger total file size (6 files)
- Preferred for real-time rendering and importance sampling
**Output:** Six files with face suffixes: `_+X.hdr`, `_-X.hdr`, etc.
```bash
hdrgen -p studio --projection cubemap --width 512 -o output/studio_cube
# Creates: studio_cube_+X.hdr, studio_cube_-X.hdr, ..., studio_cube_-Z.hdr
```
## File Formats
### HDR (Radiance RGBE)
Standard format for HDR images. Widely supported, compact, 8-bit per channel with shared exponent.
**Specifications:**
- Format: RGBE (RGB + 8-bit shared exponent)
- Precision: ~7 decimal digits
- Dynamic range: 10^-38 to 10^38
- File size: 4 bytes per pixel
- Extension: `.hdr`
**Advantages:**
- Small file size
- Fast to write
- Universal support
- Good for most IBL use cases
**Limitations:**
- Limited precision (8-bit mantissa)
- No alpha channel
- No arbitrary metadata
### EXR (OpenEXR)
High-precision format from ILM. Better precision, alpha channel support, extensive metadata.
**Specifications:**
- Format: Half-float (16-bit) or float (32-bit) per channel
- Precision: Half = 11-bit mantissa, Float = 24-bit mantissa
- Dynamic range: Half = 10^-5 to 65504
- File size: 6 bytes (half) or 12 bytes (float) per pixel
- Extension: `.exr`
**Note:** Current implementation converts to HDR. For production EXR writing, use `@openexr/node` or similar library.
## API Usage
### As ES6 Module
```javascript
import { HDRGenerator } from './src/hdrgen.js';
// Generate lat-long sun & sky
const result = HDRGenerator.generate({
preset: 'sun-sky',
width: 2048,
height: 1024,
projection: 'latlong',
format: 'hdr',
output: 'output/sky.hdr',
presetOptions: {
sunElevation: 45,
sunAzimuth: 135,
sunIntensity: 100.0
}
});
// Access raw image data
const { latLongImage } = result;
console.log(`Generated ${latLongImage.width}x${latLongImage.height} HDR image`);
```
### Programmatic Generation
```javascript
import { HDRImage, EnvMapPresets, HDRWriter } from './src/hdrgen.js';
// Create custom environment
const image = new HDRImage(2048, 1024);
// Apply preset
EnvMapPresets.sunSky(image, {
sunElevation: 30,
sunIntensity: 150.0
});
// Write to file
HDRWriter.writeRGBE(image, 'output/custom.hdr');
```
### Custom Procedural Environments
```javascript
import { HDRImage, Vec3 } from './src/hdrgen.js';
const image = new HDRImage(1024, 512);
for (let y = 0; y < image.height; y++) {
for (let x = 0; x < image.width; x++) {
const u = x / image.width;
const v = y / image.height;
// Custom procedural function
const r = Math.sin(u * Math.PI * 4) * 0.5 + 0.5;
const g = Math.sin(v * Math.PI * 4) * 0.5 + 0.5;
const b = 0.5;
image.setPixel(x, y, r * 10.0, g * 10.0, b * 10.0);
}
}
HDRWriter.writeRGBE(image, 'output/procedural.hdr');
```
## Resolution Guidelines
### Lat-Long Environments
| Use Case | Resolution | Aspect | File Size (HDR) |
|----------|-----------|--------|-----------------|
| Quick preview | 512x256 | 2:1 | ~0.5 MB |
| Development | 1024x512 | 2:1 | ~2 MB |
| Production (low) | 2048x1024 | 2:1 | ~8 MB |
| Production (standard) | 4096x2048 | 2:1 | ~32 MB |
| Production (high) | 8192x4096 | 2:1 | ~128 MB |
### Cubemap Environments
| Use Case | Face Size | Total Resolution | File Size (HDR x6) |
|----------|----------|------------------|-------------------|
| Preview | 128x128 | 128 | ~0.4 MB |
| Low | 256x256 | 256 | ~1.5 MB |
| Medium | 512x512 | 512 | ~6 MB |
| High | 1024x1024 | 1K | ~24 MB |
| Ultra | 2048x2048 | 2K | ~96 MB |
**Recommendation:** Start with 1024x512 lat-long for development, use 2048x1024 or higher for final renders.
## Testing & Validation
### Energy Conservation Test
White furnace with diffuse white material should reflect exactly the furnace intensity:
```bash
# Generate test environment
hdrgen -p white-furnace --intensity 1.0 -o output/furnace_test.hdr
# In your renderer:
# 1. Load furnace_test.hdr
# 2. Create material: diffuse white (albedo = 1.0)
# 3. Render sphere
# 4. Expected result: sphere appears with color = (1.0, 1.0, 1.0)
```
### Sun Direction Validation
```bash
# Generate known sun position (45° elevation, 90° east)
hdrgen -p sun-sky --sun-elevation 45 --sun-azimuth 90 -o output/sun_test.hdr
# Visual check: Bright spot should be in upper-right quadrant of lat-long image
# Azimuth 90° = right side of image (east)
# Elevation 45° = mid-height of image
```
### Studio Lighting Validation
```bash
# Generate studio environment
hdrgen -p studio -o output/studio_test.hdr
# Expected light positions:
# - Key light: Front-right (bright warm spot)
# - Fill light: Front-left (dimmer cool glow)
# - Rim light: Back (sharp highlight)
```
## Importing in DCCs
### Blender
1. Switch to **Shading** workspace
2. Select **World** shader
3. Add **Environment Texture** node
4. Open generated `.hdr` file
5. Connect to **Background** shader
### Houdini
1. Create **Environment Light**
2. Set **Environment Map** to generated `.hdr` file
3. Adjust **Intensity** if needed
### Maya
1. Create **Skydome Light**
2. Load generated `.hdr` in **Color** attribute
3. Set **Exposure** if needed
### Unreal Engine
1. Import `.hdr` as **Texture Cube** (for cubemaps) or **Texture 2D** (for lat-long)
2. Create **Skylight** actor
3. Set **Source Type** to **SLS Specified Cubemap**
4. Assign texture
### Unity
1. Import `.hdr` file
2. Set **Texture Shape** to **Cube** (for cubemap) or **2D** (for lat-long)
3. In **Lighting** window, assign to **Environment Skybox**
## Technical Details
### Color Space
All generated environments are in **linear color space** (no gamma encoding). This is correct for PBR rendering and HDR textures.
- Input values: Linear RGB
- Output values: Linear RGB (HDR, values can exceed 1.0)
- No sRGB transfer function applied
### HDR Range
Values are unbounded and can significantly exceed 1.0:
- Sun disk: 50-200+ (direct sunlight simulation)
- Sky: 0.1-2.0 (indirect ambient)
- Studio lights: 10-100 (controlled lighting)
- White furnace: 0.1-10.0 (testing range)
### Coordinate System
**Lat-Long (Equirectangular):**
- U (horizontal): 0 = -180° (west), 0.5 = 0° (north), 1.0 = 180° (east)
- V (vertical): 0 = -90° (down), 0.5 = 0° (horizon), 1.0 = 90° (up)
- Direction: +X right, +Y up, +Z forward
**Cubemap (OpenGL Convention):**
- Faces: +X, -X, +Y, -Y, +Z, -Z
- +Y is up (top face)
- Right-handed coordinate system
## Troubleshooting
### Generated files appear too dark/bright
Adjust intensity parameters:
```bash
# Increase sun intensity
hdrgen -p sun-sky --sun-intensity 200 -o output/bright_sky.hdr
# Decrease studio key light
hdrgen -p studio --key-intensity 25 -o output/dim_studio.hdr
```
### Sun position is incorrect
Check azimuth convention:
- 0° = North (top of lat-long image, middle)
- 90° = East (right side of lat-long image)
- 180° = South (bottom, middle)
- 270° = West (left side)
### Cubemap faces don't align properly
Ensure DCC is using OpenGL convention (+Y up). Some DCCs (DirectX convention) may require face reordering.
### EXR files aren't working
Current implementation writes HDR format. For true EXR support, integrate `@openexr/node` or similar library.
## Limitations
- **EXR Writing:** Currently writes HDR format instead (requires external library for true EXR)
- **Sky Model:** Simplified procedural sky (not full Hosek-Wilkie or Nishita)
- **Compression:** HDR files are uncompressed (no RLE compression)
- **Metadata:** Minimal file metadata (no custom tags)
## Roadmap
- [ ] Proper EXR writing with compression
- [ ] More presets (indoor, sunset, overcast, etc.)
- [ ] Importance sampling map generation
- [ ] Diffuse/specular pre-filtering
- [ ] HDRI panorama manipulation (rotate, exposure)
- [ ] Animation (time-of-day sequence)
- [ ] Web-based visualizer
## License
Apache License 2.0
Copyright 2024 - Present, Light Transport Entertainment Inc.
## References
- [HDR Image Formats](https://www.pauldebevec.com/Research/HDR/)
- [Radiance RGBE Format](https://floyd.lbl.gov/radiance/refer/Notes/picture_format.html)
- [OpenEXR Specification](https://www.openexr.com/)
- [PBR Theory](https://www.pbrt.org/)
- [Hosek-Wilkie Sky Model](https://cgg.mff.cuni.cz/projects/SkylightModelling/)
## Contributing
Contributions welcome! Please ensure:
- Code follows existing style
- Tests pass: `npm test`
- Examples work: `npm run example`
- Documentation is updated
## Support
For issues or questions, see: https://github.com/syoyo/tinyusdz