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

gltf2_blender_scene.py « imp « blender « io_scene_gltf2 - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: aa9684c716e2147da5063ad0252cfb5cb0f97bd0 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# Copyright 2018-2019 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import bpy
from math import sqrt
from mathutils import Quaternion
from .gltf2_blender_node import BlenderNode
from .gltf2_blender_skin import BlenderSkin
from .gltf2_blender_animation import BlenderAnimation
from .gltf2_blender_animation_utils import simulate_stash


class BlenderScene():
    """Blender Scene."""
    def __new__(cls, *args, **kwargs):
        raise RuntimeError("%s should not be instantiated" % cls)

    @staticmethod
    def create(gltf, scene_idx):
        """Scene creation."""
        gltf.blender_active_collection = None
        if scene_idx is not None:
            pyscene = gltf.data.scenes[scene_idx]
            list_nodes = pyscene.nodes

            # Create a new scene only if not already exists in .blend file
            # TODO : put in current scene instead ?
            if pyscene.name not in [scene.name for scene in bpy.data.scenes]:
                # TODO: There is a bug in 2.8 alpha that break CLEAR_KEEP_TRANSFORM
                # if we are creating a new scene
                scene = bpy.context.scene
                if bpy.context.collection.name in bpy.data.collections: # avoid master collection
                    gltf.blender_active_collection = bpy.context.collection.name
                if scene.render.engine not in ['CYCLES', 'BLENDER_EEVEE']:
                    scene.render.engine = "BLENDER_EEVEE"

                gltf.blender_scene = scene.name
            else:
                gltf.blender_scene = pyscene.name

            # Switch to newly created main scene
            bpy.context.window.scene = bpy.data.scenes[gltf.blender_scene]
            if bpy.context.collection.name in bpy.data.collections: # avoid master collection
                gltf.blender_active_collection = bpy.context.collection.name

        else:
            # No scene in glTF file, create all objects in current scene
            scene = bpy.context.scene
            if scene.render.engine not in ['CYCLES', 'BLENDER_EEVEE']:
                scene.render.engine = "BLENDER_EEVEE"
            if bpy.context.collection.name in bpy.data.collections: # avoid master collection
                gltf.blender_active_collection = bpy.context.collection.name
            gltf.blender_scene = scene.name
            list_nodes = BlenderScene.get_root_nodes(gltf)

        if bpy.app.debug_value != 100:
            # Create Yup2Zup empty
            obj_rotation = bpy.data.objects.new("Yup2Zup", None)
            obj_rotation.rotation_mode = 'QUATERNION'
            obj_rotation.rotation_quaternion = Quaternion((sqrt(2) / 2, sqrt(2) / 2, 0.0, 0.0))

            if gltf.blender_active_collection is not None:
                bpy.data.collections[gltf.blender_active_collection].objects.link(obj_rotation)
            else:
                bpy.data.scenes[gltf.blender_scene].collection.objects.link(obj_rotation)

        if list_nodes is not None:
            for node_idx in list_nodes:
                BlenderNode.create(gltf, node_idx, None)  # None => No parent

        # Now that all mesh / bones are created, create vertex groups on mesh
        if gltf.data.skins:
            for skin_id, skin in enumerate(gltf.data.skins):
                if hasattr(skin, "node_ids"):
                    BlenderSkin.create_vertex_groups(gltf, skin_id)

            for skin_id, skin in enumerate(gltf.data.skins):
                if hasattr(skin, "node_ids"):
                    BlenderSkin.assign_vertex_groups(gltf, skin_id)

            for skin_id, skin in enumerate(gltf.data.skins):
                if hasattr(skin, "node_ids"):
                    BlenderSkin.create_armature_modifiers(gltf, skin_id)

        if gltf.data.animations:
            for anim_idx, anim in enumerate(gltf.data.animations):
                # Blender armature name -> action all its bones should use
                gltf.arma_cache = {}
                # Things we need to stash when we're done.
                gltf.needs_stash = []

                if list_nodes is not None:
                    for node_idx in list_nodes:
                        BlenderAnimation.anim(gltf, anim_idx, node_idx)

                for (obj, anim_name, action) in gltf.needs_stash:
                    simulate_stash(obj, anim_name, action)

            # Restore first animation
            anim_name = gltf.data.animations[0].track_name
            for node_idx in list_nodes:
                BlenderAnimation.restore_animation(gltf, node_idx, anim_name)

        if bpy.app.debug_value != 100:
            # Parent root node to rotation object
            if list_nodes is not None:
                exclude_nodes = []
                for node_idx in list_nodes:
                    if gltf.data.nodes[node_idx].is_joint:
                        # Do not change parent if root node is already parented (can be the case for skinned mesh)
                        if not bpy.data.objects[gltf.data.nodes[node_idx].blender_armature_name].parent:
                            bpy.data.objects[gltf.data.nodes[node_idx].blender_armature_name].parent = obj_rotation
                        else:
                            exclude_nodes.append(node_idx)
                    else:
                        # Do not change parent if root node is already parented (can be the case for skinned mesh)
                        if not bpy.data.objects[gltf.data.nodes[node_idx].blender_object].parent:
                            bpy.data.objects[gltf.data.nodes[node_idx].blender_object].parent = obj_rotation
                        else:
                            exclude_nodes.append(node_idx)

                if gltf.animation_object is False:





                    # Avoid rotation bug if collection is hidden or disabled
                    if gltf.blender_active_collection is not None:
                        gltf.collection_hide_viewport = bpy.data.collections[gltf.blender_active_collection].hide_viewport
                        bpy.data.collections[gltf.blender_active_collection].hide_viewport = False
                        # TODO for visibility ... but seems not exposed on bpy for now

                    for node_idx in list_nodes:

                        if node_idx in exclude_nodes:
                            continue # for root node that are parented by the process
                            # for example skinned meshes

                        for obj_ in bpy.context.scene.objects:
                            obj_.select_set(False)
                        if gltf.data.nodes[node_idx].is_joint:
                            bpy.data.objects[gltf.data.nodes[node_idx].blender_armature_name].select_set(True)
                            bpy.context.view_layer.objects.active = bpy.data.objects[gltf.data.nodes[node_idx].blender_armature_name]

                        else:
                            bpy.data.objects[gltf.data.nodes[node_idx].blender_object].select_set(True)
                            bpy.context.view_layer.objects.active = bpy.data.objects[gltf.data.nodes[node_idx].blender_object]

                        bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM')

                    # remove object
                    #bpy.context.scene.collection.objects.unlink(obj_rotation)
                    bpy.data.objects.remove(obj_rotation)

                    # Restore collection hidden / disabled values
                    if gltf.blender_active_collection is not None:
                        bpy.data.collections[gltf.blender_active_collection].hide_viewport = gltf.collection_hide_viewport
                        # TODO restore visibility when expose in bpy

        # Make first root object the new active one
        if list_nodes is not None:
            if gltf.data.nodes[list_nodes[0]].blender_object:
                bl_name = gltf.data.nodes[list_nodes[0]].blender_object
            else:
                bl_name = gltf.data.nodes[list_nodes[0]].blender_armature_name
            bpy.context.view_layer.objects.active = bpy.data.objects[bl_name]

    @staticmethod
    def get_root_nodes(gltf):
        if gltf.data.nodes is None:
            return None

        parents = {}
        for idx, node  in enumerate(gltf.data.nodes):
            pynode = gltf.data.nodes[idx]
            if pynode.children:
                for child_idx in pynode.children:
                    parents[child_idx] = idx

        roots = []
        for idx, node in enumerate(gltf.data.nodes):
            if idx not in parents.keys():
                roots.append(idx)

        return roots