Ejemplo n.º 1
0
def parse_combxyz(node: bpy.types.ShaderNodeCombineXYZ,
                  out_socket: bpy.types.NodeSocket,
                  state: ParserState) -> vec3str:
    x = c.parse_value_input(node.inputs[0])
    y = c.parse_value_input(node.inputs[1])
    z = c.parse_value_input(node.inputs[2])
    return f'vec3({x}, {y}, {z})'
Ejemplo n.º 2
0
def parse_tex_wave(node: bpy.types.ShaderNodeTexWave, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
    c.write_procedurals()
    state.curshader.add_function(c_functions.str_tex_wave)
    if node.inputs[0].is_linked:
        co = c.parse_vector_input(node.inputs[0])
    else:
        co = 'bposition'
    scale = c.parse_value_input(node.inputs[1])
    distortion = c.parse_value_input(node.inputs[2])
    detail = c.parse_value_input(node.inputs[3])
    detail_scale = c.parse_value_input(node.inputs[4])
    if node.wave_profile == 'SIN':
        wave_profile = 0
    else:
        wave_profile = 1
    if node.wave_type == 'BANDS':
        wave_type = 0
    else:
        wave_type = 1

    # Color
    if out_socket == node.outputs[0]:
        res = 'vec3(tex_wave_f({0} * {1},{2},{3},{4},{5},{6}))'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale)
    # Fac
    else:
        res = 'tex_wave_f({0} * {1},{2},{3},{4},{5},{6})'.format(co, scale, wave_type, wave_profile, distortion, detail, detail_scale)

    if state.sample_bump:
        c.write_bump(node, out_socket, res)

    return res
Ejemplo n.º 3
0
def parse_combrgb(node: bpy.types.ShaderNodeCombineRGB,
                  out_socket: bpy.types.NodeSocket,
                  state: ParserState) -> vec3str:
    r = c.parse_value_input(node.inputs[0])
    g = c.parse_value_input(node.inputs[1])
    b = c.parse_value_input(node.inputs[2])
    return f'vec3({r}, {g}, {b})'
Ejemplo n.º 4
0
def parse_tex_checker(node: bpy.types.ShaderNodeTexChecker,
                      out_socket: bpy.types.NodeSocket,
                      state: ParserState) -> Union[floatstr, vec3str]:
    state.curshader.add_function(c_functions.str_tex_checker)

    if node.inputs[0].is_linked:
        co = c.parse_vector_input(node.inputs[0])
    else:
        co = 'bposition'

    # Color
    if out_socket == node.outputs[0]:
        col1 = c.parse_vector_input(node.inputs[1])
        col2 = c.parse_vector_input(node.inputs[2])
        scale = c.parse_value_input(node.inputs[3])
        res = f'tex_checker({co}, {col1}, {col2}, {scale})'
    # Fac
    else:
        scale = c.parse_value_input(node.inputs[3])
        res = 'tex_checker_f({0}, {1})'.format(co, scale)

    if state.sample_bump:
        c.write_bump(node, out_socket, res)

    return res
Ejemplo n.º 5
0
def parse_bsdfprincipled(node: bpy.types.ShaderNodeBsdfPrincipled, out_socket: NodeSocket, state: ParserState) -> None:
    if state.parse_surface:
        c.write_normal(node.inputs[20])
        state.out_basecol = c.parse_vector_input(node.inputs[0])
        # subsurface = c.parse_vector_input(node.inputs[1])
        # subsurface_radius = c.parse_vector_input(node.inputs[2])
        # subsurface_color = c.parse_vector_input(node.inputs[3])
        state.out_metallic = c.parse_value_input(node.inputs[4])
        state.out_specular = c.parse_value_input(node.inputs[5])
        # specular_tint = c.parse_vector_input(node.inputs[6])
        state.out_roughness = c.parse_value_input(node.inputs[7])
        # aniso = c.parse_vector_input(node.inputs[8])
        # aniso_rot = c.parse_vector_input(node.inputs[9])
        # sheen = c.parse_vector_input(node.inputs[10])
        # sheen_tint = c.parse_vector_input(node.inputs[11])
        # clearcoat = c.parse_vector_input(node.inputs[12])
        # clearcoat_rough = c.parse_vector_input(node.inputs[13])
        # ior = c.parse_vector_input(node.inputs[14])
        # transmission = c.parse_vector_input(node.inputs[15])
        # transmission_roughness = c.parse_vector_input(node.inputs[16])
        if node.inputs[17].is_linked or node.inputs[17].default_value[0] != 0.0:
            state.out_emission = '({0}.x)'.format(c.parse_vector_input(node.inputs[17]))
            state.emission_found = True
        # clearcoar_normal = c.parse_vector_input(node.inputs[21])
        # tangent = c.parse_vector_input(node.inputs[22])
    if state.parse_opacity:
        if len(node.inputs) > 21:
            state.out_opacity = c.parse_value_input(node.inputs[19])
