Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gltf2_blender_gather_materials_unlit.py « exp « blender « io_scene_gltf2 - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e104b7f1f30316ffdae863a29aa1b6c598329f9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# SPDX-License-Identifier: Apache-2.0
# Copyright 2018-2021 The glTF-Blender-IO authors.

from io_scene_gltf2.blender.exp import gltf2_blender_gather_texture_info
from io_scene_gltf2.blender.exp import gltf2_blender_get


def detect_shadeless_material(blender_material, export_settings):
    """Detect if this material is "shadeless" ie. should be exported
    with KHR_materials_unlit. Returns None if not. Otherwise, returns
    a dict with info from parsing the node tree.
    """
    if not blender_material.use_nodes: return None

    # Old Background node detection (unlikely to happen)
    bg_socket = gltf2_blender_get.get_socket(blender_material, "Background")
    if bg_socket is not None:
        return {'rgb_socket': bg_socket}

    # Look for
    # * any color socket, connected to...
    # * optionally, the lightpath trick, connected to...
    # * optionally, a mix-with-transparent (for alpha), connected to...
    # * the output node

    info = {}

    for node in blender_material.node_tree.nodes:
        if node.type == 'OUTPUT_MATERIAL' and node.is_active_output:
            socket = node.inputs[0]
            break
    else:
        return None

    # Be careful not to misidentify a lightpath trick as mix-alpha.
    result = __detect_lightpath_trick(socket)
    if result is not None:
        socket = result['next_socket']
    else:
        result = __detect_mix_alpha(socket)
        if result is not None:
            socket = result['next_socket']
            info['alpha_socket'] = result['alpha_socket']

        result = __detect_lightpath_trick(socket)
        if result is not None:
            socket = result['next_socket']

    # Check if a color socket, or connected to a color socket
    if socket.type != 'RGBA':
        from_socket = gltf2_blender_get.previous_socket(socket)
        if from_socket is None: return None
        if from_socket.type != 'RGBA': return None

    info['rgb_socket'] = socket
    return info


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],
    }


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}


def gather_base_color_factor(info, export_settings):
    rgb, alpha = None, None

    if 'rgb_socket' in info:
        rgb = gltf2_blender_get.get_factor_from_socket(info['rgb_socket'], kind='RGB')
    if 'alpha_socket' in info:
        alpha = gltf2_blender_get.get_factor_from_socket(info['alpha_socket'], kind='VALUE')

    if rgb is None: rgb = [1.0, 1.0, 1.0]
    if alpha is None: alpha = 1.0

    rgba = [*rgb, alpha]
    if rgba == [1, 1, 1, 1]: return None
    return rgba


def gather_base_color_texture(info, export_settings):
    sockets = (info.get('rgb_socket'), info.get('alpha_socket'))
    sockets = tuple(s for s in sockets if s is not None)
    if sockets:
        # NOTE: separate RGB and Alpha textures will not get combined
        # because gather_image determines how to pack images based on the
        # names of sockets, and the names are hard-coded to a Principled
        # style graph.
        unlit_texture, unlit_use_active_uvmap = gltf2_blender_gather_texture_info.gather_texture_info(
            sockets[0],
            sockets,
            export_settings,
        )
        return unlit_texture, ["unlitTexture"] if unlit_use_active_uvmap else None
    return None, None