adding more nodes
This commit is contained in:
66
backend/nodes/shade.py
Normal file
66
backend/nodes/shade.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""Shaded presentation — render surface with directional lighting."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
from scipy.ndimage import sobel
|
||||
|
||||
from backend.node_registry import register_node
|
||||
from backend.data_types import DataField
|
||||
|
||||
|
||||
@register_node(display_name="Shade")
|
||||
class Shade:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"field": ("DATA_FIELD",),
|
||||
"azimuth": ("FLOAT", {"default": 315.0, "min": 0.0, "max": 360.0, "step": 1.0}),
|
||||
"elevation": ("FLOAT", {"default": 45.0, "min": 5.0, "max": 85.0, "step": 1.0}),
|
||||
"blend": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.05}),
|
||||
}
|
||||
}
|
||||
|
||||
OUTPUTS = (
|
||||
('DATA_FIELD', 'shaded'),
|
||||
)
|
||||
FUNCTION = "process"
|
||||
|
||||
DESCRIPTION = (
|
||||
"Render a surface with directional hillshade lighting. "
|
||||
"Azimuth controls the light direction (0=north, 90=east). "
|
||||
"Elevation controls the light angle above the horizon. "
|
||||
"Blend mixes original data (0) with shaded relief (1). "
|
||||
)
|
||||
|
||||
def process(self, field: DataField, azimuth: float, elevation: float,
|
||||
blend: float) -> tuple:
|
||||
data = np.asarray(field.data, dtype=np.float64)
|
||||
|
||||
gx = sobel(data, axis=1) / (8.0 * field.dx)
|
||||
gy = sobel(data, axis=0) / (8.0 * field.dy)
|
||||
|
||||
az_rad = np.radians(azimuth)
|
||||
el_rad = np.radians(elevation)
|
||||
|
||||
# Lambertian shading
|
||||
lx = np.cos(el_rad) * np.sin(az_rad)
|
||||
ly = np.cos(el_rad) * np.cos(az_rad)
|
||||
lz = np.sin(el_rad)
|
||||
|
||||
normal_z = 1.0 / np.sqrt(gx**2 + gy**2 + 1.0)
|
||||
normal_x = -gx * normal_z
|
||||
normal_y = -gy * normal_z
|
||||
|
||||
shade = np.clip(normal_x * lx + normal_y * ly + normal_z * lz, 0.0, 1.0)
|
||||
|
||||
# Normalize original data to [0, 1]
|
||||
dmin, dmax = data.min(), data.max()
|
||||
if dmax > dmin:
|
||||
norm_data = (data - dmin) / (dmax - dmin)
|
||||
else:
|
||||
norm_data = np.ones_like(data) * 0.5
|
||||
|
||||
result = (1.0 - blend) * norm_data + blend * shade
|
||||
return (field.replace(data=result, si_unit_z=""),)
|
||||
Reference in New Issue
Block a user