Ejemplo n.º 6
0
def parse_tex_noise(node: bpy.types.ShaderNodeTexNoise, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
    c.write_procedurals()
    state.curshader.add_function(c_functions.str_tex_noise)
    c.assets_add(os.path.join(arm.utils.get_sdk_path(), 'armory', 'Assets', 'noise256.png'))
    c.assets_add_embedded_data('noise256.png')
    state.curshader.add_uniform('sampler2D snoise256', link='$noise256.png')

    if node.inputs[0].is_linked:
        co = c.parse_vector_input(node.inputs[0])
    else:
        co = 'bposition'

    scale = c.parse_value_input(node.inputs[2])
    detail = c.parse_value_input(node.inputs[3])
    roughness = c.parse_value_input(node.inputs[4])
    distortion = c.parse_value_input(node.inputs[5])

    # Color
    if out_socket == node.outputs[1]:
        res = 'vec3(tex_noise({0} * {1},{2},{3}), tex_noise({0} * {1} + 120.0,{2},{3}), tex_noise({0} * {1} + 168.0,{2},{3}))'.format(co, scale, detail, distortion)
    # Fac
    else:
        res = 'tex_noise({0} * {1},{2},{3})'.format(co, scale, detail, distortion)

    if state.sample_bump:
        c.write_bump(node, out_socket, res, 0.1)

    return res
Ejemplo n.º 7
0
def parse_bump(node: bpy.types.ShaderNodeBump,
               out_socket: bpy.types.NodeSocket,
               state: ParserState) -> vec3str:
    # Interpolation strength
    strength = c.parse_value_input(node.inputs[0])
    # Height multiplier
    # distance = c.parse_value_input(node.inputs[1])
    state.sample_bump = True
    height = c.parse_value_input(node.inputs[2])
    state.sample_bump = False
    nor = c.parse_vector_input(node.inputs[3])
    if state.sample_bump_res != '':
        if node.invert:
            ext = ('1', '2', '3', '4')
        else:
            ext = ('2', '1', '4', '3')
        state.curshader.write(
            'float {0}_fh1 = {0}_{1} - {0}_{2}; float {0}_fh2 = {0}_{3} - {0}_{4};'
            .format(state.sample_bump_res, ext[0], ext[1], ext[2], ext[3]))
        state.curshader.write(
            '{0}_fh1 *= ({1}) * 3.0; {0}_fh2 *= ({1}) * 3.0;'.format(
                state.sample_bump_res, strength))
        state.curshader.write(
            'vec3 {0}_a = normalize(vec3(2.0, 0.0, {0}_fh1));'.format(
                state.sample_bump_res))
        state.curshader.write(
            'vec3 {0}_b = normalize(vec3(0.0, 2.0, {0}_fh2));'.format(
                state.sample_bump_res))
        res = 'normalize(mat3({0}_a, {0}_b, normalize(vec3({0}_fh1, {0}_fh2, 2.0))) * n)'.format(
            state.sample_bump_res)
        state.sample_bump_res = ''
    else:
        res = 'n'
    return res
Ejemplo n.º 8
0
def parse_combhsv(node: bpy.types.ShaderNodeCombineHSV,
                  out_socket: bpy.types.NodeSocket,
                  state: ParserState) -> vec3str:
    state.curshader.add_function(c_functions.str_hue_sat)
    h = c.parse_value_input(node.inputs[0])
    s = c.parse_value_input(node.inputs[1])
    v = c.parse_value_input(node.inputs[2])
    return f'hsv_to_rgb(vec3({h}, {s}, {v}))'
Ejemplo n.º 9
0
def parse_displacement(node: bpy.types.ShaderNodeDisplacement,
                       out_socket: bpy.types.NodeSocket,
                       state: ParserState) -> vec3str:
    height = c.parse_value_input(node.inputs[0])
    midlevel = c.parse_value_input(node.inputs[1])
    scale = c.parse_value_input(node.inputs[2])
    nor = c.parse_vector_input(node.inputs[3])
    return f'(vec3({height}) * {scale})'
Ejemplo n.º 10
0
def parse_brightcontrast(node: bpy.types.ShaderNodeBrightContrast,
                         out_socket: bpy.types.NodeSocket,
                         state: ParserState) -> vec3str:
    out_col = c.parse_vector_input(node.inputs[0])
    bright = c.parse_value_input(node.inputs[1])
    contr = c.parse_value_input(node.inputs[2])

    state.curshader.add_function(c_functions.str_brightcontrast)

    return 'brightcontrast({0}, {1}, {2})'.format(out_col, bright, contr)
Ejemplo n.º 11
0
def parse_huesat(node: bpy.types.ShaderNodeHueSaturation,
                 out_socket: bpy.types.NodeSocket,
                 state: ParserState) -> vec3str:
    state.curshader.add_function(c_functions.str_hue_sat)
    hue = c.parse_value_input(node.inputs[0])
    sat = c.parse_value_input(node.inputs[1])
    val = c.parse_value_input(node.inputs[2])
    fac = c.parse_value_input(node.inputs[3])
    col = c.parse_vector_input(node.inputs[4])

    return f'hue_sat({col}, vec4({hue}-0.5, {sat}, {val}, 1.0-{fac}))'
Ejemplo n.º 12
0
def parse_bsdfdiffuse(node: bpy.types.ShaderNodeBsdfDiffuse,
                      out_socket: NodeSocket, state: ParserState) -> None:
    if state.parse_surface:
        c.write_normal(node.inputs[2])
        state.out_basecol = c.parse_vector_input(node.inputs[0])
        state.out_roughness = c.parse_value_input(node.inputs[1])
        state.out_specular = '0.0'
Ejemplo n.º 13
0
def parse_mixshader(node: bpy.types.ShaderNodeMixShader,
                    out_socket: NodeSocket, state: ParserState) -> None:
    prefix = '' if node.inputs[0].is_linked else 'const '
    fac = c.parse_value_input(node.inputs[0])
    fac_var = c.node_name(node.name) + '_fac'
    fac_inv_var = c.node_name(node.name) + '_fac_inv'
    state.curshader.write('{0}float {1} = {2};'.format(prefix, fac_var, fac))
    state.curshader.write('{0}float {1} = 1.0 - {2};'.format(
        prefix, fac_inv_var, fac_var))
    bc1, rough1, met1, occ1, spec1, opac1, emi1 = c.parse_shader_input(
        node.inputs[1])
    bc2, rough2, met2, occ2, spec2, opac2, emi2 = c.parse_shader_input(
        node.inputs[2])
    if state.parse_surface:
        state.out_basecol = '({0} * {3} + {1} * {2})'.format(
            bc1, bc2, fac_var, fac_inv_var)
        state.out_roughness = '({0} * {3} + {1} * {2})'.format(
            rough1, rough2, fac_var, fac_inv_var)
        state.out_metallic = '({0} * {3} + {1} * {2})'.format(
            met1, met2, fac_var, fac_inv_var)
        state.out_occlusion = '({0} * {3} + {1} * {2})'.format(
            occ1, occ2, fac_var, fac_inv_var)
        state.out_specular = '({0} * {3} + {1} * {2})'.format(
            spec1, spec2, fac_var, fac_inv_var)
        state.out_emission = '({0} * {3} + {1} * {2})'.format(
            emi1, emi2, fac_var, fac_inv_var)
    if state.parse_opacity:
        state.out_opacity = '({0} * {3} + {1} * {2})'.format(
            opac1, opac2, fac_var, fac_inv_var)
Ejemplo n.º 14
0
def parse_bsdfanisotropic(node: bpy.types.ShaderNodeBsdfAnisotropic, out_socket: NodeSocket, state: ParserState) -> None:
    if state.parse_surface:
        c.write_normal(node.inputs[4])
        # Revert to glossy
        state.out_basecol = c.parse_vector_input(node.inputs[0])
        state.out_roughness = c.parse_value_input(node.inputs[1])
        state.out_metallic = '1.0'
Ejemplo n.º 15
0
def parse_invert(node: bpy.types.ShaderNodeInvert,
                 out_socket: bpy.types.NodeSocket,
                 state: ParserState) -> vec3str:
    fac = c.parse_value_input(node.inputs[0])
    out_col = c.parse_vector_input(node.inputs[1])

    return f'mix({out_col}, vec3(1.0) - ({out_col}), {fac})'
Ejemplo n.º 16
0
def parse_bsdfglossy(node: bpy.types.ShaderNodeBsdfGlossy,
                     out_socket: NodeSocket, state: ParserState) -> None:
    if state.parse_surface:
        c.write_normal(node.inputs[2])
        state.out_basecol = c.parse_vector_input(node.inputs[0])
        state.out_roughness = c.parse_value_input(node.inputs[1])
        state.out_metallic = '1.0'
Ejemplo n.º 17
0
def parse_vectorrotate(node: bpy.types.ShaderNodeVectorRotate,
                       out_socket: bpy.types.NodeSocket,
                       state: ParserState) -> vec3str:

    type = node.rotation_type
    input_vector: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[0])
    input_center: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[1])
    input_axis: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[2])
    input_angle: bpy.types.NodeSocket = c.parse_value_input(node.inputs[3])
    input_rotation: bpy.types.NodeSocket = c.parse_vector_input(node.inputs[4])

    if node.invert:
        input_invert = "0"
    else:
        input_invert = "1"

    state.curshader.add_function(c_functions.str_rotate_around_axis)

    if type == 'AXIS_ANGLE':
        return f'vec3( (length({input_axis}) != 0.0) ? rotate_around_axis({input_vector} - {input_center}, normalize({input_axis}), {input_angle} * {input_invert}) + {input_center} : {input_vector} )'
    elif type == 'X_AXIS':
        return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(1.0, 0.0, 0.0), {input_angle} * {input_invert}) + {input_center} )'
    elif type == 'Y_AXIS':
        return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 1.0, 0.0), {input_angle} * {input_invert}) + {input_center} )'
    elif type == 'Z_AXIS':
        return f'vec3( rotate_around_axis({input_vector} - {input_center}, vec3(0.0, 0.0, 1.0), {input_angle} * {input_invert}) + {input_center} )'
    elif type == 'EULER_XYZ':
        state.curshader.add_function(c_functions.str_euler_to_mat3)
        return f'vec3( mat3(({input_invert} < 0.0) ? transpose(euler_to_mat3({input_rotation})) : euler_to_mat3({input_rotation})) * ({input_vector} - {input_center}) + {input_center})'

    return f'(vec3(1.0, 0.0, 0.0))'
