Exemplo n.º 1
0
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()
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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)"