コード例 #1
0
def __gather_texture_transform_and_tex_coord(primary_socket, export_settings):
    # We're expecting
    #
    #     [UV Map] => [Mapping] => [UV Wrapping] => [Texture Node] => ... => primary_socket
    #
    # The [UV Wrapping] is for wrap modes like MIRROR that use nodes,
    # [Mapping] is for KHR_texture_transform, and [UV Map] is for texCoord.
    blender_shader_node = __get_tex_from_socket(primary_socket).shader_node

    # Skip over UV wrapping stuff (it goes in the sampler)
    result = detect_manual_uv_wrapping(blender_shader_node)
    if result:
        node = previous_node(result['next_socket'])
    else:
        node = previous_node(blender_shader_node.inputs['Vector'])

    texture_transform = None
    if node and node.type == 'MAPPING':
        texture_transform = gltf2_blender_get.get_texture_transform_from_mapping_node(
            node)
        node = previous_node(node.inputs['Vector'])

    texcoord_idx = 0
    if node and node.type == 'UVMAP' and node.uv_map:
        # Try to gather map index.
        for blender_mesh in bpy.data.meshes:
            i = blender_mesh.uv_layers.find(node.uv_map)
            if i >= 0:
                texcoord_idx = i
                break

    return texture_transform, texcoord_idx or None
コード例 #2
0
def __detect_lightpath_trick(socket):
    # Detects this (used to prevent casting light on other objects) See ex.
    # https://blender.stackexchange.com/a/21535/88681
    #
    #                 [   Lightpath  ]    [    Mix    ]
    #                 [ Is Camera Ray] => [Factor     ] => socket
    #                     (don't care) => [Shader     ]
    #      next_socket => [ Emission ] => [Shader     ]
    #
    # The Emission node can be omitted.
    # Returns None if not detected. Otherwise, a dict containing
    # next_socket.
    prev = gltf2_blender_get.previous_node(socket)
    if prev is None or prev.type != 'MIX_SHADER': return None
    in0 = gltf2_blender_get.previous_socket(prev.inputs[0])
    if in0 is None or in0.node.type != 'LIGHT_PATH': return None
    if in0.name != 'Is Camera Ray': return None
    next_socket = prev.inputs[2]

    # Detect emission
    prev = gltf2_blender_get.previous_node(next_socket)
    if prev is not None and prev.type == 'EMISSION':
        next_socket = prev.inputs[0]

    return {'next_socket': next_socket}
コード例 #3
0
def detect_manual_uv_wrapping(blender_shader_node):
    # Detects UV wrapping done using math nodes. This is for emulating wrap
    # modes Blender doesn't support. It looks like
    #
    #     next_socket => [Sep XYZ] => [Wrap S] => [Comb XYZ] => blender_shader_node
    #                              => [Wrap T] =>
    #
    # The [Wrap _] blocks are either math nodes (eg. PINGPONG for mirrored
    # repeat), or can be omitted.
    #
    # Returns None if not detected. Otherwise a dict containing the wrap
    # mode in each direction (or None), and next_socket.
    result = {}

    comb = previous_node(blender_shader_node.inputs['Vector'])
    if comb is None or comb.type != 'COMBXYZ': return None

    for soc in ['X', 'Y']:
        node = previous_node(comb.inputs[soc])
        if node is None: return None

        if node.type == 'SEPXYZ':
            # Passed through without change
            wrap = None
            prev_socket = previous_socket(comb.inputs[soc])
        elif node.type == 'MATH':
            # Math node applies a manual wrap
            if (node.operation == 'PINGPONG' and get_const_from_socket(
                    node.inputs[1], kind='VALUE') == 1.0):  # scale = 1
                wrap = TextureWrap.MirroredRepeat
            elif (node.operation == 'WRAP' and get_const_from_socket(
                    node.inputs[1], kind='VALUE') == 0.0 and  # min = 0
                  get_const_from_socket(node.inputs[2], kind='VALUE')
                  == 1.0):  # max = 1
                wrap = TextureWrap.Repeat
            else:
                return None

            prev_socket = previous_socket(node.inputs[0])
        else:
            return None

        if prev_socket is None: return None
        prev_node = prev_socket.node
        if prev_node.type != 'SEPXYZ': return None
        # Make sure X goes to X, etc.
        if prev_socket.name != soc: return None
        # Make sure both attach to the same SeparateXYZ node
        if soc == 'X':
            sep = prev_node
        else:
            if sep != prev_node: return None

        result['wrap_s' if soc == 'X' else 'wrap_t'] = wrap

    result['next_socket'] = sep.inputs[0]
    return result
コード例 #4
0
def __detect_mix_alpha(socket):
    # Detects this (used for an alpha hookup)
    #
    #                  [   Mix   ]
    #  alpha_socket => [Factor   ] => socket
    # [Transparent] => [Shader   ]
    #   next_socket => [Shader   ]
    #
    # Returns None if not detected. Otherwise, a dict containing alpha_socket
    # and next_socket.
    prev = gltf2_blender_get.previous_node(socket)
    if prev is None or prev.type != 'MIX_SHADER': return None
    in1 = gltf2_blender_get.previous_node(prev.inputs[1])
    if in1 is None or in1.type != 'BSDF_TRANSPARENT': return None
    return {
        'alpha_socket': prev.inputs[0],
        'next_socket': prev.inputs[2],
    }
コード例 #5
0
def __gather_occlusion_strength(primary_socket, export_settings):
    # Look for a MixRGB node that mixes with pure white in front of
    # primary_socket. The mix factor gives the occlusion strength.
    node = gltf2_blender_get.previous_node(primary_socket)
    if node and node.type == 'MIX_RGB' and node.blend_type == 'MIX':
        fac = gltf2_blender_get.get_const_from_socket(node.inputs['Fac'], kind='VALUE')
        col1 = gltf2_blender_get.get_const_from_socket(node.inputs['Color1'], kind='RGB')
        col2 = gltf2_blender_get.get_const_from_socket(node.inputs['Color2'], kind='RGB')
        if fac is not None:
            if col1 == [1, 1, 1] and col2 is None:
                return fac
            if col1 is None and col2 == [1, 1, 1]:
                return 1.0 - fac  # reversed for reversed inputs

    return None