Ejemplo n.º 18
0
def parse_wavelength(node: bpy.types.ShaderNodeWavelength,
                     out_socket: bpy.types.NodeSocket,
                     state: ParserState) -> vec3str:
    state.curshader.add_function(c_functions.str_wavelength_to_rgb)
    wl = c.parse_value_input(node.inputs[0])
    # Roughly map to cycles - 450 to 600 nanometers
    return f'wavelength_to_rgb(({wl} - 450.0) / 150.0)'
Ejemplo n.º 19
0
def parse_gamma(node: bpy.types.ShaderNodeGamma,
                out_socket: bpy.types.NodeSocket,
                state: ParserState) -> vec3str:
    out_col = c.parse_vector_input(node.inputs[0])
    gamma = c.parse_value_input(node.inputs[1])

    return 'pow({0}, vec3({1}))'.format(out_col, gamma)
Ejemplo n.º 20
0
def parse_blackbody(node: bpy.types.ShaderNodeBlackbody,
                    out_socket: bpy.types.NodeSocket,
                    state: ParserState) -> vec3str:

    t = c.parse_value_input(node.inputs[0])

    state.curshader.add_function(c_functions.str_blackbody)
    return f'blackbody({t})'
Ejemplo n.º 21
0
def parse_clamp(node: bpy.types.ShaderNodeClamp,
                out_socket: bpy.types.NodeSocket,
                state: ParserState) -> floatstr:
    value = c.parse_value_input(node.inputs['Value'])
    minVal = c.parse_value_input(node.inputs['Min'])
    maxVal = c.parse_value_input(node.inputs['Max'])

    if node.clamp_type == 'MINMAX':
        # Condition is minVal < maxVal, otherwise use 'RANGE' type
        return f'clamp({value}, {minVal}, {maxVal})'

    elif node.clamp_type == 'RANGE':
        return f'{minVal} < {maxVal} ? clamp({value}, {minVal}, {maxVal}) : clamp({value}, {maxVal}, {minVal})'

    else:
        log.warn(f'Clamp node: unsupported clamp type {node.clamp_type}.')
        return value
