216 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			216 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|  | """
 | ||
|  | This module contains a list of all material nodes that Leenkx supports | ||
|  | (excluding output nodes), as well as Leenkx-related metadata. | ||
|  | """
 | ||
|  | from enum import IntEnum, unique | ||
|  | from dataclasses import dataclass | ||
|  | from typing import Any, Callable, Optional | ||
|  | 
 | ||
|  | import bpy | ||
|  | 
 | ||
|  | import lnx.material.lnx_nodes.shader_data_node as shader_data_node | ||
|  | import lnx.material.cycles_nodes.nodes_color as nodes_color | ||
|  | import lnx.material.cycles_nodes.nodes_converter as nodes_converter | ||
|  | import lnx.material.cycles_nodes.nodes_input as nodes_input | ||
|  | import lnx.material.cycles_nodes.nodes_shader as nodes_shader | ||
|  | import lnx.material.cycles_nodes.nodes_texture as nodes_texture | ||
|  | import lnx.material.cycles_nodes.nodes_vector as nodes_vector | ||
|  | import lnx.material.parser_state | ||
|  | 
 | ||
|  | if lnx.is_reload(__name__): | ||
|  |     shader_data_node = lnx.reload_module(shader_data_node) | ||
|  |     nodes_color = lnx.reload_module(nodes_color) | ||
|  |     nodes_converter = lnx.reload_module(nodes_converter) | ||
|  |     nodes_input = lnx.reload_module(nodes_input) | ||
|  |     nodes_shader = lnx.reload_module(nodes_shader) | ||
|  |     nodes_texture = lnx.reload_module(nodes_texture) | ||
|  |     nodes_vector = lnx.reload_module(nodes_vector) | ||
|  |     lnx.material.parser_state = lnx.reload_module(lnx.material.parser_state) | ||
|  | else: | ||
|  |     lnx.enable_reload(__name__) | ||
|  | 
 | ||
|  | 
 | ||
|  | @unique | ||
|  | class ComputeDXDYVariant(IntEnum): | ||
|  |     ALWAYS = 0 | ||
|  |     """Always compute dx/dy variants of the corresponding node.
 | ||
|  |     Use this for input nodes that represent leafs of the node graph | ||
|  |     if some of their output values vary between fragments. | ||
|  |     """
 | ||
|  | 
 | ||
|  |     NEVER = 1 | ||
|  |     """Never compute dx/dy variants of the corresponding node.
 | ||
|  |     Use this for nodes whose output values do not change with respect | ||
|  |     to fragment positions. | ||
|  |     """
 | ||
|  | 
 | ||
|  |     DYNAMIC = 2 | ||
|  |     """Compute dx/dy variants if any input socket of the corresponding node
 | ||
|  |     is connected to a node that requires dx/dy variants. | ||
|  |     """
 | ||
|  | 
 | ||
|  | 
 | ||
|  | @dataclass | ||
|  | class MaterialNodeMeta: | ||
|  |     # Use Any here due to contravariance | ||
|  |     parse_func: Callable[[Any, bpy.types.NodeSocket, lnx.material.parser_state.ParserState], Optional[str]] | ||
|  |     """The function used to parse this node and to translate it to GLSL output code.""" | ||
|  | 
 | ||
|  |     compute_dxdy_variants: ComputeDXDYVariant = ComputeDXDYVariant.DYNAMIC | ||
|  |     """Specifies when this node should compute dx/dy variants
 | ||
|  |     if the ParserState is in the dx/dy offset pass. | ||
|  |     """
 | ||
|  | 
 | ||
|  | 
 | ||
