Files
DobidopandClaude c2b3bb5a50 Merge ComfyStereoViewer and StereoscopeGenerator into unified ComfyStereo
Combines three powerful stereoscopic tools into one comprehensive package:

1. Core Stereo Generation
   - Depth-based stereo conversion with GPU acceleration
   - Advanced fill techniques (Polylines, GPU Warp, Hybrid Edge, etc.)
   - Edge-aware depth blurring for artifact reduction
   - Side-by-Side, Top-Bottom, and Red-Cyan Anaglyph output formats

2. Native VR Viewing (Optional - requires PyOpenXR)
   - Auto-launch directly into VR headset without browser
   - Support for all VR headsets (Quest, Vive, Index, WMR)
   - Multiple projection types (Flat, Curved, 180° Dome, 360° Sphere)
   - Image and video playback support

3. StereoDiffusion AI (Optional - requires diffusers)
   - AI-powered stereo generation using diffusion models
   - DDIM inversion with null-text optimization
   - Bilateral Neighbor Attention for stereo consistency
   - Works with ComfyUI MODEL/CLIP/VAE or HuggingFace models

Changes:
- Added native_viewer/ module with PyOpenXR implementation
- Added native_nodes.py with 3 VR viewer nodes
- Added stereodiffusion_nodes.py with AI stereo generation
- Added supporting modules: model_wrappers, model_loader, inversion,
  stereo_utils, diffusion_utils
- Updated __init__.py with graceful optional dependency handling
- Consolidated all requirements into single requirements.txt
- Comprehensive README with setup guides and troubleshooting
- Added NOTICE and licenses/ for proper attribution

The package now offers 6+ nodes total with modular installation options.
Users can install just the base, or add VR viewing and/or AI generation.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 22:10:56 +01:00

188 lines
5.7 KiB
Python

"""
Geometry creation functions for different projection types
"""
import math
import numpy as np
def create_sphere_mesh(radius=100.0, segments=60, rings=40):
"""Create sphere geometry for 360° viewing"""
vertices = []
indices = []
# Generate vertices
for ring in range(rings + 1):
theta = ring * math.pi / rings
sin_theta = math.sin(theta)
cos_theta = math.cos(theta)
for seg in range(segments + 1):
phi = seg * 2 * math.pi / segments
sin_phi = math.sin(phi)
cos_phi = math.cos(phi)
# Position
x = radius * sin_theta * cos_phi
y = radius * cos_theta
z = radius * sin_theta * sin_phi
# UV coordinates (flipped for inside viewing)
u = 1.0 - (seg / segments)
v = ring / rings
vertices.extend([x, y, z, u, v])
# Generate indices
for ring in range(rings):
for seg in range(segments):
first = ring * (segments + 1) + seg
second = first + segments + 1
# Two triangles per quad
indices.extend([first, second, first + 1])
indices.extend([second, second + 1, first + 1])
return np.array(vertices, dtype=np.float32), np.array(indices, dtype=np.uint32)
def create_flat_screen(width=3.0, height=2.25, distance=3.0, horizontal_offset=0.0, vertical_offset=0.0):
"""Create flat screen geometry (like a cinema screen in VR)"""
vertices = []
indices = []
# Calculate aspect ratio preserving dimensions
half_width = width / 2.0
half_height = height / 2.0
# Create a simple quad facing the viewer
# Position the screen at the given distance
z = -distance
# In VR, y=0 is typically floor level, eye level is around 1.5-1.7m
# Position screen center at typical seated eye height (~1.2m)
eye_height = 1.2
y_offset = eye_height + vertical_offset
# Horizontal offset for user adjustment
x_offset = horizontal_offset
# Four corners of the screen (centered at eye height)
positions = [
[-half_width + x_offset, -half_height + y_offset, z], # Bottom left
[half_width + x_offset, -half_height + y_offset, z], # Bottom right
[half_width + x_offset, half_height + y_offset, z], # Top right
[-half_width + x_offset, half_height + y_offset, z], # Top left
]
# UV coordinates
uvs = [
[0.0, 1.0], # Bottom left
[1.0, 1.0], # Bottom right
[1.0, 0.0], # Top right
[0.0, 0.0], # Top left
]
# Build vertices
for i in range(4):
vertices.extend(positions[i])
vertices.extend(uvs[i])
# Two triangles to form the quad
indices = [0, 1, 2, 0, 2, 3]
return np.array(vertices, dtype=np.float32), np.array(indices, dtype=np.uint32)
def create_curved_screen(width=3.0, height=2.25, distance=3.0, curve_amount=0.3,
horizontal_offset=0.0, vertical_offset=0.0):
"""Create curved screen geometry (gently curved like IMAX)"""
vertices = []
indices = []
segments_h = 20 # Horizontal segments for curvature
segments_v = 10 # Vertical segments
half_height = height / 2.0
# In VR, y=0 is typically floor level, eye level is around 1.5-1.7m
# Position screen center at typical seated eye height (~1.2m)
eye_height = 1.2
y_offset = eye_height + vertical_offset
# Horizontal offset for user adjustment
x_offset = horizontal_offset
for v in range(segments_v + 1):
# Center screen at eye height
y = -half_height + (v / segments_v) * height + y_offset
v_uv = 1.0 - (v / segments_v)
for h in range(segments_h + 1):
# Create curve using an arc
angle = (h / segments_h - 0.5) * math.pi * curve_amount
x = distance * math.sin(angle)
z = -distance * math.cos(angle)
# Scale x based on desired width
x = x * (width / (2.0 * distance * math.sin(math.pi * curve_amount / 2.0)))
# Apply horizontal offset
x = x + x_offset
u = h / segments_h
vertices.extend([x, y, z, u, v_uv])
# Generate indices
for v in range(segments_v):
for h in range(segments_h):
first = v * (segments_h + 1) + h
second = first + segments_h + 1
indices.extend([first, second, first + 1])
indices.extend([second, second + 1, first + 1])
return np.array(vertices, dtype=np.float32), np.array(indices, dtype=np.uint32)
def create_dome_180(radius=10.0, segments=60):
"""Create 180° dome/hemisphere geometry"""
vertices = []
indices = []
rings = segments // 2
# Generate only the front hemisphere
for ring in range(rings + 1):
theta = ring * (math.pi / 2) / rings # 0 to π/2 (front hemisphere)
sin_theta = math.sin(theta)
cos_theta = math.cos(theta)
for seg in range(segments + 1):
phi = seg * math.pi / segments # 0 to π (180 degrees horizontally)
sin_phi = math.sin(phi)
cos_phi = math.cos(phi)
# Position
x = radius * sin_theta * sin_phi
y = radius * cos_theta
z = -radius * sin_theta * cos_phi
# UV coordinates
u = seg / segments
v = ring / rings
vertices.extend([x, y, z, u, v])
# Generate indices
for ring in range(rings):
for seg in range(segments):
first = ring * (segments + 1) + seg
second = first + segments + 1
indices.extend([first, second, first + 1])
indices.extend([second, second + 1, first + 1])
return np.array(vertices, dtype=np.float32), np.array(indices, dtype=np.uint32)