Ejemplo n.º 22
0
def parse_emission(node: bpy.types.ShaderNodeEmission, out_socket: NodeSocket, state: ParserState) -> None:
    if state.parse_surface:
        # Multiply basecol
        state.out_basecol = c.parse_vector_input(node.inputs[0])
        state.out_emission = '1.0'
        state.emission_found = True
        emission_strength = c.parse_value_input(node.inputs[1])
        state.out_basecol = '({0} * {1})'.format(state.out_basecol, emission_strength)
Ejemplo n.º 23
0
def parse_bsdfglass(node: bpy.types.ShaderNodeBsdfGlass,
                    out_socket: NodeSocket, state: ParserState) -> None:
    if state.parse_surface:
        c.write_normal(node.inputs[3])
        state.out_roughness = c.parse_value_input(node.inputs[1])
    if state.parse_opacity:
        state.out_opacity = '(1.0 - {0}.r)'.format(
            c.parse_vector_input(node.inputs[0]))
Ejemplo n.º 24
0
def parse_fresnel(node: bpy.types.ShaderNodeFresnel,
                  out_socket: bpy.types.NodeSocket,
                  state: ParserState) -> floatstr:
    state.curshader.add_function(c_functions.str_fresnel)
    ior = c.parse_value_input(node.inputs[0])
    if node.inputs[1].is_linked:
        dotnv = 'dot({0}, vVec)'.format(c.parse_vector_input(node.inputs[1]))
    else:
        dotnv = 'dotNV'
    return 'fresnel({0}, {1})'.format(ior, dotnv)