|  | ALL_NODES: dict[str, MaterialNodeMeta] = { | ||
|  |     # --- nodes_color | ||
|  |     'BRIGHTCONTRAST': MaterialNodeMeta(parse_func=nodes_color.parse_brightcontrast), | ||
|  |     'CURVE_RGB': MaterialNodeMeta(parse_func=nodes_color.parse_curvergb), | ||
|  |     'GAMMA': MaterialNodeMeta(parse_func=nodes_color.parse_gamma), | ||
|  |     'HUE_SAT': MaterialNodeMeta(parse_func=nodes_color.parse_huesat), | ||
|  |     'INVERT': MaterialNodeMeta(parse_func=nodes_color.parse_invert), | ||
|  |     'LIGHT_FALLOFF': MaterialNodeMeta(parse_func=nodes_color.parse_lightfalloff), | ||
|  |     'MIX': MaterialNodeMeta(parse_func=nodes_color.parse_mix), | ||
|  | 
 | ||
|  |     # --- nodes_converter | ||
|  |     'BLACKBODY': MaterialNodeMeta(parse_func=nodes_converter.parse_blackbody), | ||
|  |     'CLAMP': MaterialNodeMeta(parse_func=nodes_converter.parse_clamp), | ||
|  |     'COMBHSV': MaterialNodeMeta(parse_func=nodes_converter.parse_combhsv), | ||
|  |     'COMBRGB': MaterialNodeMeta(parse_func=nodes_converter.parse_combrgb), | ||
|  |     'COMBXYZ': MaterialNodeMeta(parse_func=nodes_converter.parse_combxyz), | ||
|  |     'MAP_RANGE': MaterialNodeMeta(parse_func=nodes_converter.parse_maprange), | ||
|  |     'MATH': MaterialNodeMeta(parse_func=nodes_converter.parse_math), | ||
|  |     'RGBTOBW': MaterialNodeMeta(parse_func=nodes_converter.parse_rgbtobw), | ||
|  |     'SEPHSV': MaterialNodeMeta(parse_func=nodes_converter.parse_sephsv), | ||
|  |     'SEPRGB': MaterialNodeMeta(parse_func=nodes_converter.parse_seprgb), | ||
|  |     'SEPXYZ': MaterialNodeMeta(parse_func=nodes_converter.parse_sepxyz), | ||
|  |     'VALTORGB': MaterialNodeMeta(parse_func=nodes_converter.parse_valtorgb),  # ColorRamp | ||
|  |     'VECT_MATH': MaterialNodeMeta(parse_func=nodes_converter.parse_vectormath), | ||
|  |     'WAVELENGTH': MaterialNodeMeta(parse_func=nodes_converter.parse_wavelength), | ||
|  | 
 | ||
|  |     # --- nodes_input | ||
|  |     'ATTRIBUTE': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_attribute, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'CAMERA': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_camera, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'FRESNEL': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_fresnel, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'HAIR_INFO': MaterialNodeMeta(parse_func=nodes_input.parse_hairinfo), | ||
|  |     'LAYER_WEIGHT': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_layerweight, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'LIGHT_PATH': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_lightpath, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'NEW_GEOMETRY': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_geometry, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'OBJECT_INFO': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_objectinfo, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'PARTICLE_INFO': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_particleinfo, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'RGB': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_rgb, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'TANGENT': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_tangent, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'TEX_COORD': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_texcoord, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'UVMAP': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_uvmap, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ), | ||
|  |     'VALUE': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_value, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'VERTEX_COLOR': MaterialNodeMeta(parse_func=nodes_input.parse_vertex_color), | ||
|  |     'WIREFRAME': MaterialNodeMeta( | ||
|  |         parse_func=nodes_input.parse_wireframe, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  | 
 | ||
|  |     # --- nodes_shader | ||
|  |     'ADD_SHADER': MaterialNodeMeta(parse_func=nodes_shader.parse_addshader), | ||
|  |     'AMBIENT_OCCLUSION': MaterialNodeMeta(parse_func=nodes_shader.parse_ambientocclusion), | ||
|  |     'BSDF_ANISOTROPIC': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfanisotropic), | ||
|  |     'BSDF_DIFFUSE': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfdiffuse), | ||
|  |     'BSDF_GLASS': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfglass), | ||
|  |     'BSDF_PRINCIPLED': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfprincipled), | ||
|  |     'BSDF_TRANSLUCENT': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdftranslucent), | ||
|  |     'BSDF_TRANSPARENT': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdftransparent), | ||
|  |     'BSDF_REFRACTION': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfrefraction), | ||
|  |     'EMISSION': MaterialNodeMeta(parse_func=nodes_shader.parse_emission), | ||
|  |     'HOLDOUT': MaterialNodeMeta( | ||
|  |         parse_func=nodes_shader.parse_holdout, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'MIX_SHADER': MaterialNodeMeta(parse_func=nodes_shader.parse_mixshader), | ||
|  |     'SUBSURFACE_SCATTERING': MaterialNodeMeta(parse_func=nodes_shader.parse_subsurfacescattering), | ||
|  | 
 | ||
|  |     # --- nodes_texture | ||
|  |     'TEX_BRICK': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_brick), | ||
|  |     'TEX_CHECKER': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_checker), | ||
|  |     'TEX_ENVIRONMENT': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_environment), | ||
|  |     'TEX_GRADIENT': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_gradient), | ||
|  |     'TEX_IMAGE': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_image), | ||
|  |     'TEX_MAGIC': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_magic), | ||
|  |     'TEX_NOISE': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_noise), | ||
|  |     'TEX_POINTDENSITY': MaterialNodeMeta( | ||
|  |         parse_func=nodes_texture.parse_tex_pointdensity, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.NEVER | ||
|  |     ), | ||
|  |     'TEX_SKY': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_sky), | ||
|  |     'TEX_VORONOI': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_voronoi), | ||
|  |     'TEX_WAVE': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_wave), | ||
|  | 
 | ||
