Source code for procfunc.nodes.shader

import logging
from typing import Any, Literal, NamedTuple

import procfunc as pf
from procfunc import types as pt
from procfunc.nodes import types as nt
from procfunc.nodes.util.bindings_util import (
    raise_error_or_warn,
    raise_shader_normal_error,
)

TBlendType = Literal[
    "MIX",
    "DARKEN",
    "MULTIPLY",
    "BURN",
    "LIGHTEN",
    "SCREEN",
    "DODGE",
    "ADD",
    "OVERLAY",
    "SOFT_LIGHT",
    "LINEAR_LIGHT",
    "DIFFERENCE",
    "EXCLUSION",
    "SUBTRACT",
    "DIVIDE",
    "HUE",
    "SATURATION",
    "COLOR",
    "VALUE",
]
TRenderTarget = Literal["ALL", "EEVEE", "CYCLES"]

logger = logging.getLogger(__name__)


[docs] def add_shader( a: nt.ProcNode[nt.Shader] | None, b: nt.ProcNode[nt.Shader] | None, ) -> nt.ProcNode[nt.Shader]: """ Uses a AddShader Shader Node. Both inputs are required: an unconnected shader input renders pure black, so callers must pass an explicit None to deliberately leave one disconnected. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/add.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeAddShader", inputs={("Shader", 0): a, ("Shader", 1): b}, attrs={}, )
[docs] class AmbientOcclusionResult(NamedTuple): color: nt.ProcNode[pt.Color] ao: nt.ProcNode[float]
[docs] def ambient_occlusion( color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), distance: nt.SocketOrVal[float] = 1.0, normal: nt.SocketOrVal[pt.Vector] = None, inside: bool = False, only_local: bool = False, samples: int = 16, ) -> AmbientOcclusionResult: """ Uses a AmbientOcclusion Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/ao.html """ inputs = {"Color": color, "Distance": distance} if normal is not None: raise_shader_normal_error("ambient_occlusion", logger=logger) inputs["Normal"] = normal res = nt.ProcNode.from_nodetype( node_type="ShaderNodeAmbientOcclusion", inputs=inputs, attrs={"inside": inside, "only_local": only_local, "samples": samples}, ) return AmbientOcclusionResult( color=res._output_socket("color"), ao=res._output_socket("ao") )
[docs] class AttributeResult(NamedTuple): color: nt.ProcNode[pt.Color] vector: nt.ProcNode[pt.Vector] fac: nt.ProcNode[float] alpha: nt.ProcNode[float]
[docs] def attribute( attribute_name: str = "", attribute_type: Literal[ "GEOMETRY", "OBJECT", "INSTANCER", "VIEW_LAYER" ] = "GEOMETRY", ) -> AttributeResult: """ Uses a Attribute Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/attribute.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeAttribute", inputs={}, attrs={"attribute_name": attribute_name, "attribute_type": attribute_type}, ) return AttributeResult( color=res._output_socket("color"), vector=res._output_socket("vector"), fac=res._output_socket("fac"), alpha=res._output_socket("alpha"), )
[docs] def background( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), strength: nt.SocketOrVal[float] = 1.0, ) -> nt.ProcNode[nt.Shader]: """ Uses a Background Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/background.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeBackground", inputs={"Color": color, "Strength": strength}, attrs={}, )
[docs] def bevel( radius: nt.SocketOrVal[float] = 0.05, normal: nt.SocketOrVal[pt.Vector] = None, samples: int = 4, ) -> nt.ProcNode[pt.Vector]: """ Uses a Bevel Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/bevel.html """ inputs = {"Radius": radius} if normal is not None: raise_shader_normal_error("bevel", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBevel", inputs=inputs, attrs={"samples": samples}, )
[docs] def anisotropic_bsdf( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), roughness: nt.SocketOrVal[float] = 0.5, anisotropy: nt.SocketOrVal[float] = 0.0, rotation: nt.SocketOrVal[float] = 0.0, normal: nt.SocketOrVal[pt.Vector] = None, tangent: nt.SocketOrVal[pt.Vector] = (0, 0, 0), distribution: Literal[ "BECKMANN", "GGX", "ASHIKHMIN_SHIRLEY", "MULTI_GGX" ] = "MULTI_GGX", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfAnisotropic Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/principled.html """ # Normal omitted unless wired: unconnected means 'use surface normal', and # strict-None forbids passing None for a value socket. inputs = { "Color": color, "Roughness": roughness, "Anisotropy": anisotropy, "Rotation": rotation, "Tangent": tangent, } if normal is not None: raise_shader_normal_error("anisotropic_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfAnisotropic", inputs=inputs, attrs={"distribution": distribution}, )
[docs] def diffuse_bsdf( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), roughness: nt.SocketOrVal[float] = 0.0, normal: nt.SocketOrVal[pt.Vector] = None, ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfDiffuse Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/diffuse.html """ inputs = {"Color": color, "Roughness": roughness} if normal is not None: raise_shader_normal_error("diffuse_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfDiffuse", inputs=inputs, attrs={}, )
[docs] def glass_bsdf( color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), roughness: nt.SocketOrVal[float] = 0.0, ior: nt.SocketOrVal[float] = 1.5, normal: nt.SocketOrVal[pt.Vector] = None, distribution: Literal["BECKMANN", "GGX", "MULTI_GGX"] = "MULTI_GGX", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfGlass Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/glass.html """ inputs = {"Color": color, "Roughness": roughness, "IOR": ior} if normal is not None: raise_shader_normal_error("glass_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfGlass", inputs=inputs, attrs={"distribution": distribution}, )
[docs] def hair_bsdf( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), offset: nt.SocketOrVal[float] = 0.0, roughness_u: nt.SocketOrVal[float] = 0.1, roughness_v: nt.SocketOrVal[float] = 1.0, tangent: nt.SocketOrVal[pt.Vector] = (0, 0, 0), component: Literal["Reflection", "Transmission"] = "Reflection", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfHair Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/hair.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfHair", inputs={ "Color": color, "Offset": offset, "RoughnessU": roughness_u, "RoughnessV": roughness_v, "Tangent": tangent, }, attrs={"component": component}, )
[docs] def principled_hair_bsdf( color: nt.SocketOrVal[pt.Color] = (0.017513, 0.005763, 0.002059, 1), roughness: nt.SocketOrVal[float] = 0.3, radial_roughness: nt.SocketOrVal[float] = 0.3, coat: nt.SocketOrVal[float] = 0.0, ior: nt.SocketOrVal[float] = 1.55, offset: nt.SocketOrVal[float] = 0.034907, random_roughness: nt.SocketOrVal[float] = 0.0, random: nt.SocketOrVal[float] = 0.0, model: Literal["CHIANG", "HUANG"] = "CHIANG", parametrization: Literal["ABSORPTION", "MELANIN", "COLOR"] = "COLOR", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfHairPrincipled Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/hair_principled.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfHairPrincipled", inputs={ "Color": color, "Roughness": roughness, "Radial Roughness": radial_roughness, "Coat": coat, "IOR": ior, "Offset": offset, "Random Roughness": random_roughness, "Random": random, }, attrs={"model": model, "parametrization": parametrization}, )
TSubsurfaceMethod = Literal["BURLEY", "RANDOM_WALK", "RANDOM_WALK_SKIN"]
[docs] def principled_bsdf( base_color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), metallic: nt.SocketOrVal[float] = 0.0, roughness: nt.SocketOrVal[float] = 0.5, ior: nt.SocketOrVal[float] = 1.5, alpha: nt.SocketOrVal[float] = 1.0, normal: nt.SocketOrVal[pt.Vector] | None = None, # subsurface scattering subsurface_method: TSubsurfaceMethod = "RANDOM_WALK", subsurface_weight: nt.SocketOrVal[float] = 0.0, subsurface_radius: nt.SocketOrVal[pt.Vector] = (1, 0.2, 0.1), subsurface_scale: nt.SocketOrVal[float] = 0.05, subsurface_ior: nt.SocketOrVal[float] | None = None, subsurface_anisotropy: nt.SocketOrVal[float] | None = None, # specular distribution: Literal["GGX", "MULTI_GGX"] = "MULTI_GGX", specular_ior_level: nt.SocketOrVal[float] = 0.5, specular_tint: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), anisotropic: nt.SocketOrVal[float] = 0.0, anisotropic_rotation: nt.SocketOrVal[float] = 0.0, tangent: nt.SocketOrVal[pt.Vector] | None = None, transmission_weight: nt.SocketOrVal[float] = 0.0, coat_weight: nt.SocketOrVal[float] = 0.0, coat_roughness: nt.SocketOrVal[float] = 0.03, coat_ior: nt.SocketOrVal[float] = 1.5, coat_tint: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), coat_normal: nt.SocketOrVal[pt.Vector] | None = None, sheen_weight: nt.SocketOrVal[float] = 0.0, sheen_roughness: nt.SocketOrVal[float] = 0.5, sheen_tint: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), emission_color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), emission_strength: nt.SocketOrVal[float] = 0.0, thin_film_thickness: nt.SocketOrVal[float] = 0.0, thin_film_ior: nt.SocketOrVal[float] = 1.33, ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfPrincipled Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. subsurface_ior: Only supported if subsurface_method is RANDOM_WALK_SKIN. distribution: configurs specular shading See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/principled.html """ if normal is not None or coat_normal is not None: raise_shader_normal_error("principled_bsdf", logger=logger) inputs = { "Base Color": base_color, "Metallic": metallic, "Roughness": roughness, "IOR": ior, "Alpha": alpha, "Subsurface Weight": subsurface_weight, "Subsurface Radius": subsurface_radius, "Subsurface Scale": subsurface_scale, "Specular IOR Level": specular_ior_level, "Specular Tint": specular_tint, "Anisotropic": anisotropic, "Anisotropic Rotation": anisotropic_rotation, "Transmission Weight": transmission_weight, "Coat Weight": coat_weight, "Coat Roughness": coat_roughness, "Coat IOR": coat_ior, "Coat Tint": coat_tint, "Sheen Weight": sheen_weight, "Sheen Roughness": sheen_roughness, "Sheen Tint": sheen_tint, "Emission Color": emission_color, "Emission Strength": emission_strength, "Thin Film Thickness": thin_film_thickness, "Thin Film IOR": thin_film_ior, } if normal is not None: inputs["Normal"] = normal if coat_normal is not None: inputs["Coat Normal"] = coat_normal if tangent is not None: inputs["Tangent"] = tangent if subsurface_ior is not None: assert subsurface_method == "RANDOM_WALK_SKIN" inputs["Subsurface IOR"] = subsurface_ior if subsurface_anisotropy is not None: assert subsurface_method in ["RANDOM_WALK", "RANDOM_WALK_SKIN"] inputs["Subsurface Anisotropy"] = subsurface_anisotropy return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfPrincipled", inputs=inputs, attrs={"distribution": distribution, "subsurface_method": subsurface_method}, )
[docs] def ray_portal_bsdf( color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), position: nt.SocketOrVal[pt.Vector] = (0, 0, 0), direction: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfRayPortal Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/ray_portal.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfRayPortal", inputs={"Color": color, "Position": position, "Direction": direction}, attrs={}, )
[docs] def refraction_bsdf( color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), roughness: nt.SocketOrVal[float] = 0.0, ior: nt.SocketOrVal[float] = 1.45, normal: nt.SocketOrVal[pt.Vector] = None, distribution: Literal["BECKMANN", "GGX"] = "BECKMANN", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfRefraction Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/refraction.html """ inputs = {"Color": color, "Roughness": roughness, "IOR": ior} if normal is not None: raise_shader_normal_error("refraction_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfRefraction", inputs=inputs, attrs={"distribution": distribution}, )
[docs] def sheen_bsdf( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), roughness: nt.SocketOrVal[float] = 0.5, normal: nt.SocketOrVal[pt.Vector] = None, distribution: Literal["ASHIKHMIN", "MICROFIBER"] = "MICROFIBER", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfSheen Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/sheen.html """ inputs = {"Color": color, "Roughness": roughness} if normal is not None: raise_shader_normal_error("sheen_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfSheen", inputs=inputs, attrs={"distribution": distribution}, )
[docs] def toon_bsdf( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), size: nt.SocketOrVal[float] = 0.5, smooth: nt.SocketOrVal[float] = 0.0, normal: nt.SocketOrVal[pt.Vector] = None, component: Literal["DIFFUSE", "GLOSSY"] = "DIFFUSE", ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfToon Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/toon.html """ inputs = {"Color": color, "Size": size, "Smooth": smooth} if normal is not None: raise_shader_normal_error("toon_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfToon", inputs=inputs, attrs={"component": component}, )
[docs] def translucent_bsdf( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), normal: nt.SocketOrVal[pt.Vector] = None, ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfTranslucent Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/translucent.html """ inputs = {"Color": color} if normal is not None: raise_shader_normal_error("translucent_bsdf", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfTranslucent", inputs=inputs, attrs={}, )
[docs] def transparent_bsdf( color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), ) -> nt.ProcNode[nt.Shader]: """ Uses a BsdfTransparent Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/transparent.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeBsdfTransparent", inputs={"Color": color}, attrs={}, )
[docs] def bump( strength: nt.SocketOrVal[float] = 1.0, distance: nt.SocketOrVal[float] = 1.0, height: nt.SocketOrVal[float] = 1.0, normal: nt.SocketOrVal[pt.Vector] = None, invert: bool = False, ) -> nt.ProcNode[pt.Vector]: """ Uses a Bump Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/bump.html """ msg = ( "Using the Bump shader node! We recommend using the shader's Displacement output instead" ", as it has more capabilities e.g. mesh-based displacement " "To suppress this warning, set pf.context.globals.warn_mode_avoid_normal_bump = 'ignore'" ) raise_error_or_warn(msg, pf.context.globals.warn_mode_avoid_normal_bump, logger) inputs = {"Strength": strength, "Distance": distance, "Height": height} if normal is not None: inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeBump", inputs=inputs, attrs={"invert": invert}, )
[docs] class CameraDataResult(NamedTuple): view_vector: nt.ProcNode[pt.Vector] view_z_depth: nt.ProcNode[float] view_distance: nt.ProcNode[float]
[docs] def camera_data() -> CameraDataResult: """ Uses a CameraData Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/camera_data.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeCameraData", inputs={}, attrs={}, ) return CameraDataResult( view_vector=res._output_socket("view_vector"), view_z_depth=res._output_socket("view_z_depth"), view_distance=res._output_socket("view_distance"), )
[docs] def displacement( height: nt.SocketOrVal[float] = 0.0, midlevel: nt.SocketOrVal[float] = 0.5, scale: nt.SocketOrVal[float] = 1.0, normal: nt.SocketOrVal[pt.Vector] | None = None, space: Literal["OBJECT", "WORLD"] = "OBJECT", ) -> nt.ProcNode[pt.Vector]: """ Uses a Displacement Shader Node. A disconnected Normal defaults to the surface normal, so we omit the input entirely when None rather than passing None to a value socket (strict-None policy). See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/displacement.html """ inputs = {"Height": height, "Midlevel": midlevel, "Scale": scale} if normal is not None: inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeDisplacement", inputs=inputs, attrs={"space": space}, )
[docs] def eevee_specular( base_color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), specular: nt.SocketOrVal[pt.Color] = (0.03, 0.03, 0.03, 1), roughness: nt.SocketOrVal[float] = 0.2, emissive_color: nt.SocketOrVal[pt.Color] = (0, 0, 0, 1), transparency: nt.SocketOrVal[float] = 0.0, normal: nt.SocketOrVal[pt.Vector] = None, clear_coat: nt.SocketOrVal[float] = 0.0, clear_coat_roughness: nt.SocketOrVal[float] = 0.0, clear_coat_normal: nt.SocketOrVal[pt.Vector] = None, ) -> nt.ProcNode[nt.Shader]: """ Uses a EeveeSpecular Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/specular_bsdf.html """ inputs = { "Base Color": base_color, "Specular": specular, "Roughness": roughness, "Emissive Color": emissive_color, "Transparency": transparency, "Clear Coat": clear_coat, "Clear Coat Roughness": clear_coat_roughness, } if normal is not None: inputs["Normal"] = normal if clear_coat_normal is not None: inputs["Clear Coat Normal"] = clear_coat_normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeEeveeSpecular", inputs=inputs, attrs={}, )
[docs] def emission( color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), strength: nt.SocketOrVal[float] = 1.0, ) -> nt.ProcNode[nt.Shader]: """ Uses a Emission Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/emission.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeEmission", inputs={"Color": color, "Strength": strength}, attrs={}, )
[docs] def fresnel( ior: nt.SocketOrVal[float] = 1.5, normal: nt.SocketOrVal[pt.Vector] = None ) -> nt.ProcNode[float]: """ Uses a Fresnel Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/fresnel.html """ inputs = {"IOR": ior} if normal is not None: raise_shader_normal_error("fresnel", logger=logger) inputs["Normal"] = normal return nt.ProcNode.from_nodetype( node_type="ShaderNodeFresnel", inputs=inputs, attrs={}, )
[docs] class HairInfoResult(NamedTuple): is_strand: nt.ProcNode[float] intercept: nt.ProcNode[float] length: nt.ProcNode[float] thickness: nt.ProcNode[float] tangent_normal: nt.ProcNode[pt.Vector] random: nt.ProcNode[float]
[docs] def hair_info() -> HairInfoResult: """ Uses a HairInfo Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/hair_info.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeHairInfo", inputs={}, attrs={}, ) return HairInfoResult( is_strand=res._output_socket("is_strand"), intercept=res._output_socket("intercept"), length=res._output_socket("length"), thickness=res._output_socket("thickness"), tangent_normal=res._output_socket("tangent_normal"), random=res._output_socket("random"), )
[docs] def holdout() -> nt.ProcNode[nt.Shader]: """ Uses a Holdout Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/holdout.html """ return nt.ProcNode.from_nodetype(node_type="ShaderNodeHoldout", inputs={}, attrs={})
[docs] def invert( fac: nt.SocketOrVal[float] = 1.0, color: nt.SocketOrVal[pt.Color] = (0, 0, 0, 1) ) -> nt.ProcNode[pt.Color]: """ Uses a Invert Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/color/invert_color.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeInvert", inputs={"Fac": fac, "Color": color}, attrs={}, )
[docs] class LayerWeightResult(NamedTuple): fresnel: nt.ProcNode[float] facing: nt.ProcNode[float]
[docs] def layer_weight( blend: nt.SocketOrVal[float] = 0.5, normal: nt.SocketOrVal[pt.Vector] = (0.0, 0.0, 0.0), ) -> LayerWeightResult: """ Uses a LayerWeight Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/layer_weight.html """ if normal != (0.0, 0.0, 0.0): raise_shader_normal_error("layer_weight", logger=logger) res = nt.ProcNode.from_nodetype( node_type="ShaderNodeLayerWeight", inputs={"Blend": blend, "Normal": normal}, attrs={}, ) return LayerWeightResult( fresnel=res._output_socket("fresnel"), facing=res._output_socket("facing"), )
[docs] class LightFalloffResult(NamedTuple): quadratic: nt.ProcNode[float] linear: nt.ProcNode[float] constant: nt.ProcNode[float]
[docs] def light_falloff( strength: nt.SocketOrVal[float] = 100.0, smooth: nt.SocketOrVal[float] = 0.0 ) -> LightFalloffResult: """ Uses a LightFalloff Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/color/light_falloff.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeLightFalloff", inputs={"Strength": strength, "Smooth": smooth}, attrs={}, ) return LightFalloffResult( quadratic=res._output_socket("quadratic"), linear=res._output_socket("linear"), constant=res._output_socket("constant"), )
[docs] class LightPathResult(NamedTuple): is_camera_ray: nt.ProcNode[float] is_shadow_ray: nt.ProcNode[float] is_diffuse_ray: nt.ProcNode[float] is_glossy_ray: nt.ProcNode[float] is_singular_ray: nt.ProcNode[float] is_reflection_ray: nt.ProcNode[float] is_transmission_ray: nt.ProcNode[float] ray_length: nt.ProcNode[float] ray_depth: nt.ProcNode[float] diffuse_depth: nt.ProcNode[float] glossy_depth: nt.ProcNode[float] transparent_depth: nt.ProcNode[float] transmission_depth: nt.ProcNode[float]
[docs] def light_path() -> LightPathResult: """ Uses a LightPath Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/light_path.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeLightPath", inputs={}, attrs={}, ) return LightPathResult( is_camera_ray=res._output_socket("is_camera_ray"), is_shadow_ray=res._output_socket("is_shadow_ray"), is_diffuse_ray=res._output_socket("is_diffuse_ray"), is_glossy_ray=res._output_socket("is_glossy_ray"), is_singular_ray=res._output_socket("is_singular_ray"), is_reflection_ray=res._output_socket("is_reflection_ray"), is_transmission_ray=res._output_socket("is_transmission_ray"), ray_length=res._output_socket("ray_length"), ray_depth=res._output_socket("ray_depth"), diffuse_depth=res._output_socket("diffuse_depth"), glossy_depth=res._output_socket("glossy_depth"), transparent_depth=res._output_socket("transparent_depth"), transmission_depth=res._output_socket("transmission_depth"), )
[docs] def mapping( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), location: nt.SocketOrVal[pt.Vector] = (0, 0, 0), rotation: nt.SocketOrVal[pt.Vector] = (0, 0, 0), scale: nt.SocketOrVal[pt.Vector] = (1, 1, 1), vector_type: Literal["POINT", "TEXTURE", "VECTOR", "NORMAL"] = "POINT", ) -> nt.ProcNode[pt.Vector]: """ Uses a Mapping Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/mapping.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeMapping", inputs={ "Vector": vector, "Location": location, "Rotation": rotation, "Scale": scale, }, attrs={"vector_type": vector_type}, )
[docs] def mix_shader( factor: nt.SocketOrVal[float], a: nt.ProcNode[nt.Shader] | None, b: nt.ProcNode[nt.Shader] | None, ) -> nt.ProcNode[nt.Shader]: """ Uses a MixShader Shader Node. All inputs are required: an unconnected shader input renders pure black, so callers must pass an explicit None to deliberately leave one disconnected. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/mix.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeMixShader", inputs={"Fac": factor, ("Shader", 0): a, ("Shader", 1): b}, attrs={}, )
[docs] class NormalResult(NamedTuple): normal: nt.ProcNode[pt.Vector] dot: nt.ProcNode[float]
[docs] def normal(normal: nt.SocketOrVal[pt.Vector] = (0, 0, 1)) -> NormalResult: """ Uses a Normal Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/normal.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeNormal", inputs={"Normal": normal}, attrs={}, ) return NormalResult( normal=res._output_socket("normal"), dot=res._output_socket("dot"), )
[docs] def normal_map( strength: nt.SocketOrVal[float] = 1.0, color: nt.SocketOrVal[pt.Color] = (0.5, 0.5, 1, 1), space: Literal[ "TANGENT", "OBJECT", "WORLD", "BLENDER_OBJECT", "BLENDER_WORLD" ] = "TANGENT", uv_map: str = "", ) -> nt.ProcNode[pt.Vector]: """ Uses a NormalMap Shader Node. This node is discouraged. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/normal_map.html """ raise_shader_normal_error("normal_map", logger=logger) return nt.ProcNode.from_nodetype( node_type="ShaderNodeNormalMap", inputs={"Strength": strength, "Color": color}, attrs={"space": space, "uv_map": uv_map}, )
[docs] class ObjectInfoResult(NamedTuple): location: nt.ProcNode[pt.Vector] color: nt.ProcNode[pt.Color] alpha: nt.ProcNode[float] object_index: nt.ProcNode[int] material_index: nt.ProcNode[int] random: nt.ProcNode[float]
[docs] def object_info() -> ObjectInfoResult: """ Uses a ObjectInfo Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/object_info.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeObjectInfo", inputs={}, attrs={}, ) return ObjectInfoResult( location=res._output_socket("location"), color=res._output_socket("color"), alpha=res._output_socket("alpha"), object_index=res._output_socket("object_index"), material_index=res._output_socket("material_index"), random=res._output_socket("random"), )
# NOTE: procfunc expects python code to `return LightResult()` instead ''' def output_aov( color: t.SocketOrVal[pt.Color] = (0, 0, 0, 1), value: t.SocketOrVal[float] = 0.0, aov_name: str = "", ) -> t.ProcNode: """ Uses a OutputAOV Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/output/aov.html """ raise_io_error("output_aov", logger=logger) return t.ProcNode.from_nodetype( node_type="ShaderNodeOutputAOV", inputs={"Color": color, "Value": value}, attrs={"aov_name": aov_name}, ) def output_light( surface: t.ProcNode[t.Shader] = None, is_active_output: bool = True, target: TRenderTarget = "ALL", ) -> t.ProcNode: """ Uses a OutputLight Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/output/light.html """ raise_io_error("output_light", logger=logger) return t.ProcNode.from_nodetype( node_type="ShaderNodeOutputLight", inputs={"Surface": surface}, attrs={"is_active_output": is_active_output, "target": target}, ) def output_line_style( color: t.SocketOrVal[pt.Color] = (1, 0, 1, 1), color_fac: t.SocketOrVal[float] = 1.0, alpha: t.SocketOrVal[float] = 1.0, alpha_fac: t.SocketOrVal[float] = 1.0, blend_type: TBlendType = "MIX", is_active_output: bool = True, target: TRenderTarget = "ALL", use_alpha: bool = False, ) -> t.ProcNode: """ Uses a OutputLineStyle Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/output/aov.html """ raise_io_error("output_line_style", logger=logger) return t.ProcNode.from_nodetype( node_type="ShaderNodeOutputLineStyle", inputs={ "Color": color, "Color Fac": color_fac, "Alpha": alpha, "Alpha Fac": alpha_fac, }, attrs={ "blend_type": blend_type, "is_active_output": is_active_output, "target": target, "use_alpha": use_alpha, }, ) def output_material( surface: t.ProcNode[t.Shader] = None, volume: t.ProcNode[t.Shader] = None, displacement: t.SocketOrVal[pt.Vector] = (0, 0, 0), thickness: t.SocketOrVal[float] = 0.0, is_active_output: bool = True, target: TRenderTarget = "ALL", ) -> t.ProcNode: """ Uses a OutputMaterial Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/output/material.html """ return t.ProcNode.from_nodetype( node_type="ShaderNodeOutputMaterial", inputs={ "Surface": surface, "Volume": volume, "Displacement": displacement, "Thickness": thickness, }, attrs={"is_active_output": is_active_output, "target": target}, ) ''' ''' def output_world( surface: t.ProcNode[t.Shader] = None, volume: t.ProcNode[t.Shader] = None, is_active_output: bool = True, target: TRenderTarget = "ALL", ) -> t.ProcNode: """ Uses a OutputWorld Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/output/world.html """ return t.ProcNode.from_nodetype( node_type="ShaderNodeOutputWorld", inputs={"Surface": surface, "Volume": volume}, attrs={"is_active_output": is_active_output, "target": target}, ) '''
[docs] class ParticleInfoResult(NamedTuple): index: nt.ProcNode[int] random: nt.ProcNode[float] age: nt.ProcNode[float] lifetime: nt.ProcNode[float] location: nt.ProcNode[pt.Vector] size: nt.ProcNode[float] velocity: nt.ProcNode[pt.Vector] angular_velocity: nt.ProcNode[pt.Vector]
[docs] def particle_info() -> ParticleInfoResult: """ Uses a ParticleInfo Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/particle_info.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeParticleInfo", inputs={}, attrs={}, ) return ParticleInfoResult( index=res._output_socket("index"), random=res._output_socket("random"), age=res._output_socket("age"), lifetime=res._output_socket("lifetime"), location=res._output_socket("location"), size=res._output_socket("size"), velocity=res._output_socket("velocity"), angular_velocity=res._output_socket("angular_velocity"), )
[docs] class PointInfoResult(NamedTuple): position: nt.ProcNode[pt.Vector] radius: nt.ProcNode[float] random: nt.ProcNode[float]
[docs] def point_info() -> PointInfoResult: """ Uses a PointInfo Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/point_info.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodePointInfo", inputs={}, attrs={}, ) return PointInfoResult( position=res._output_socket("position"), radius=res._output_socket("radius"), random=res._output_socket("random"), )
[docs] def script( bytecode: str = "", bytecode_hash: str = "", filepath: str = "", mode: Literal["INTERNAL", "EXTERNAL"] = "INTERNAL", script: Any = None, use_auto_update: bool = False, ) -> nt.ProcNode[nt.Shader]: """ Uses a Script Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/osl.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeScript", inputs={}, attrs={ "bytecode": bytecode, "bytecode_hash": bytecode_hash, "filepath": filepath, "mode": mode, "script": script, "use_auto_update": use_auto_update, }, )
[docs] class ShaderToRGBResult(NamedTuple): color: nt.ProcNode[pt.Color] alpha: nt.ProcNode[float]
[docs] def shader_to_rgb( shader: nt.ProcNode[nt.Shader] | None, ) -> ShaderToRGBResult: """ Uses a ShaderToRGB Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/shader_to_rgb.html """ node = nt.ProcNode.from_nodetype( node_type="ShaderNodeShaderToRGB", inputs={"Shader": shader}, attrs={}, ) return ShaderToRGBResult(node._output_socket("color"), node._output_socket("alpha"))
[docs] def squeeze( value: nt.SocketOrVal[float] = 0.0, width: nt.SocketOrVal[float] = 1.0, center: nt.SocketOrVal[float] = 0.0, ) -> nt.ProcNode[float]: """ Uses a Squeeze Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/map_range.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeSqueeze", inputs={"Value": value, "Width": width, "Center": center}, attrs={}, )
[docs] def subsurface_scattering( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), scale: nt.SocketOrVal[float] = 0.05, radius: nt.SocketOrVal[pt.Vector] = (1, 0.2, 0.1), ior: nt.SocketOrVal[float] = 1.4, roughness: nt.SocketOrVal[float] = 1.0, anisotropy: nt.SocketOrVal[float] = 0.0, normal: nt.SocketOrVal[pt.Vector] = (0.0, 0.0, 0.0), falloff: Literal["BURLEY", "RANDOM_WALK", "RANDOM_WALK_SKIN"] = "RANDOM_WALK", ) -> nt.ProcNode[nt.Shader]: """ Uses a SubsurfaceScattering Shader Node. Args: normal: Avoid using this input. We recommend using the shader's Displacement output instead, which supports bumpmapping OR real mesh render/export. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/volume_scatter.html """ if normal != (0.0, 0.0, 0.0): raise_shader_normal_error("subsurface_scattering", logger=logger) return nt.ProcNode.from_nodetype( node_type="ShaderNodeSubsurfaceScattering", inputs={ "Color": color, "Scale": scale, "Radius": radius, "IOR": ior, "Roughness": roughness, "Anisotropy": anisotropy, "Normal": normal, }, attrs={"falloff": falloff}, )
[docs] def tangent( axis: Literal["X", "Y", "Z"] = "Z", direction_type: Literal["RADIAL", "UV_MAP"] = "RADIAL", uv_map: str = "", ) -> nt.ProcNode[pt.Vector]: """ Uses a Tangent Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/tangent.html """ if uv_map != "" and direction_type != "UV_MAP": raise ValueError("uv_map is only available when direction_type is UV_MAP") return nt.ProcNode.from_nodetype( node_type="ShaderNodeTangent", inputs={}, attrs={"axis": axis, "direction_type": direction_type, "uv_map": uv_map}, )
[docs] class CoordResult(NamedTuple): generated: nt.ProcNode[pt.Vector] normal: nt.ProcNode[pt.Vector] uv: nt.ProcNode[pt.Vector] object: nt.ProcNode[pt.Vector] camera: nt.ProcNode[pt.Vector] window: nt.ProcNode[pt.Vector] reflection: nt.ProcNode[pt.Vector]
[docs] def coord(from_instancer: bool = False, object: Any = None) -> CoordResult: """ Uses a TexCoord Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/texture_coordinate.html """ res = nt.ProcNode.from_nodetype( node_type="ShaderNodeTexCoord", inputs={}, attrs={"from_instancer": from_instancer, "object": object}, ) return CoordResult( generated=res._output_socket("generated"), normal=res._output_socket("normal"), uv=res._output_socket("uv"), object=res._output_socket("object"), camera=res._output_socket("camera"), window=res._output_socket("window"), reflection=res._output_socket("reflection"), )
[docs] class GeometryResult(NamedTuple): position: nt.ProcNode[pt.Vector] normal: nt.ProcNode[pt.Vector] tangent: nt.ProcNode[pt.Vector] true_normal: nt.ProcNode[pt.Vector] incoming: nt.ProcNode[pt.Vector] parametric: nt.ProcNode[pt.Vector] backfacing: nt.ProcNode[float] pointiness: nt.ProcNode[float] random_per_island: nt.ProcNode[float]
[docs] def geometry() -> GeometryResult: res = nt.ProcNode.from_nodetype( node_type="ShaderNodeNewGeometry", inputs={}, attrs={}, ) return GeometryResult( position=res._output_socket("position"), normal=res._output_socket("normal"), tangent=res._output_socket("tangent"), true_normal=res._output_socket("true_normal"), incoming=res._output_socket("incoming"), parametric=res._output_socket("parametric"), backfacing=res._output_socket("backfacing"), pointiness=res._output_socket("pointiness"), random_per_island=res._output_socket("random_per_island"), )
[docs] def uv_along_stroke(use_tips: bool = False) -> nt.ProcNode[pt.Vector]: """ Uses a UVAlongStroke Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/uv_map.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeUVAlongStroke", inputs={}, attrs={"use_tips": use_tips}, )
[docs] def uv_map(from_instancer: bool = False, uv_map: str = "") -> nt.ProcNode[pt.Vector]: """ Uses a UVMap Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/uv_map.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeUVMap", inputs={}, attrs={"from_instancer": from_instancer, "uv_map": uv_map}, )
[docs] def vector_displacement( vector: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), midlevel: nt.SocketOrVal[float] = 0.0, scale: nt.SocketOrVal[float] = 1.0, space: Literal["TANGENT", "OBJECT", "WORLD"] = "TANGENT", ) -> nt.ProcNode[pt.Vector]: """ Uses a VectorDisplacement Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/vector_displacement.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorDisplacement", inputs={"Vector": vector, "Midlevel": midlevel, "Scale": scale}, attrs={"space": space}, )
[docs] class VertexColorResult(NamedTuple): color: nt.ProcNode[pt.Color] alpha: nt.ProcNode[float]
[docs] def vertex_color(layer_name: str = "") -> VertexColorResult: """ Uses a VertexColor Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/vertex_color.html """ node = nt.ProcNode.from_nodetype( node_type="ShaderNodeVertexColor", inputs={}, attrs={"layer_name": layer_name}, ) return VertexColorResult(node._output_socket("color"), node._output_socket("alpha"))
[docs] def volume_absorption( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), density: nt.SocketOrVal[float] = 1.0, ) -> nt.ProcNode[nt.Shader]: """ Uses a VolumeAbsorption Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/volume_absorption.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeVolumeAbsorption", inputs={"Color": color, "Density": density}, attrs={}, )
[docs] class VolumeInfoResult(NamedTuple): color: nt.ProcNode[pt.Color] density: nt.ProcNode[float] flame: nt.ProcNode[float] temperature: nt.ProcNode[float]
[docs] def volume_info() -> VolumeInfoResult: """ Uses a VolumeInfo Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/volume_info.html """ node = nt.ProcNode.from_nodetype( node_type="ShaderNodeVolumeInfo", inputs={}, attrs={}, ) return VolumeInfoResult( node._output_socket("color"), node._output_socket("density"), node._output_socket("flame"), node._output_socket("temperature"), )
[docs] def volume_principled( color: nt.SocketOrVal[pt.Color] = (0.5, 0.5, 0.5, 1), color_attribute: nt.SocketOrVal[str] = "", density: nt.SocketOrVal[float] = 1.0, density_attribute: nt.SocketOrVal[str] = "density", anisotropy: nt.SocketOrVal[float] = 0.0, absorption_color: nt.SocketOrVal[pt.Color] = (0, 0, 0, 1), emission_strength: nt.SocketOrVal[float] = 0.0, emission_color: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), blackbody_intensity: nt.SocketOrVal[float] = 0.0, blackbody_tint: nt.SocketOrVal[pt.Color] = (1, 1, 1, 1), temperature: nt.SocketOrVal[float] = 1000.0, temperature_attribute: nt.SocketOrVal[str] = "temperature", ) -> nt.ProcNode[nt.Shader]: """ Uses a VolumePrincipled Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/volume_principled.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeVolumePrincipled", inputs={ "Color": color, "Color Attribute": color_attribute, "Density": density, "Density Attribute": density_attribute, "Anisotropy": anisotropy, "Absorption Color": absorption_color, "Emission Strength": emission_strength, "Emission Color": emission_color, "Blackbody Intensity": blackbody_intensity, "Blackbody Tint": blackbody_tint, "Temperature": temperature, "Temperature Attribute": temperature_attribute, }, attrs={}, )
[docs] def volume_scatter( color: nt.SocketOrVal[pt.Color] = (0.8, 0.8, 0.8, 1), density: nt.SocketOrVal[float] = 1.0, anisotropy: nt.SocketOrVal[float] = 0.0, ) -> nt.ProcNode[nt.Shader]: """ Uses a VolumeScatter Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/shader/volume_scatter.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeVolumeScatter", inputs={"Color": color, "Density": density, "Anisotropy": anisotropy}, attrs={}, )
[docs] def wavelength(wavelength: nt.SocketOrVal[float] = 500.0) -> nt.ProcNode[pt.Color]: """ Uses a Wavelength Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/wavelength.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeWavelength", inputs={"Wavelength": wavelength}, attrs={}, )
[docs] def wireframe( size: nt.SocketOrVal[float] = 0.01, use_pixel_size: bool = False ) -> nt.ProcNode[float]: """ Uses a Wireframe Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/input/wireframe.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeWireframe", inputs={"Size": size}, attrs={"use_pixel_size": use_pixel_size}, )