Ejemplo n.º 25
0
def parse_curvevec(node: bpy.types.ShaderNodeVectorCurve, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
    fac = c.parse_value_input(node.inputs[0])
    vec = c.parse_vector_input(node.inputs[1])
    curves = node.mapping.curves
    name = c.node_name(node.name)
    # mapping.curves[0].points[0].handle_type # bezier curve
    return '(vec3({0}, {1}, {2}) * {3})'.format(
        c.vector_curve(name + '0', vec + '.x', curves[0].points),
        c.vector_curve(name + '1', vec + '.y', curves[1].points),
        c.vector_curve(name + '2', vec + '.z', curves[2].points), fac)
Ejemplo n.º 26
0
def parse_tex_voronoi(node: bpy.types.ShaderNodeTexVoronoi,
                      out_socket: bpy.types.NodeSocket,
                      state: ParserState) -> Union[floatstr, vec3str]:
    outp = 0
    if out_socket.type == 'RGBA':
        outp = 1
    elif out_socket.type == 'VECTOR':
        outp = 2
    m = 0
    if node.distance == 'MANHATTAN':
        m = 1
    elif node.distance == 'CHEBYCHEV':
        m = 2
    elif node.distance == 'MINKOWSKI':
        m = 3

    c.write_procedurals()
    state.curshader.add_function(c_functions.str_tex_voronoi)

    if node.inputs[0].is_linked:
        co = c.parse_vector_input(node.inputs[0])
    else:
        co = 'bposition'

    scale = c.parse_value_input(node.inputs[2])
    exp = c.parse_value_input(node.inputs[4])
    randomness = c.parse_value_input(node.inputs[5])

    # Color or Position
    if out_socket == node.outputs[1] or out_socket == node.outputs[2]:
        res = 'tex_voronoi({0}, {1}, {2}, {3}, {4}, {5})'.format(
            co, randomness, m, outp, scale, exp)
    # Distance
    else:
        res = 'tex_voronoi({0}, {1}, {2}, {3}, {4}, {5}).x'.format(
            co, randomness, m, outp, scale, exp)

    if state.sample_bump:
        c.write_bump(node, out_socket, res)

    return res
Ejemplo n.º 27
0
def parse_maprange(node: bpy.types.ShaderNodeMapRange,
                   out_socket: bpy.types.NodeSocket,
                   state: ParserState) -> floatstr:

    interp = node.interpolation_type

    value: str = c.parse_value_input(
        node.inputs[0]) if node.inputs[0].is_linked else c.to_vec1(
            node.inputs[0].default_value)
    fromMin = c.parse_value_input(node.inputs[1])
    fromMax = c.parse_value_input(node.inputs[2])
    toMin = c.parse_value_input(node.inputs[3])
    toMax = c.parse_value_input(node.inputs[4])

    if interp == "LINEAR":

        state.curshader.add_function(c_functions.str_map_range_linear)
        return f'map_range_linear({value}, {fromMin}, {fromMax}, {toMin}, {toMax})'

    elif interp == "STEPPED":

        steps = float(c.parse_value_input(node.inputs[5]))
        state.curshader.add_function(c_functions.str_map_range_stepped)
        return f'map_range_stepped({value}, {fromMin}, {fromMax}, {toMin}, {toMax}, {steps})'

    elif interp == "SMOOTHSTEP":

        state.curshader.add_function(c_functions.str_map_range_smoothstep)
        return f'map_range_smoothstep({value}, {fromMin}, {fromMax}, {toMin}, {toMax})'

    elif interp == "SMOOTHERSTEP":

        state.curshader.add_function(c_functions.str_map_range_smootherstep)
        return f'map_range_smootherstep({value}, {fromMin}, {fromMax}, {toMin}, {toMax})'
Ejemplo n.º 28
0
def parse_curvergb(node: bpy.types.ShaderNodeRGBCurve,
                   out_socket: bpy.types.NodeSocket,
                   state: ParserState) -> vec3str:
    fac = c.parse_value_input(node.inputs[0])
    vec = c.parse_vector_input(node.inputs[1])
    curves = node.mapping.curves
    name = c.node_name(node.name)
    # mapping.curves[0].points[0].handle_type
    return '(sqrt(vec3({0}, {1}, {2}) * vec3({4}, {5}, {6})) * {3})'.format(
        c.vector_curve(name + '0', vec + '.x', curves[0].points),
        c.vector_curve(name + '1', vec + '.y', curves[1].points),
        c.vector_curve(name + '2', vec + '.z', curves[2].points), fac,
        c.vector_curve(name + '3a', vec + '.x', curves[3].points),
        c.vector_curve(name + '3b', vec + '.y', curves[3].points),
        c.vector_curve(name + '3c', vec + '.z', curves[3].points))
Ejemplo n.º 29
0
def parse_layerweight(node: bpy.types.ShaderNodeLayerWeight,
                      out_socket: bpy.types.NodeSocket,
                      state: ParserState) -> floatstr:
    blend = c.parse_value_input(node.inputs[0])
    if node.inputs[1].is_linked:
        dotnv = 'dot({0}, vVec)'.format(c.parse_vector_input(node.inputs[1]))
    else:
        dotnv = 'dotNV'

    # Fresnel
    if out_socket == node.outputs[0]:
        state.curshader.add_function(c_functions.str_fresnel)
        return 'fresnel(1.0 / (1.0 - {0}), {1})'.format(blend, dotnv)
    # Facing
    elif out_socket == node.outputs[1]:
        return '(1.0 - pow({0}, ({1} < 0.5) ? 2.0 * {1} : 0.5 / (1.0 - {1})))'.format(
            dotnv, blend)
Ejemplo n.º 30
0
def parse_tex_musgrave(node: bpy.types.ShaderNodeTexMusgrave, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
    state.curshader.add_function(c_functions.str_tex_musgrave)

    if node.inputs[0].is_linked:
        co = c.parse_vector_input(node.inputs[0])
    else:
        co = 'bposition'

    scale = c.parse_value_input(node.inputs['Scale'])
    # detail = c.parse_value_input(node.inputs[2])
    # distortion = c.parse_value_input(node.inputs[3])

    res = f'tex_musgrave_f({co} * {scale} * 0.5)'

    if state.sample_bump:
        c.write_bump(node, out_socket, res)

    return res