113 lines
4.8 KiB
Markdown
113 lines
4.8 KiB
Markdown
|
|
# Documentation
|
|
- Class name: ConvertNormals
|
|
- Category: image/filters
|
|
- Output node: False
|
|
- Repo Ref: https://github.com/comfyanonymous/ComfyUI
|
|
|
|
ConvertNormals节点专门用于转换法线贴图的格式,调整其比例,并可选择性地进行归一化或填充缺失区域。它支持多种输入和输出模式,能够灵活地调整法线贴图以适应不同的渲染或处理需求。这个节点在图形和图像处理流程中特别有用,尤其是在需要将法线贴图转换或调整以满足特定用途时。
|
|
|
|
# Input types
|
|
## Required
|
|
- normals
|
|
- 需要转换的输入法线贴图张量。这是节点操作的核心参数,它会根据其他输入参数进行各种转换。
|
|
- Comfy dtype: IMAGE
|
|
- Python dtype: torch.Tensor
|
|
- input_mode
|
|
- 指定输入法线贴图的格式,影响其初始处理方式。该参数决定了在进行进一步转换之前,对法线贴图进行的初始调整。
|
|
- Comfy dtype: COMBO[STRING]
|
|
- Python dtype: str
|
|
- output_mode
|
|
- 定义输出法线贴图的期望格式,指导对张量进行最终调整。此参数确保转换后的法线贴图满足特定的格式要求。
|
|
- Comfy dtype: COMBO[STRING]
|
|
- Python dtype: str
|
|
- scale_XY
|
|
- 应用于法线贴图X和Y分量的缩放因子,影响其整体外观。此参数允许微调法线贴图在表面上的视觉效果。
|
|
- Comfy dtype: FLOAT
|
|
- Python dtype: float
|
|
- normalize
|
|
- 一个布尔标志,指示是否在转换后对法线贴图进行归一化。归一化确保法线贴图的向量为单位长度,这通常是为了保证一致的光照效果。
|
|
- Comfy dtype: BOOLEAN
|
|
- Python dtype: bool
|
|
- fix_black
|
|
- 一个布尔标志,当启用时,会对法线贴图中的黑色区域进行修正,可能会基于optional_fill参数填充这些区域。这对于修复或增强具有缺失数据的法线贴图很有用。
|
|
- Comfy dtype: BOOLEAN
|
|
- Python dtype: bool
|
|
## Optional
|
|
- optional_fill
|
|
- 一个可选的张量,用于在启用fix_black时填充法线贴图中的黑色区域。此参数允许应用自定义填充模式或颜色,增强了节点的多功能性。
|
|
- Comfy dtype: IMAGE
|
|
- Python dtype: torch.Tensor
|
|
|
|
# Output types
|
|
- image
|
|
- 转换后的法线贴图张量,根据指定的输入和输出模式、缩放、归一化和可选填充进行调整。这个输出可以直接用于后续的处理或渲染步骤。
|
|
- Comfy dtype: IMAGE
|
|
- Python dtype: torch.Tensor
|
|
|
|
|
|
## Usage tips
|
|
- Infra type: `GPU`
|
|
- Common nodes: unknown
|
|
|
|
|
|
## Source code
|
|
```python
|
|
class ConvertNormals:
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"normals": ("IMAGE",),
|
|
"input_mode": (["BAE", "MiDaS", "Standard"],),
|
|
"output_mode": (["BAE", "MiDaS", "Standard"],),
|
|
"scale_XY": ("FLOAT",{"default": 1, "min": 0, "max": 100, "step": 0.001}),
|
|
"normalize": ("BOOLEAN", {"default": True}),
|
|
"fix_black": ("BOOLEAN", {"default": True}),
|
|
},
|
|
"optional": {
|
|
"optional_fill": ("IMAGE",),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "convert_normals"
|
|
|
|
CATEGORY = "image/filters"
|
|
|
|
def convert_normals(self, normals, input_mode, output_mode, scale_XY, normalize, fix_black, optional_fill=None):
|
|
t = normals.detach().clone()
|
|
|
|
if input_mode == "BAE":
|
|
t[:,:,:,0] = 1 - t[:,:,:,0] # invert R
|
|
elif input_mode == "MiDaS":
|
|
t[:,:,:,:3] = torch.stack([1 - t[:,:,:,2], t[:,:,:,1], t[:,:,:,0]], dim=3) # BGR -> RGB and invert R
|
|
|
|
if fix_black:
|
|
key = torch.clamp(1 - t[:,:,:,2] * 2, min=0, max=1)
|
|
if optional_fill == None:
|
|
t[:,:,:,0] += key * 0.5
|
|
t[:,:,:,1] += key * 0.5
|
|
t[:,:,:,2] += key
|
|
else:
|
|
fill = optional_fill.detach().clone()
|
|
if fill.shape[1:3] != t.shape[1:3]:
|
|
fill = torch.nn.functional.interpolate(fill.movedim(-1,1), size=(t.shape[1], t.shape[2]), mode='bilinear').movedim(1,-1)
|
|
if fill.shape[0] != t.shape[0]:
|
|
fill = fill[0].unsqueeze(0).expand(t.shape[0], -1, -1, -1)
|
|
t[:,:,:,:3] += fill[:,:,:,:3] * key.unsqueeze(3).expand(-1, -1, -1, 3)
|
|
|
|
t[:,:,:,:2] = (t[:,:,:,:2] - 0.5) * scale_XY + 0.5
|
|
|
|
if normalize:
|
|
t[:,:,:,:3] = torch.nn.functional.normalize(t[:,:,:,:3] * 2 - 1, dim=3) / 2 + 0.5
|
|
|
|
if output_mode == "BAE":
|
|
t[:,:,:,0] = 1 - t[:,:,:,0] # invert R
|
|
elif output_mode == "MiDaS":
|
|
t[:,:,:,:3] = torch.stack([t[:,:,:,2], t[:,:,:,1], 1 - t[:,:,:,0]], dim=3) # invert R and BGR -> RGB
|
|
|
|
return (t,)
|
|
|
|
```
|