|  |     # --- nodes_vector | ||
|  |     'BUMP': MaterialNodeMeta(parse_func=nodes_vector.parse_bump), | ||
|  |     'CURVE_VEC': MaterialNodeMeta(parse_func=nodes_vector.parse_curvevec), | ||
|  |     'DISPLACEMENT': MaterialNodeMeta(parse_func=nodes_vector.parse_displacement), | ||
|  |     'MAPPING': MaterialNodeMeta(parse_func=nodes_vector.parse_mapping), | ||
|  |     'NORMAL': MaterialNodeMeta(parse_func=nodes_vector.parse_normal), | ||
|  |     'NORMAL_MAP': MaterialNodeMeta(parse_func=nodes_vector.parse_normalmap), | ||
|  |     'VECTOR_ROTATE': MaterialNodeMeta(parse_func=nodes_vector.parse_vectorrotate), | ||
|  |     'VECT_TRANSFORM': MaterialNodeMeta(parse_func=nodes_vector.parse_vectortransform), | ||
|  | 
 | ||
|  |     # --- lnx_nodes | ||
|  |     'LnxShaderDataNode': MaterialNodeMeta( | ||
|  |         parse_func=shader_data_node.ShaderDataNode.parse, | ||
|  |         compute_dxdy_variants=ComputeDXDYVariant.ALWAYS | ||
|  |     ) | ||
|  | } | ||
|  | 
 | ||
|  | if bpy.app.version > (3, 2, 0): | ||
|  |     ALL_NODES['SEPARATE_COLOR'] = MaterialNodeMeta(parse_func=nodes_converter.parse_separate_color) | ||
|  |     ALL_NODES['COMBINE_COLOR'] = MaterialNodeMeta(parse_func=nodes_converter.parse_combine_color) | ||
|  | if bpy.app.version < (4, 1, 0): | ||
|  |     ALL_NODES['BSDF_VELVET'] = MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfvelvet) | ||
|  |     ALL_NODES['TEX_MUSGRAVE'] = MaterialNodeMeta(parse_func=nodes_texture.parse_tex_musgrave) | ||
|  | if bpy.app.version >= (4, 0, 0): | ||
|  |     ALL_NODES['BSDF_SHEEN'] = MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfsheen) | ||
|  |      | ||
|  | ALL_NODES['BSDF_GLOSSY'] = MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfglossy) | ||
|  | 
 | ||
|  | def get_node_meta(node: bpy.types.Node) -> MaterialNodeMeta: | ||
|  |     type_identifier = node.type if node.type != 'CUSTOM' else node.bl_idname | ||
|  |     return ALL_NODES[type_identifier] |