Files
2024-07-04 11:34:32 +08:00

4.8 KiB

Documentation

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

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,)