def parse_shader(node: bpy.types.Node, socket: bpy.types.NodeSocket) -> Tuple[str, ...]: # Use switch-like lookup via dictionary # (better performance, better code readability) # 'NODE_TYPE': parser_function node_parser_funcs: Dict[str, Callable] = { 'MIX_SHADER': nodes_shader.parse_mixshader, 'ADD_SHADER': nodes_shader.parse_addshader, 'BSDF_PRINCIPLED': nodes_shader.parse_bsdfprincipled, 'BSDF_DIFFUSE': nodes_shader.parse_bsdfdiffuse, 'BSDF_GLOSSY': nodes_shader.parse_bsdfglossy, 'AMBIENT_OCCLUSION': nodes_shader.parse_ambientocclusion, 'BSDF_ANISOTROPIC': nodes_shader.parse_bsdfanisotropic, 'EMISSION': nodes_shader.parse_emission, 'BSDF_GLASS': nodes_shader.parse_bsdfglass, 'HOLDOUT': nodes_shader.parse_holdout, 'SUBSURFACE_SCATTERING': nodes_shader.parse_subsurfacescattering, 'BSDF_TRANSLUCENT': nodes_shader.parse_bsdftranslucent, 'BSDF_TRANSPARENT': nodes_shader.parse_bsdftransparent, 'BSDF_VELVET': nodes_shader.parse_bsdfvelvet, } if node.type in node_parser_funcs: node_parser_funcs[node.type](node, socket, state) elif node.type == 'GROUP': if node.node_tree.name.startswith('Armory PBR'): if state.parse_surface: # Normal if node.inputs[5].is_linked and node.inputs[5].links[0].from_node.type == 'NORMAL_MAP': log.warn(mat_name() + ' - Do not use Normal Map node with Armory PBR, connect Image Texture directly') parse_normal_map_color_input(node.inputs[5]) # Base color state.out_basecol = parse_vector_input(node.inputs[0]) # Occlusion state.out_occlusion = parse_value_input(node.inputs[2]) # Roughness state.out_roughness = parse_value_input(node.inputs[3]) # Metallic state.out_metallic = parse_value_input(node.inputs[4]) # Emission if node.inputs[6].is_linked or node.inputs[6].default_value != 0.0: state.out_emission = parse_value_input(node.inputs[6]) state.emission_found = True if state.parse_opacity: state.out_opacity = parse_value_input(node.inputs[1]) else: return parse_group(node, socket) elif node.type == 'GROUP_INPUT': return parse_group_input(node, socket) elif node.type == 'CUSTOM': if node.bl_idname == 'ArmShaderDataNode': return node.parse(state.frag, state.vert) else: # TODO: Print node tree name (save in ParserState) log.warn(f'Material node type {node.type} not supported') return state.get_outs()
def parse_material_output(node: bpy.types.Node, custom_particle_node: bpy.types.Node): global particle_info parse_surface = state.parse_surface parse_opacity = state.parse_opacity parse_displacement = state.parse_displacement state.emission_found = False particle_info = { 'index': False, 'age': False, 'lifetime': False, 'location': False, 'size': False, 'velocity': False, 'angular_velocity': False } state.sample_bump = False state.sample_bump_res = '' state.procedurals_written = False wrd = bpy.data.worlds['Arm'] # Surface if parse_surface or parse_opacity: state.parents = [] state.parsed = set() state.normal_parsed = False curshader = state.frag state.curshader = curshader out_basecol, out_roughness, out_metallic, out_occlusion, out_specular, out_opacity, out_emission = parse_shader_input( node.inputs[0]) if parse_surface: curshader.write('basecol = {0};'.format(out_basecol)) curshader.write('roughness = {0};'.format(out_roughness)) curshader.write('metallic = {0};'.format(out_metallic)) curshader.write('occlusion = {0};'.format(out_occlusion)) curshader.write('specular = {0};'.format(out_specular)) if '_Emission' in wrd.world_defs: curshader.write('emission = {0};'.format(out_emission)) if parse_opacity: curshader.write('opacity = {0} - 0.0002;'.format(out_opacity)) # Volume # parse_volume_input(node.inputs[1]) # Displacement if parse_displacement and disp_enabled() and node.inputs[2].is_linked: state.parents = [] state.parsed = set() state.normal_parsed = False rpdat = arm.utils.get_rp() if rpdat.arm_rp_displacement == 'Tessellation' and state.tese is not None: state.curshader = state.tese else: state.curshader = state.vert out_disp = parse_displacement_input(node.inputs[2]) state.curshader.write('vec3 disp = {0};'.format(out_disp)) if custom_particle_node is not None: if not (parse_displacement and disp_enabled() and node.inputs[2].is_linked): state.parents = [] state.parsed = set() state.normal_parsed = False state.curshader = state.vert custom_particle_node.parse(state.curshader, state.con)
def parse_vector(node: bpy.types.Node, socket: bpy.types.NodeSocket) -> str: """Parses the vector/color output value from the given node and socket.""" node_parser_funcs: Dict[str, Callable] = { 'ATTRIBUTE': nodes_input.parse_attribute, # RGB outputs 'RGB': nodes_input.parse_rgb, 'TEX_BRICK': nodes_texture.parse_tex_brick, 'TEX_CHECKER': nodes_texture.parse_tex_checker, 'TEX_ENVIRONMENT': nodes_texture.parse_tex_environment, 'TEX_GRADIENT': nodes_texture.parse_tex_gradient, 'TEX_IMAGE': nodes_texture.parse_tex_image, 'TEX_MAGIC': nodes_texture.parse_tex_magic, 'TEX_MUSGRAVE': nodes_texture.parse_tex_musgrave, 'TEX_NOISE': nodes_texture.parse_tex_noise, 'TEX_POINTDENSITY': nodes_texture.parse_tex_pointdensity, 'TEX_SKY': nodes_texture.parse_tex_sky, 'TEX_VORONOI': nodes_texture.parse_tex_voronoi, 'TEX_WAVE': nodes_texture.parse_tex_wave, 'VERTEX_COLOR': nodes_input.parse_vertex_color, 'BRIGHTCONTRAST': nodes_color.parse_brightcontrast, 'GAMMA': nodes_color.parse_gamma, 'HUE_SAT': nodes_color.parse_huesat, 'INVERT': nodes_color.parse_invert, 'MIX_RGB': nodes_color.parse_mixrgb, 'BLACKBODY': nodes_converter.parse_blackbody, 'VALTORGB': nodes_converter.parse_valtorgb, # ColorRamp 'CURVE_VEC': nodes_vector.parse_curvevec, # Vector Curves 'CURVE_RGB': nodes_color.parse_curvergb, 'COMBHSV': nodes_converter.parse_combhsv, 'COMBRGB': nodes_converter.parse_combrgb, 'WAVELENGTH': nodes_converter.parse_wavelength, # Vector outputs 'CAMERA': nodes_input.parse_camera, 'NEW_GEOMETRY': nodes_input.parse_geometry, 'HAIR_INFO': nodes_input.parse_hairinfo, 'OBJECT_INFO': nodes_input.parse_objectinfo, 'PARTICLE_INFO': nodes_input.parse_particleinfo, 'TANGENT': nodes_input.parse_tangent, 'TEX_COORD': nodes_input.parse_texcoord, 'UVMAP': nodes_input.parse_uvmap, 'BUMP': nodes_vector.parse_bump, 'MAPPING': nodes_vector.parse_mapping, 'NORMAL': nodes_vector.parse_normal, 'NORMAL_MAP': nodes_vector.parse_normalmap, 'VECT_TRANSFORM': nodes_vector.parse_vectortransform, 'COMBXYZ': nodes_converter.parse_combxyz, 'VECT_MATH': nodes_converter.parse_vectormath, 'DISPLACEMENT': nodes_vector.parse_displacement, 'VECTOR_ROTATE': nodes_vector.parse_vectorrotate, } if node.type in node_parser_funcs: return node_parser_funcs[node.type](node, socket, state) elif node.type == 'GROUP': return parse_group(node, socket) elif node.type == 'GROUP_INPUT': return parse_group_input(node, socket) elif node.type == 'CUSTOM': if node.bl_idname == 'ArmShaderDataNode': return node.parse(state.frag, state.vert) log.warn(f'Material node type {node.type} not supported') return "vec3(0, 0, 0)"