@tushar-br/editing-pack 1.0.188 → 1.0.190
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/staging_area/Blender/blender.pdb.ts_part_0 +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__init__.py +0 -173
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/camera.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/engine.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/operators.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/presets.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/properties.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/ui.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/__pycache__/version_update.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/geom/shader_data.h +0 -452
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/geom/triangle.h +0 -278
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/geom/triangle_intersect.h +0 -166
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/geom/volume.h +0 -104
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/globals.h +0 -13
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/image.h +0 -12
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/displacement_shader.h +0 -43
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/guiding.h +0 -641
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/init_from_bake.h +0 -344
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/init_from_camera.h +0 -110
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/intersect_closest.h +0 -443
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/intersect_dedicated_light.h +0 -232
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/intersect_shadow.h +0 -183
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/intersect_subsurface.h +0 -24
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/intersect_volume_stack.h +0 -250
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/megakernel.h +0 -114
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/mnee.h +0 -1123
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/path_state.h +0 -425
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shade_background.h +0 -210
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shade_dedicated_light.h +0 -243
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shade_light.h +0 -95
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shade_shadow.h +0 -192
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shade_surface.h +0 -885
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shade_volume.h +0 -2947
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shadow_catcher.h +0 -79
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shadow_linking.h +0 -69
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/shadow_state_template.h +0 -99
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/state.h +0 -276
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/state_flow.h +0 -255
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/state_template.h +0 -152
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/state_util.h +0 -602
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/subsurface.h +0 -251
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/subsurface_disk.h +0 -220
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/subsurface_random_walk.h +0 -462
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/surface_shader.h +0 -1198
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/volume_shader.h +0 -539
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/integrator/volume_stack.h +0 -258
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/area.h +0 -537
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/background.h +0 -500
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/common.h +0 -86
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/distant.h +0 -167
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/distribution.h +0 -60
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/light.h +0 -499
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/point.h +0 -240
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/sample.h +0 -545
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/spot.h +0 -347
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/tree.h +0 -951
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/light/triangle.h +0 -339
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/osl/camera.h +0 -81
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/osl/closures_setup.h +0 -1259
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/osl/closures_template.h +0 -277
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/osl/osl.h +0 -287
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/osl/services_gpu.h +0 -1327
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/osl/types.h +0 -157
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/lcg.h +0 -53
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/mapping.h +0 -251
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/mis.h +0 -41
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/pattern.h +0 -188
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/sobol_burley.h +0 -203
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/tabulated_sobol.h +0 -178
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/sample/util.h +0 -79
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/ao.h +0 -148
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/aov.h +0 -49
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/attribute.h +0 -326
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/bevel.h +0 -334
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/blackbody.h +0 -35
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/brick.h +0 -147
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/brightness.h +0 -32
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/bump.h +0 -72
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/camera.h +0 -42
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/checker.h +0 -54
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/clamp.h +0 -40
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/closure.h +0 -1559
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/color_util.h +0 -409
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/convert.h +0 -66
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/displace.h +0 -240
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/fractal_noise.h +0 -550
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/fresnel.h +0 -80
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/gabor.h +0 -392
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/gamma.h +0 -27
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/geometry.h +0 -280
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/gradient.h +0 -80
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/hsv.h +0 -54
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/ies.h +0 -38
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/image.h +0 -273
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/invert.h +0 -33
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/light_path.h +0 -150
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/magic.h +0 -132
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/map_range.h +0 -164
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/mapping.h +0 -74
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/mapping_util.h +0 -37
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/math.h +0 -73
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/math_util.h +0 -278
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/mix.h +0 -125
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/node_types_template.h +0 -115
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/noise.h +0 -761
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/noisetex.h +0 -370
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/normal.h +0 -38
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/radial_tiling.h +0 -81
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/radial_tiling_shared.h +0 -1179
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/ramp.h +0 -185
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/ramp_util.h +0 -80
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/sepcomb_color.h +0 -62
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/sepcomb_vector.h +0 -45
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/sky.h +0 -309
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/svm.h +0 -492
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/tex_coord.h +0 -506
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/types.h +0 -530
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/util.h +0 -160
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/value.h +0 -34
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/vector_rotate.h +0 -79
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/vector_transform.h +0 -130
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/vertex_color.h +0 -107
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/voronoi.h +0 -1248
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/wave.h +0 -137
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/wavelength.h +0 -36
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/white_noise.h +0 -74
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/svm/wireframe.h +0 -116
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/tables.h +0 -124
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/types.h +0 -1923
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/colorspace.h +0 -54
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/differential.h +0 -169
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/ies.h +0 -145
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/lookup_table.h +0 -74
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/nanovdb.h +0 -436
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/profiler.h +0 -28
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/kernel/util/texture_3d.h +0 -232
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/atomic.h +0 -315
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/color.h +0 -439
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/defines.h +0 -131
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/guiding.h +0 -40
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/half.h +0 -178
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/hash.h +0 -650
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math.h +0 -24
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_base.h +0 -953
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_dual.h +0 -59
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_fast.h +0 -650
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_float2.h +0 -274
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_float3.h +0 -847
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_float4.h +0 -666
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_float8.h +0 -471
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_int2.h +0 -59
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_int3.h +0 -117
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_int4.h +0 -296
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_int8.h +0 -353
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/math_intersect.h +0 -452
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/projection.h +0 -308
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/projection_inverse.h +0 -95
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/rect.h +0 -61
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/static_assert.h +0 -21
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/texture.h +0 -100
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/transform.h +0 -650
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types.h +0 -32
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_base.h +0 -94
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_dual.h +0 -134
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_float2.h +0 -71
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_float3.h +0 -200
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_float4.h +0 -134
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_float8.h +0 -134
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_int2.h +0 -44
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_int3.h +0 -158
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_int4.h +0 -91
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_int8.h +0 -94
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_rgbe.h +0 -109
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_spectrum.h +0 -28
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_uchar2.h +0 -39
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_uchar3.h +0 -39
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_uchar4.h +0 -45
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_uint2.h +0 -37
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_uint3.h +0 -91
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_uint4.h +0 -37
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/source/util/types_ushort4.h +0 -19
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/ui.py +0 -2645
- package/staging_area/Blender/5.0/scripts/addons_core/cycles/version_update.py +0 -330
- package/staging_area/Blender/5.0/scripts/addons_core/hydra_storm/__init__.py +0 -33
- package/staging_area/Blender/5.0/scripts/addons_core/hydra_storm/engine.py +0 -47
- package/staging_area/Blender/5.0/scripts/addons_core/hydra_storm/properties.py +0 -62
- package/staging_area/Blender/5.0/scripts/addons_core/hydra_storm/ui.py +0 -280
- package/staging_area/Blender/5.0/scripts/addons_core/io_anim_bvh/__init__.py +0 -397
- package/staging_area/Blender/5.0/scripts/addons_core/io_anim_bvh/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_anim_bvh/export_bvh.py +0 -294
- package/staging_area/Blender/5.0/scripts/addons_core/io_anim_bvh/import_bvh.py +0 -795
- package/staging_area/Blender/5.0/scripts/addons_core/io_curve_svg/__init__.py +0 -115
- package/staging_area/Blender/5.0/scripts/addons_core/io_curve_svg/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_curve_svg/import_svg.py +0 -1911
- package/staging_area/Blender/5.0/scripts/addons_core/io_curve_svg/svg_colors.py +0 -153
- package/staging_area/Blender/5.0/scripts/addons_core/io_curve_svg/svg_util.py +0 -107
- package/staging_area/Blender/5.0/scripts/addons_core/io_curve_svg/svg_util_test.py +0 -166
- package/staging_area/Blender/5.0/scripts/addons_core/io_mesh_uv_layout/__init__.py +0 -302
- package/staging_area/Blender/5.0/scripts/addons_core/io_mesh_uv_layout/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_mesh_uv_layout/export_uv_eps.py +0 -82
- package/staging_area/Blender/5.0/scripts/addons_core/io_mesh_uv_layout/export_uv_png.py +0 -119
- package/staging_area/Blender/5.0/scripts/addons_core/io_mesh_uv_layout/export_uv_svg.py +0 -54
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/__init__.py +0 -740
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/data_types.py +0 -62
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/encode_bin.py +0 -434
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/export_fbx_bin.py +0 -3819
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/fbx2json.py +0 -341
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/fbx_utils.py +0 -1931
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/fbx_utils_threading.py +0 -194
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/import_fbx.py +0 -4045
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/json2fbx.py +0 -165
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_fbx/parse_fbx.py +0 -274
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/__init__.py +0 -2250
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/blender_default.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/conversion.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/data_path.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/extras.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/gltf2_blender_math.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/gltf2_blender_ui.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/gltf2_blender_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/json_util.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/__pycache__/material_helpers.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/blender_default.py +0 -15
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/conversion.py +0 -229
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/data_path.py +0 -110
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/extras.py +0 -89
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/gltf2_blender_math.py +0 -209
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/gltf2_blender_ui.py +0 -751
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/gltf2_blender_utils.py +0 -70
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/json_util.py +0 -27
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/com/material_helpers.py +0 -32
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/__pycache__/cache.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/__pycache__/sampler.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/accessors.py +0 -189
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/action.py +0 -1062
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/anim_utils.py +0 -321
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/animations.py +0 -22
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/drivers.py +0 -83
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/fcurves/animation.py +0 -35
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/fcurves/channel_target.py +0 -53
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/fcurves/channels.py +0 -378
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/fcurves/keyframes.py +0 -207
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/fcurves/sampler.py +0 -231
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/keyframes.py +0 -127
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/armature/action_sampled.py +0 -55
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/armature/channel_target.py +0 -54
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/armature/channels.py +0 -236
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/armature/keyframes.py +0 -95
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/armature/sampler.py +0 -230
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/data/channel_target.py +0 -48
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/data/channels.py +0 -118
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/data/keyframes.py +0 -152
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/data/sampler.py +0 -135
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/object/action_sampled.py +0 -58
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/object/channel_target.py +0 -51
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/object/channels.py +0 -136
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/object/keyframes.py +0 -88
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/object/sampler.py +0 -171
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/sampling_cache.py +0 -754
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/shapekeys/action_sampled.py +0 -43
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/shapekeys/channel_target.py +0 -38
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/shapekeys/channels.py +0 -79
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/shapekeys/keyframes.py +0 -145
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/sampled/shapekeys/sampler.py +0 -111
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/scene_animation.py +0 -244
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/animation/tracks.py +0 -846
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/cache.py +0 -182
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/cameras.py +0 -152
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/export.py +0 -412
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/exporter.py +0 -536
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/gather.py +0 -157
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/joints.py +0 -110
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/light_spots.py +0 -47
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/lights.py +0 -212
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/__pycache__/encode_image.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/__pycache__/image.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/__pycache__/search_node_tree.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/__pycache__/texture.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/__pycache__/texture_info.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/__pycache__/unlit.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/encode_image.py +0 -491
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/anisotropy.py +0 -259
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/clearcoat.py +0 -156
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/emission.py +0 -115
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/ior.py +0 -45
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/sheen.py +0 -129
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/specular.py +0 -140
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/transmission.py +0 -76
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/variants.py +0 -19
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/extensions/volume.py +0 -118
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/image.py +0 -514
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/material_utils.py +0 -13
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/material_viewport.py +0 -32
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/materials.py +0 -714
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/pbr_metallic_roughness.py +0 -257
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/search_node_tree.py +0 -1120
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/texture.py +0 -248
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/texture_info.py +0 -291
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/material/unlit.py +0 -191
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/mesh.py +0 -160
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/nodes.py +0 -577
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_attributes.py +0 -252
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/primitive_extract.py +0 -1662
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/primitives.py +0 -366
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/sampler.py +0 -187
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/skins.py +0 -148
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/exp/tree.py +0 -976
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/KHR_materials_anisotropy.py +0 -116
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/KHR_materials_pbrSpecularGlossiness.py +0 -203
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/KHR_materials_unlit.py +0 -56
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/KHR_materials_anisotropy.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/KHR_materials_pbrSpecularGlossiness.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/KHR_materials_unlit.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/animation.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/animation_node.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/animation_pointer.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/animation_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/animation_weight.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/blender_gltf.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/camera.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/draco_compression_extension.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/image.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/light.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/material.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/material_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/mesh.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/node.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/pbrMetallicRoughness.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/scene.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/texture.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/__pycache__/vnode.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/animation.py +0 -170
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/animation_node.py +0 -170
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/animation_pointer.py +0 -787
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/animation_utils.py +0 -174
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/animation_weight.py +0 -95
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/blender_gltf.py +0 -633
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/camera.py +0 -75
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/draco_compression_extension.py +0 -138
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/image.py +0 -102
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/light.py +0 -143
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/material.py +0 -113
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/material_utils.py +0 -196
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/mesh.py +0 -920
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/node.py +0 -348
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/pbrMetallicRoughness.py +0 -903
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/scene.py +0 -133
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/texture.py +0 -233
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/blender/imp/vnode.py +0 -661
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/extern_draco.dll +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/__init__.py +0 -5
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/__pycache__/constants.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/__pycache__/debug.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/__pycache__/draco.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/__pycache__/gltf2_io.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/__pycache__/gltf2_io_extensions.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/__pycache__/path.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/constants.py +0 -159
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/debug.py +0 -129
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/draco.py +0 -46
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/gltf2_io.py +0 -1217
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/gltf2_io_extensions.py +0 -30
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/lights_punctual.py +0 -68
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/path.py +0 -19
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/com/variants.py +0 -32
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/__pycache__/binary_data.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/__pycache__/image_data.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/__pycache__/user_extensions.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/binary_data.py +0 -35
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/buffer.py +0 -54
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/draco.py +0 -174
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/export.py +0 -122
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/image_data.py +0 -80
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/exp/user_extensions.py +0 -17
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/__init__.py +0 -5
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/__pycache__/gltf2_io_binary.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/__pycache__/gltf2_io_gltf.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/__pycache__/user_extensions.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/gltf2_io_binary.py +0 -215
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/gltf2_io_gltf.py +0 -198
- package/staging_area/Blender/5.0/scripts/addons_core/io_scene_gltf2/io/imp/user_extensions.py +0 -13
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/README.md +0 -5
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/__init__.py +0 -64
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/interface.py +0 -526
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/operators.py +0 -2421
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/preferences.py +0 -398
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/utils/constants.py +0 -192
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/utils/draw.py +0 -219
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/utils/nodes.py +0 -299
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/utils/paths.py +0 -169
- package/staging_area/Blender/5.0/scripts/addons_core/node_wrangler/utils/paths_test.py +0 -290
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__init__.py +0 -56
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/asset_browser.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/functions.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/gui.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/keymaps.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/operators.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/pose_creation.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/__pycache__/pose_usage.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/asset_browser.py +0 -99
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/functions.py +0 -57
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/gui.py +0 -229
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/keymaps.py +0 -29
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/operators.py +0 -299
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/pose_creation.py +0 -413
- package/staging_area/Blender/5.0/scripts/addons_core/pose_library/pose_usage.py +0 -85
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/__init__.py +0 -907
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/base_generate.py +0 -536
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/base_rig.py +0 -351
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/feature_set_list.py +0 -357
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/feature_sets/__init__.py +0 -16
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/generate.py +0 -762
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarig_menu.py +0 -271
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Animals/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Animals/bird.py +0 -1397
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Animals/cat.py +0 -2854
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Animals/horse.py +0 -1401
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Animals/shark.py +0 -692
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Animals/wolf.py +0 -3088
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Basic/basic_human.py +0 -618
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/Basic/basic_quadruped.py +0 -715
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/metarigs/human.py +0 -2625
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/operators/__init__.py +0 -34
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/operators/action_layers.py +0 -658
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/operators/copy_mirror_parameters.py +0 -316
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/operators/generic_ui_list.py +0 -191
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/operators/upgrade_face.py +0 -457
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rig_lists.py +0 -116
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rig_ui_template.py +0 -1445
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/basic/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/basic/copy_chain.py +0 -167
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/basic/pivot.py +0 -242
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/basic/raw_copy.py +0 -228
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/basic/super_copy.py +0 -191
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/chain_rigs.py +0 -388
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/experimental/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/experimental/super_chain.py +0 -853
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/face/basic_tongue.py +0 -195
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/face/skin_eye.py +0 -843
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/face/skin_jaw.py +0 -880
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/faces/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/faces/super_face.py +0 -2378
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/arm.py +0 -209
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/front_paw.py +0 -270
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/leg.py +0 -746
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/limb_rigs.py +0 -1287
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/limb_utils.py +0 -78
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/paw.py +0 -360
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/rear_paw.py +0 -172
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/simple_tentacle.py +0 -169
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/spline_tentacle.py +0 -1486
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/super_finger.py +0 -699
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/super_limb.py +0 -46
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/limbs/super_palm.py +0 -426
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/anchor.py +0 -142
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/basic_chain.py +0 -565
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/glue.py +0 -325
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/skin_nodes.py +0 -604
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/skin_parents.py +0 -505
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/skin_rigs.py +0 -250
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/stretchy_chain.py +0 -422
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/skin/transform/basic.py +0 -141
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/spines/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/spines/basic_spine.py +0 -387
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/spines/basic_tail.py +0 -242
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/spines/spine_rigs.py +0 -295
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/spines/super_head.py +0 -424
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/spines/super_spine.py +0 -150
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/utils.py +0 -175
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rigs/widgets.py +0 -483
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/rot_mode.py +0 -311
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/ui.py +0 -1834
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/__init__.py +0 -40
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/action_layers.py +0 -454
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/animation.py +0 -1024
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/bones.py +0 -742
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/collections.py +0 -83
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/components.py +0 -102
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/errors.py +0 -28
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/layers.py +0 -396
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/mechanism.py +0 -669
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/metaclass.py +0 -170
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/misc.py +0 -533
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/naming.py +0 -366
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/node_merger.py +0 -345
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/objects.py +0 -206
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/rig.py +0 -747
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/switch_parent.py +0 -533
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/widgets.py +0 -531
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/widgets_basic.py +0 -305
- package/staging_area/Blender/5.0/scripts/addons_core/rigify/utils/widgets_special.py +0 -226
- package/staging_area/Blender/5.0/scripts/addons_core/ui_translate/__init__.py +0 -60
- package/staging_area/Blender/5.0/scripts/addons_core/ui_translate/settings.py +0 -194
- package/staging_area/Blender/5.0/scripts/addons_core/ui_translate/update_addon.py +0 -378
- package/staging_area/Blender/5.0/scripts/addons_core/ui_translate/update_repo.py +0 -248
- package/staging_area/Blender/5.0/scripts/addons_core/ui_translate/update_ui.py +0 -267
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/__init__.py +0 -55
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/action_map.py +0 -177
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/action_map_io.py +0 -346
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/configs/default.py +0 -434
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/defaults.py +0 -1587
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/gui.py +0 -295
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/operators.py +0 -540
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/preferences.py +0 -67
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/properties.py +0 -228
- package/staging_area/Blender/5.0/scripts/addons_core/viewport_vr_preview/versioning.py +0 -38
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/__init__.py +0 -14
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/chainingiterators.py +0 -644
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/functions.py +0 -313
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/predicates.py +0 -670
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/shaders.py +0 -1248
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/types.py +0 -159
- package/staging_area/Blender/5.0/scripts/freestyle/modules/freestyle/utils.py +0 -541
- package/staging_area/Blender/5.0/scripts/freestyle/modules/parameter_editor.py +0 -1589
- package/staging_area/Blender/5.0/scripts/freestyle/styles/anisotropic_diffusion.py +0 -41
- package/staging_area/Blender/5.0/scripts/freestyle/styles/apriori_and_causal_density.py +0 -34
- package/staging_area/Blender/5.0/scripts/freestyle/styles/apriori_density.py +0 -33
- package/staging_area/Blender/5.0/scripts/freestyle/styles/backbone_stretcher.py +0 -28
- package/staging_area/Blender/5.0/scripts/freestyle/styles/blueprint_circles.py +0 -39
- package/staging_area/Blender/5.0/scripts/freestyle/styles/blueprint_ellipses.py +0 -39
- package/staging_area/Blender/5.0/scripts/freestyle/styles/blueprint_squares.py +0 -40
- package/staging_area/Blender/5.0/scripts/freestyle/styles/cartoon.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/contour.py +0 -33
- package/staging_area/Blender/5.0/scripts/freestyle/styles/curvature2d.py +0 -29
- package/staging_area/Blender/5.0/scripts/freestyle/styles/external_contour.py +0 -33
- package/staging_area/Blender/5.0/scripts/freestyle/styles/external_contour_sketchy.py +0 -39
- package/staging_area/Blender/5.0/scripts/freestyle/styles/external_contour_smooth.py +0 -37
- package/staging_area/Blender/5.0/scripts/freestyle/styles/haloing.py +0 -43
- package/staging_area/Blender/5.0/scripts/freestyle/styles/ignore_small_occlusions.py +0 -30
- package/staging_area/Blender/5.0/scripts/freestyle/styles/invisible_lines.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/japanese_bigbrush.py +0 -53
- package/staging_area/Blender/5.0/scripts/freestyle/styles/long_anisotropically_dense.py +0 -67
- package/staging_area/Blender/5.0/scripts/freestyle/styles/multiple_parameterization.py +0 -41
- package/staging_area/Blender/5.0/scripts/freestyle/styles/nature.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/near_lines.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/occluded_by_specific_object.py +0 -36
- package/staging_area/Blender/5.0/scripts/freestyle/styles/polygonalize.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/qi0.py +0 -31
- package/staging_area/Blender/5.0/scripts/freestyle/styles/qi0_not_external_contour.py +0 -38
- package/staging_area/Blender/5.0/scripts/freestyle/styles/qi1.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/qi2.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/sequentialsplit_sketchy.py +0 -39
- package/staging_area/Blender/5.0/scripts/freestyle/styles/sketchy_multiple_parameterization.py +0 -37
- package/staging_area/Blender/5.0/scripts/freestyle/styles/sketchy_topology_broken.py +0 -39
- package/staging_area/Blender/5.0/scripts/freestyle/styles/sketchy_topology_preserved.py +0 -36
- package/staging_area/Blender/5.0/scripts/freestyle/styles/split_at_highest_2d_curvatures.py +0 -34
- package/staging_area/Blender/5.0/scripts/freestyle/styles/split_at_tvertices.py +0 -33
- package/staging_area/Blender/5.0/scripts/freestyle/styles/suggestive.py +0 -33
- package/staging_area/Blender/5.0/scripts/freestyle/styles/thickness_fof_depth_discontinuity.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/tipremover.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/tvertex_remover.py +0 -32
- package/staging_area/Blender/5.0/scripts/freestyle/styles/uniformpruning_zsort.py +0 -31
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/_bpy_restrict_state.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/_bpy_types.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/_console_python.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/_keyingsets_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/_rna_xml.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/addon_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/bl_app_template_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/nodeitems_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/rna_keymap_ui.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/__pycache__/rna_prop_ui.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_animsys_refactor.py +0 -230
- package/staging_area/Blender/5.0/scripts/modules/_bl_console_utils/__init__.py +0 -7
- package/staging_area/Blender/5.0/scripts/modules/_bl_console_utils/autocomplete/__init__.py +0 -7
- package/staging_area/Blender/5.0/scripts/modules/_bl_console_utils/autocomplete/complete_calltip.py +0 -174
- package/staging_area/Blender/5.0/scripts/modules/_bl_console_utils/autocomplete/complete_import.py +0 -180
- package/staging_area/Blender/5.0/scripts/modules/_bl_console_utils/autocomplete/complete_namespace.py +0 -192
- package/staging_area/Blender/5.0/scripts/modules/_bl_console_utils/autocomplete/intellisense.py +0 -138
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/__init__.py +0 -5
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/bl_extract_messages.py +0 -1363
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/merge_po.py +0 -132
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/settings.py +0 -824
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/settings_user.py +0 -7
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/utils.py +0 -1709
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/utils_cli.py +0 -144
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/utils_languages_menu.py +0 -68
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/utils_rtl.py +0 -179
- package/staging_area/Blender/5.0/scripts/modules/_bl_i18n_utils/utils_spell_check.py +0 -955
- package/staging_area/Blender/5.0/scripts/modules/_bl_previews_utils/bl_previews_render.py +0 -537
- package/staging_area/Blender/5.0/scripts/modules/_bl_rna_utils/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_rna_utils/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_rna_utils/__pycache__/data_path.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_rna_utils/data_path.py +0 -76
- package/staging_area/Blender/5.0/scripts/modules/_bl_text_utils/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_text_utils/external_editor.py +0 -54
- package/staging_area/Blender/5.0/scripts/modules/_bl_ui_utils/__init__.py +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_ui_utils/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_ui_utils/__pycache__/layout.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bl_ui_utils/layout.py +0 -21
- package/staging_area/Blender/5.0/scripts/modules/_blendfile_header.py +0 -234
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/addons/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/addons/cli.py +0 -42
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/assets/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/assets/remote_library_listing/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/assets/remote_library_listing/blender_asset_library_openapi.py +0 -98
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/assets/remote_library_listing/blender_asset_library_openapi.yaml +0 -83
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/__pycache__/junction_module.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/__pycache__/wheel_manager.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/junction_module.py +0 -165
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/permissions.py +0 -16
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/stale_file_manager.py +0 -417
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/tags.py +0 -54
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/extensions/wheel_manager.py +0 -686
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/freedesktop.py +0 -598
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/grease_pencil/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/grease_pencil/stroke.py +0 -402
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/http/__init__.py +0 -3
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/http/downloader.py +0 -1348
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/system_info/text_generate_runtime.py +0 -256
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/system_info/url_prefill_runtime.py +0 -60
- package/staging_area/Blender/5.0/scripts/modules/_bpy_internal/system_info/url_prefill_startup.py +0 -107
- package/staging_area/Blender/5.0/scripts/modules/_bpy_restrict_state.py +0 -50
- package/staging_area/Blender/5.0/scripts/modules/_bpy_types.py +0 -1563
- package/staging_area/Blender/5.0/scripts/modules/_console_python.py +0 -368
- package/staging_area/Blender/5.0/scripts/modules/_console_shell.py +0 -73
- package/staging_area/Blender/5.0/scripts/modules/_graphviz_export.py +0 -194
- package/staging_area/Blender/5.0/scripts/modules/_keyingsets_utils.py +0 -355
- package/staging_area/Blender/5.0/scripts/modules/_rna_info.py +0 -984
- package/staging_area/Blender/5.0/scripts/modules/_rna_manual_reference.py +0 -4446
- package/staging_area/Blender/5.0/scripts/modules/_rna_xml.py +0 -422
- package/staging_area/Blender/5.0/scripts/modules/addon_utils.py +0 -1992
- package/staging_area/Blender/5.0/scripts/modules/bl_app_override/__init__.py +0 -211
- package/staging_area/Blender/5.0/scripts/modules/bl_app_override/helpers.py +0 -153
- package/staging_area/Blender/5.0/scripts/modules/bl_app_template_utils.py +0 -177
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/__init__.py +0 -9
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/__pycache__/io.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/__pycache__/keymap_from_toolbar.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/__pycache__/keymap_hierarchy.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/io.py +0 -308
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py +0 -394
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/keymap_hierarchy.py +0 -247
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/platform_helpers.py +0 -55
- package/staging_area/Blender/5.0/scripts/modules/bl_keymap_utils/versioning.py +0 -328
- package/staging_area/Blender/5.0/scripts/modules/blend_render_info.py +0 -123
- package/staging_area/Blender/5.0/scripts/modules/bpy/__init__.py +0 -75
- package/staging_area/Blender/5.0/scripts/modules/bpy/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy/__pycache__/ops.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy/__pycache__/path.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy/ops.py +0 -184
- package/staging_area/Blender/5.0/scripts/modules/bpy/path.py +0 -459
- package/staging_area/Blender/5.0/scripts/modules/bpy/utils/__init__.py +0 -1382
- package/staging_area/Blender/5.0/scripts/modules/bpy/utils/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy/utils/__pycache__/previews.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy/utils/previews.py +0 -136
- package/staging_area/Blender/5.0/scripts/modules/bpy/utils/toolsystem.py +0 -11
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/__init__.py +0 -20
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/__pycache__/asset_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/__pycache__/io_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/__pycache__/node_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/__pycache__/object_utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/anim_utils.py +0 -1038
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/asset_utils.py +0 -50
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/bmesh_utils.py +0 -56
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/id_map_utils.py +0 -53
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/image_utils.py +0 -194
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/io_utils.py +0 -620
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/keyconfig_utils.py +0 -141
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/mesh_utils.py +0 -464
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/node_shader_utils.py +0 -829
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/node_utils.py +0 -88
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/object_utils.py +0 -289
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/view3d_utils.py +0 -181
- package/staging_area/Blender/5.0/scripts/modules/bpy_extras/wm_utils/progress_report.py +0 -160
- package/staging_area/Blender/5.0/scripts/modules/gpu_extras/__init__.py +0 -8
- package/staging_area/Blender/5.0/scripts/modules/gpu_extras/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/gpu_extras/__pycache__/presets.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/modules/gpu_extras/batch.py +0 -80
- package/staging_area/Blender/5.0/scripts/modules/gpu_extras/presets.py +0 -102
- package/staging_area/Blender/5.0/scripts/modules/nodeitems_utils.py +0 -178
- package/staging_area/Blender/5.0/scripts/modules/rna_keymap_ui.py +0 -505
- package/staging_area/Blender/5.0/scripts/modules/rna_prop_ui.py +0 -269
- package/staging_area/Blender/5.0/scripts/presets/camera/1_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/1_slash_1.8_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/1_slash_2.3_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/1_slash_2.5_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/1_slash_2.7_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/1_slash_3.2_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/2_slash_3_inch.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/APS-C.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/APS-C_(Canon).py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/APS-H_(Canon).py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Analog_16mm.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Analog_35mm.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Analog_65mm.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Analog_IMAX.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Analog_Super_16.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Analog_Super_35.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Arri_Alexa_65.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Arri_Alexa_LF.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Arri_Alexa_Mini_&_SXT.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Blackmagic_Pocket_&_Studio.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Blackmagic_Pocket_4K.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Blackmagic_Pocket_6k.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Blackmagic_URSA_4.6K.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Foveon_(Sigma).py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Fullframe.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/MFT.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/Medium-format_(Hasselblad).py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/RED_Dragon_5K.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/RED_Dragon_6K.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/RED_Helium_8K.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/camera/RED_Monstro_8K.py +0 -4
- package/staging_area/Blender/5.0/scripts/presets/cloth/Cotton.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/cloth/Denim.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/cloth/Leather.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/cloth/Rubber.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/cloth/Silk.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_A.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_B.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_C.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_D50.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_D55.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_D65.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_D75.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_D93.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_E.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F1.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F10.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F11.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F12.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F2.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F3.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F4.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F5.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F6.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F7.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F8.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_F9.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-B1.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-B2.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-B3.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-B4.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-B5.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-BH1.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-RGB1.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-V1.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/color_management/white_balance/Illuminant_LED-V2.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/cycles/integrator/Default.py +0 -14
- package/staging_area/Blender/5.0/scripts/presets/cycles/integrator/Direct_Light.py +0 -14
- package/staging_area/Blender/5.0/scripts/presets/cycles/integrator/Fast_Global_Illumination.py +0 -14
- package/staging_area/Blender/5.0/scripts/presets/cycles/integrator/Full_Global_Illumination.py +0 -14
- package/staging_area/Blender/5.0/scripts/presets/cycles/integrator/Limited_Global_Illumination.py +0 -14
- package/staging_area/Blender/5.0/scripts/presets/cycles/performance/Default.py +0 -11
- package/staging_area/Blender/5.0/scripts/presets/cycles/performance/Faster_Render.py +0 -11
- package/staging_area/Blender/5.0/scripts/presets/cycles/performance/Lower_Memory.py +0 -11
- package/staging_area/Blender/5.0/scripts/presets/cycles/sampling/Final.py +0 -12
- package/staging_area/Blender/5.0/scripts/presets/cycles/sampling/Preview.py +0 -12
- package/staging_area/Blender/5.0/scripts/presets/cycles/viewport_sampling/Final.py +0 -11
- package/staging_area/Blender/5.0/scripts/presets/cycles/viewport_sampling/Preview.py +0 -11
- package/staging_area/Blender/5.0/scripts/presets/eevee/raytracing/Default.py +0 -22
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/DVD_(note_colon__this_changes_render_resolution).py +0 -24
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/H264_in_MP4.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/H264_in_Matroska.py +0 -17
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/H264_in_Matroska_for_scrubbing.py +0 -14
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/Ogg_Theora.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/WebM_(VP9+Opus).py +0 -9
- package/staging_area/Blender/5.0/scripts/presets/ffmpeg/Xvid.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/fluid/Honey.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/fluid/Oil.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/fluid/Water.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/12.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/120.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/23.98.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/24.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/240.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/25.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/29.97.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/30.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/50.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/59.94.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/6.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/60.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/8.py +0 -3
- package/staging_area/Blender/5.0/scripts/presets/framerate/Custom.py +0 -1
- package/staging_area/Blender/5.0/scripts/presets/framerate/__pycache__/30.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/presets/gpencil_material/Fill_Only.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/gpencil_material/Stroke_Only.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/gpencil_material/Stroke_and_Fill.py +0 -25
- package/staging_area/Blender/5.0/scripts/presets/hair_dynamics/Default.py +0 -17
- package/staging_area/Blender/5.0/scripts/presets/interface_theme/Blender_Dark.xml +0 -6
- package/staging_area/Blender/5.0/scripts/presets/interface_theme/Blender_Light.xml +0 -1246
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/Blender.py +0 -384
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/Blender_27x.py +0 -106
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/Industry_Compatible.py +0 -41
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/__pycache__/Blender.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/keymap_data/__pycache__/blender_default.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/keymap_data/blender_default.py +0 -9083
- package/staging_area/Blender/5.0/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +0 -3896
- package/staging_area/Blender/5.0/scripts/presets/pixel_density/Custom.py +0 -1
- package/staging_area/Blender/5.0/scripts/presets/pixel_density/Pixels_slash_Centimeter.py +0 -2
- package/staging_area/Blender/5.0/scripts/presets/pixel_density/Pixels_slash_Inch.py +0 -2
- package/staging_area/Blender/5.0/scripts/presets/pixel_density/Pixels_slash_Meter.py +0 -2
- package/staging_area/Blender/5.0/scripts/presets/render/4K_DCI_2160p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/4K_UHDTV_2160p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/4K_UW_1600p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/DVCPRO_HD_1080p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/DVCPRO_HD_720p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/HDTV_1080p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/HDTV_720p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/HDV_1080p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/HDV_NTSC_1080p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/HDV_PAL_1080p.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/TV_NTSC_16_colon_9.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/TV_NTSC_4_colon_3.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/TV_PAL_16_colon_9.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/render/TV_PAL_4_colon_3.py +0 -8
- package/staging_area/Blender/5.0/scripts/presets/safe_areas/14_colon_9_in_16_colon_9.py +0 -7
- package/staging_area/Blender/5.0/scripts/presets/safe_areas/16_colon_9.py +0 -7
- package/staging_area/Blender/5.0/scripts/presets/safe_areas/4_colon_3_in_16_colon_9.py +0 -7
- package/staging_area/Blender/5.0/scripts/presets/text_editor/Internal.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/text_editor/Visual_Studio_Code.py +0 -12
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/1_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/1_slash_1.8_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/1_slash_2.3_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/1_slash_2.5_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/1_slash_2.7_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/1_slash_3.2_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/2_slash_3_inch.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/APS-C.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/APS-C_(Canon).py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/APS-H_(Canon).py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Analog_16mm.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Analog_35mm.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Analog_65mm.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Analog_IMAX.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Analog_Super_16.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Analog_Super_35.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Arri_Alexa_65.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Arri_Alexa_LF.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Arri_Alexa_Mini_&_SXT.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Blackmagic_Pocket_&_Studio.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Blackmagic_Pocket_4K.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Blackmagic_Pocket_6k.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Blackmagic_URSA_4.6K.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Foveon_(Sigma).py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Fullframe.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/MFT.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/Medium-format_(Hasselblad).py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/RED_Dragon_5K.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/RED_Dragon_6K.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/RED_Helium_8K.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_camera/RED_Monstro_8K.py +0 -6
- package/staging_area/Blender/5.0/scripts/presets/tracking_settings/Blurry_Footage.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/tracking_settings/Default.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/tracking_settings/Fast_Motion.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/tracking_settings/Planar.py +0 -18
- package/staging_area/Blender/5.0/scripts/presets/tracking_track_color/Default.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/tracking_track_color/Far_Plane.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/tracking_track_color/Near_Plane.py +0 -5
- package/staging_area/Blender/5.0/scripts/presets/tracking_track_color/Object.py +0 -5
- package/staging_area/Blender/5.0/scripts/startup/__pycache__/keyingsets_builtins.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/__pycache__/nodeitems_builtins.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py +0 -56
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/2D_Animation/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/2D_Animation/startup.blend +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Sculpting/__init__.py +0 -30
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Sculpting/startup.blend +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Storyboarding/__init__.py +0 -51
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Storyboarding/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Storyboarding/startup.blend +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/VFX/startup.blend +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py +0 -51
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Video_Editing/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_app_templates_system/Video_Editing/startup.blend +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__init__.py +0 -88
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/add_mesh_torus.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/anim.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/assets.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/bone_selection_sets.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/clip.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/connect_to_output.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/console.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/constraint.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/copy_global_transform.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/file.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/freestyle.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/geometry_nodes.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/grease_pencil.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/image.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/image_as_planes.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/mesh.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/node.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/object.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/object_align.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/object_quick_effects.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/object_randomize_transform.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/presets.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/rigidbody.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/screen_play_rendered_anim.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/sequencer.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/spreadsheet.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/userpref.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/uvcalc_follow_active.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/uvcalc_lightmap.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/uvcalc_transform.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/vertexpaint_dirt.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/view3d.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/wm.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/__pycache__/world.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/add_mesh_torus.py +0 -262
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/anim.py +0 -924
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/assets.py +0 -157
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/bmesh/find_adjacent.py +0 -341
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/bone_selection_sets.py +0 -439
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/clip.py +0 -1044
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/connect_to_output.py +0 -360
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/console.py +0 -156
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/constraint.py +0 -121
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/copy_global_transform.py +0 -823
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/file.py +0 -308
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/freestyle.py +0 -226
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/geometry_nodes.py +0 -394
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/grease_pencil.py +0 -63
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/image.py +0 -322
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/image_as_planes.py +0 -1216
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/mesh.py +0 -61
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/node.py +0 -1340
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/node_editor/__pycache__/node_functions.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/node_editor/node_functions.py +0 -97
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/object.py +0 -1014
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/object_align.py +0 -407
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/object_quick_effects.py +0 -680
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/object_randomize_transform.py +0 -181
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/presets.py +0 -1057
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/rigidbody.py +0 -323
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/screen_play_rendered_anim.py +0 -219
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/sequencer.py +0 -438
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/spreadsheet.py +0 -46
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/userpref.py +0 -1324
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/uvcalc_follow_active.py +0 -313
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/uvcalc_lightmap.py +0 -688
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/uvcalc_transform.py +0 -551
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/vertexpaint_dirt.py +0 -198
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/view3d.py +0 -316
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/wm.py +0 -3722
- package/staging_area/Blender/5.0/scripts/startup/bl_operators/world.py +0 -168
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__init__.py +0 -299
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/__init__.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/anim.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/asset_shelf.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/generic_ui_list.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/node_add_menu.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/node_add_menu_compositor.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/node_add_menu_geometry.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/node_add_menu_shader.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/node_add_menu_texture.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_animviz.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_collection.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_constraint.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_armature.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_bone.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_camera.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_curve.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_curves.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_empty.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_grease_pencil.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_lattice.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_light.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_lightprobe.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_mesh.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_metaball.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_modifier.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_pointcloud.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_shaderfx.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_speaker.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_data_volume.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_freestyle.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_grease_pencil_common.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_mask_common.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_material.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_material_gpencil.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_object.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_output.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_paint_common.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_particle.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_cloth.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_common.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_dynamicpaint.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_field.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_fluid.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_geometry_nodes.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_rigidbody.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_rigidbody_constraint.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_physics_softbody.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_render.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_scene.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_strip.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_strip_modifier.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_texture.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_view_layer.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_workspace.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/properties_world.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_clip.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_console.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_dopesheet.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_filebrowser.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_graph.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_image.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_info.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_nla.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_node.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_outliner.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_properties.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_sequencer.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_spreadsheet.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_statusbar.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_text.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_time.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_toolsystem_common.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_toolsystem_toolbar.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_topbar.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_userpref.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_view3d.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_view3d_sidebar.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/space_view3d_toolbar.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/__pycache__/utils.cpython-311.pyc +0 -0
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/anim.py +0 -62
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/asset_shelf.py +0 -41
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/generic_ui_list.py +0 -262
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/node_add_menu.py +0 -505
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/node_add_menu_compositor.py +0 -437
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/node_add_menu_geometry.py +0 -1158
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/node_add_menu_shader.py +0 -511
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/node_add_menu_texture.py +0 -167
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_animviz.py +0 -123
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_collection.py +0 -146
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_constraint.py +0 -1793
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_armature.py +0 -436
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_bone.py +0 -625
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_camera.py +0 -603
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_curve.py +0 -461
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_curves.py +0 -219
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_empty.py +0 -84
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_grease_pencil.py +0 -536
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_lattice.py +0 -105
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_light.py +0 -315
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_lightprobe.py +0 -413
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_mesh.py +0 -744
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_metaball.py +0 -137
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_modifier.py +0 -323
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_pointcloud.py +0 -175
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_shaderfx.py +0 -31
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_speaker.py +0 -157
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_data_volume.py +0 -239
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_freestyle.py +0 -1343
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_grease_pencil_common.py +0 -607
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_mask_common.py +0 -461
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_material.py +0 -460
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_material_gpencil.py +0 -272
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_object.py +0 -656
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_output.py +0 -736
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_paint_common.py +0 -1904
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_particle.py +0 -2308
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_cloth.py +0 -524
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_common.py +0 -360
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_dynamicpaint.py +0 -974
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_field.py +0 -487
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_fluid.py +0 -1629
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_geometry_nodes.py +0 -64
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_rigidbody.py +0 -345
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py +0 -554
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_physics_softbody.py +0 -471
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_render.py +0 -1180
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_scene.py +0 -495
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_strip.py +0 -1056
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_strip_modifier.py +0 -49
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_texture.py +0 -997
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_view_layer.py +0 -348
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_workspace.py +0 -195
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/properties_world.py +0 -282
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_clip.py +0 -2112
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_console.py +0 -157
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_dopesheet.py +0 -1123
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_filebrowser.py +0 -950
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_graph.py +0 -615
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_image.py +0 -1896
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_info.py +0 -117
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_nla.py +0 -429
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_node.py +0 -1247
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_outliner.py +0 -559
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_properties.py +0 -205
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_sequencer.py +0 -2097
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_spreadsheet.py +0 -83
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_statusbar.py +0 -41
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_text.py +0 -479
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_time.py +0 -364
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_toolsystem_common.py +0 -1256
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_toolsystem_toolbar.py +0 -4123
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_topbar.py +0 -891
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_userpref.py +0 -3108
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_view3d.py +0 -9421
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_view3d_sidebar.py +0 -183
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/space_view3d_toolbar.py +0 -2438
- package/staging_area/Blender/5.0/scripts/startup/bl_ui/utils.py +0 -40
- package/staging_area/Blender/5.0/scripts/startup/keyingsets_builtins.py +0 -686
- package/staging_area/Blender/5.0/scripts/startup/nodeitems_builtins.py +0 -54
- package/staging_area/Blender/5.0/scripts/templates_osl/advanced_camera.osl +0 -76
- package/staging_area/Blender/5.0/scripts/templates_osl/basic_camera.osl +0 -14
- package/staging_area/Blender/5.0/scripts/templates_osl/basic_shader.osl +0 -10
- package/staging_area/Blender/5.0/scripts/templates_osl/cubemap_camera.osl +0 -42
- package/staging_area/Blender/5.0/scripts/templates_osl/empty_shader.osl +0 -6
- package/staging_area/Blender/5.0/scripts/templates_osl/gabor_noise.osl +0 -17
- package/staging_area/Blender/5.0/scripts/templates_osl/lyapunov_texture.osl +0 -141
- package/staging_area/Blender/5.0/scripts/templates_osl/noise.osl +0 -27
- package/staging_area/Blender/5.0/scripts/templates_osl/ramp_closure.osl +0 -20
- package/staging_area/Blender/5.0/scripts/templates_py/addon_add_object.py +0 -84
- package/staging_area/Blender/5.0/scripts/templates_py/background_job.py +0 -118
- package/staging_area/Blender/5.0/scripts/templates_py/batch_export.py +0 -42
- package/staging_area/Blender/5.0/scripts/templates_py/bmesh_simple.py +0 -22
- package/staging_area/Blender/5.0/scripts/templates_py/bmesh_simple_editmode.py +0 -23
- package/staging_area/Blender/5.0/scripts/templates_py/builtin_keyingset.py +0 -37
- package/staging_area/Blender/5.0/scripts/templates_py/custom_nodes.py +0 -172
- package/staging_area/Blender/5.0/scripts/templates_py/driver_functions.py +0 -35
- package/staging_area/Blender/5.0/scripts/templates_py/external_script_stub.py +0 -13
- package/staging_area/Blender/5.0/scripts/templates_py/gizmo_custom_geometry.py +0 -157
- package/staging_area/Blender/5.0/scripts/templates_py/gizmo_operator.py +0 -235
- package/staging_area/Blender/5.0/scripts/templates_py/gizmo_operator_target.py +0 -50
- package/staging_area/Blender/5.0/scripts/templates_py/gizmo_simple_2d.py +0 -59
- package/staging_area/Blender/5.0/scripts/templates_py/gizmo_simple_3d.py +0 -47
- package/staging_area/Blender/5.0/scripts/templates_py/image_processing.py +0 -35
- package/staging_area/Blender/5.0/scripts/templates_py/operator_file_export.py +0 -76
- package/staging_area/Blender/5.0/scripts/templates_py/operator_file_import.py +0 -79
- package/staging_area/Blender/5.0/scripts/templates_py/operator_mesh_add.py +0 -116
- package/staging_area/Blender/5.0/scripts/templates_py/operator_mesh_uv.py +0 -56
- package/staging_area/Blender/5.0/scripts/templates_py/operator_modal.py +0 -58
- package/staging_area/Blender/5.0/scripts/templates_py/operator_modal_draw.py +0 -83
- package/staging_area/Blender/5.0/scripts/templates_py/operator_modal_timer.py +0 -54
- package/staging_area/Blender/5.0/scripts/templates_py/operator_modal_view3d.py +0 -77
- package/staging_area/Blender/5.0/scripts/templates_py/operator_modal_view3d_raycast.py +0 -115
- package/staging_area/Blender/5.0/scripts/templates_py/operator_node.py +0 -66
- package/staging_area/Blender/5.0/scripts/templates_py/operator_simple.py +0 -42
- package/staging_area/Blender/5.0/scripts/templates_py/ui_asset_shelf.py +0 -29
- package/staging_area/Blender/5.0/scripts/templates_py/ui_list.py +0 -44
- package/staging_area/Blender/5.0/scripts/templates_py/ui_list_generic.py +0 -47
- package/staging_area/Blender/5.0/scripts/templates_py/ui_list_simple.py +0 -70
- package/staging_area/Blender/5.0/scripts/templates_py/ui_menu.py +0 -50
- package/staging_area/Blender/5.0/scripts/templates_py/ui_menu_simple.py +0 -27
- package/staging_area/Blender/5.0/scripts/templates_py/ui_panel.py +0 -73
- package/staging_area/Blender/5.0/scripts/templates_py/ui_panel_simple.py +0 -38
- package/staging_area/Blender/5.0/scripts/templates_py/ui_pie_menu.py +0 -31
- package/staging_area/Blender/5.0/scripts/templates_py/ui_previews_custom_icon.py +0 -76
- package/staging_area/Blender/5.0/scripts/templates_py/ui_previews_dynamic_enum.py +0 -141
- package/staging_area/Blender/5.0/scripts/templates_py/ui_tool_simple.py +0 -91
- package/staging_area/Blender/5.0/scripts/templates_toml/blender_manifest.toml +0 -75
- package/staging_area/Blender/blender-launcher.exe +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-console-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-console-l1-2-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-datetime-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-debug-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-errorhandling-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-fibers-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-file-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-file-l1-2-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-file-l2-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-handle-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-heap-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-interlocked-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-libraryloader-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-localization-l1-2-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-memory-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-namedpipe-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-processenvironment-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-processthreads-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-processthreads-l1-1-1.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-profile-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-rtlsupport-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-string-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-synch-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-synch-l1-2-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-sysinfo-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-timezone-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-core-util-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-conio-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-convert-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-environment-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-filesystem-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-heap-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-locale-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-math-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-multibyte-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-private-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-process-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-runtime-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-stdio-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-string-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-time-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/api-ms-win-crt-utility-l1-1-0.dll +0 -0
- package/staging_area/Blender/blender.crt/blender.crt.manifest +0 -54
- package/staging_area/Blender/blender.crt/concrt140.dll +0 -0
- package/staging_area/Blender/blender.crt/msvcp140.dll +0 -0
- package/staging_area/Blender/blender.crt/msvcp140_1.dll +0 -0
- package/staging_area/Blender/blender.crt/msvcp140_2.dll +0 -0
- package/staging_area/Blender/blender.crt/msvcp140_atomic_wait.dll +0 -0
- package/staging_area/Blender/blender.crt/msvcp140_codecvt_ids.dll +0 -0
- package/staging_area/Blender/blender.crt/vcruntime140.dll +0 -0
- package/staging_area/Blender/blender.crt/vcruntime140_1.dll +0 -0
|
@@ -1,4045 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2013-2023 Blender Foundation
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
4
|
-
|
|
5
|
-
# FBX 7.1.0 -> 7.4.0 loader for Blender
|
|
6
|
-
|
|
7
|
-
# Not totally pep8 compliant.
|
|
8
|
-
# pep8 import_fbx.py --ignore=E501,E123,E702,E125
|
|
9
|
-
|
|
10
|
-
if "bpy" in locals():
|
|
11
|
-
import importlib
|
|
12
|
-
if "parse_fbx" in locals():
|
|
13
|
-
importlib.reload(parse_fbx)
|
|
14
|
-
if "fbx_utils" in locals():
|
|
15
|
-
importlib.reload(fbx_utils)
|
|
16
|
-
|
|
17
|
-
import bpy
|
|
18
|
-
from bpy.app.translations import pgettext_rpt as rpt_
|
|
19
|
-
from mathutils import Matrix, Euler, Vector, Quaternion
|
|
20
|
-
from bpy_extras import anim_utils
|
|
21
|
-
|
|
22
|
-
# Also imported in .fbx_utils, so importing here is unlikely to further affect Blender startup time.
|
|
23
|
-
import numpy as np
|
|
24
|
-
|
|
25
|
-
# -----
|
|
26
|
-
# Utils
|
|
27
|
-
from . import parse_fbx, fbx_utils
|
|
28
|
-
|
|
29
|
-
from .parse_fbx import (
|
|
30
|
-
data_types,
|
|
31
|
-
FBXElem,
|
|
32
|
-
)
|
|
33
|
-
from .fbx_utils import (
|
|
34
|
-
PerfMon,
|
|
35
|
-
units_blender_to_fbx_factor,
|
|
36
|
-
units_convertor_iter,
|
|
37
|
-
array_to_matrix4,
|
|
38
|
-
similar_values,
|
|
39
|
-
similar_values_iter,
|
|
40
|
-
FBXImportSettings,
|
|
41
|
-
vcos_transformed,
|
|
42
|
-
nors_transformed,
|
|
43
|
-
parray_as_ndarray,
|
|
44
|
-
astype_view_signedness,
|
|
45
|
-
MESH_ATTRIBUTE_MATERIAL_INDEX,
|
|
46
|
-
MESH_ATTRIBUTE_POSITION,
|
|
47
|
-
MESH_ATTRIBUTE_EDGE_VERTS,
|
|
48
|
-
MESH_ATTRIBUTE_CORNER_VERT,
|
|
49
|
-
MESH_ATTRIBUTE_SHARP_FACE,
|
|
50
|
-
MESH_ATTRIBUTE_SHARP_EDGE,
|
|
51
|
-
expand_shape_key_range,
|
|
52
|
-
FBX_KTIME_V7,
|
|
53
|
-
FBX_KTIME_V8,
|
|
54
|
-
FBX_TIMECODE_DEFINITION_TO_KTIME_PER_SECOND,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
LINEAR_INTERPOLATION_VALUE = bpy.types.Keyframe.bl_rna.properties['interpolation'].enum_items['LINEAR'].value
|
|
58
|
-
|
|
59
|
-
# global singleton, assign on execution
|
|
60
|
-
fbx_elem_nil = None
|
|
61
|
-
|
|
62
|
-
# Units converters...
|
|
63
|
-
convert_deg_to_rad_iter = units_convertor_iter("degree", "radian")
|
|
64
|
-
|
|
65
|
-
MAT_CONVERT_BONE = fbx_utils.MAT_CONVERT_BONE.inverted()
|
|
66
|
-
MAT_CONVERT_LIGHT = fbx_utils.MAT_CONVERT_LIGHT.inverted()
|
|
67
|
-
MAT_CONVERT_CAMERA = fbx_utils.MAT_CONVERT_CAMERA.inverted()
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def validate_blend_names(name):
|
|
71
|
-
assert(type(name) == bytes)
|
|
72
|
-
# Blender typically does not accept names over 63 bytes...
|
|
73
|
-
if len(name) > 63:
|
|
74
|
-
import hashlib
|
|
75
|
-
h = hashlib.sha1(name).hexdigest()
|
|
76
|
-
n = 55
|
|
77
|
-
name_utf8 = name[:n].decode('utf-8', 'replace') + "_" + h[:7]
|
|
78
|
-
while len(name_utf8.encode()) > 63:
|
|
79
|
-
n -= 1
|
|
80
|
-
name_utf8 = name[:n].decode('utf-8', 'replace') + "_" + h[:7]
|
|
81
|
-
return name_utf8
|
|
82
|
-
else:
|
|
83
|
-
# We use 'replace' even though FBX 'specs' say it should always be utf8, see T53841.
|
|
84
|
-
return name.decode('utf-8', 'replace')
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def elem_find_first(elem, id_search, default=None):
|
|
88
|
-
for fbx_item in elem.elems:
|
|
89
|
-
if fbx_item.id == id_search:
|
|
90
|
-
return fbx_item
|
|
91
|
-
return default
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def elem_find_iter(elem, id_search):
|
|
95
|
-
for fbx_item in elem.elems:
|
|
96
|
-
if fbx_item.id == id_search:
|
|
97
|
-
yield fbx_item
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def elem_find_first_string(elem, id_search):
|
|
101
|
-
fbx_item = elem_find_first(elem, id_search)
|
|
102
|
-
if fbx_item is not None and fbx_item.props: # Do not error on complete empty properties (see T45291).
|
|
103
|
-
assert(len(fbx_item.props) == 1)
|
|
104
|
-
assert(fbx_item.props_type[0] == data_types.STRING)
|
|
105
|
-
return fbx_item.props[0].decode('utf-8', 'replace')
|
|
106
|
-
return None
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def elem_find_first_string_as_bytes(elem, id_search):
|
|
110
|
-
fbx_item = elem_find_first(elem, id_search)
|
|
111
|
-
if fbx_item is not None and fbx_item.props: # Do not error on complete empty properties (see T45291).
|
|
112
|
-
assert(len(fbx_item.props) == 1)
|
|
113
|
-
assert(fbx_item.props_type[0] == data_types.STRING)
|
|
114
|
-
return fbx_item.props[0] # Keep it as bytes as requested...
|
|
115
|
-
return None
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def elem_find_first_bytes(elem, id_search, decode=True):
|
|
119
|
-
fbx_item = elem_find_first(elem, id_search)
|
|
120
|
-
if fbx_item is not None and fbx_item.props: # Do not error on complete empty properties (see T45291).
|
|
121
|
-
assert(len(fbx_item.props) == 1)
|
|
122
|
-
assert(fbx_item.props_type[0] == data_types.BYTES)
|
|
123
|
-
return fbx_item.props[0]
|
|
124
|
-
return None
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def elem_repr(elem):
|
|
128
|
-
return "%s: props[%d=%r], elems=(%r)" % (
|
|
129
|
-
elem.id,
|
|
130
|
-
len(elem.props),
|
|
131
|
-
", ".join([repr(p) for p in elem.props]),
|
|
132
|
-
# elem.props_type,
|
|
133
|
-
b", ".join([e.id for e in elem.elems]),
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def elem_split_name_class(elem):
|
|
138
|
-
assert(elem.props_type[-2] == data_types.STRING)
|
|
139
|
-
elem_name, elem_class = elem.props[-2].split(b'\x00\x01')
|
|
140
|
-
return elem_name, elem_class
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def elem_name_ensure_class(elem, clss=...):
|
|
144
|
-
elem_name, elem_class = elem_split_name_class(elem)
|
|
145
|
-
if clss is not ...:
|
|
146
|
-
assert(elem_class == clss)
|
|
147
|
-
return validate_blend_names(elem_name)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def elem_name_ensure_classes(elem, clss=...):
|
|
151
|
-
elem_name, elem_class = elem_split_name_class(elem)
|
|
152
|
-
if clss is not ...:
|
|
153
|
-
assert(elem_class in clss)
|
|
154
|
-
return validate_blend_names(elem_name)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def elem_split_name_class_nodeattr(elem):
|
|
158
|
-
assert(elem.props_type[-2] == data_types.STRING)
|
|
159
|
-
elem_name, elem_class = elem.props[-2].split(b'\x00\x01')
|
|
160
|
-
assert(elem_class == b'NodeAttribute')
|
|
161
|
-
assert(elem.props_type[-1] == data_types.STRING)
|
|
162
|
-
elem_class = elem.props[-1]
|
|
163
|
-
return elem_name, elem_class
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def elem_uuid(elem):
|
|
167
|
-
assert(elem.props_type[0] == data_types.INT64)
|
|
168
|
-
return elem.props[0]
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def elem_prop_first(elem, default=None):
|
|
172
|
-
return elem.props[0] if (elem is not None) and elem.props else default
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# ----
|
|
176
|
-
# Support for
|
|
177
|
-
# Properties70: { ... P:
|
|
178
|
-
# Custom properties ("user properties" in FBX) are ignored here and get handled separately (see #104773).
|
|
179
|
-
def elem_props_find_first(elem, elem_prop_id):
|
|
180
|
-
if elem is None:
|
|
181
|
-
# When properties are not found... Should never happen, but happens - as usual.
|
|
182
|
-
return None
|
|
183
|
-
# support for templates (tuple of elems)
|
|
184
|
-
if type(elem) is not FBXElem:
|
|
185
|
-
assert(type(elem) is tuple)
|
|
186
|
-
for e in elem:
|
|
187
|
-
result = elem_props_find_first(e, elem_prop_id)
|
|
188
|
-
if result is not None:
|
|
189
|
-
return result
|
|
190
|
-
assert(len(elem) > 0)
|
|
191
|
-
return None
|
|
192
|
-
|
|
193
|
-
for subelem in elem.elems:
|
|
194
|
-
assert(subelem.id == b'P')
|
|
195
|
-
# 'U' flag indicates that the property has been defined by the user.
|
|
196
|
-
if subelem.props[0] == elem_prop_id and b'U' not in subelem.props[3]:
|
|
197
|
-
return subelem
|
|
198
|
-
return None
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def elem_props_get_color_rgb(elem, elem_prop_id, default=None):
|
|
202
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
203
|
-
if elem_prop is not None:
|
|
204
|
-
assert(elem_prop.props[0] == elem_prop_id)
|
|
205
|
-
if elem_prop.props[1] == b'Color':
|
|
206
|
-
# FBX version 7300
|
|
207
|
-
assert(elem_prop.props[1] == b'Color')
|
|
208
|
-
assert(elem_prop.props[2] == b'')
|
|
209
|
-
else:
|
|
210
|
-
assert(elem_prop.props[1] == b'ColorRGB')
|
|
211
|
-
assert(elem_prop.props[2] == b'Color')
|
|
212
|
-
assert(elem_prop.props_type[4:7] == bytes((data_types.FLOAT64,)) * 3)
|
|
213
|
-
return elem_prop.props[4:7]
|
|
214
|
-
return default
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def elem_props_get_vector_3d(elem, elem_prop_id, default=None):
|
|
218
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
219
|
-
if elem_prop is not None:
|
|
220
|
-
assert(elem_prop.props_type[4:7] == bytes((data_types.FLOAT64,)) * 3)
|
|
221
|
-
return elem_prop.props[4:7]
|
|
222
|
-
return default
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def elem_props_get_number(elem, elem_prop_id, default=None):
|
|
226
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
227
|
-
if elem_prop is not None:
|
|
228
|
-
assert(elem_prop.props[0] == elem_prop_id)
|
|
229
|
-
if elem_prop.props[1] == b'double':
|
|
230
|
-
assert(elem_prop.props[1] == b'double')
|
|
231
|
-
assert(elem_prop.props[2] == b'Number')
|
|
232
|
-
else:
|
|
233
|
-
assert(elem_prop.props[1] == b'Number')
|
|
234
|
-
assert(elem_prop.props[2] == b'')
|
|
235
|
-
|
|
236
|
-
# we could allow other number types
|
|
237
|
-
assert(elem_prop.props_type[4] == data_types.FLOAT64)
|
|
238
|
-
|
|
239
|
-
return elem_prop.props[4]
|
|
240
|
-
return default
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def elem_props_get_integer(elem, elem_prop_id, default=None):
|
|
244
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
245
|
-
if elem_prop is not None:
|
|
246
|
-
assert(elem_prop.props[0] == elem_prop_id)
|
|
247
|
-
if elem_prop.props[1] == b'int':
|
|
248
|
-
assert(elem_prop.props[1] == b'int')
|
|
249
|
-
assert(elem_prop.props[2] == b'Integer')
|
|
250
|
-
elif elem_prop.props[1] == b'ULongLong':
|
|
251
|
-
assert(elem_prop.props[1] == b'ULongLong')
|
|
252
|
-
assert(elem_prop.props[2] == b'')
|
|
253
|
-
|
|
254
|
-
# we could allow other number types
|
|
255
|
-
assert(elem_prop.props_type[4] in {data_types.INT32, data_types.INT64})
|
|
256
|
-
|
|
257
|
-
return elem_prop.props[4]
|
|
258
|
-
return default
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
def elem_props_get_bool(elem, elem_prop_id, default=None):
|
|
262
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
263
|
-
if elem_prop is not None:
|
|
264
|
-
assert(elem_prop.props[0] == elem_prop_id)
|
|
265
|
-
# b'Bool' with a capital seems to be used for animated property... go figure...
|
|
266
|
-
assert(elem_prop.props[1] in {b'bool', b'Bool'})
|
|
267
|
-
assert(elem_prop.props[2] == b'')
|
|
268
|
-
|
|
269
|
-
# we could allow other number types
|
|
270
|
-
assert(elem_prop.props_type[4] == data_types.INT32)
|
|
271
|
-
assert(elem_prop.props[4] in {0, 1})
|
|
272
|
-
|
|
273
|
-
return bool(elem_prop.props[4])
|
|
274
|
-
return default
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def elem_props_get_enum(elem, elem_prop_id, default=None):
|
|
278
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
279
|
-
if elem_prop is not None:
|
|
280
|
-
assert(elem_prop.props[0] == elem_prop_id)
|
|
281
|
-
assert(elem_prop.props[1] == b'enum')
|
|
282
|
-
assert(elem_prop.props[2] == b'')
|
|
283
|
-
assert(elem_prop.props[3] == b'')
|
|
284
|
-
|
|
285
|
-
# we could allow other number types
|
|
286
|
-
assert(elem_prop.props_type[4] == data_types.INT32)
|
|
287
|
-
|
|
288
|
-
return elem_prop.props[4]
|
|
289
|
-
return default
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
def elem_props_get_visibility(elem, elem_prop_id, default=None):
|
|
293
|
-
elem_prop = elem_props_find_first(elem, elem_prop_id)
|
|
294
|
-
if elem_prop is not None:
|
|
295
|
-
assert(elem_prop.props[0] == elem_prop_id)
|
|
296
|
-
assert(elem_prop.props[1] == b'Visibility')
|
|
297
|
-
assert(elem_prop.props[2] == b'')
|
|
298
|
-
|
|
299
|
-
# we could allow other number types
|
|
300
|
-
assert(elem_prop.props_type[4] == data_types.FLOAT64)
|
|
301
|
-
|
|
302
|
-
return elem_prop.props[4]
|
|
303
|
-
return default
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
# ----------------------------------------------------------------------------
|
|
307
|
-
# Blender
|
|
308
|
-
|
|
309
|
-
# ------
|
|
310
|
-
# Object
|
|
311
|
-
from collections import namedtuple
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
FBXTransformData = namedtuple("FBXTransformData", (
|
|
315
|
-
"loc", "geom_loc",
|
|
316
|
-
"rot", "rot_ofs", "rot_piv", "pre_rot", "pst_rot", "rot_ord", "rot_alt_mat", "geom_rot",
|
|
317
|
-
"sca", "sca_ofs", "sca_piv", "geom_sca",
|
|
318
|
-
))
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
def blen_read_custom_properties(fbx_obj, blen_obj, settings):
|
|
322
|
-
# There doesn't seem to be a way to put user properties into templates, so this only get the object properties:
|
|
323
|
-
fbx_obj_props = elem_find_first(fbx_obj, b'Properties70')
|
|
324
|
-
if fbx_obj_props:
|
|
325
|
-
for fbx_prop in fbx_obj_props.elems:
|
|
326
|
-
assert(fbx_prop.id == b'P')
|
|
327
|
-
|
|
328
|
-
if b'U' in fbx_prop.props[3]:
|
|
329
|
-
if fbx_prop.props[0] == b'UDP3DSMAX':
|
|
330
|
-
# Special case for 3DS Max user properties:
|
|
331
|
-
try:
|
|
332
|
-
assert(fbx_prop.props[1] == b'KString')
|
|
333
|
-
except AssertionError as exc:
|
|
334
|
-
print(exc)
|
|
335
|
-
assert(fbx_prop.props_type[4] == data_types.STRING)
|
|
336
|
-
items = fbx_prop.props[4].decode('utf-8', 'replace')
|
|
337
|
-
for item in items.split('\r\n'):
|
|
338
|
-
if item:
|
|
339
|
-
split_item = item.split('=', 1)
|
|
340
|
-
if len(split_item) != 2:
|
|
341
|
-
split_item = item.split(':', 1)
|
|
342
|
-
if len(split_item) != 2:
|
|
343
|
-
print("cannot parse UDP3DSMAX custom property '%s', ignoring..." % item)
|
|
344
|
-
else:
|
|
345
|
-
prop_name, prop_value = split_item
|
|
346
|
-
prop_name = validate_blend_names(prop_name.strip().encode('utf-8'))
|
|
347
|
-
blen_obj[prop_name] = prop_value.strip()
|
|
348
|
-
else:
|
|
349
|
-
prop_name = validate_blend_names(fbx_prop.props[0])
|
|
350
|
-
prop_type = fbx_prop.props[1]
|
|
351
|
-
if prop_type in {b'Vector', b'Vector3D', b'Color', b'ColorRGB'}:
|
|
352
|
-
assert(fbx_prop.props_type[4:7] == bytes((data_types.FLOAT64,)) * 3)
|
|
353
|
-
blen_obj[prop_name] = fbx_prop.props[4:7]
|
|
354
|
-
elif prop_type in {b'Vector4', b'ColorRGBA'}:
|
|
355
|
-
assert(fbx_prop.props_type[4:8] == bytes((data_types.FLOAT64,)) * 4)
|
|
356
|
-
blen_obj[prop_name] = fbx_prop.props[4:8]
|
|
357
|
-
elif prop_type == b'Vector2D':
|
|
358
|
-
assert(fbx_prop.props_type[4:6] == bytes((data_types.FLOAT64,)) * 2)
|
|
359
|
-
blen_obj[prop_name] = fbx_prop.props[4:6]
|
|
360
|
-
elif prop_type in {b'Integer', b'int'}:
|
|
361
|
-
assert(fbx_prop.props_type[4] == data_types.INT32)
|
|
362
|
-
blen_obj[prop_name] = fbx_prop.props[4]
|
|
363
|
-
elif prop_type == b'KString':
|
|
364
|
-
assert(fbx_prop.props_type[4] == data_types.STRING)
|
|
365
|
-
blen_obj[prop_name] = fbx_prop.props[4].decode('utf-8', 'replace')
|
|
366
|
-
elif prop_type in {b'Number', b'double', b'Double'}:
|
|
367
|
-
assert(fbx_prop.props_type[4] == data_types.FLOAT64)
|
|
368
|
-
blen_obj[prop_name] = fbx_prop.props[4]
|
|
369
|
-
elif prop_type in {b'Float', b'float'}:
|
|
370
|
-
assert(fbx_prop.props_type[4] == data_types.FLOAT32)
|
|
371
|
-
blen_obj[prop_name] = fbx_prop.props[4]
|
|
372
|
-
elif prop_type in {b'Bool', b'bool'}:
|
|
373
|
-
assert(fbx_prop.props_type[4] == data_types.INT32)
|
|
374
|
-
blen_obj[prop_name] = fbx_prop.props[4] != 0
|
|
375
|
-
elif prop_type in {b'Enum', b'enum'}:
|
|
376
|
-
assert(fbx_prop.props_type[4:6] == bytes((data_types.INT32, data_types.STRING)))
|
|
377
|
-
val = fbx_prop.props[4]
|
|
378
|
-
if settings.use_custom_props_enum_as_string and fbx_prop.props[5]:
|
|
379
|
-
enum_items = fbx_prop.props[5].decode('utf-8', 'replace').split('~')
|
|
380
|
-
if val >= 0 and val < len(enum_items):
|
|
381
|
-
blen_obj[prop_name] = enum_items[val]
|
|
382
|
-
else:
|
|
383
|
-
print("WARNING: User property '%s' has wrong enum value, skipped" % prop_name)
|
|
384
|
-
else:
|
|
385
|
-
blen_obj[prop_name] = val
|
|
386
|
-
else:
|
|
387
|
-
print(
|
|
388
|
-
"WARNING: User property type '%s' is not supported" %
|
|
389
|
-
prop_type.decode(
|
|
390
|
-
'utf-8', 'replace'))
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
def blen_read_object_transform_do(transform_data):
|
|
394
|
-
# This is a nightmare. FBX SDK uses Maya way to compute the transformation matrix of a node - utterly simple:
|
|
395
|
-
#
|
|
396
|
-
# WorldTransform = ParentWorldTransform @ T @ Roff @ Rp @ Rpre @ R @ Rpost-1 @ Rp-1 @ Soff @ Sp @ S @ Sp-1
|
|
397
|
-
#
|
|
398
|
-
# Where all those terms are 4 x 4 matrices that contain:
|
|
399
|
-
# WorldTransform: Transformation matrix of the node in global space.
|
|
400
|
-
# ParentWorldTransform: Transformation matrix of the parent node in global space.
|
|
401
|
-
# T: Translation
|
|
402
|
-
# Roff: Rotation offset
|
|
403
|
-
# Rp: Rotation pivot
|
|
404
|
-
# Rpre: Pre-rotation
|
|
405
|
-
# R: Rotation
|
|
406
|
-
# Rpost-1: Inverse of the post-rotation (FBX 2011 documentation incorrectly specifies this without inversion)
|
|
407
|
-
# Rp-1: Inverse of the rotation pivot
|
|
408
|
-
# Soff: Scaling offset
|
|
409
|
-
# Sp: Scaling pivot
|
|
410
|
-
# S: Scaling
|
|
411
|
-
# Sp-1: Inverse of the scaling pivot
|
|
412
|
-
#
|
|
413
|
-
# But it was still too simple, and FBX notion of compatibility is... quite specific. So we also have to
|
|
414
|
-
# support 3DSMax way:
|
|
415
|
-
#
|
|
416
|
-
# WorldTransform = ParentWorldTransform @ T @ R @ S @ OT @ OR @ OS
|
|
417
|
-
#
|
|
418
|
-
# Where all those terms are 4 x 4 matrices that contain:
|
|
419
|
-
# WorldTransform: Transformation matrix of the node in global space
|
|
420
|
-
# ParentWorldTransform: Transformation matrix of the parent node in global space
|
|
421
|
-
# T: Translation
|
|
422
|
-
# R: Rotation
|
|
423
|
-
# S: Scaling
|
|
424
|
-
# OT: Geometric transform translation
|
|
425
|
-
# OR: Geometric transform rotation
|
|
426
|
-
# OS: Geometric transform scale
|
|
427
|
-
#
|
|
428
|
-
# Notes:
|
|
429
|
-
# Geometric transformations ***are not inherited***: ParentWorldTransform does not contain the OT, OR, OS
|
|
430
|
-
# of WorldTransform's parent node.
|
|
431
|
-
# The R matrix takes into account the rotation order. Other rotation matrices are always 'XYZ' order.
|
|
432
|
-
#
|
|
433
|
-
# Taken from https://help.autodesk.com/view/FBX/2020/ENU/
|
|
434
|
-
# ?guid=FBX_Developer_Help_nodes_and_scene_graph_fbx_nodes_computing_transformation_matrix_html
|
|
435
|
-
|
|
436
|
-
# translation
|
|
437
|
-
lcl_translation = Matrix.Translation(transform_data.loc)
|
|
438
|
-
geom_loc = Matrix.Translation(transform_data.geom_loc)
|
|
439
|
-
|
|
440
|
-
# rotation
|
|
441
|
-
def to_rot(rot, rot_ord): return Euler(convert_deg_to_rad_iter(rot), rot_ord).to_matrix().to_4x4()
|
|
442
|
-
lcl_rot = to_rot(transform_data.rot, transform_data.rot_ord) @ transform_data.rot_alt_mat
|
|
443
|
-
pre_rot = to_rot(transform_data.pre_rot, 'XYZ')
|
|
444
|
-
pst_rot = to_rot(transform_data.pst_rot, 'XYZ')
|
|
445
|
-
geom_rot = to_rot(transform_data.geom_rot, 'XYZ')
|
|
446
|
-
|
|
447
|
-
rot_ofs = Matrix.Translation(transform_data.rot_ofs)
|
|
448
|
-
rot_piv = Matrix.Translation(transform_data.rot_piv)
|
|
449
|
-
sca_ofs = Matrix.Translation(transform_data.sca_ofs)
|
|
450
|
-
sca_piv = Matrix.Translation(transform_data.sca_piv)
|
|
451
|
-
|
|
452
|
-
# scale
|
|
453
|
-
lcl_scale = Matrix()
|
|
454
|
-
lcl_scale[0][0], lcl_scale[1][1], lcl_scale[2][2] = transform_data.sca
|
|
455
|
-
geom_scale = Matrix()
|
|
456
|
-
geom_scale[0][0], geom_scale[1][1], geom_scale[2][2] = transform_data.geom_sca
|
|
457
|
-
|
|
458
|
-
base_mat = (
|
|
459
|
-
lcl_translation @
|
|
460
|
-
rot_ofs @
|
|
461
|
-
rot_piv @
|
|
462
|
-
pre_rot @
|
|
463
|
-
lcl_rot @
|
|
464
|
-
pst_rot.inverted_safe() @
|
|
465
|
-
rot_piv.inverted_safe() @
|
|
466
|
-
sca_ofs @
|
|
467
|
-
sca_piv @
|
|
468
|
-
lcl_scale @
|
|
469
|
-
sca_piv.inverted_safe()
|
|
470
|
-
)
|
|
471
|
-
geom_mat = geom_loc @ geom_rot @ geom_scale
|
|
472
|
-
# We return mat without 'geometric transforms' too, because it is to be used for children, sigh...
|
|
473
|
-
return (base_mat @ geom_mat, base_mat, geom_mat)
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
# XXX This might be weak, now that we can add vgroups from both bones and shapes, name collisions become
|
|
477
|
-
# more likely, will have to make this more robust!!!
|
|
478
|
-
def add_vgroup_to_objects(vg_indices, vg_weights, vg_name, objects):
|
|
479
|
-
assert(len(vg_indices) == len(vg_weights))
|
|
480
|
-
if vg_indices:
|
|
481
|
-
for obj in objects:
|
|
482
|
-
# We replace/override here...
|
|
483
|
-
vg = obj.vertex_groups.get(vg_name)
|
|
484
|
-
if vg is None:
|
|
485
|
-
vg = obj.vertex_groups.new(name=vg_name)
|
|
486
|
-
vg_add = vg.add
|
|
487
|
-
for i, w in zip(vg_indices, vg_weights):
|
|
488
|
-
vg_add((i,), w, 'REPLACE')
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
def blen_read_object_transform_preprocess(fbx_props, fbx_obj, rot_alt_mat, use_prepost_rot):
|
|
492
|
-
# This is quite involved, 'fbxRNode.cpp' from openscenegraph used as a reference
|
|
493
|
-
const_vector_zero_3d = 0.0, 0.0, 0.0
|
|
494
|
-
const_vector_one_3d = 1.0, 1.0, 1.0
|
|
495
|
-
|
|
496
|
-
loc = list(elem_props_get_vector_3d(fbx_props, b'Lcl Translation', const_vector_zero_3d))
|
|
497
|
-
rot = list(elem_props_get_vector_3d(fbx_props, b'Lcl Rotation', const_vector_zero_3d))
|
|
498
|
-
sca = list(elem_props_get_vector_3d(fbx_props, b'Lcl Scaling', const_vector_one_3d))
|
|
499
|
-
|
|
500
|
-
geom_loc = list(elem_props_get_vector_3d(fbx_props, b'GeometricTranslation', const_vector_zero_3d))
|
|
501
|
-
geom_rot = list(elem_props_get_vector_3d(fbx_props, b'GeometricRotation', const_vector_zero_3d))
|
|
502
|
-
geom_sca = list(elem_props_get_vector_3d(fbx_props, b'GeometricScaling', const_vector_one_3d))
|
|
503
|
-
|
|
504
|
-
rot_ofs = elem_props_get_vector_3d(fbx_props, b'RotationOffset', const_vector_zero_3d)
|
|
505
|
-
rot_piv = elem_props_get_vector_3d(fbx_props, b'RotationPivot', const_vector_zero_3d)
|
|
506
|
-
sca_ofs = elem_props_get_vector_3d(fbx_props, b'ScalingOffset', const_vector_zero_3d)
|
|
507
|
-
sca_piv = elem_props_get_vector_3d(fbx_props, b'ScalingPivot', const_vector_zero_3d)
|
|
508
|
-
|
|
509
|
-
is_rot_act = elem_props_get_bool(fbx_props, b'RotationActive', False)
|
|
510
|
-
|
|
511
|
-
if is_rot_act:
|
|
512
|
-
if use_prepost_rot:
|
|
513
|
-
pre_rot = elem_props_get_vector_3d(fbx_props, b'PreRotation', const_vector_zero_3d)
|
|
514
|
-
pst_rot = elem_props_get_vector_3d(fbx_props, b'PostRotation', const_vector_zero_3d)
|
|
515
|
-
else:
|
|
516
|
-
pre_rot = const_vector_zero_3d
|
|
517
|
-
pst_rot = const_vector_zero_3d
|
|
518
|
-
rot_ord = {
|
|
519
|
-
0: 'XYZ',
|
|
520
|
-
1: 'XZY',
|
|
521
|
-
2: 'YZX',
|
|
522
|
-
3: 'YXZ',
|
|
523
|
-
4: 'ZXY',
|
|
524
|
-
5: 'ZYX',
|
|
525
|
-
6: 'XYZ', # XXX eSphericXYZ, not really supported...
|
|
526
|
-
}.get(elem_props_get_enum(fbx_props, b'RotationOrder', 0))
|
|
527
|
-
else:
|
|
528
|
-
pre_rot = const_vector_zero_3d
|
|
529
|
-
pst_rot = const_vector_zero_3d
|
|
530
|
-
rot_ord = 'XYZ'
|
|
531
|
-
|
|
532
|
-
return FBXTransformData(loc, geom_loc,
|
|
533
|
-
rot, rot_ofs, rot_piv, pre_rot, pst_rot, rot_ord, rot_alt_mat, geom_rot,
|
|
534
|
-
sca, sca_ofs, sca_piv, geom_sca)
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
# ---------
|
|
538
|
-
# Animation
|
|
539
|
-
def _blen_read_object_transform_do_anim(transform_data, lcl_translation_mat, lcl_rot_euler, lcl_scale_mat,
|
|
540
|
-
extra_pre_matrix, extra_post_matrix):
|
|
541
|
-
"""Specialized version of blen_read_object_transform_do for animation that pre-calculates the non-animated matrices
|
|
542
|
-
and returns a function that calculates (base_mat @ geom_mat). See the comments in blen_read_object_transform_do for
|
|
543
|
-
a full description of what this function is doing.
|
|
544
|
-
|
|
545
|
-
The lcl_translation_mat, lcl_rot_euler and lcl_scale_mat arguments should have their values updated each frame and
|
|
546
|
-
then calling the returned function will calculate the matrix for the current frame.
|
|
547
|
-
|
|
548
|
-
extra_pre_matrix and extra_post_matrix are any extra matrices to multiply first/last."""
|
|
549
|
-
# Translation
|
|
550
|
-
geom_loc = Matrix.Translation(transform_data.geom_loc)
|
|
551
|
-
|
|
552
|
-
# Rotation
|
|
553
|
-
def to_rot_xyz(rot):
|
|
554
|
-
# All the rotations that can be precalculated have a fixed XYZ order.
|
|
555
|
-
return Euler(convert_deg_to_rad_iter(rot), 'XYZ').to_matrix().to_4x4()
|
|
556
|
-
pre_rot = to_rot_xyz(transform_data.pre_rot)
|
|
557
|
-
pst_rot_inv = to_rot_xyz(transform_data.pst_rot).inverted_safe()
|
|
558
|
-
geom_rot = to_rot_xyz(transform_data.geom_rot)
|
|
559
|
-
|
|
560
|
-
# Offsets and pivots
|
|
561
|
-
rot_ofs = Matrix.Translation(transform_data.rot_ofs)
|
|
562
|
-
rot_piv = Matrix.Translation(transform_data.rot_piv)
|
|
563
|
-
rot_piv_inv = rot_piv.inverted_safe()
|
|
564
|
-
sca_ofs = Matrix.Translation(transform_data.sca_ofs)
|
|
565
|
-
sca_piv = Matrix.Translation(transform_data.sca_piv)
|
|
566
|
-
sca_piv_inv = sca_piv.inverted_safe()
|
|
567
|
-
|
|
568
|
-
# Scale
|
|
569
|
-
geom_scale = Matrix()
|
|
570
|
-
geom_scale[0][0], geom_scale[1][1], geom_scale[2][2] = transform_data.geom_sca
|
|
571
|
-
|
|
572
|
-
# Some matrices can be combined in advance, using the associative property of matrix multiplication, so that less
|
|
573
|
-
# matrix multiplication is required each frame.
|
|
574
|
-
geom_mat = geom_loc @ geom_rot @ geom_scale
|
|
575
|
-
post_lcl_translation = rot_ofs @ rot_piv @ pre_rot
|
|
576
|
-
post_lcl_rotation = transform_data.rot_alt_mat @ pst_rot_inv @ rot_piv_inv @ sca_ofs @ sca_piv
|
|
577
|
-
post_lcl_scaling = sca_piv_inv @ geom_mat @ extra_post_matrix
|
|
578
|
-
|
|
579
|
-
# Get the bound to_matrix method to avoid re-binding it on each call.
|
|
580
|
-
lcl_rot_euler_to_matrix_3x3 = lcl_rot_euler.to_matrix
|
|
581
|
-
# Get the unbound Matrix.to_4x4 method to avoid having to look it up again on each call.
|
|
582
|
-
matrix_to_4x4 = Matrix.to_4x4
|
|
583
|
-
|
|
584
|
-
if extra_pre_matrix == Matrix():
|
|
585
|
-
# There aren't any other matrices that must be multiplied before lcl_translation_mat that extra_pre_matrix can
|
|
586
|
-
# be combined with, so skip extra_pre_matrix when it's the identity matrix.
|
|
587
|
-
return lambda: (lcl_translation_mat @
|
|
588
|
-
post_lcl_translation @
|
|
589
|
-
matrix_to_4x4(lcl_rot_euler_to_matrix_3x3()) @
|
|
590
|
-
post_lcl_rotation @
|
|
591
|
-
lcl_scale_mat @
|
|
592
|
-
post_lcl_scaling)
|
|
593
|
-
else:
|
|
594
|
-
return lambda: (extra_pre_matrix @
|
|
595
|
-
lcl_translation_mat @
|
|
596
|
-
post_lcl_translation @
|
|
597
|
-
matrix_to_4x4(lcl_rot_euler_to_matrix_3x3()) @
|
|
598
|
-
post_lcl_rotation @
|
|
599
|
-
lcl_scale_mat @
|
|
600
|
-
post_lcl_scaling)
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
def _transformation_curves_gen(item, values_arrays, channel_keys):
|
|
604
|
-
"""Yields flattened location/rotation/scaling values for imported PoseBone/Object Lcl Translation/Rotation/Scaling
|
|
605
|
-
animation curve values.
|
|
606
|
-
|
|
607
|
-
The value arrays must have the same lengths, where each index of each array corresponds to a single keyframe.
|
|
608
|
-
|
|
609
|
-
Each value array must have a corresponding channel key tuple that identifies the fbx property
|
|
610
|
-
(b'Lcl Translation'/b'Lcl Rotation'/b'Lcl Scaling') and the channel (x/y/z as 0/1/2) of that property."""
|
|
611
|
-
from operator import setitem
|
|
612
|
-
from functools import partial
|
|
613
|
-
|
|
614
|
-
if item.is_bone:
|
|
615
|
-
bl_obj = item.bl_obj.pose.bones[item.bl_bone]
|
|
616
|
-
else:
|
|
617
|
-
bl_obj = item.bl_obj
|
|
618
|
-
|
|
619
|
-
rot_mode = bl_obj.rotation_mode
|
|
620
|
-
transform_data = item.fbx_transform_data
|
|
621
|
-
rot_eul_prev = bl_obj.rotation_euler.copy()
|
|
622
|
-
rot_quat_prev = bl_obj.rotation_quaternion.copy()
|
|
623
|
-
|
|
624
|
-
# Pre-compute combined pre-matrix
|
|
625
|
-
# Remove that rest pose matrix from current matrix (also in parent space) by computing the inverted local rest
|
|
626
|
-
# matrix of the bone, if relevant.
|
|
627
|
-
combined_pre_matrix = item.get_bind_matrix().inverted_safe() if item.is_bone else Matrix()
|
|
628
|
-
# item.pre_matrix will contain any correction for a parent's correction matrix or the global matrix
|
|
629
|
-
if item.pre_matrix:
|
|
630
|
-
combined_pre_matrix @= item.pre_matrix
|
|
631
|
-
|
|
632
|
-
# Pre-compute combined post-matrix
|
|
633
|
-
# Compensate for changes in the local matrix during processing
|
|
634
|
-
combined_post_matrix = item.anim_compensation_matrix.copy() if item.anim_compensation_matrix else Matrix()
|
|
635
|
-
# item.post_matrix will contain any correction for lights, camera and bone orientation
|
|
636
|
-
if item.post_matrix:
|
|
637
|
-
combined_post_matrix @= item.post_matrix
|
|
638
|
-
|
|
639
|
-
# Create matrices/euler from the initial transformation values of this item.
|
|
640
|
-
# These variables will be updated in-place as we iterate through each frame.
|
|
641
|
-
lcl_translation_mat = Matrix.Translation(transform_data.loc)
|
|
642
|
-
lcl_rotation_eul = Euler(convert_deg_to_rad_iter(transform_data.rot), transform_data.rot_ord)
|
|
643
|
-
lcl_scaling_mat = Matrix()
|
|
644
|
-
lcl_scaling_mat[0][0], lcl_scaling_mat[1][1], lcl_scaling_mat[2][2] = transform_data.sca
|
|
645
|
-
|
|
646
|
-
# Create setters into lcl_translation_mat, lcl_rotation_eul and lcl_scaling_mat for each values_array and convert
|
|
647
|
-
# any rotation values into radians.
|
|
648
|
-
lcl_setters = []
|
|
649
|
-
values_arrays_converted = []
|
|
650
|
-
for values_array, (fbx_prop, channel) in zip(values_arrays, channel_keys):
|
|
651
|
-
if fbx_prop == b'Lcl Translation':
|
|
652
|
-
# lcl_translation_mat.translation[channel] = value
|
|
653
|
-
setter = partial(setitem, lcl_translation_mat.translation, channel)
|
|
654
|
-
elif fbx_prop == b'Lcl Rotation':
|
|
655
|
-
# FBX rotations are in degrees, but Blender uses radians, so convert all rotation values in advance.
|
|
656
|
-
values_array = np.deg2rad(values_array)
|
|
657
|
-
# lcl_rotation_eul[channel] = value
|
|
658
|
-
setter = partial(setitem, lcl_rotation_eul, channel)
|
|
659
|
-
else:
|
|
660
|
-
assert(fbx_prop == b'Lcl Scaling')
|
|
661
|
-
# lcl_scaling_mat[channel][channel] = value
|
|
662
|
-
setter = partial(setitem, lcl_scaling_mat[channel], channel)
|
|
663
|
-
lcl_setters.append(setter)
|
|
664
|
-
values_arrays_converted.append(values_array)
|
|
665
|
-
|
|
666
|
-
# Create an iterator that gets one value from each array. Each iterated tuple will be all the imported
|
|
667
|
-
# Lcl Translation/Lcl Rotation/Lcl Scaling values for a single frame, in that order.
|
|
668
|
-
# Note that an FBX animation does not have to animate all the channels, so only the animated channels of each
|
|
669
|
-
# property will be present.
|
|
670
|
-
# .data, the memoryview of an np.ndarray, is faster to iterate than the ndarray itself.
|
|
671
|
-
frame_values_it = zip(*(arr.data for arr in values_arrays_converted))
|
|
672
|
-
|
|
673
|
-
# Getting the unbound methods in advance avoids having to look them up again on each call within the loop.
|
|
674
|
-
mat_decompose = Matrix.decompose
|
|
675
|
-
quat_to_axis_angle = Quaternion.to_axis_angle
|
|
676
|
-
quat_to_euler = Quaternion.to_euler
|
|
677
|
-
quat_dot = Quaternion.dot
|
|
678
|
-
|
|
679
|
-
calc_mat = _blen_read_object_transform_do_anim(transform_data,
|
|
680
|
-
lcl_translation_mat, lcl_rotation_eul, lcl_scaling_mat,
|
|
681
|
-
combined_pre_matrix, combined_post_matrix)
|
|
682
|
-
|
|
683
|
-
# Iterate through the values for each frame.
|
|
684
|
-
for frame_values in frame_values_it:
|
|
685
|
-
# Set each value into its corresponding lcl matrix/euler.
|
|
686
|
-
for lcl_setter, value in zip(lcl_setters, frame_values):
|
|
687
|
-
lcl_setter(value)
|
|
688
|
-
|
|
689
|
-
# Calculate the updated matrix for this frame.
|
|
690
|
-
mat = calc_mat()
|
|
691
|
-
|
|
692
|
-
# Now we have a virtual matrix of transform from AnimCurves, we can yield keyframe values!
|
|
693
|
-
loc, rot, sca = mat_decompose(mat)
|
|
694
|
-
if rot_mode == 'QUATERNION':
|
|
695
|
-
if quat_dot(rot_quat_prev, rot) < 0.0:
|
|
696
|
-
rot = -rot
|
|
697
|
-
rot_quat_prev = rot
|
|
698
|
-
elif rot_mode == 'AXIS_ANGLE':
|
|
699
|
-
vec, ang = quat_to_axis_angle(rot)
|
|
700
|
-
rot = ang, vec.x, vec.y, vec.z
|
|
701
|
-
else: # Euler
|
|
702
|
-
rot = quat_to_euler(rot, rot_mode, rot_eul_prev)
|
|
703
|
-
rot_eul_prev = rot
|
|
704
|
-
|
|
705
|
-
# Yield order matches the order that the location/rotation/scale FCurves are created in.
|
|
706
|
-
yield from loc
|
|
707
|
-
yield from rot
|
|
708
|
-
yield from sca
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
def _combine_curve_keyframe_times(times_and_values_tuples, initial_values):
|
|
712
|
-
"""Combine multiple parsed animation curves, that affect different channels, such that every animation curve
|
|
713
|
-
contains the keyframes from every other curve, interpolating the values for the newly inserted keyframes in each
|
|
714
|
-
curve.
|
|
715
|
-
|
|
716
|
-
Currently, linear interpolation is assumed, but FBX does store how keyframes should be interpolated, so correctly
|
|
717
|
-
interpolating the keyframe values is a TODO."""
|
|
718
|
-
if len(times_and_values_tuples) == 1:
|
|
719
|
-
# Nothing to do when there is only a single curve.
|
|
720
|
-
times, values = times_and_values_tuples[0]
|
|
721
|
-
return times, [values]
|
|
722
|
-
|
|
723
|
-
all_times = [t[0] for t in times_and_values_tuples]
|
|
724
|
-
|
|
725
|
-
# Get the combined sorted unique times of all the curves.
|
|
726
|
-
sorted_all_times = np.unique(np.concatenate(all_times))
|
|
727
|
-
|
|
728
|
-
values_arrays = []
|
|
729
|
-
for (times, values), initial_value in zip(times_and_values_tuples, initial_values):
|
|
730
|
-
if sorted_all_times.size == times.size:
|
|
731
|
-
# `sorted_all_times` will always contain all values in `times` and both `times` and `sorted_all_times` must
|
|
732
|
-
# be strictly increasing, so if both arrays have the same size, they must be identical.
|
|
733
|
-
extended_values = values
|
|
734
|
-
else:
|
|
735
|
-
# For now, linear interpolation is assumed. NumPy conveniently has a fast C-compiled function for this.
|
|
736
|
-
# Efficiently implementing other FBX supported interpolation will most likely be much more complicated.
|
|
737
|
-
extended_values = np.interp(sorted_all_times, times, values, left=initial_value)
|
|
738
|
-
values_arrays.append(extended_values)
|
|
739
|
-
return sorted_all_times, values_arrays
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
def blen_read_invalid_animation_curve(key_times, key_values):
|
|
743
|
-
"""FBX will parse animation curves even when their keyframe times are invalid (not strictly increasing). It's
|
|
744
|
-
unclear exactly how FBX handles invalid curves, but this matches in some cases and is how the FBX IO addon has been
|
|
745
|
-
handling invalid keyframe times for a long time.
|
|
746
|
-
|
|
747
|
-
Notably, this function will also correctly parse valid animation curves, though is much slower than the trivial,
|
|
748
|
-
regular way.
|
|
749
|
-
|
|
750
|
-
The returned keyframe times are guaranteed to be strictly increasing."""
|
|
751
|
-
sorted_unique_times = np.unique(key_times)
|
|
752
|
-
|
|
753
|
-
# Unsure if this can be vectorized with numpy, so using iteration for now.
|
|
754
|
-
def index_gen():
|
|
755
|
-
idx = 0
|
|
756
|
-
key_times_data = key_times.data
|
|
757
|
-
key_times_len = len(key_times)
|
|
758
|
-
# Iterating .data, the memoryview of the array, is faster than iterating the array directly.
|
|
759
|
-
for curr_fbxktime in sorted_unique_times.data:
|
|
760
|
-
if key_times_data[idx] < curr_fbxktime:
|
|
761
|
-
if idx >= 0:
|
|
762
|
-
idx += 1
|
|
763
|
-
if idx >= key_times_len:
|
|
764
|
-
# We have reached our last element for this curve, stay on it from now on...
|
|
765
|
-
idx = -1
|
|
766
|
-
yield idx
|
|
767
|
-
|
|
768
|
-
indices = np.fromiter(index_gen(), dtype=np.int64, count=len(sorted_unique_times))
|
|
769
|
-
indexed_times = key_times[indices]
|
|
770
|
-
indexed_values = key_values[indices]
|
|
771
|
-
|
|
772
|
-
# Linear interpolate the value for each time in sorted_unique_times according to the times and values at each index
|
|
773
|
-
# and the previous index.
|
|
774
|
-
interpolated_values = np.empty_like(indexed_values)
|
|
775
|
-
|
|
776
|
-
# Where the index is 0, there's no previous value to interpolate from, so we set the value without interpolating.
|
|
777
|
-
# Because the indices are in increasing order, all zeroes must be at the start, so we can find the index of the last
|
|
778
|
-
# zero and use that to index with a slice instead of a boolean array for performance.
|
|
779
|
-
# Equivalent to, but as a slice:
|
|
780
|
-
# idx_zero_mask = indices == 0
|
|
781
|
-
# idx_nonzero_mask = ~idx_zero_mask
|
|
782
|
-
first_nonzero_idx = np.searchsorted(indices, 0, side='right')
|
|
783
|
-
idx_zero_slice = slice(0, first_nonzero_idx) # [:first_nonzero_idx]
|
|
784
|
-
idx_nonzero_slice = slice(first_nonzero_idx, None) # [first_nonzero_idx:]
|
|
785
|
-
|
|
786
|
-
interpolated_values[idx_zero_slice] = indexed_values[idx_zero_slice]
|
|
787
|
-
|
|
788
|
-
indexed_times_nonzero_idx = indexed_times[idx_nonzero_slice]
|
|
789
|
-
indexed_values_nonzero_idx = indexed_values[idx_nonzero_slice]
|
|
790
|
-
indices_nonzero = indices[idx_nonzero_slice]
|
|
791
|
-
|
|
792
|
-
prev_indices_nonzero = indices_nonzero - 1
|
|
793
|
-
prev_indexed_times_nonzero_idx = key_times[prev_indices_nonzero]
|
|
794
|
-
prev_indexed_values_nonzero_idx = key_values[prev_indices_nonzero]
|
|
795
|
-
|
|
796
|
-
ifac_a = sorted_unique_times[idx_nonzero_slice] - prev_indexed_times_nonzero_idx
|
|
797
|
-
ifac_b = indexed_times_nonzero_idx - prev_indexed_times_nonzero_idx
|
|
798
|
-
# If key_times contains two (or more) duplicate times in a row, then values in `ifac_b` can be zero which would
|
|
799
|
-
# result in division by zero.
|
|
800
|
-
# Use the `np.errstate` context manager to suppress printing the RuntimeWarning to the system console.
|
|
801
|
-
with np.errstate(divide='ignore'):
|
|
802
|
-
ifac = ifac_a / ifac_b
|
|
803
|
-
interpolated_values[idx_nonzero_slice] = ((indexed_values_nonzero_idx - prev_indexed_values_nonzero_idx) * ifac
|
|
804
|
-
+ prev_indexed_values_nonzero_idx)
|
|
805
|
-
|
|
806
|
-
# If the time to interpolate at is larger than the time in indexed_times, then the value has been extrapolated.
|
|
807
|
-
# Extrapolated values are excluded.
|
|
808
|
-
valid_mask = indexed_times >= sorted_unique_times
|
|
809
|
-
|
|
810
|
-
key_times = sorted_unique_times[valid_mask]
|
|
811
|
-
key_values = interpolated_values[valid_mask]
|
|
812
|
-
|
|
813
|
-
return key_times, key_values
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
def _convert_fbx_time_to_blender_time(key_times, blen_start_offset, fbx_start_offset, fps, fbx_ktime):
|
|
817
|
-
timefac = fps / fbx_ktime
|
|
818
|
-
|
|
819
|
-
# Convert from FBX timing to Blender timing.
|
|
820
|
-
# Cannot subtract in-place because key_times could be read directly from FBX and could be used by multiple Actions.
|
|
821
|
-
key_times = key_times - fbx_start_offset
|
|
822
|
-
# FBX times are integers and timefac is a Python float, so the new array will be a np.float64 array.
|
|
823
|
-
key_times = key_times * timefac
|
|
824
|
-
|
|
825
|
-
key_times += blen_start_offset
|
|
826
|
-
|
|
827
|
-
return key_times
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
def blen_read_animation_curve(fbx_curve):
|
|
831
|
-
"""Read an animation curve from FBX data.
|
|
832
|
-
|
|
833
|
-
The parsed keyframe times are guaranteed to be strictly increasing."""
|
|
834
|
-
key_times = parray_as_ndarray(elem_prop_first(elem_find_first(fbx_curve, b'KeyTime')))
|
|
835
|
-
key_values = parray_as_ndarray(elem_prop_first(elem_find_first(fbx_curve, b'KeyValueFloat')))
|
|
836
|
-
|
|
837
|
-
assert(len(key_values) == len(key_times))
|
|
838
|
-
|
|
839
|
-
# The FBX SDK specifies that only one key per time is allowed and that the keys are sorted in time order.
|
|
840
|
-
# https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_cpp_ref_class_fbx_anim_curve_html
|
|
841
|
-
all_times_strictly_increasing = (key_times[1:] > key_times[:-1]).all()
|
|
842
|
-
|
|
843
|
-
if all_times_strictly_increasing:
|
|
844
|
-
return key_times, key_values
|
|
845
|
-
else:
|
|
846
|
-
# FBX will still read animation curves even if they are invalid.
|
|
847
|
-
return blen_read_invalid_animation_curve(key_times, key_values)
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
def blen_store_keyframes(fbx_key_times, blen_fcurve, key_values, blen_start_offset, fps, fbx_ktime, fbx_start_offset=0):
|
|
851
|
-
"""Set all keyframe times and values for a newly created FCurve.
|
|
852
|
-
Linear interpolation is currently assumed.
|
|
853
|
-
|
|
854
|
-
This is a convenience function for calling blen_store_keyframes_multi with only a single fcurve and values array."""
|
|
855
|
-
blen_store_keyframes_multi(fbx_key_times, [(blen_fcurve, key_values)], blen_start_offset, fps, fbx_ktime,
|
|
856
|
-
fbx_start_offset)
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
def blen_store_keyframes_multi(fbx_key_times, fcurve_and_key_values_pairs, blen_start_offset, fps, fbx_ktime,
|
|
860
|
-
fbx_start_offset=0):
|
|
861
|
-
"""Set all keyframe times and values for multiple pairs of newly created FCurves and keyframe values arrays, where
|
|
862
|
-
each pair has the same keyframe times.
|
|
863
|
-
Linear interpolation is currently assumed."""
|
|
864
|
-
bl_key_times = _convert_fbx_time_to_blender_time(fbx_key_times, blen_start_offset, fbx_start_offset, fps, fbx_ktime)
|
|
865
|
-
num_keys = len(bl_key_times)
|
|
866
|
-
|
|
867
|
-
# Compatible with C float type
|
|
868
|
-
bl_keyframe_dtype = np.single
|
|
869
|
-
# Compatible with C char type
|
|
870
|
-
bl_enum_dtype = np.ubyte
|
|
871
|
-
|
|
872
|
-
# The keyframe_points 'co' are accessed as flattened pairs of (time, value).
|
|
873
|
-
# The key times are the same for each (blen_fcurve, key_values) pair, so only the values need to be updated for each
|
|
874
|
-
# array of values.
|
|
875
|
-
keyframe_points_co = np.empty(len(bl_key_times) * 2, dtype=bl_keyframe_dtype)
|
|
876
|
-
# Even indices are times.
|
|
877
|
-
keyframe_points_co[0::2] = bl_key_times
|
|
878
|
-
|
|
879
|
-
interpolation_array = np.full(num_keys, LINEAR_INTERPOLATION_VALUE, dtype=bl_enum_dtype)
|
|
880
|
-
|
|
881
|
-
for blen_fcurve, key_values in fcurve_and_key_values_pairs:
|
|
882
|
-
# The fcurve must be newly created and thus have no keyframe_points.
|
|
883
|
-
assert(len(blen_fcurve.keyframe_points) == 0)
|
|
884
|
-
|
|
885
|
-
# Odd indices are values.
|
|
886
|
-
keyframe_points_co[1::2] = key_values
|
|
887
|
-
|
|
888
|
-
# Add the keyframe points to the FCurve and then set the 'co' and 'interpolation' of each point.
|
|
889
|
-
blen_fcurve.keyframe_points.add(num_keys)
|
|
890
|
-
blen_fcurve.keyframe_points.foreach_set('co', keyframe_points_co)
|
|
891
|
-
blen_fcurve.keyframe_points.foreach_set('interpolation', interpolation_array)
|
|
892
|
-
|
|
893
|
-
# Since we inserted our keyframes in 'ultra-fast' mode, we have to update the fcurves now.
|
|
894
|
-
blen_fcurve.update()
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
def blen_read_animations_action_item(channelbag, item, cnodes, fps, anim_offset, global_scale, shape_key_deforms,
|
|
898
|
-
fbx_ktime):
|
|
899
|
-
"""
|
|
900
|
-
'Bake' loc/rot/scale into the channelbag,
|
|
901
|
-
taking any pre_ and post_ matrix into account to transform from fbx into blender space.
|
|
902
|
-
"""
|
|
903
|
-
from bpy.types import ShapeKey, Material, Camera
|
|
904
|
-
|
|
905
|
-
fbx_curves: dict[bytes, dict[int, FBXElem]] = {}
|
|
906
|
-
for curves, fbxprop in cnodes.values():
|
|
907
|
-
channels_dict = fbx_curves.setdefault(fbxprop, {})
|
|
908
|
-
for (fbx_acdata, _blen_data), channel in curves.values():
|
|
909
|
-
if channel in channels_dict:
|
|
910
|
-
# Ignore extra curves when one has already been found for this channel because FBX's default animation
|
|
911
|
-
# system implementation only uses the first curve assigned to a channel.
|
|
912
|
-
# Additional curves per channel are allowed by the FBX specification, but the handling of these curves
|
|
913
|
-
# is considered the responsibility of the application that created them. Note that each curve node is
|
|
914
|
-
# expected to have a unique set of channels, so these additional curves with the same channel would have
|
|
915
|
-
# to belong to separate curve nodes. See the FBX SDK documentation for FbxAnimCurveNode.
|
|
916
|
-
continue
|
|
917
|
-
channels_dict[channel] = fbx_acdata
|
|
918
|
-
|
|
919
|
-
# Leave if no curves are attached (if a blender curve is attached to scale but without keys it defaults to 0).
|
|
920
|
-
if len(fbx_curves) == 0:
|
|
921
|
-
return
|
|
922
|
-
|
|
923
|
-
if isinstance(item, Material):
|
|
924
|
-
grpname = item.name
|
|
925
|
-
props = [("diffuse_color", 3, grpname or "Diffuse Color")]
|
|
926
|
-
elif isinstance(item, ShapeKey):
|
|
927
|
-
props = [(item.path_from_id("value"), 1, "Key")]
|
|
928
|
-
elif isinstance(item, Camera):
|
|
929
|
-
props = [(item.path_from_id("lens"), 1, "Camera"), (item.dof.path_from_id("focus_distance"), 1, "Camera")]
|
|
930
|
-
else: # Object or PoseBone:
|
|
931
|
-
if item.is_bone:
|
|
932
|
-
bl_obj = item.bl_obj.pose.bones[item.bl_bone]
|
|
933
|
-
else:
|
|
934
|
-
bl_obj = item.bl_obj
|
|
935
|
-
|
|
936
|
-
# We want to create actions for objects, but for bones we 'reuse' armatures' actions!
|
|
937
|
-
grpname = bl_obj.name
|
|
938
|
-
|
|
939
|
-
# Since we might get other channels animated in the end, due to all FBX transform magic,
|
|
940
|
-
# we need to add curves for whole loc/rot/scale in any case.
|
|
941
|
-
props = [(bl_obj.path_from_id("location"), 3, grpname or "Location"),
|
|
942
|
-
None,
|
|
943
|
-
(bl_obj.path_from_id("scale"), 3, grpname or "Scale")]
|
|
944
|
-
rot_mode = bl_obj.rotation_mode
|
|
945
|
-
if rot_mode == 'QUATERNION':
|
|
946
|
-
props[1] = (bl_obj.path_from_id("rotation_quaternion"), 4, grpname or "Quaternion Rotation")
|
|
947
|
-
elif rot_mode == 'AXIS_ANGLE':
|
|
948
|
-
props[1] = (bl_obj.path_from_id("rotation_axis_angle"), 4, grpname or "Axis Angle Rotation")
|
|
949
|
-
else: # Euler
|
|
950
|
-
props[1] = (bl_obj.path_from_id("rotation_euler"), 3, grpname or "Euler Rotation")
|
|
951
|
-
|
|
952
|
-
blen_curves = [channelbag.fcurves.new(prop, index=channel, group_name=grpname)
|
|
953
|
-
for prop, nbr_channels, grpname in props for channel in range(nbr_channels)]
|
|
954
|
-
|
|
955
|
-
if isinstance(item, Material):
|
|
956
|
-
for fbxprop, channel_to_curve in fbx_curves.items():
|
|
957
|
-
assert(fbxprop == b'DiffuseColor')
|
|
958
|
-
for channel, curve in channel_to_curve.items():
|
|
959
|
-
assert(channel in {0, 1, 2})
|
|
960
|
-
blen_curve = blen_curves[channel]
|
|
961
|
-
fbx_key_times, values = blen_read_animation_curve(curve)
|
|
962
|
-
blen_store_keyframes(fbx_key_times, blen_curve, values, anim_offset, fps, fbx_ktime)
|
|
963
|
-
|
|
964
|
-
elif isinstance(item, ShapeKey):
|
|
965
|
-
for fbxprop, channel_to_curve in fbx_curves.items():
|
|
966
|
-
assert(fbxprop == b'DeformPercent')
|
|
967
|
-
for channel, curve in channel_to_curve.items():
|
|
968
|
-
assert(channel == 0)
|
|
969
|
-
blen_curve = blen_curves[channel]
|
|
970
|
-
|
|
971
|
-
fbx_key_times, values = blen_read_animation_curve(curve)
|
|
972
|
-
# A fully activated shape key in FBX DeformPercent is 100.0 whereas it is 1.0 in Blender.
|
|
973
|
-
values = values / 100.0
|
|
974
|
-
blen_store_keyframes(fbx_key_times, blen_curve, values, anim_offset, fps, fbx_ktime)
|
|
975
|
-
|
|
976
|
-
# Store the minimum and maximum shape key values, so that the shape key's slider range can be expanded
|
|
977
|
-
# if necessary after reading all animations.
|
|
978
|
-
if values.size:
|
|
979
|
-
deform_values = shape_key_deforms.setdefault(item, [])
|
|
980
|
-
deform_values.append(values.min())
|
|
981
|
-
deform_values.append(values.max())
|
|
982
|
-
|
|
983
|
-
elif isinstance(item, Camera):
|
|
984
|
-
for fbxprop, channel_to_curve in fbx_curves.items():
|
|
985
|
-
is_focus_distance = fbxprop == b'FocusDistance'
|
|
986
|
-
assert(fbxprop == b'FocalLength' or is_focus_distance)
|
|
987
|
-
for channel, curve in channel_to_curve.items():
|
|
988
|
-
assert(channel == 0)
|
|
989
|
-
# The indices are determined by the creation of the `props` list above.
|
|
990
|
-
blen_curve = blen_curves[1 if is_focus_distance else 0]
|
|
991
|
-
|
|
992
|
-
fbx_key_times, values = blen_read_animation_curve(curve)
|
|
993
|
-
if is_focus_distance:
|
|
994
|
-
# Remap the imported values from FBX to Blender.
|
|
995
|
-
values = values / 1000.0
|
|
996
|
-
values *= global_scale
|
|
997
|
-
blen_store_keyframes(fbx_key_times, blen_curve, values, anim_offset, fps, fbx_ktime)
|
|
998
|
-
|
|
999
|
-
else: # Object or PoseBone:
|
|
1000
|
-
transform_data = item.fbx_transform_data
|
|
1001
|
-
|
|
1002
|
-
# Each transformation curve needs to have keyframes at the times of every other transformation curve
|
|
1003
|
-
# (interpolating missing values), so that we can construct a matrix at every keyframe.
|
|
1004
|
-
transform_prop_to_attr = {
|
|
1005
|
-
b'Lcl Translation': transform_data.loc,
|
|
1006
|
-
b'Lcl Rotation': transform_data.rot,
|
|
1007
|
-
b'Lcl Scaling': transform_data.sca,
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
times_and_values_tuples = []
|
|
1011
|
-
initial_values = []
|
|
1012
|
-
channel_keys = []
|
|
1013
|
-
for fbxprop, channel_to_curve in fbx_curves.items():
|
|
1014
|
-
if fbxprop not in transform_prop_to_attr:
|
|
1015
|
-
# Currently, we only care about transformation curves.
|
|
1016
|
-
continue
|
|
1017
|
-
for channel, curve in channel_to_curve.items():
|
|
1018
|
-
assert(channel in {0, 1, 2})
|
|
1019
|
-
fbx_key_times, values = blen_read_animation_curve(curve)
|
|
1020
|
-
|
|
1021
|
-
channel_keys.append((fbxprop, channel))
|
|
1022
|
-
|
|
1023
|
-
initial_values.append(transform_prop_to_attr[fbxprop][channel])
|
|
1024
|
-
|
|
1025
|
-
times_and_values_tuples.append((fbx_key_times, values))
|
|
1026
|
-
if not times_and_values_tuples:
|
|
1027
|
-
# If `times_and_values_tuples` is empty, all the imported animation curves are for properties other than
|
|
1028
|
-
# transformation (e.g. animated custom properties), so there is nothing to do until support for those other
|
|
1029
|
-
# properties is added.
|
|
1030
|
-
return
|
|
1031
|
-
|
|
1032
|
-
# Combine the keyframe times of all the transformation curves so that each curve has a value at every time.
|
|
1033
|
-
combined_fbx_times, values_arrays = _combine_curve_keyframe_times(times_and_values_tuples, initial_values)
|
|
1034
|
-
|
|
1035
|
-
# Convert from FBX Lcl Translation/Lcl Rotation/Lcl Scaling to the Blender location/rotation/scaling properties
|
|
1036
|
-
# of this Object/PoseBone.
|
|
1037
|
-
# The number of fcurves for the Blender properties varies depending on the rotation mode.
|
|
1038
|
-
num_loc_channels = 3
|
|
1039
|
-
num_rot_channels = 4 if rot_mode in {'QUATERNION', 'AXIS_ANGLE'} else 3 # Variations of EULER are all 3
|
|
1040
|
-
num_sca_channels = 3
|
|
1041
|
-
num_channels = num_loc_channels + num_rot_channels + num_sca_channels
|
|
1042
|
-
num_frames = len(combined_fbx_times)
|
|
1043
|
-
full_length = num_channels * num_frames
|
|
1044
|
-
|
|
1045
|
-
# Do the conversion.
|
|
1046
|
-
flattened_channel_values_gen = _transformation_curves_gen(item, values_arrays, channel_keys)
|
|
1047
|
-
flattened_channel_values = np.fromiter(flattened_channel_values_gen, dtype=np.single, count=full_length)
|
|
1048
|
-
|
|
1049
|
-
# Reshape to one row per frame and then view the transpose so that each row corresponds to a single channel.
|
|
1050
|
-
# e.g.
|
|
1051
|
-
# loc_channels = channel_values[:num_loc_channels]
|
|
1052
|
-
# rot_channels = channel_values[num_loc_channels:num_loc_channels + num_rot_channels]
|
|
1053
|
-
# sca_channels = channel_values[num_loc_channels + num_rot_channels:]
|
|
1054
|
-
channel_values = flattened_channel_values.reshape(num_frames, num_channels).T
|
|
1055
|
-
|
|
1056
|
-
# Each channel has the same keyframe times, so the combined times can be passed once along with all the curves
|
|
1057
|
-
# and values arrays.
|
|
1058
|
-
blen_store_keyframes_multi(combined_fbx_times, zip(blen_curves, channel_values), anim_offset, fps, fbx_ktime)
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_offset, global_scale, fbx_ktime):
|
|
1062
|
-
"""
|
|
1063
|
-
Recreate an action per stack/layer/object combinations.
|
|
1064
|
-
Only the first found action is linked to objects, more complex setups are not handled,
|
|
1065
|
-
it's up to user to reproduce them!
|
|
1066
|
-
"""
|
|
1067
|
-
from bpy.types import ShapeKey, Material, Camera
|
|
1068
|
-
|
|
1069
|
-
shape_key_values = {}
|
|
1070
|
-
actions = {}
|
|
1071
|
-
for as_uuid, ((fbx_asdata, _blen_data), alayers) in stacks.items():
|
|
1072
|
-
stack_name = elem_name_ensure_class(fbx_asdata, b'AnimStack')
|
|
1073
|
-
for al_uuid, ((fbx_aldata, _blen_data), items) in alayers.items():
|
|
1074
|
-
layer_name = elem_name_ensure_class(fbx_aldata, b'AnimLayer')
|
|
1075
|
-
for item, cnodes in items.items():
|
|
1076
|
-
if isinstance(item, Material):
|
|
1077
|
-
id_data = item
|
|
1078
|
-
elif isinstance(item, ShapeKey):
|
|
1079
|
-
id_data = item.id_data
|
|
1080
|
-
elif isinstance(item, Camera):
|
|
1081
|
-
id_data = item
|
|
1082
|
-
else:
|
|
1083
|
-
id_data = item.bl_obj
|
|
1084
|
-
# XXX Ignore rigged mesh animations - those are a nightmare to handle, see note about it in
|
|
1085
|
-
# FbxImportHelperNode class definition.
|
|
1086
|
-
if id_data and id_data.type == 'MESH' and id_data.parent and id_data.parent.type == 'ARMATURE':
|
|
1087
|
-
continue
|
|
1088
|
-
if id_data is None:
|
|
1089
|
-
continue
|
|
1090
|
-
|
|
1091
|
-
# Create new action if needed (should always be needed, except for keyblocks from shapekeys cases).
|
|
1092
|
-
key = (as_uuid, al_uuid, id_data)
|
|
1093
|
-
action = actions.get(key)
|
|
1094
|
-
if action is None:
|
|
1095
|
-
if stack_name == layer_name:
|
|
1096
|
-
action_name = "|".join((id_data.name, stack_name))
|
|
1097
|
-
else:
|
|
1098
|
-
action_name = "|".join((id_data.name, stack_name, layer_name))
|
|
1099
|
-
actions[key] = action = bpy.data.actions.new(action_name)
|
|
1100
|
-
action.use_fake_user = True
|
|
1101
|
-
|
|
1102
|
-
# Always use the same name for the slot. It should be simple
|
|
1103
|
-
# to switch between imported Actions while keeping Slot
|
|
1104
|
-
# auto-assignment, which means that all Actions should use
|
|
1105
|
-
# the same slot name. As long as there's no separate
|
|
1106
|
-
# indicator for the "intended object name" for this FBX
|
|
1107
|
-
# animation, this is the best Blender can do. Maybe the
|
|
1108
|
-
# 'stack name' would be a better choice?
|
|
1109
|
-
action.slots.new(id_data.id_type, "Slot")
|
|
1110
|
-
|
|
1111
|
-
# If none yet assigned, assign this action to id_data.
|
|
1112
|
-
if not id_data.animation_data:
|
|
1113
|
-
id_data.animation_data_create()
|
|
1114
|
-
if not id_data.animation_data.action:
|
|
1115
|
-
id_data.animation_data.action = action
|
|
1116
|
-
id_data.animation_data.action_slot = action.slots[0]
|
|
1117
|
-
|
|
1118
|
-
# And actually populate the action!
|
|
1119
|
-
channelbag = anim_utils.action_ensure_channelbag_for_slot(action, action.slots[0])
|
|
1120
|
-
blen_read_animations_action_item(channelbag, item, cnodes, scene.render.fps, anim_offset, global_scale,
|
|
1121
|
-
shape_key_values, fbx_ktime)
|
|
1122
|
-
|
|
1123
|
-
# If the minimum/maximum animated value is outside the slider range of the shape key, attempt to expand the slider
|
|
1124
|
-
# range until the animated range fits and has extra room to be decreased or increased further.
|
|
1125
|
-
# Shape key slider_min and slider_max have hard min/max values, if an imported animation uses a value outside that
|
|
1126
|
-
# range, a warning message will be printed to the console and the slider_min/slider_max values will end up clamped.
|
|
1127
|
-
shape_key_values_in_range = True
|
|
1128
|
-
for shape_key, deform_values in shape_key_values.items():
|
|
1129
|
-
min_animated_deform = min(deform_values)
|
|
1130
|
-
max_animated_deform = max(deform_values)
|
|
1131
|
-
shape_key_values_in_range &= expand_shape_key_range(shape_key, min_animated_deform)
|
|
1132
|
-
shape_key_values_in_range &= expand_shape_key_range(shape_key, max_animated_deform)
|
|
1133
|
-
if not shape_key_values_in_range:
|
|
1134
|
-
print("WARNING: The imported animated Value of a Shape Key is beyond the minimum/maximum allowed and will be"
|
|
1135
|
-
" clamped during playback.")
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
# ----
|
|
1139
|
-
# Mesh
|
|
1140
|
-
|
|
1141
|
-
def blen_read_geom_layerinfo(fbx_layer):
|
|
1142
|
-
return (
|
|
1143
|
-
validate_blend_names(elem_find_first_string_as_bytes(fbx_layer, b'Name')),
|
|
1144
|
-
elem_find_first_string_as_bytes(fbx_layer, b'MappingInformationType'),
|
|
1145
|
-
elem_find_first_string_as_bytes(fbx_layer, b'ReferenceInformationType'),
|
|
1146
|
-
)
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
def blen_read_geom_validate_blen_data(blen_data, blen_dtype, item_size):
|
|
1150
|
-
"""Validate blen_data when it's not a bpy_prop_collection.
|
|
1151
|
-
Returns whether blen_data is a bpy_prop_collection"""
|
|
1152
|
-
blen_data_is_collection = isinstance(blen_data, bpy.types.bpy_prop_collection)
|
|
1153
|
-
if not blen_data_is_collection:
|
|
1154
|
-
if item_size > 1:
|
|
1155
|
-
assert(len(blen_data.shape) == 2)
|
|
1156
|
-
assert(blen_data.shape[1] == item_size)
|
|
1157
|
-
assert(blen_data.dtype == blen_dtype)
|
|
1158
|
-
return blen_data_is_collection
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
def blen_read_geom_parse_fbx_data(fbx_data, stride, item_size):
|
|
1162
|
-
"""Parse fbx_data as an array.array into a 2d np.ndarray that shares the same memory, where each row is a single
|
|
1163
|
-
item"""
|
|
1164
|
-
# Technically stride < item_size could be supported, but there's probably not a use case for it since it would
|
|
1165
|
-
# result in a view of the data with self-overlapping memory.
|
|
1166
|
-
assert(stride >= item_size)
|
|
1167
|
-
# View the array.array as an np.ndarray.
|
|
1168
|
-
fbx_data_np = parray_as_ndarray(fbx_data)
|
|
1169
|
-
|
|
1170
|
-
if stride == item_size:
|
|
1171
|
-
if item_size > 1:
|
|
1172
|
-
# Need to make sure fbx_data_np has a whole number of items to be able to view item_size elements per row.
|
|
1173
|
-
items_remainder = len(fbx_data_np) % item_size
|
|
1174
|
-
if items_remainder:
|
|
1175
|
-
print("ERROR: not a whole number of items in this FBX layer, skipping the partial item!")
|
|
1176
|
-
fbx_data_np = fbx_data_np[:-items_remainder]
|
|
1177
|
-
fbx_data_np = fbx_data_np.reshape(-1, item_size)
|
|
1178
|
-
else:
|
|
1179
|
-
# Create a view of fbx_data_np that is only the first item_size elements of each stride. Note that the view will
|
|
1180
|
-
# not be C-contiguous.
|
|
1181
|
-
stride_remainder = len(fbx_data_np) % stride
|
|
1182
|
-
if stride_remainder:
|
|
1183
|
-
if stride_remainder < item_size:
|
|
1184
|
-
print("ERROR: not a whole number of items in this FBX layer, skipping the partial item!")
|
|
1185
|
-
# Not enough in the remainder for a full item, so cut off the partial stride
|
|
1186
|
-
fbx_data_np = fbx_data_np[:-stride_remainder]
|
|
1187
|
-
# Reshape to one stride per row and then create a view that includes only the first item_size elements
|
|
1188
|
-
# of each stride.
|
|
1189
|
-
fbx_data_np = fbx_data_np.reshape(-1, stride)[:, :item_size]
|
|
1190
|
-
else:
|
|
1191
|
-
print("ERROR: not a whole number of strides in this FBX layer! There are a whole number of items, but"
|
|
1192
|
-
" this could indicate an error!")
|
|
1193
|
-
# There is not a whole number of strides, but there is a whole number of items.
|
|
1194
|
-
# This is a pain to deal with because fbx_data_np.reshape(-1, stride) is not possible.
|
|
1195
|
-
# A view of just the items can be created using stride_tricks.as_strided by specifying the shape and
|
|
1196
|
-
# strides of the view manually.
|
|
1197
|
-
# Extreme care must be taken when using stride_tricks.as_strided because improper usage can result in
|
|
1198
|
-
# a view that gives access to memory outside the array.
|
|
1199
|
-
from numpy.lib import stride_tricks
|
|
1200
|
-
|
|
1201
|
-
# fbx_data_np should always start off as flat and C-contiguous.
|
|
1202
|
-
assert(fbx_data_np.strides == (fbx_data_np.itemsize,))
|
|
1203
|
-
|
|
1204
|
-
num_whole_strides = len(fbx_data_np) // stride
|
|
1205
|
-
# Plus the one partial stride that is enough elements for a complete item.
|
|
1206
|
-
num_items = num_whole_strides + 1
|
|
1207
|
-
shape = (num_items, item_size)
|
|
1208
|
-
|
|
1209
|
-
# strides are the number of bytes to step to get to the next element, for each axis.
|
|
1210
|
-
step_per_item = fbx_data_np.itemsize * stride
|
|
1211
|
-
step_per_item_element = fbx_data_np.itemsize
|
|
1212
|
-
strides = (step_per_item, step_per_item_element)
|
|
1213
|
-
|
|
1214
|
-
fbx_data_np = stride_tricks.as_strided(fbx_data_np, shape, strides)
|
|
1215
|
-
else:
|
|
1216
|
-
# There's a whole number of strides, so first reshape to one stride per row and then create a view that
|
|
1217
|
-
# includes only the first item_size elements of each stride.
|
|
1218
|
-
fbx_data_np = fbx_data_np.reshape(-1, stride)[:, :item_size]
|
|
1219
|
-
|
|
1220
|
-
return fbx_data_np
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
def blen_read_geom_check_fbx_data_length(blen_data, fbx_data_np, is_indices=False):
|
|
1224
|
-
"""Check that there are the same number of items in blen_data and fbx_data_np.
|
|
1225
|
-
|
|
1226
|
-
Returns a tuple of two elements:
|
|
1227
|
-
0: fbx_data_np or, if fbx_data_np contains more items than blen_data, a view of fbx_data_np with the excess
|
|
1228
|
-
items removed
|
|
1229
|
-
1: Whether the returned fbx_data_np contains enough items to completely fill blen_data"""
|
|
1230
|
-
bl_num_items = len(blen_data)
|
|
1231
|
-
fbx_num_items = len(fbx_data_np)
|
|
1232
|
-
enough_data = fbx_num_items >= bl_num_items
|
|
1233
|
-
if not enough_data:
|
|
1234
|
-
if is_indices:
|
|
1235
|
-
print("ERROR: not enough indices in this FBX layer, missing data will be left as default!")
|
|
1236
|
-
else:
|
|
1237
|
-
print("ERROR: not enough data in this FBX layer, missing data will be left as default!")
|
|
1238
|
-
elif fbx_num_items > bl_num_items:
|
|
1239
|
-
if is_indices:
|
|
1240
|
-
print("ERROR: too many indices in this FBX layer, skipping excess!")
|
|
1241
|
-
else:
|
|
1242
|
-
print("ERROR: too much data in this FBX layer, skipping excess!")
|
|
1243
|
-
fbx_data_np = fbx_data_np[:bl_num_items]
|
|
1244
|
-
|
|
1245
|
-
return fbx_data_np, enough_data
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
def blen_read_geom_xform(fbx_data_np, xform):
|
|
1249
|
-
"""xform is either None, or a function that takes fbx_data_np as its only positional argument and returns an
|
|
1250
|
-
np.ndarray with the same total number of elements as fbx_data_np.
|
|
1251
|
-
It is acceptable for xform to return an array with a different dtype to fbx_data_np.
|
|
1252
|
-
|
|
1253
|
-
Returns xform(fbx_data_np) when xform is not None and ensures the result of xform(fbx_data_np) has the same shape as
|
|
1254
|
-
fbx_data_np before returning it.
|
|
1255
|
-
When xform is None, fbx_data_np is returned as is."""
|
|
1256
|
-
if xform is not None:
|
|
1257
|
-
item_size = fbx_data_np.shape[1]
|
|
1258
|
-
fbx_total_data = fbx_data_np.size
|
|
1259
|
-
fbx_data_np = xform(fbx_data_np)
|
|
1260
|
-
# The amount of data should not be changed by xform
|
|
1261
|
-
assert(fbx_data_np.size == fbx_total_data)
|
|
1262
|
-
# Ensure fbx_data_np is still item_size elements per row
|
|
1263
|
-
if len(fbx_data_np.shape) != 2 or fbx_data_np.shape[1] != item_size:
|
|
1264
|
-
fbx_data_np = fbx_data_np.reshape(-1, item_size)
|
|
1265
|
-
return fbx_data_np
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
def blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_data, stride, item_size, descr,
|
|
1269
|
-
xform):
|
|
1270
|
-
"""Generic fbx_layer to blen_data foreach setter for Direct layers.
|
|
1271
|
-
blen_data must be a bpy_prop_collection or 2d np.ndarray whose second axis length is item_size.
|
|
1272
|
-
fbx_data must be an array.array."""
|
|
1273
|
-
fbx_data_np = blen_read_geom_parse_fbx_data(fbx_data, stride, item_size)
|
|
1274
|
-
fbx_data_np, enough_data = blen_read_geom_check_fbx_data_length(blen_data, fbx_data_np)
|
|
1275
|
-
fbx_data_np = blen_read_geom_xform(fbx_data_np, xform)
|
|
1276
|
-
|
|
1277
|
-
blen_data_is_collection = blen_read_geom_validate_blen_data(blen_data, blen_dtype, item_size)
|
|
1278
|
-
|
|
1279
|
-
if blen_data_is_collection:
|
|
1280
|
-
if not enough_data:
|
|
1281
|
-
blen_total_data = len(blen_data) * item_size
|
|
1282
|
-
buffer = np.empty(blen_total_data, dtype=blen_dtype)
|
|
1283
|
-
# It's not clear what values should be used for the missing data, so read the current values into a buffer.
|
|
1284
|
-
blen_data.foreach_get(blen_attr, buffer)
|
|
1285
|
-
|
|
1286
|
-
# Change the buffer shape to one item per row
|
|
1287
|
-
buffer.shape = (-1, item_size)
|
|
1288
|
-
|
|
1289
|
-
# Copy the fbx data into the start of the buffer
|
|
1290
|
-
buffer[:len(fbx_data_np)] = fbx_data_np
|
|
1291
|
-
else:
|
|
1292
|
-
# Convert the buffer to the Blender C type of blen_attr
|
|
1293
|
-
buffer = astype_view_signedness(fbx_data_np, blen_dtype)
|
|
1294
|
-
|
|
1295
|
-
# Set blen_attr of blen_data. The buffer must be flat and C-contiguous, which ravel() ensures
|
|
1296
|
-
blen_data.foreach_set(blen_attr, buffer.ravel())
|
|
1297
|
-
else:
|
|
1298
|
-
assert(blen_data.size % item_size == 0)
|
|
1299
|
-
blen_data = blen_data.view()
|
|
1300
|
-
blen_data.shape = (-1, item_size)
|
|
1301
|
-
blen_data[:len(fbx_data_np)] = fbx_data_np
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
def blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_data, fbx_layer_index, stride,
|
|
1305
|
-
item_size, descr, xform):
|
|
1306
|
-
"""Generic fbx_layer to blen_data foreach setter for IndexToDirect layers.
|
|
1307
|
-
blen_data must be a bpy_prop_collection or 2d np.ndarray whose second axis length is item_size.
|
|
1308
|
-
fbx_data must be an array.array or a 1d np.ndarray."""
|
|
1309
|
-
fbx_data_np = blen_read_geom_parse_fbx_data(fbx_data, stride, item_size)
|
|
1310
|
-
fbx_data_np = blen_read_geom_xform(fbx_data_np, xform)
|
|
1311
|
-
|
|
1312
|
-
# fbx_layer_index is allowed to be a 1d np.ndarray for use with blen_read_geom_array_foreach_set_looptovert.
|
|
1313
|
-
if not isinstance(fbx_layer_index, np.ndarray):
|
|
1314
|
-
fbx_layer_index = parray_as_ndarray(fbx_layer_index)
|
|
1315
|
-
|
|
1316
|
-
fbx_layer_index, enough_indices = blen_read_geom_check_fbx_data_length(blen_data, fbx_layer_index, is_indices=True)
|
|
1317
|
-
|
|
1318
|
-
blen_data_is_collection = blen_read_geom_validate_blen_data(blen_data, blen_dtype, item_size)
|
|
1319
|
-
|
|
1320
|
-
blen_data_items_len = len(blen_data)
|
|
1321
|
-
blen_data_len = blen_data_items_len * item_size
|
|
1322
|
-
fbx_num_items = len(fbx_data_np)
|
|
1323
|
-
|
|
1324
|
-
# Find all indices that are out of bounds of fbx_data_np.
|
|
1325
|
-
min_index_inclusive = -fbx_num_items
|
|
1326
|
-
max_index_inclusive = fbx_num_items - 1
|
|
1327
|
-
valid_index_mask = np.equal(fbx_layer_index, fbx_layer_index.clip(min_index_inclusive, max_index_inclusive))
|
|
1328
|
-
indices_invalid = not valid_index_mask.all()
|
|
1329
|
-
|
|
1330
|
-
fbx_data_items = fbx_data_np.reshape(-1, item_size)
|
|
1331
|
-
|
|
1332
|
-
if indices_invalid or not enough_indices:
|
|
1333
|
-
if blen_data_is_collection:
|
|
1334
|
-
buffer = np.empty(blen_data_len, dtype=blen_dtype)
|
|
1335
|
-
buffer_item_view = buffer.view()
|
|
1336
|
-
buffer_item_view.shape = (-1, item_size)
|
|
1337
|
-
# Since we don't know what the default values should be for the missing data, read the current values into a
|
|
1338
|
-
# buffer.
|
|
1339
|
-
blen_data.foreach_get(blen_attr, buffer)
|
|
1340
|
-
else:
|
|
1341
|
-
buffer_item_view = blen_data
|
|
1342
|
-
|
|
1343
|
-
if not enough_indices:
|
|
1344
|
-
# Reduce the length of the view to the same length as the number of indices.
|
|
1345
|
-
buffer_item_view = buffer_item_view[:len(fbx_layer_index)]
|
|
1346
|
-
|
|
1347
|
-
# Copy the result of indexing fbx_data_items by each element in fbx_layer_index into the buffer.
|
|
1348
|
-
if indices_invalid:
|
|
1349
|
-
print("ERROR: indices in this FBX layer out of bounds of the FBX data, skipping invalid indices!")
|
|
1350
|
-
buffer_item_view[valid_index_mask] = fbx_data_items[fbx_layer_index[valid_index_mask]]
|
|
1351
|
-
else:
|
|
1352
|
-
buffer_item_view[:] = fbx_data_items[fbx_layer_index]
|
|
1353
|
-
|
|
1354
|
-
if blen_data_is_collection:
|
|
1355
|
-
blen_data.foreach_set(blen_attr, buffer.ravel())
|
|
1356
|
-
else:
|
|
1357
|
-
if blen_data_is_collection:
|
|
1358
|
-
# Cast the buffer to the Blender C type of blen_attr
|
|
1359
|
-
fbx_data_items = astype_view_signedness(fbx_data_items, blen_dtype)
|
|
1360
|
-
buffer_items = fbx_data_items[fbx_layer_index]
|
|
1361
|
-
blen_data.foreach_set(blen_attr, buffer_items.ravel())
|
|
1362
|
-
else:
|
|
1363
|
-
blen_data[:] = fbx_data_items[fbx_layer_index]
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
def blen_read_geom_array_foreach_set_allsame(blen_data, blen_attr, blen_dtype, fbx_data, stride, item_size, descr,
|
|
1367
|
-
xform):
|
|
1368
|
-
"""Generic fbx_layer to blen_data foreach setter for AllSame layers.
|
|
1369
|
-
blen_data must be a bpy_prop_collection or 2d np.ndarray whose second axis length is item_size.
|
|
1370
|
-
fbx_data must be an array.array."""
|
|
1371
|
-
fbx_data_np = blen_read_geom_parse_fbx_data(fbx_data, stride, item_size)
|
|
1372
|
-
fbx_data_np = blen_read_geom_xform(fbx_data_np, xform)
|
|
1373
|
-
blen_data_is_collection = blen_read_geom_validate_blen_data(blen_data, blen_dtype, item_size)
|
|
1374
|
-
fbx_items_len = len(fbx_data_np)
|
|
1375
|
-
blen_items_len = len(blen_data)
|
|
1376
|
-
|
|
1377
|
-
if fbx_items_len < 1:
|
|
1378
|
-
print("ERROR: not enough data in this FBX layer, skipping!")
|
|
1379
|
-
return
|
|
1380
|
-
|
|
1381
|
-
if blen_data_is_collection:
|
|
1382
|
-
# Create an array filled with the value from fbx_data_np
|
|
1383
|
-
buffer = np.full((blen_items_len, item_size), fbx_data_np[0], dtype=blen_dtype)
|
|
1384
|
-
|
|
1385
|
-
blen_data.foreach_set(blen_attr, buffer.ravel())
|
|
1386
|
-
else:
|
|
1387
|
-
blen_data[:] = fbx_data_np[0]
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
def blen_read_geom_array_foreach_set_looptovert(mesh, blen_data, blen_attr, blen_dtype, fbx_data, stride, item_size,
|
|
1391
|
-
descr, xform):
|
|
1392
|
-
"""Generic fbx_layer to blen_data foreach setter for face corner ByVertice layers.
|
|
1393
|
-
blen_data must be a bpy_prop_collection or 2d np.ndarray whose second axis length is item_size.
|
|
1394
|
-
fbx_data must be an array.array"""
|
|
1395
|
-
# The fbx_data is mapped to vertices. To expand fbx_data to face corners, get an array of the vertex index of each
|
|
1396
|
-
# face corner that will then be used to index fbx_data.
|
|
1397
|
-
corner_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes)
|
|
1398
|
-
blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_data, corner_vertex_indices, stride,
|
|
1399
|
-
item_size, descr, xform)
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
# generic error printers.
|
|
1403
|
-
def blen_read_geom_array_error_mapping(descr, fbx_layer_mapping, quiet=False):
|
|
1404
|
-
if not quiet:
|
|
1405
|
-
print("warning layer %r mapping type unsupported: %r" % (descr, fbx_layer_mapping))
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
def blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet=False):
|
|
1409
|
-
if not quiet:
|
|
1410
|
-
print("warning layer %r ref type unsupported: %r" % (descr, fbx_layer_ref))
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
def blen_read_geom_array_mapped_vert(
|
|
1414
|
-
mesh, blen_data, blen_attr, blen_dtype,
|
|
1415
|
-
fbx_layer_data, fbx_layer_index,
|
|
1416
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1417
|
-
stride, item_size, descr,
|
|
1418
|
-
xform=None, quiet=False,
|
|
1419
|
-
):
|
|
1420
|
-
if fbx_layer_mapping == b'ByVertice':
|
|
1421
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1422
|
-
# XXX Looks like we often get no fbx_layer_index in this case, shall not happen but happens...
|
|
1423
|
-
# We fallback to 'Direct' mapping in this case.
|
|
1424
|
-
# ~ assert(fbx_layer_index is not None)
|
|
1425
|
-
if fbx_layer_index is None:
|
|
1426
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1427
|
-
item_size, descr, xform)
|
|
1428
|
-
else:
|
|
1429
|
-
blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_layer_data,
|
|
1430
|
-
fbx_layer_index, stride, item_size, descr, xform)
|
|
1431
|
-
return True
|
|
1432
|
-
elif fbx_layer_ref == b'Direct':
|
|
1433
|
-
assert(fbx_layer_index is None)
|
|
1434
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size,
|
|
1435
|
-
descr, xform)
|
|
1436
|
-
return True
|
|
1437
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1438
|
-
elif fbx_layer_mapping == b'AllSame':
|
|
1439
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1440
|
-
assert(fbx_layer_index is None)
|
|
1441
|
-
blen_read_geom_array_foreach_set_allsame(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1442
|
-
item_size, descr, xform)
|
|
1443
|
-
return True
|
|
1444
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1445
|
-
else:
|
|
1446
|
-
blen_read_geom_array_error_mapping(descr, fbx_layer_mapping, quiet)
|
|
1447
|
-
|
|
1448
|
-
return False
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
def blen_read_geom_array_mapped_edge(
|
|
1452
|
-
mesh, blen_data, blen_attr, blen_dtype,
|
|
1453
|
-
fbx_layer_data, fbx_layer_index,
|
|
1454
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1455
|
-
stride, item_size, descr,
|
|
1456
|
-
xform=None, quiet=False,
|
|
1457
|
-
):
|
|
1458
|
-
if fbx_layer_mapping == b'ByEdge':
|
|
1459
|
-
if fbx_layer_ref == b'Direct':
|
|
1460
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size,
|
|
1461
|
-
descr, xform)
|
|
1462
|
-
return True
|
|
1463
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1464
|
-
elif fbx_layer_mapping == b'AllSame':
|
|
1465
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1466
|
-
assert(fbx_layer_index is None)
|
|
1467
|
-
blen_read_geom_array_foreach_set_allsame(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1468
|
-
item_size, descr, xform)
|
|
1469
|
-
return True
|
|
1470
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1471
|
-
else:
|
|
1472
|
-
blen_read_geom_array_error_mapping(descr, fbx_layer_mapping, quiet)
|
|
1473
|
-
|
|
1474
|
-
return False
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
def blen_read_geom_array_mapped_polygon(
|
|
1478
|
-
mesh, blen_data, blen_attr, blen_dtype,
|
|
1479
|
-
fbx_layer_data, fbx_layer_index,
|
|
1480
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1481
|
-
stride, item_size, descr,
|
|
1482
|
-
xform=None, quiet=False,
|
|
1483
|
-
):
|
|
1484
|
-
if fbx_layer_mapping == b'ByPolygon':
|
|
1485
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1486
|
-
# XXX Looks like we often get no fbx_layer_index in this case, shall not happen but happens...
|
|
1487
|
-
# We fallback to 'Direct' mapping in this case.
|
|
1488
|
-
# ~ assert(fbx_layer_index is not None)
|
|
1489
|
-
if fbx_layer_index is None:
|
|
1490
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1491
|
-
item_size, descr, xform)
|
|
1492
|
-
else:
|
|
1493
|
-
blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_layer_data,
|
|
1494
|
-
fbx_layer_index, stride, item_size, descr, xform)
|
|
1495
|
-
return True
|
|
1496
|
-
elif fbx_layer_ref == b'Direct':
|
|
1497
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size,
|
|
1498
|
-
descr, xform)
|
|
1499
|
-
return True
|
|
1500
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1501
|
-
elif fbx_layer_mapping == b'AllSame':
|
|
1502
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1503
|
-
assert(fbx_layer_index is None)
|
|
1504
|
-
blen_read_geom_array_foreach_set_allsame(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1505
|
-
item_size, descr, xform)
|
|
1506
|
-
return True
|
|
1507
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1508
|
-
else:
|
|
1509
|
-
blen_read_geom_array_error_mapping(descr, fbx_layer_mapping, quiet)
|
|
1510
|
-
|
|
1511
|
-
return False
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
def blen_read_geom_array_mapped_polyloop(
|
|
1515
|
-
mesh, blen_data, blen_attr, blen_dtype,
|
|
1516
|
-
fbx_layer_data, fbx_layer_index,
|
|
1517
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1518
|
-
stride, item_size, descr,
|
|
1519
|
-
xform=None, quiet=False,
|
|
1520
|
-
):
|
|
1521
|
-
if fbx_layer_mapping == b'ByPolygonVertex':
|
|
1522
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1523
|
-
# XXX Looks like we often get no fbx_layer_index in this case, shall not happen but happens...
|
|
1524
|
-
# We fallback to 'Direct' mapping in this case.
|
|
1525
|
-
# ~ assert(fbx_layer_index is not None)
|
|
1526
|
-
if fbx_layer_index is None:
|
|
1527
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1528
|
-
item_size, descr, xform)
|
|
1529
|
-
else:
|
|
1530
|
-
blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_layer_data,
|
|
1531
|
-
fbx_layer_index, stride, item_size, descr, xform)
|
|
1532
|
-
return True
|
|
1533
|
-
elif fbx_layer_ref == b'Direct':
|
|
1534
|
-
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size,
|
|
1535
|
-
descr, xform)
|
|
1536
|
-
return True
|
|
1537
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1538
|
-
elif fbx_layer_mapping == b'ByVertice':
|
|
1539
|
-
if fbx_layer_ref == b'Direct':
|
|
1540
|
-
assert(fbx_layer_index is None)
|
|
1541
|
-
blen_read_geom_array_foreach_set_looptovert(mesh, blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1542
|
-
item_size, descr, xform)
|
|
1543
|
-
return True
|
|
1544
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1545
|
-
elif fbx_layer_mapping == b'AllSame':
|
|
1546
|
-
if fbx_layer_ref == b'IndexToDirect':
|
|
1547
|
-
assert(fbx_layer_index is None)
|
|
1548
|
-
blen_read_geom_array_foreach_set_allsame(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
|
|
1549
|
-
item_size, descr, xform)
|
|
1550
|
-
return True
|
|
1551
|
-
blen_read_geom_array_error_ref(descr, fbx_layer_ref, quiet)
|
|
1552
|
-
else:
|
|
1553
|
-
blen_read_geom_array_error_mapping(descr, fbx_layer_mapping, quiet)
|
|
1554
|
-
|
|
1555
|
-
return False
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
def blen_read_geom_layer_material(fbx_obj, mesh):
|
|
1559
|
-
fbx_layer = elem_find_first(fbx_obj, b'LayerElementMaterial')
|
|
1560
|
-
|
|
1561
|
-
if fbx_layer is None:
|
|
1562
|
-
return
|
|
1563
|
-
|
|
1564
|
-
(fbx_layer_name,
|
|
1565
|
-
fbx_layer_mapping,
|
|
1566
|
-
fbx_layer_ref,
|
|
1567
|
-
) = blen_read_geom_layerinfo(fbx_layer)
|
|
1568
|
-
|
|
1569
|
-
layer_id = b'Materials'
|
|
1570
|
-
fbx_layer_data = elem_prop_first(elem_find_first(fbx_layer, layer_id))
|
|
1571
|
-
|
|
1572
|
-
blen_data = MESH_ATTRIBUTE_MATERIAL_INDEX.ensure(mesh.attributes).data
|
|
1573
|
-
fbx_item_size = 1
|
|
1574
|
-
assert(fbx_item_size == MESH_ATTRIBUTE_MATERIAL_INDEX.item_size)
|
|
1575
|
-
blen_read_geom_array_mapped_polygon(
|
|
1576
|
-
mesh, blen_data, MESH_ATTRIBUTE_MATERIAL_INDEX.foreach_attribute, MESH_ATTRIBUTE_MATERIAL_INDEX.dtype,
|
|
1577
|
-
fbx_layer_data, None,
|
|
1578
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1579
|
-
1, fbx_item_size, layer_id,
|
|
1580
|
-
)
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
def blen_read_geom_layer_uv(fbx_obj, mesh):
|
|
1584
|
-
for layer_id in (b'LayerElementUV',):
|
|
1585
|
-
for fbx_layer in elem_find_iter(fbx_obj, layer_id):
|
|
1586
|
-
# all should be valid
|
|
1587
|
-
(fbx_layer_name,
|
|
1588
|
-
fbx_layer_mapping,
|
|
1589
|
-
fbx_layer_ref,
|
|
1590
|
-
) = blen_read_geom_layerinfo(fbx_layer)
|
|
1591
|
-
|
|
1592
|
-
fbx_layer_data = elem_prop_first(elem_find_first(fbx_layer, b'UV'))
|
|
1593
|
-
fbx_layer_index = elem_prop_first(elem_find_first(fbx_layer, b'UVIndex'))
|
|
1594
|
-
|
|
1595
|
-
# Always init our new layers with (0, 0) UVs.
|
|
1596
|
-
uv_lay = mesh.uv_layers.new(name=fbx_layer_name, do_init=False)
|
|
1597
|
-
if uv_lay is None:
|
|
1598
|
-
print("Failed to add {%r %r} UVLayer to %r (probably too many of them?)"
|
|
1599
|
-
"" % (layer_id, fbx_layer_name, mesh.name))
|
|
1600
|
-
continue
|
|
1601
|
-
|
|
1602
|
-
blen_data = uv_lay.uv
|
|
1603
|
-
|
|
1604
|
-
# some valid files omit this data
|
|
1605
|
-
if fbx_layer_data is None:
|
|
1606
|
-
print("%r %r missing data" % (layer_id, fbx_layer_name))
|
|
1607
|
-
continue
|
|
1608
|
-
|
|
1609
|
-
blen_read_geom_array_mapped_polyloop(
|
|
1610
|
-
mesh, blen_data, "vector", np.single,
|
|
1611
|
-
fbx_layer_data, fbx_layer_index,
|
|
1612
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1613
|
-
2, 2, layer_id,
|
|
1614
|
-
)
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
def blen_read_geom_layer_color(fbx_obj, mesh, colors_type):
|
|
1618
|
-
if colors_type == 'NONE':
|
|
1619
|
-
return
|
|
1620
|
-
use_srgb = colors_type == 'SRGB'
|
|
1621
|
-
layer_type = 'BYTE_COLOR' if use_srgb else 'FLOAT_COLOR'
|
|
1622
|
-
color_prop_name = "color_srgb" if use_srgb else "color"
|
|
1623
|
-
# almost same as UVs
|
|
1624
|
-
for layer_id in (b'LayerElementColor',):
|
|
1625
|
-
for fbx_layer in elem_find_iter(fbx_obj, layer_id):
|
|
1626
|
-
# all should be valid
|
|
1627
|
-
(fbx_layer_name,
|
|
1628
|
-
fbx_layer_mapping,
|
|
1629
|
-
fbx_layer_ref,
|
|
1630
|
-
) = blen_read_geom_layerinfo(fbx_layer)
|
|
1631
|
-
|
|
1632
|
-
fbx_layer_data = elem_prop_first(elem_find_first(fbx_layer, b'Colors'))
|
|
1633
|
-
fbx_layer_index = elem_prop_first(elem_find_first(fbx_layer, b'ColorIndex'))
|
|
1634
|
-
|
|
1635
|
-
color_lay = mesh.color_attributes.new(name=fbx_layer_name, type=layer_type, domain='CORNER')
|
|
1636
|
-
|
|
1637
|
-
if color_lay is None:
|
|
1638
|
-
print("Failed to add {%r %r} vertex color layer to %r (probably too many of them?)"
|
|
1639
|
-
"" % (layer_id, fbx_layer_name, mesh.name))
|
|
1640
|
-
continue
|
|
1641
|
-
|
|
1642
|
-
blen_data = color_lay.data
|
|
1643
|
-
|
|
1644
|
-
# some valid files omit this data
|
|
1645
|
-
if fbx_layer_data is None:
|
|
1646
|
-
print("%r %r missing data" % (layer_id, fbx_layer_name))
|
|
1647
|
-
continue
|
|
1648
|
-
|
|
1649
|
-
blen_read_geom_array_mapped_polyloop(
|
|
1650
|
-
mesh, blen_data, color_prop_name, np.single,
|
|
1651
|
-
fbx_layer_data, fbx_layer_index,
|
|
1652
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1653
|
-
4, 4, layer_id,
|
|
1654
|
-
)
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
def blen_read_geom_layer_smooth(fbx_obj, mesh):
|
|
1658
|
-
fbx_layer = elem_find_first(fbx_obj, b'LayerElementSmoothing')
|
|
1659
|
-
|
|
1660
|
-
if fbx_layer is None:
|
|
1661
|
-
return
|
|
1662
|
-
|
|
1663
|
-
# all should be valid
|
|
1664
|
-
(fbx_layer_name,
|
|
1665
|
-
fbx_layer_mapping,
|
|
1666
|
-
fbx_layer_ref,
|
|
1667
|
-
) = blen_read_geom_layerinfo(fbx_layer)
|
|
1668
|
-
|
|
1669
|
-
layer_id = b'Smoothing'
|
|
1670
|
-
fbx_layer_data = elem_prop_first(elem_find_first(fbx_layer, layer_id))
|
|
1671
|
-
|
|
1672
|
-
# udk has 'Direct' mapped, with no Smoothing, not sure why, but ignore these
|
|
1673
|
-
if fbx_layer_data is None:
|
|
1674
|
-
return
|
|
1675
|
-
|
|
1676
|
-
if fbx_layer_mapping == b'ByEdge':
|
|
1677
|
-
# some models have bad edge data, we can't use this info...
|
|
1678
|
-
if not mesh.edges:
|
|
1679
|
-
print("warning skipping sharp edges data, no valid edges...")
|
|
1680
|
-
return
|
|
1681
|
-
|
|
1682
|
-
blen_data = MESH_ATTRIBUTE_SHARP_EDGE.ensure(mesh.attributes).data
|
|
1683
|
-
fbx_item_size = 1
|
|
1684
|
-
assert(fbx_item_size == MESH_ATTRIBUTE_SHARP_EDGE.item_size)
|
|
1685
|
-
blen_read_geom_array_mapped_edge(
|
|
1686
|
-
mesh, blen_data, MESH_ATTRIBUTE_SHARP_EDGE.foreach_attribute, MESH_ATTRIBUTE_SHARP_EDGE.dtype,
|
|
1687
|
-
fbx_layer_data, None,
|
|
1688
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1689
|
-
1, fbx_item_size, layer_id,
|
|
1690
|
-
xform=np.logical_not, # in FBX, 0 (False) is sharp, but in Blender True is sharp.
|
|
1691
|
-
)
|
|
1692
|
-
elif fbx_layer_mapping == b'ByPolygon':
|
|
1693
|
-
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.ensure(mesh.attributes)
|
|
1694
|
-
blen_data = sharp_face.data
|
|
1695
|
-
fbx_item_size = 1
|
|
1696
|
-
assert(fbx_item_size == MESH_ATTRIBUTE_SHARP_FACE.item_size)
|
|
1697
|
-
sharp_face_set_successfully = blen_read_geom_array_mapped_polygon(
|
|
1698
|
-
mesh, blen_data, MESH_ATTRIBUTE_SHARP_FACE.foreach_attribute, MESH_ATTRIBUTE_SHARP_FACE.dtype,
|
|
1699
|
-
fbx_layer_data, None,
|
|
1700
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1701
|
-
1, fbx_item_size, layer_id,
|
|
1702
|
-
xform=lambda s: (s == 0), # smoothgroup bitflags, treat as booleans for now
|
|
1703
|
-
)
|
|
1704
|
-
if not sharp_face_set_successfully:
|
|
1705
|
-
mesh.attributes.remove(sharp_face)
|
|
1706
|
-
else:
|
|
1707
|
-
print("warning layer %r mapping type unsupported: %r" % (fbx_layer.id, fbx_layer_mapping))
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
def blen_read_geom_layer_edge_crease(fbx_obj, mesh):
|
|
1711
|
-
fbx_layer = elem_find_first(fbx_obj, b'LayerElementEdgeCrease')
|
|
1712
|
-
|
|
1713
|
-
if fbx_layer is None:
|
|
1714
|
-
return False
|
|
1715
|
-
|
|
1716
|
-
# all should be valid
|
|
1717
|
-
(fbx_layer_name,
|
|
1718
|
-
fbx_layer_mapping,
|
|
1719
|
-
fbx_layer_ref,
|
|
1720
|
-
) = blen_read_geom_layerinfo(fbx_layer)
|
|
1721
|
-
|
|
1722
|
-
if fbx_layer_mapping != b'ByEdge':
|
|
1723
|
-
return False
|
|
1724
|
-
|
|
1725
|
-
layer_id = b'EdgeCrease'
|
|
1726
|
-
fbx_layer_data = elem_prop_first(elem_find_first(fbx_layer, layer_id))
|
|
1727
|
-
|
|
1728
|
-
# some models have bad edge data, we can't use this info...
|
|
1729
|
-
if not mesh.edges:
|
|
1730
|
-
print("warning skipping edge crease data, no valid edges...")
|
|
1731
|
-
return False
|
|
1732
|
-
|
|
1733
|
-
if fbx_layer_mapping == b'ByEdge':
|
|
1734
|
-
# some models have bad edge data, we can't use this info...
|
|
1735
|
-
if not mesh.edges:
|
|
1736
|
-
print("warning skipping edge crease data, no valid edges...")
|
|
1737
|
-
return False
|
|
1738
|
-
|
|
1739
|
-
blen_data = mesh.edge_creases_ensure().data
|
|
1740
|
-
return blen_read_geom_array_mapped_edge(
|
|
1741
|
-
mesh, blen_data, "value", np.single,
|
|
1742
|
-
fbx_layer_data, None,
|
|
1743
|
-
fbx_layer_mapping, fbx_layer_ref,
|
|
1744
|
-
1, 1, layer_id,
|
|
1745
|
-
# Blender squares those values before sending them to OpenSubdiv, when other software don't,
|
|
1746
|
-
# so we need to compensate that to get similar results through FBX...
|
|
1747
|
-
xform=np.sqrt,
|
|
1748
|
-
)
|
|
1749
|
-
else:
|
|
1750
|
-
print("warning layer %r mapping type unsupported: %r" % (fbx_layer.id, fbx_layer_mapping))
|
|
1751
|
-
return False
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
def blen_read_geom_layer_normal(fbx_obj, mesh, xform=None):
|
|
1755
|
-
fbx_layer = elem_find_first(fbx_obj, b'LayerElementNormal')
|
|
1756
|
-
|
|
1757
|
-
if fbx_layer is None:
|
|
1758
|
-
return False
|
|
1759
|
-
|
|
1760
|
-
(fbx_layer_name,
|
|
1761
|
-
fbx_layer_mapping,
|
|
1762
|
-
fbx_layer_ref,
|
|
1763
|
-
) = blen_read_geom_layerinfo(fbx_layer)
|
|
1764
|
-
|
|
1765
|
-
layer_id = b'Normals'
|
|
1766
|
-
fbx_layer_data = elem_prop_first(elem_find_first(fbx_layer, layer_id))
|
|
1767
|
-
fbx_layer_index = elem_prop_first(elem_find_first(fbx_layer, b'NormalsIndex'))
|
|
1768
|
-
|
|
1769
|
-
if fbx_layer_data is None:
|
|
1770
|
-
print("warning %r %r missing data" % (layer_id, fbx_layer_name))
|
|
1771
|
-
return False
|
|
1772
|
-
|
|
1773
|
-
# Normals are temporarily set here so that they can be retrieved again after a call to Mesh.validate().
|
|
1774
|
-
bl_norm_dtype = np.single
|
|
1775
|
-
item_size = 3
|
|
1776
|
-
# try loops, then polygons, then vertices.
|
|
1777
|
-
tries = ((mesh.attributes["temp_custom_normals"].data, "Loops", False, blen_read_geom_array_mapped_polyloop),
|
|
1778
|
-
(mesh.polygons, "Polygons", True, blen_read_geom_array_mapped_polygon),
|
|
1779
|
-
(mesh.vertices, "Vertices", True, blen_read_geom_array_mapped_vert))
|
|
1780
|
-
for blen_data, blen_data_type, is_fake, func in tries:
|
|
1781
|
-
bdata = np.zeros((len(blen_data), item_size), dtype=bl_norm_dtype) if is_fake else blen_data
|
|
1782
|
-
if func(mesh, bdata, "vector", bl_norm_dtype,
|
|
1783
|
-
fbx_layer_data, fbx_layer_index, fbx_layer_mapping, fbx_layer_ref, 3, item_size, layer_id, xform, True):
|
|
1784
|
-
if blen_data_type == "Polygons":
|
|
1785
|
-
# To expand to per-loop normals, repeat each per-polygon normal by the number of loops of each polygon.
|
|
1786
|
-
poly_loop_totals = np.empty(len(mesh.polygons), dtype=np.uintc)
|
|
1787
|
-
mesh.polygons.foreach_get("loop_total", poly_loop_totals)
|
|
1788
|
-
loop_normals = np.repeat(bdata, poly_loop_totals, axis=0)
|
|
1789
|
-
mesh.attributes["temp_custom_normals"].data.foreach_set("vector", loop_normals.ravel())
|
|
1790
|
-
elif blen_data_type == "Vertices":
|
|
1791
|
-
# We have to copy vnors to lnors! Far from elegant, but simple.
|
|
1792
|
-
loop_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes)
|
|
1793
|
-
mesh.attributes["temp_custom_normals"].data.foreach_set("vector", bdata[loop_vertex_indices].ravel())
|
|
1794
|
-
return True
|
|
1795
|
-
|
|
1796
|
-
blen_read_geom_array_error_mapping("normal", fbx_layer_mapping)
|
|
1797
|
-
blen_read_geom_array_error_ref("normal", fbx_layer_ref)
|
|
1798
|
-
return False
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
def blen_read_geom(fbx_tmpl, fbx_obj, settings):
|
|
1802
|
-
# Vertices are in object space, but we are post-multiplying all transforms with the inverse of the
|
|
1803
|
-
# global matrix, so we need to apply the global matrix to the vertices to get the correct result.
|
|
1804
|
-
geom_mat_co = settings.global_matrix if settings.bake_space_transform else None
|
|
1805
|
-
# We need to apply the inverse transpose of the global matrix when transforming normals.
|
|
1806
|
-
geom_mat_no = Matrix(settings.global_matrix_inv_transposed) if settings.bake_space_transform else None
|
|
1807
|
-
if geom_mat_no is not None:
|
|
1808
|
-
# Remove translation & scaling!
|
|
1809
|
-
geom_mat_no.translation = Vector()
|
|
1810
|
-
geom_mat_no.normalize()
|
|
1811
|
-
|
|
1812
|
-
# TODO, use 'fbx_tmpl'
|
|
1813
|
-
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'Geometry')
|
|
1814
|
-
|
|
1815
|
-
fbx_verts = elem_prop_first(elem_find_first(fbx_obj, b'Vertices'))
|
|
1816
|
-
fbx_polys = elem_prop_first(elem_find_first(fbx_obj, b'PolygonVertexIndex'))
|
|
1817
|
-
fbx_edges = elem_prop_first(elem_find_first(fbx_obj, b'Edges'))
|
|
1818
|
-
|
|
1819
|
-
# The dtypes when empty don't matter, but are set to what the fbx arrays are expected to be.
|
|
1820
|
-
fbx_verts = parray_as_ndarray(fbx_verts) if fbx_verts else np.empty(0, dtype=data_types.ARRAY_FLOAT64)
|
|
1821
|
-
fbx_polys = parray_as_ndarray(fbx_polys) if fbx_polys else np.empty(0, dtype=data_types.ARRAY_INT32)
|
|
1822
|
-
fbx_edges = parray_as_ndarray(fbx_edges) if fbx_edges else np.empty(0, dtype=data_types.ARRAY_INT32)
|
|
1823
|
-
|
|
1824
|
-
# Each vert is a 3d vector so is made of 3 components.
|
|
1825
|
-
tot_verts = len(fbx_verts) // 3
|
|
1826
|
-
if tot_verts * 3 != len(fbx_verts):
|
|
1827
|
-
print("ERROR: Not a whole number of vertices. Ignoring the partial vertex!")
|
|
1828
|
-
# Remove any remainder.
|
|
1829
|
-
fbx_verts = fbx_verts[:tot_verts * 3]
|
|
1830
|
-
|
|
1831
|
-
tot_loops = len(fbx_polys)
|
|
1832
|
-
tot_edges = len(fbx_edges)
|
|
1833
|
-
|
|
1834
|
-
mesh = bpy.data.meshes.new(name=elem_name_utf8)
|
|
1835
|
-
attributes = mesh.attributes
|
|
1836
|
-
|
|
1837
|
-
if tot_verts:
|
|
1838
|
-
if geom_mat_co is not None:
|
|
1839
|
-
fbx_verts = vcos_transformed(fbx_verts, geom_mat_co, MESH_ATTRIBUTE_POSITION.dtype)
|
|
1840
|
-
else:
|
|
1841
|
-
fbx_verts = fbx_verts.astype(MESH_ATTRIBUTE_POSITION.dtype, copy=False)
|
|
1842
|
-
|
|
1843
|
-
mesh.vertices.add(tot_verts)
|
|
1844
|
-
MESH_ATTRIBUTE_POSITION.foreach_set(attributes, fbx_verts.ravel())
|
|
1845
|
-
|
|
1846
|
-
if tot_loops:
|
|
1847
|
-
bl_loop_start_dtype = np.uintc
|
|
1848
|
-
|
|
1849
|
-
mesh.loops.add(tot_loops)
|
|
1850
|
-
# The end of each polygon is specified by an inverted index.
|
|
1851
|
-
fbx_loop_end_idx = np.flatnonzero(fbx_polys < 0)
|
|
1852
|
-
|
|
1853
|
-
tot_polys = len(fbx_loop_end_idx)
|
|
1854
|
-
|
|
1855
|
-
# Un-invert the loop ends.
|
|
1856
|
-
fbx_polys[fbx_loop_end_idx] ^= -1
|
|
1857
|
-
# Set loop vertex indices, casting to the Blender C type first for performance.
|
|
1858
|
-
MESH_ATTRIBUTE_CORNER_VERT.foreach_set(
|
|
1859
|
-
attributes, astype_view_signedness(fbx_polys, MESH_ATTRIBUTE_CORNER_VERT.dtype))
|
|
1860
|
-
|
|
1861
|
-
poly_loop_starts = np.empty(tot_polys, dtype=bl_loop_start_dtype)
|
|
1862
|
-
# The first loop is always a loop start.
|
|
1863
|
-
poly_loop_starts[0] = 0
|
|
1864
|
-
# Ignoring the last loop end, the indices after every loop end are the remaining loop starts.
|
|
1865
|
-
poly_loop_starts[1:] = fbx_loop_end_idx[:-1] + 1
|
|
1866
|
-
|
|
1867
|
-
mesh.polygons.add(tot_polys)
|
|
1868
|
-
mesh.polygons.foreach_set("loop_start", poly_loop_starts)
|
|
1869
|
-
|
|
1870
|
-
blen_read_geom_layer_material(fbx_obj, mesh)
|
|
1871
|
-
blen_read_geom_layer_uv(fbx_obj, mesh)
|
|
1872
|
-
blen_read_geom_layer_color(fbx_obj, mesh, settings.colors_type)
|
|
1873
|
-
|
|
1874
|
-
if tot_edges:
|
|
1875
|
-
# edges in fact index the polygons (NOT the vertices)
|
|
1876
|
-
|
|
1877
|
-
# The first vertex index of each edge is the vertex index of the corresponding loop in fbx_polys.
|
|
1878
|
-
edges_a = fbx_polys[fbx_edges]
|
|
1879
|
-
|
|
1880
|
-
# The second vertex index of each edge is the vertex index of the next loop in the same polygon. The
|
|
1881
|
-
# complexity here is that if the first vertex index was the last loop of that polygon in fbx_polys, the next
|
|
1882
|
-
# loop in the polygon is the first loop of that polygon, which is not the next loop in fbx_polys.
|
|
1883
|
-
|
|
1884
|
-
# Copy fbx_polys, but rolled backwards by 1 so that indexing the result by [fbx_edges] will get the next
|
|
1885
|
-
# loop of the same polygon unless the first vertex index was the last loop of the polygon.
|
|
1886
|
-
fbx_polys_next = np.roll(fbx_polys, -1)
|
|
1887
|
-
# Get the first loop of each polygon and set them into fbx_polys_next at the same indices as the last loop
|
|
1888
|
-
# of each polygon in fbx_polys.
|
|
1889
|
-
fbx_polys_next[fbx_loop_end_idx] = fbx_polys[poly_loop_starts]
|
|
1890
|
-
|
|
1891
|
-
# Indexing fbx_polys_next by fbx_edges now gets the vertex index of the next loop in fbx_polys.
|
|
1892
|
-
edges_b = fbx_polys_next[fbx_edges]
|
|
1893
|
-
|
|
1894
|
-
# edges_a and edges_b need to be combined so that the first vertex index of each edge is immediately
|
|
1895
|
-
# followed by the second vertex index of that same edge.
|
|
1896
|
-
# Stack edges_a and edges_b as individual columns like np.column_stack((edges_a, edges_b)).
|
|
1897
|
-
# np.concatenate is used because np.column_stack doesn't allow specifying the dtype of the returned array.
|
|
1898
|
-
edges_conv = np.concatenate((edges_a.reshape(-1, 1), edges_b.reshape(-1, 1)),
|
|
1899
|
-
axis=1, dtype=MESH_ATTRIBUTE_EDGE_VERTS.dtype, casting='unsafe')
|
|
1900
|
-
|
|
1901
|
-
# Add the edges and set their vertex indices.
|
|
1902
|
-
mesh.edges.add(len(edges_conv))
|
|
1903
|
-
# ravel() because edges_conv must be flat and C-contiguous when passed to foreach_set.
|
|
1904
|
-
MESH_ATTRIBUTE_EDGE_VERTS.foreach_set(attributes, edges_conv.ravel())
|
|
1905
|
-
elif tot_edges:
|
|
1906
|
-
print("ERROR: No polygons, but edges exist. Ignoring the edges!")
|
|
1907
|
-
|
|
1908
|
-
# must be after edge, face loading.
|
|
1909
|
-
blen_read_geom_layer_smooth(fbx_obj, mesh)
|
|
1910
|
-
|
|
1911
|
-
blen_read_geom_layer_edge_crease(fbx_obj, mesh)
|
|
1912
|
-
|
|
1913
|
-
ok_normals = False
|
|
1914
|
-
if settings.use_custom_normals:
|
|
1915
|
-
# Note: we store 'temp' normals in loops, since validate() may alter final mesh,
|
|
1916
|
-
# we can only set custom lnors *after* calling it.
|
|
1917
|
-
mesh.attributes.new("temp_custom_normals", 'FLOAT_VECTOR', 'CORNER')
|
|
1918
|
-
if geom_mat_no is None:
|
|
1919
|
-
ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh)
|
|
1920
|
-
else:
|
|
1921
|
-
ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh,
|
|
1922
|
-
lambda v_array: nors_transformed(v_array, geom_mat_no))
|
|
1923
|
-
|
|
1924
|
-
mesh.validate(clean_customdata=False) # *Very* important to not remove lnors here!
|
|
1925
|
-
|
|
1926
|
-
if ok_normals:
|
|
1927
|
-
bl_nors_dtype = np.single
|
|
1928
|
-
clnors = np.empty(len(mesh.loops) * 3, dtype=bl_nors_dtype)
|
|
1929
|
-
mesh.attributes["temp_custom_normals"].data.foreach_get("vector", clnors)
|
|
1930
|
-
|
|
1931
|
-
# Iterating clnors into a nested tuple first is faster than passing clnors.reshape(-1, 3) directly into
|
|
1932
|
-
# normals_split_custom_set. We use clnors.data since it is a memoryview, which is faster to iterate than clnors.
|
|
1933
|
-
mesh.normals_split_custom_set(tuple(zip(*(iter(clnors.data),) * 3)))
|
|
1934
|
-
if settings.use_custom_normals:
|
|
1935
|
-
mesh.attributes.remove(mesh.attributes["temp_custom_normals"])
|
|
1936
|
-
|
|
1937
|
-
if settings.use_custom_props:
|
|
1938
|
-
blen_read_custom_properties(fbx_obj, mesh, settings)
|
|
1939
|
-
|
|
1940
|
-
return mesh
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
def blen_read_shapes(fbx_tmpl, fbx_data, objects, me, scene):
|
|
1944
|
-
if not fbx_data:
|
|
1945
|
-
# No shape key data. Nothing to do.
|
|
1946
|
-
return
|
|
1947
|
-
|
|
1948
|
-
me_vcos = MESH_ATTRIBUTE_POSITION.to_ndarray(me.attributes)
|
|
1949
|
-
me_vcos_vector_view = me_vcos.reshape(-1, 3)
|
|
1950
|
-
|
|
1951
|
-
objects = list({node.bl_obj for node in objects})
|
|
1952
|
-
assert(objects)
|
|
1953
|
-
|
|
1954
|
-
# Blender has a hard minimum and maximum shape key Value. If an imported shape key has a value outside this range it
|
|
1955
|
-
# will be clamped, and we'll print a warning message to the console.
|
|
1956
|
-
shape_key_values_in_range = True
|
|
1957
|
-
bc_uuid_to_keyblocks = {}
|
|
1958
|
-
for bc_uuid, fbx_sdata, fbx_bcdata, shapes_assigned_to_channel in fbx_data:
|
|
1959
|
-
num_shapes_assigned_to_channel = len(shapes_assigned_to_channel)
|
|
1960
|
-
if num_shapes_assigned_to_channel > 1:
|
|
1961
|
-
# Relevant design task: #104698
|
|
1962
|
-
raise RuntimeError("FBX in-between Shapes are not currently supported") # See bug report #84111
|
|
1963
|
-
elem_name_utf8 = elem_name_ensure_class(fbx_sdata, b'Geometry')
|
|
1964
|
-
indices = elem_prop_first(elem_find_first(fbx_sdata, b'Indexes'))
|
|
1965
|
-
dvcos = elem_prop_first(elem_find_first(fbx_sdata, b'Vertices'))
|
|
1966
|
-
|
|
1967
|
-
indices = parray_as_ndarray(indices) if indices else np.empty(0, dtype=data_types.ARRAY_INT32)
|
|
1968
|
-
dvcos = parray_as_ndarray(dvcos) if dvcos else np.empty(0, dtype=data_types.ARRAY_FLOAT64)
|
|
1969
|
-
|
|
1970
|
-
# If there's not a whole number of vectors, trim off the remainder.
|
|
1971
|
-
# 3 components per vector.
|
|
1972
|
-
remainder = len(dvcos) % 3
|
|
1973
|
-
if remainder:
|
|
1974
|
-
dvcos = dvcos[:-remainder]
|
|
1975
|
-
dvcos = dvcos.reshape(-1, 3)
|
|
1976
|
-
|
|
1977
|
-
# There must be the same number of indices as vertex coordinate differences.
|
|
1978
|
-
assert(len(indices) == len(dvcos))
|
|
1979
|
-
|
|
1980
|
-
# We completely ignore normals here!
|
|
1981
|
-
weight = elem_prop_first(elem_find_first(fbx_bcdata, b'DeformPercent'), default=100.0) / 100.0
|
|
1982
|
-
|
|
1983
|
-
# The FullWeights array stores the deformation percentages of the BlendShapeChannel that fully activate each
|
|
1984
|
-
# Shape assigned to the BlendShapeChannel. Blender also uses this array to store Vertex Group weights, but this
|
|
1985
|
-
# is not part of the FBX standard.
|
|
1986
|
-
full_weights = elem_prop_first(elem_find_first(fbx_bcdata, b'FullWeights'))
|
|
1987
|
-
full_weights = parray_as_ndarray(full_weights) if full_weights else np.empty(0, dtype=data_types.ARRAY_FLOAT64)
|
|
1988
|
-
|
|
1989
|
-
# Special case for Blender exported Shape Keys with a Vertex Group assigned. The Vertex Group weights are stored
|
|
1990
|
-
# in the FullWeights array.
|
|
1991
|
-
# XXX - It's possible, though very rare, to get a false positive here and create a Vertex Group when we
|
|
1992
|
-
# shouldn't. This should only be possible when there are extraneous FullWeights or when there is a single
|
|
1993
|
-
# FullWeight and its value is not 100.0.
|
|
1994
|
-
if (
|
|
1995
|
-
# Blender exported Shape Keys only ever export as 1 Shape per BlendShapeChannel.
|
|
1996
|
-
num_shapes_assigned_to_channel == 1
|
|
1997
|
-
# There should be one vertex weight for each vertex moved by the Shape.
|
|
1998
|
-
and len(full_weights) == len(indices)
|
|
1999
|
-
# Skip creating a Vertex Group when all the weights are 100.0 because such a Vertex Group has no effect.
|
|
2000
|
-
# This also avoids creating a Vertex Group for imported Shapes that only move a single vertex because
|
|
2001
|
-
# their BlendShapeChannel's singular FullWeight is expected to always be 100.0.
|
|
2002
|
-
and not np.all(full_weights == 100.0)
|
|
2003
|
-
# Blender vertex weights are always within the [0.0, 1.0] range (scaled to [0.0, 100.0] when saving to
|
|
2004
|
-
# FBX). This can eliminate imported BlendShapeChannels from Unreal that have extraneous FullWeights
|
|
2005
|
-
# because the extraneous values are usually negative.
|
|
2006
|
-
and np.all((full_weights >= 0.0) & (full_weights <= 100.0))
|
|
2007
|
-
):
|
|
2008
|
-
# Not doing the division in-place because it's technically possible for FBX BlendShapeChannels to be used by
|
|
2009
|
-
# more than one FBX BlendShape, though this shouldn't be the case for Blender exported Shape Keys.
|
|
2010
|
-
vgweights = full_weights / 100.0
|
|
2011
|
-
else:
|
|
2012
|
-
vgweights = None
|
|
2013
|
-
# There must be a FullWeight for each Shape. Any extra FullWeights are ignored.
|
|
2014
|
-
assert(len(full_weights) >= num_shapes_assigned_to_channel)
|
|
2015
|
-
|
|
2016
|
-
# To add shape keys to the mesh, an Object using the mesh is needed.
|
|
2017
|
-
if me.shape_keys is None:
|
|
2018
|
-
objects[0].shape_key_add(name="Basis", from_mix=False)
|
|
2019
|
-
kb = objects[0].shape_key_add(name=elem_name_utf8, from_mix=False)
|
|
2020
|
-
kb.value = 0.0
|
|
2021
|
-
me.shape_keys.use_relative = True # Should already be set as such.
|
|
2022
|
-
|
|
2023
|
-
# Only need to set the shape key co if there are any non-zero dvcos.
|
|
2024
|
-
if dvcos.any():
|
|
2025
|
-
shape_cos = me_vcos_vector_view.copy()
|
|
2026
|
-
shape_cos[indices] += dvcos
|
|
2027
|
-
kb.points.foreach_set("co", shape_cos.ravel())
|
|
2028
|
-
|
|
2029
|
-
shape_key_values_in_range &= expand_shape_key_range(kb, weight)
|
|
2030
|
-
|
|
2031
|
-
kb.value = weight
|
|
2032
|
-
|
|
2033
|
-
# Add vgroup if necessary.
|
|
2034
|
-
if vgweights is not None:
|
|
2035
|
-
# VertexGroup.add only allows sequences of int indices, but iterating the indices array directly would
|
|
2036
|
-
# produce numpy scalars of types such as np.int32. The underlying memoryview of the indices array, however,
|
|
2037
|
-
# does produce standard Python ints when iterated, so pass indices.data to add_vgroup_to_objects instead of
|
|
2038
|
-
# indices.
|
|
2039
|
-
# memoryviews tend to be faster to iterate than numpy arrays anyway, so vgweights.data is passed too.
|
|
2040
|
-
add_vgroup_to_objects(indices.data, vgweights.data, kb.name, objects)
|
|
2041
|
-
kb.vertex_group = kb.name
|
|
2042
|
-
|
|
2043
|
-
bc_uuid_to_keyblocks.setdefault(bc_uuid, []).append(kb)
|
|
2044
|
-
|
|
2045
|
-
if not shape_key_values_in_range:
|
|
2046
|
-
print("WARNING: The imported Value of a Shape Key on the Mesh '%s' is beyond the minimum/maximum allowed and"
|
|
2047
|
-
" has been clamped." % me.name)
|
|
2048
|
-
|
|
2049
|
-
return bc_uuid_to_keyblocks
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
# --------
|
|
2053
|
-
# Material
|
|
2054
|
-
|
|
2055
|
-
def blen_read_material(fbx_tmpl, fbx_obj, settings):
|
|
2056
|
-
from bpy_extras import node_shader_utils
|
|
2057
|
-
from math import sqrt
|
|
2058
|
-
|
|
2059
|
-
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'Material')
|
|
2060
|
-
|
|
2061
|
-
if settings.mtl_name_collision_mode == "REFERENCE_EXISTING":
|
|
2062
|
-
if (ma := bpy.data.materials.get(elem_name_utf8)):
|
|
2063
|
-
return ma
|
|
2064
|
-
|
|
2065
|
-
nodal_material_wrap_map = settings.nodal_material_wrap_map
|
|
2066
|
-
ma = bpy.data.materials.new(name=elem_name_utf8)
|
|
2067
|
-
|
|
2068
|
-
const_color_white = 1.0, 1.0, 1.0
|
|
2069
|
-
const_color_black = 0.0, 0.0, 0.0
|
|
2070
|
-
|
|
2071
|
-
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
|
2072
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
2073
|
-
fbx_props_no_template = (fbx_props[0], fbx_elem_nil)
|
|
2074
|
-
|
|
2075
|
-
ma_wrap = node_shader_utils.PrincipledBSDFWrapper(ma, is_readonly=False)
|
|
2076
|
-
ma_wrap.base_color = elem_props_get_color_rgb(fbx_props, b'DiffuseColor', const_color_white)
|
|
2077
|
-
# No specular color in Principled BSDF shader, assumed to be either white or take some tint from diffuse one...
|
|
2078
|
-
# TODO: add way to handle tint option (guesstimate from spec color + intensity...)?
|
|
2079
|
-
ma_wrap.specular = elem_props_get_number(fbx_props, b'SpecularFactor', 0.25) * 2.0
|
|
2080
|
-
# XXX Totally empirical conversion, trying to adapt it (and protect against invalid negative values, see T96076):
|
|
2081
|
-
# From [1.0 - 0.0] Principled BSDF range to [0.0 - 100.0] FBX shininess range)...
|
|
2082
|
-
fbx_shininess = max(elem_props_get_number(fbx_props, b'Shininess', 20.0), 0.0)
|
|
2083
|
-
ma_wrap.roughness = 1.0 - (sqrt(fbx_shininess) / 10.0)
|
|
2084
|
-
# Sweetness... Looks like we are not the only ones to not know exactly how FBX is supposed to work (see T59850).
|
|
2085
|
-
# According to one of its developers, Unity uses that formula to extract alpha value:
|
|
2086
|
-
#
|
|
2087
|
-
# alpha = 1 - TransparencyFactor
|
|
2088
|
-
# if (alpha == 1 or alpha == 0):
|
|
2089
|
-
# alpha = 1 - TransparentColor.r
|
|
2090
|
-
#
|
|
2091
|
-
# Until further info, let's assume this is correct way to do, hence the following code for TransparentColor.
|
|
2092
|
-
# However, there are some cases (from 3DSMax, see T65065), where we do have TransparencyFactor only defined
|
|
2093
|
-
# in the template to 0.0, and then materials defining TransparentColor to pure white (1.0, 1.0, 1.0),
|
|
2094
|
-
# and setting alpha value in Opacity... try to cope with that too. :((((
|
|
2095
|
-
alpha = 1.0 - elem_props_get_number(fbx_props, b'TransparencyFactor', 0.0)
|
|
2096
|
-
if (alpha == 1.0 or alpha == 0.0):
|
|
2097
|
-
alpha = elem_props_get_number(fbx_props_no_template, b'Opacity', None)
|
|
2098
|
-
if alpha is None:
|
|
2099
|
-
alpha = 1.0 - elem_props_get_color_rgb(fbx_props, b'TransparentColor', const_color_black)[0]
|
|
2100
|
-
ma_wrap.alpha = alpha
|
|
2101
|
-
ma_wrap.metallic = elem_props_get_number(fbx_props, b'ReflectionFactor', 0.0)
|
|
2102
|
-
# We have no metallic (a.k.a. reflection) color...
|
|
2103
|
-
# elem_props_get_color_rgb(fbx_props, b'ReflectionColor', const_color_white)
|
|
2104
|
-
ma_wrap.normalmap_strength = elem_props_get_number(fbx_props, b'BumpFactor', 1.0)
|
|
2105
|
-
# Emission strength and color
|
|
2106
|
-
ma_wrap.emission_strength = elem_props_get_number(fbx_props, b'EmissiveFactor', 1.0)
|
|
2107
|
-
ma_wrap.emission_color = elem_props_get_color_rgb(fbx_props, b'EmissiveColor', const_color_black)
|
|
2108
|
-
|
|
2109
|
-
nodal_material_wrap_map[ma] = ma_wrap
|
|
2110
|
-
|
|
2111
|
-
if settings.use_custom_props:
|
|
2112
|
-
blen_read_custom_properties(fbx_obj, ma, settings)
|
|
2113
|
-
|
|
2114
|
-
return ma
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
# -------
|
|
2118
|
-
# Image & Texture
|
|
2119
|
-
|
|
2120
|
-
def blen_read_texture_image(fbx_tmpl, fbx_obj, basedir, settings):
|
|
2121
|
-
import os
|
|
2122
|
-
from bpy_extras import image_utils
|
|
2123
|
-
|
|
2124
|
-
def pack_data_from_content(image, fbx_obj):
|
|
2125
|
-
data = elem_find_first_bytes(fbx_obj, b'Content')
|
|
2126
|
-
if (data):
|
|
2127
|
-
data_len = len(data)
|
|
2128
|
-
if (data_len):
|
|
2129
|
-
image.pack(data=data, data_len=data_len)
|
|
2130
|
-
|
|
2131
|
-
elem_name_utf8 = elem_name_ensure_classes(fbx_obj, {b'Texture', b'Video'})
|
|
2132
|
-
|
|
2133
|
-
image_cache = settings.image_cache
|
|
2134
|
-
|
|
2135
|
-
# Yet another beautiful logic demonstration by Master FBX:
|
|
2136
|
-
# * RelativeFilename in both Video and Texture nodes.
|
|
2137
|
-
# * FileName in texture nodes.
|
|
2138
|
-
# * Filename in video nodes.
|
|
2139
|
-
# Aaaaaaaarrrrrrrrgggggggggggg!!!!!!!!!!!!!!
|
|
2140
|
-
filepath = elem_find_first_string(fbx_obj, b'RelativeFilename')
|
|
2141
|
-
if filepath:
|
|
2142
|
-
# Make sure we do handle a relative path, and not an absolute one (see D5143).
|
|
2143
|
-
filepath = filepath.lstrip(os.path.sep).lstrip(os.path.altsep)
|
|
2144
|
-
filepath = os.path.join(basedir, filepath)
|
|
2145
|
-
else:
|
|
2146
|
-
filepath = elem_find_first_string(fbx_obj, b'FileName')
|
|
2147
|
-
if not filepath:
|
|
2148
|
-
filepath = elem_find_first_string(fbx_obj, b'Filename')
|
|
2149
|
-
if not filepath:
|
|
2150
|
-
print("Error, could not find any file path in ", fbx_obj)
|
|
2151
|
-
print(" Falling back to: ", elem_name_utf8)
|
|
2152
|
-
filepath = elem_name_utf8
|
|
2153
|
-
else:
|
|
2154
|
-
filepath = filepath.replace('\\', '/') if (os.sep == '/') else filepath.replace('/', '\\')
|
|
2155
|
-
|
|
2156
|
-
image = image_cache.get(filepath)
|
|
2157
|
-
if image is not None:
|
|
2158
|
-
# Data is only embedded once, we may have already created the image but still be missing its data!
|
|
2159
|
-
if not image.has_data:
|
|
2160
|
-
pack_data_from_content(image, fbx_obj)
|
|
2161
|
-
return image
|
|
2162
|
-
|
|
2163
|
-
image = image_utils.load_image(
|
|
2164
|
-
filepath,
|
|
2165
|
-
dirname=basedir,
|
|
2166
|
-
place_holder=True,
|
|
2167
|
-
recursive=settings.use_image_search,
|
|
2168
|
-
)
|
|
2169
|
-
|
|
2170
|
-
# Try to use embedded data, if available!
|
|
2171
|
-
pack_data_from_content(image, fbx_obj)
|
|
2172
|
-
|
|
2173
|
-
image_cache[filepath] = image
|
|
2174
|
-
# name can be ../a/b/c
|
|
2175
|
-
image.name = os.path.basename(elem_name_utf8)
|
|
2176
|
-
|
|
2177
|
-
if settings.use_custom_props:
|
|
2178
|
-
blen_read_custom_properties(fbx_obj, image, settings)
|
|
2179
|
-
|
|
2180
|
-
return image
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
def blen_read_camera(fbx_tmpl, fbx_obj, settings):
|
|
2184
|
-
# meters to inches
|
|
2185
|
-
M2I = 0.0393700787
|
|
2186
|
-
|
|
2187
|
-
global_scale = settings.global_scale
|
|
2188
|
-
|
|
2189
|
-
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
|
2190
|
-
|
|
2191
|
-
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
|
2192
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
2193
|
-
|
|
2194
|
-
camera = bpy.data.cameras.new(name=elem_name_utf8)
|
|
2195
|
-
|
|
2196
|
-
camera.type = 'ORTHO' if elem_props_get_enum(fbx_props, b'CameraProjectionType', 0) == 1 else 'PERSP'
|
|
2197
|
-
|
|
2198
|
-
camera.dof.focus_distance = elem_props_get_number(fbx_props, b'FocusDistance', 10) * global_scale
|
|
2199
|
-
if (elem_props_get_bool(fbx_props, b'UseDepthOfField', False)):
|
|
2200
|
-
camera.dof.use_dof = True
|
|
2201
|
-
|
|
2202
|
-
camera.lens = elem_props_get_number(fbx_props, b'FocalLength', 35.0)
|
|
2203
|
-
camera.sensor_width = elem_props_get_number(fbx_props, b'FilmWidth', 32.0 * M2I) / M2I
|
|
2204
|
-
camera.sensor_height = elem_props_get_number(fbx_props, b'FilmHeight', 32.0 * M2I) / M2I
|
|
2205
|
-
|
|
2206
|
-
camera.ortho_scale = elem_props_get_number(fbx_props, b'OrthoZoom', 1.0)
|
|
2207
|
-
|
|
2208
|
-
filmaspect = camera.sensor_width / camera.sensor_height
|
|
2209
|
-
# film offset
|
|
2210
|
-
camera.shift_x = elem_props_get_number(fbx_props, b'FilmOffsetX', 0.0) / (M2I * camera.sensor_width)
|
|
2211
|
-
camera.shift_y = elem_props_get_number(fbx_props, b'FilmOffsetY', 0.0) / (M2I * camera.sensor_height * filmaspect)
|
|
2212
|
-
|
|
2213
|
-
camera.clip_start = elem_props_get_number(fbx_props, b'NearPlane', 0.01) * global_scale
|
|
2214
|
-
camera.clip_end = elem_props_get_number(fbx_props, b'FarPlane', 100.0) * global_scale
|
|
2215
|
-
|
|
2216
|
-
if settings.use_custom_props:
|
|
2217
|
-
blen_read_custom_properties(fbx_obj, camera, settings)
|
|
2218
|
-
|
|
2219
|
-
return camera
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
def blen_read_light(fbx_tmpl, fbx_obj, settings):
|
|
2223
|
-
import math
|
|
2224
|
-
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
|
2225
|
-
|
|
2226
|
-
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
|
2227
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
2228
|
-
|
|
2229
|
-
light_type = {
|
|
2230
|
-
0: 'POINT',
|
|
2231
|
-
1: 'SUN',
|
|
2232
|
-
2: 'SPOT'}.get(elem_props_get_enum(fbx_props, b'LightType', 0), 'POINT')
|
|
2233
|
-
|
|
2234
|
-
lamp = bpy.data.lights.new(name=elem_name_utf8, type=light_type)
|
|
2235
|
-
|
|
2236
|
-
if light_type == 'SPOT':
|
|
2237
|
-
spot_size = elem_props_get_number(fbx_props, b'OuterAngle', None)
|
|
2238
|
-
if spot_size is None:
|
|
2239
|
-
# Deprecated.
|
|
2240
|
-
spot_size = elem_props_get_number(fbx_props, b'Cone angle', 45.0)
|
|
2241
|
-
lamp.spot_size = math.radians(spot_size)
|
|
2242
|
-
|
|
2243
|
-
spot_blend = elem_props_get_number(fbx_props, b'InnerAngle', None)
|
|
2244
|
-
if spot_blend is None:
|
|
2245
|
-
# Deprecated.
|
|
2246
|
-
spot_blend = elem_props_get_number(fbx_props, b'HotSpot', 45.0)
|
|
2247
|
-
lamp.spot_blend = 1.0 - (spot_blend / spot_size)
|
|
2248
|
-
|
|
2249
|
-
# TODO, cycles nodes???
|
|
2250
|
-
lamp.color = elem_props_get_color_rgb(fbx_props, b'Color', (1.0, 1.0, 1.0))
|
|
2251
|
-
lamp.energy = elem_props_get_number(fbx_props, b'Intensity', 100.0) / 100.0
|
|
2252
|
-
lamp.exposure = elem_props_get_number(fbx_props, b'Exposure', 0.0)
|
|
2253
|
-
lamp.use_shadow = elem_props_get_bool(fbx_props, b'CastShadow', True)
|
|
2254
|
-
if hasattr(lamp, "cycles"):
|
|
2255
|
-
lamp.cycles.cast_shadow = lamp.use_shadow
|
|
2256
|
-
# Removed but could be restored if the value can be applied.
|
|
2257
|
-
# `lamp.shadow_color = elem_props_get_color_rgb(fbx_props, b'ShadowColor', (0.0, 0.0, 0.0))`
|
|
2258
|
-
|
|
2259
|
-
if settings.use_custom_props:
|
|
2260
|
-
blen_read_custom_properties(fbx_obj, lamp, settings)
|
|
2261
|
-
|
|
2262
|
-
return lamp
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
# ### Import Utility class
|
|
2266
|
-
class FbxImportHelperNode:
|
|
2267
|
-
"""
|
|
2268
|
-
Temporary helper node to store a hierarchy of fbxNode objects before building Objects, Armatures and Bones.
|
|
2269
|
-
It tries to keep the correction data in one place so it can be applied consistently to the imported data.
|
|
2270
|
-
"""
|
|
2271
|
-
|
|
2272
|
-
__slots__ = (
|
|
2273
|
-
'_parent', 'anim_compensation_matrix', 'is_global_animation', 'armature_setup', 'armature', 'bind_matrix',
|
|
2274
|
-
'bl_bone', 'bl_data', 'bl_obj', 'bone_child_matrix', 'children', 'clusters',
|
|
2275
|
-
'fbx_elem', 'fbx_data_elem', 'fbx_name', 'fbx_transform_data', 'fbx_type',
|
|
2276
|
-
'is_armature', 'has_bone_children', 'is_bone', 'is_root', 'is_leaf',
|
|
2277
|
-
'matrix', 'matrix_as_parent', 'matrix_geom', 'meshes', 'post_matrix', 'pre_matrix')
|
|
2278
|
-
|
|
2279
|
-
def __init__(self, fbx_elem, bl_data, fbx_transform_data, is_bone):
|
|
2280
|
-
self.fbx_name = elem_name_ensure_class(fbx_elem, b'Model') if fbx_elem else 'Unknown'
|
|
2281
|
-
self.fbx_type = fbx_elem.props[2] if fbx_elem else None
|
|
2282
|
-
self.fbx_elem = fbx_elem
|
|
2283
|
-
# FBX elem of a connected NodeAttribute/Geometry for helpers whose bl_data
|
|
2284
|
-
# does not exist or is yet to be created.
|
|
2285
|
-
self.fbx_data_elem = None
|
|
2286
|
-
self.bl_obj = None
|
|
2287
|
-
self.bl_data = bl_data
|
|
2288
|
-
# Name of bone if this is a bone (this may be different to fbx_name if there was a name conflict in Blender!)
|
|
2289
|
-
self.bl_bone = None
|
|
2290
|
-
self.fbx_transform_data = fbx_transform_data
|
|
2291
|
-
self.is_root = False
|
|
2292
|
-
self.is_bone = is_bone
|
|
2293
|
-
self.is_armature = False
|
|
2294
|
-
self.armature = None # For bones only, relevant armature node.
|
|
2295
|
-
# True if the hierarchy below this node contains bones, important to support mixed hierarchies.
|
|
2296
|
-
self.has_bone_children = False
|
|
2297
|
-
# True for leaf-bones added to the end of some bone chains to set the lengths.
|
|
2298
|
-
self.is_leaf = False
|
|
2299
|
-
self.pre_matrix = None # correction matrix that needs to be applied before the FBX transform
|
|
2300
|
-
self.bind_matrix = None # for bones this is the matrix used to bind to the skin
|
|
2301
|
-
if fbx_transform_data:
|
|
2302
|
-
self.matrix, self.matrix_as_parent, self.matrix_geom = blen_read_object_transform_do(fbx_transform_data)
|
|
2303
|
-
else:
|
|
2304
|
-
self.matrix, self.matrix_as_parent, self.matrix_geom = (None, None, None)
|
|
2305
|
-
self.post_matrix = None # correction matrix that needs to be applied after the FBX transform
|
|
2306
|
-
self.bone_child_matrix = None # Objects attached to a bone end not the beginning, this matrix corrects for that
|
|
2307
|
-
|
|
2308
|
-
# XXX Those two are to handle the fact that rigged meshes are not linked to their armature in FBX, which implies
|
|
2309
|
-
# that their animation is in global space (afaik...).
|
|
2310
|
-
# This is actually not really solvable currently, since anim_compensation_matrix is not valid if armature
|
|
2311
|
-
# itself is animated (we'd have to recompute global-to-local anim_compensation_matrix for each frame,
|
|
2312
|
-
# and for each armature action... beyond being an insane work).
|
|
2313
|
-
# Solution for now: do not read rigged meshes animations at all! sic...
|
|
2314
|
-
# a mesh moved in the hierarchy may have a different local matrix. This compensates animations for this.
|
|
2315
|
-
self.anim_compensation_matrix = None
|
|
2316
|
-
self.is_global_animation = False
|
|
2317
|
-
|
|
2318
|
-
self.meshes = None # List of meshes influenced by this bone.
|
|
2319
|
-
self.clusters = [] # Deformer Cluster nodes
|
|
2320
|
-
self.armature_setup = {} # mesh and armature matrix when the mesh was bound
|
|
2321
|
-
|
|
2322
|
-
self._parent = None
|
|
2323
|
-
self.children = []
|
|
2324
|
-
|
|
2325
|
-
@property
|
|
2326
|
-
def parent(self):
|
|
2327
|
-
return self._parent
|
|
2328
|
-
|
|
2329
|
-
@parent.setter
|
|
2330
|
-
def parent(self, value):
|
|
2331
|
-
if self._parent is not None:
|
|
2332
|
-
self._parent.children.remove(self)
|
|
2333
|
-
self._parent = value
|
|
2334
|
-
if self._parent is not None:
|
|
2335
|
-
self._parent.children.append(self)
|
|
2336
|
-
|
|
2337
|
-
@property
|
|
2338
|
-
def ignore(self):
|
|
2339
|
-
# Separating leaf status from ignore status itself.
|
|
2340
|
-
# Currently they are equivalent, but this may change in future.
|
|
2341
|
-
return self.is_leaf
|
|
2342
|
-
|
|
2343
|
-
def __repr__(self):
|
|
2344
|
-
if self.fbx_elem:
|
|
2345
|
-
return self.fbx_elem.props[1].decode()
|
|
2346
|
-
else:
|
|
2347
|
-
return "None"
|
|
2348
|
-
|
|
2349
|
-
def print_info(self, indent=0):
|
|
2350
|
-
print(" " * indent + (self.fbx_name if self.fbx_name else "(Null)")
|
|
2351
|
-
+ ("[root]" if self.is_root else "")
|
|
2352
|
-
+ ("[leaf]" if self.is_leaf else "")
|
|
2353
|
-
+ ("[ignore]" if self.ignore else "")
|
|
2354
|
-
+ ("[armature]" if self.is_armature else "")
|
|
2355
|
-
+ ("[bone]" if self.is_bone else "")
|
|
2356
|
-
+ ("[HBC]" if self.has_bone_children else "")
|
|
2357
|
-
)
|
|
2358
|
-
for c in self.children:
|
|
2359
|
-
c.print_info(indent + 1)
|
|
2360
|
-
|
|
2361
|
-
def mark_leaf_bones(self):
|
|
2362
|
-
if self.is_bone and len(self.children) == 1:
|
|
2363
|
-
child = self.children[0]
|
|
2364
|
-
if child.is_bone and len(child.children) == 0:
|
|
2365
|
-
child.is_leaf = True
|
|
2366
|
-
for child in self.children:
|
|
2367
|
-
child.mark_leaf_bones()
|
|
2368
|
-
|
|
2369
|
-
def do_bake_transform(self, settings):
|
|
2370
|
-
return (settings.bake_space_transform and self.fbx_type in (b'Mesh', b'Null') and
|
|
2371
|
-
not self.is_armature and not self.is_bone)
|
|
2372
|
-
|
|
2373
|
-
def find_correction_matrix(self, settings, parent_correction_inv=None):
|
|
2374
|
-
from bpy_extras.io_utils import axis_conversion
|
|
2375
|
-
|
|
2376
|
-
if self.parent and (self.parent.is_root or self.parent.do_bake_transform(settings)):
|
|
2377
|
-
self.pre_matrix = settings.global_matrix
|
|
2378
|
-
|
|
2379
|
-
if parent_correction_inv:
|
|
2380
|
-
self.pre_matrix = parent_correction_inv @ (self.pre_matrix if self.pre_matrix else Matrix())
|
|
2381
|
-
|
|
2382
|
-
correction_matrix = None
|
|
2383
|
-
|
|
2384
|
-
if self.is_bone:
|
|
2385
|
-
if settings.automatic_bone_orientation:
|
|
2386
|
-
# find best orientation to align bone with
|
|
2387
|
-
bone_children = tuple(child for child in self.children if child.is_bone)
|
|
2388
|
-
if len(bone_children) == 0:
|
|
2389
|
-
# no children, inherit the correction from parent (if possible)
|
|
2390
|
-
if self.parent and self.parent.is_bone:
|
|
2391
|
-
correction_matrix = parent_correction_inv.inverted() if parent_correction_inv else None
|
|
2392
|
-
else:
|
|
2393
|
-
# else find how best to rotate the bone to align the Y axis with the children
|
|
2394
|
-
best_axis = (1, 0, 0)
|
|
2395
|
-
if len(bone_children) == 1:
|
|
2396
|
-
vec = bone_children[0].get_bind_matrix().to_translation()
|
|
2397
|
-
best_axis = Vector((0, 0, 1 if vec[2] >= 0 else -1))
|
|
2398
|
-
if abs(vec[0]) > abs(vec[1]):
|
|
2399
|
-
if abs(vec[0]) > abs(vec[2]):
|
|
2400
|
-
best_axis = Vector((1 if vec[0] >= 0 else -1, 0, 0))
|
|
2401
|
-
elif abs(vec[1]) > abs(vec[2]):
|
|
2402
|
-
best_axis = Vector((0, 1 if vec[1] >= 0 else -1, 0))
|
|
2403
|
-
else:
|
|
2404
|
-
# get the child directions once because they may be checked several times
|
|
2405
|
-
child_locs = (child.get_bind_matrix().to_translation() for child in bone_children)
|
|
2406
|
-
child_locs = tuple(loc.normalized() for loc in child_locs if loc.magnitude > 0.0)
|
|
2407
|
-
|
|
2408
|
-
# I'm not sure which one I like better...
|
|
2409
|
-
if False:
|
|
2410
|
-
best_angle = -1.0
|
|
2411
|
-
for i in range(6):
|
|
2412
|
-
a = i // 2
|
|
2413
|
-
s = -1 if i % 2 == 1 else 1
|
|
2414
|
-
test_axis = Vector((s if a == 0 else 0, s if a == 1 else 0, s if a == 2 else 0))
|
|
2415
|
-
|
|
2416
|
-
# find max angle to children
|
|
2417
|
-
max_angle = 1.0
|
|
2418
|
-
for loc in child_locs:
|
|
2419
|
-
max_angle = min(max_angle, test_axis.dot(loc))
|
|
2420
|
-
|
|
2421
|
-
# is it better than the last one?
|
|
2422
|
-
if best_angle < max_angle:
|
|
2423
|
-
best_angle = max_angle
|
|
2424
|
-
best_axis = test_axis
|
|
2425
|
-
else:
|
|
2426
|
-
best_angle = -1.0
|
|
2427
|
-
for vec in child_locs:
|
|
2428
|
-
test_axis = Vector((0, 0, 1 if vec[2] >= 0 else -1))
|
|
2429
|
-
if abs(vec[0]) > abs(vec[1]):
|
|
2430
|
-
if abs(vec[0]) > abs(vec[2]):
|
|
2431
|
-
test_axis = Vector((1 if vec[0] >= 0 else -1, 0, 0))
|
|
2432
|
-
elif abs(vec[1]) > abs(vec[2]):
|
|
2433
|
-
test_axis = Vector((0, 1 if vec[1] >= 0 else -1, 0))
|
|
2434
|
-
|
|
2435
|
-
# find max angle to children
|
|
2436
|
-
max_angle = 1.0
|
|
2437
|
-
for loc in child_locs:
|
|
2438
|
-
max_angle = min(max_angle, test_axis.dot(loc))
|
|
2439
|
-
|
|
2440
|
-
# is it better than the last one?
|
|
2441
|
-
if best_angle < max_angle:
|
|
2442
|
-
best_angle = max_angle
|
|
2443
|
-
best_axis = test_axis
|
|
2444
|
-
|
|
2445
|
-
# convert best_axis to axis string
|
|
2446
|
-
to_up = 'Z' if best_axis[2] >= 0 else '-Z'
|
|
2447
|
-
if abs(best_axis[0]) > abs(best_axis[1]):
|
|
2448
|
-
if abs(best_axis[0]) > abs(best_axis[2]):
|
|
2449
|
-
to_up = 'X' if best_axis[0] >= 0 else '-X'
|
|
2450
|
-
elif abs(best_axis[1]) > abs(best_axis[2]):
|
|
2451
|
-
to_up = 'Y' if best_axis[1] >= 0 else '-Y'
|
|
2452
|
-
to_forward = 'X' if to_up not in {'X', '-X'} else 'Y'
|
|
2453
|
-
|
|
2454
|
-
# Build correction matrix
|
|
2455
|
-
if (to_up, to_forward) != ('Y', 'X'):
|
|
2456
|
-
correction_matrix = axis_conversion(from_forward='X',
|
|
2457
|
-
from_up='Y',
|
|
2458
|
-
to_forward=to_forward,
|
|
2459
|
-
to_up=to_up,
|
|
2460
|
-
).to_4x4()
|
|
2461
|
-
else:
|
|
2462
|
-
correction_matrix = settings.bone_correction_matrix
|
|
2463
|
-
else:
|
|
2464
|
-
# camera and light can be hard wired
|
|
2465
|
-
if self.fbx_type == b'Camera':
|
|
2466
|
-
correction_matrix = MAT_CONVERT_CAMERA
|
|
2467
|
-
elif self.fbx_type == b'Light':
|
|
2468
|
-
correction_matrix = MAT_CONVERT_LIGHT
|
|
2469
|
-
|
|
2470
|
-
self.post_matrix = correction_matrix
|
|
2471
|
-
|
|
2472
|
-
if self.do_bake_transform(settings):
|
|
2473
|
-
self.post_matrix = settings.global_matrix_inv @ (self.post_matrix if self.post_matrix else Matrix())
|
|
2474
|
-
|
|
2475
|
-
# process children
|
|
2476
|
-
correction_matrix_inv = correction_matrix.inverted_safe() if correction_matrix else None
|
|
2477
|
-
for child in self.children:
|
|
2478
|
-
child.find_correction_matrix(settings, correction_matrix_inv)
|
|
2479
|
-
|
|
2480
|
-
def find_armature_bones(self, armature):
|
|
2481
|
-
for child in self.children:
|
|
2482
|
-
if child.is_bone:
|
|
2483
|
-
child.armature = armature
|
|
2484
|
-
child.find_armature_bones(armature)
|
|
2485
|
-
|
|
2486
|
-
def find_armatures(self):
|
|
2487
|
-
needs_armature = False
|
|
2488
|
-
for child in self.children:
|
|
2489
|
-
if child.is_bone:
|
|
2490
|
-
needs_armature = True
|
|
2491
|
-
break
|
|
2492
|
-
if needs_armature:
|
|
2493
|
-
if self.fbx_type in {b'Null', b'Root'}:
|
|
2494
|
-
# if empty then convert into armature
|
|
2495
|
-
self.is_armature = True
|
|
2496
|
-
armature = self
|
|
2497
|
-
else:
|
|
2498
|
-
# otherwise insert a new node
|
|
2499
|
-
# XXX Maybe in case self is virtual FBX root node, we should instead add one armature per bone child?
|
|
2500
|
-
armature = FbxImportHelperNode(None, None, None, False)
|
|
2501
|
-
armature.fbx_name = "Armature"
|
|
2502
|
-
armature.is_armature = True
|
|
2503
|
-
|
|
2504
|
-
for child in tuple(self.children):
|
|
2505
|
-
if child.is_bone:
|
|
2506
|
-
child.parent = armature
|
|
2507
|
-
|
|
2508
|
-
armature.parent = self
|
|
2509
|
-
|
|
2510
|
-
armature.find_armature_bones(armature)
|
|
2511
|
-
|
|
2512
|
-
for child in self.children:
|
|
2513
|
-
if child.is_armature or child.is_bone:
|
|
2514
|
-
continue
|
|
2515
|
-
child.find_armatures()
|
|
2516
|
-
|
|
2517
|
-
def find_bone_children(self):
|
|
2518
|
-
has_bone_children = False
|
|
2519
|
-
for child in self.children:
|
|
2520
|
-
has_bone_children |= child.find_bone_children()
|
|
2521
|
-
self.has_bone_children = has_bone_children
|
|
2522
|
-
return self.is_bone or has_bone_children
|
|
2523
|
-
|
|
2524
|
-
def find_fake_bones(self, in_armature=False):
|
|
2525
|
-
if in_armature and not self.is_bone and self.has_bone_children:
|
|
2526
|
-
self.is_bone = True
|
|
2527
|
-
# if we are not a null node we need an intermediate node for the data
|
|
2528
|
-
if self.fbx_type not in {b'Null', b'Root'}:
|
|
2529
|
-
node = FbxImportHelperNode(self.fbx_elem, self.bl_data, None, False)
|
|
2530
|
-
self.fbx_elem = None
|
|
2531
|
-
self.bl_data = None
|
|
2532
|
-
|
|
2533
|
-
# transfer children
|
|
2534
|
-
for child in self.children:
|
|
2535
|
-
if child.is_bone or child.has_bone_children:
|
|
2536
|
-
continue
|
|
2537
|
-
child.parent = node
|
|
2538
|
-
|
|
2539
|
-
# attach to parent
|
|
2540
|
-
node.parent = self
|
|
2541
|
-
|
|
2542
|
-
if self.is_armature:
|
|
2543
|
-
in_armature = True
|
|
2544
|
-
for child in self.children:
|
|
2545
|
-
child.find_fake_bones(in_armature)
|
|
2546
|
-
|
|
2547
|
-
def get_world_matrix_as_parent(self):
|
|
2548
|
-
matrix = self.parent.get_world_matrix_as_parent() if self.parent else Matrix()
|
|
2549
|
-
if self.matrix_as_parent:
|
|
2550
|
-
matrix = matrix @ self.matrix_as_parent
|
|
2551
|
-
return matrix
|
|
2552
|
-
|
|
2553
|
-
def get_world_matrix(self):
|
|
2554
|
-
matrix = self.parent.get_world_matrix_as_parent() if self.parent else Matrix()
|
|
2555
|
-
if self.matrix:
|
|
2556
|
-
matrix = matrix @ self.matrix
|
|
2557
|
-
return matrix
|
|
2558
|
-
|
|
2559
|
-
def get_matrix(self):
|
|
2560
|
-
matrix = self.matrix if self.matrix else Matrix()
|
|
2561
|
-
if self.pre_matrix:
|
|
2562
|
-
matrix = self.pre_matrix @ matrix
|
|
2563
|
-
if self.post_matrix:
|
|
2564
|
-
matrix = matrix @ self.post_matrix
|
|
2565
|
-
return matrix
|
|
2566
|
-
|
|
2567
|
-
def get_bind_matrix(self):
|
|
2568
|
-
matrix = self.bind_matrix if self.bind_matrix else Matrix()
|
|
2569
|
-
if self.pre_matrix:
|
|
2570
|
-
matrix = self.pre_matrix @ matrix
|
|
2571
|
-
if self.post_matrix:
|
|
2572
|
-
matrix = matrix @ self.post_matrix
|
|
2573
|
-
return matrix
|
|
2574
|
-
|
|
2575
|
-
def make_bind_pose_local(self, parent_matrix=None):
|
|
2576
|
-
if parent_matrix is None:
|
|
2577
|
-
parent_matrix = Matrix()
|
|
2578
|
-
|
|
2579
|
-
if self.bind_matrix:
|
|
2580
|
-
bind_matrix = parent_matrix.inverted_safe() @ self.bind_matrix
|
|
2581
|
-
else:
|
|
2582
|
-
bind_matrix = self.matrix.copy() if self.matrix else None
|
|
2583
|
-
|
|
2584
|
-
self.bind_matrix = bind_matrix
|
|
2585
|
-
if bind_matrix:
|
|
2586
|
-
parent_matrix = parent_matrix @ bind_matrix
|
|
2587
|
-
|
|
2588
|
-
for child in self.children:
|
|
2589
|
-
child.make_bind_pose_local(parent_matrix)
|
|
2590
|
-
|
|
2591
|
-
def collect_skeleton_meshes(self, meshes):
|
|
2592
|
-
for _, m in self.clusters:
|
|
2593
|
-
meshes.update(m)
|
|
2594
|
-
for child in self.children:
|
|
2595
|
-
if not child.meshes:
|
|
2596
|
-
child.collect_skeleton_meshes(meshes)
|
|
2597
|
-
|
|
2598
|
-
def collect_armature_meshes(self):
|
|
2599
|
-
if self.is_armature:
|
|
2600
|
-
armature_matrix_inv = self.get_world_matrix().inverted_safe()
|
|
2601
|
-
|
|
2602
|
-
meshes = set()
|
|
2603
|
-
for child in self.children:
|
|
2604
|
-
# Children meshes may be linked to children armatures, in which case we do not want to link them
|
|
2605
|
-
# to a parent one. See T70244.
|
|
2606
|
-
child.collect_armature_meshes()
|
|
2607
|
-
if not child.meshes:
|
|
2608
|
-
child.collect_skeleton_meshes(meshes)
|
|
2609
|
-
for m in meshes:
|
|
2610
|
-
old_matrix = m.matrix
|
|
2611
|
-
m.matrix = armature_matrix_inv @ m.get_world_matrix()
|
|
2612
|
-
m.anim_compensation_matrix = old_matrix.inverted_safe() @ m.matrix
|
|
2613
|
-
m.is_global_animation = True
|
|
2614
|
-
m.parent = self
|
|
2615
|
-
self.meshes = meshes
|
|
2616
|
-
else:
|
|
2617
|
-
for child in self.children:
|
|
2618
|
-
child.collect_armature_meshes()
|
|
2619
|
-
|
|
2620
|
-
def build_skeleton(self, arm, parent_matrix, settings, parent_bone_size=1):
|
|
2621
|
-
def child_connect(par_bone, child_bone, child_head, connect_ctx):
|
|
2622
|
-
# child_bone or child_head may be None.
|
|
2623
|
-
force_connect_children, connected = connect_ctx
|
|
2624
|
-
if child_bone is not None:
|
|
2625
|
-
child_bone.parent = par_bone
|
|
2626
|
-
child_head = child_bone.head
|
|
2627
|
-
|
|
2628
|
-
if similar_values_iter(par_bone.tail, child_head):
|
|
2629
|
-
if child_bone is not None:
|
|
2630
|
-
child_bone.use_connect = True
|
|
2631
|
-
# Disallow any force-connection at this level from now on, since that child was 'really'
|
|
2632
|
-
# connected, we do not want to move current bone's tail anymore!
|
|
2633
|
-
connected = None
|
|
2634
|
-
elif force_connect_children and connected is not None:
|
|
2635
|
-
# We only store position where tail of par_bone should be in the end.
|
|
2636
|
-
# Actual tail moving and force connection of compatible child bones will happen
|
|
2637
|
-
# once all have been checked.
|
|
2638
|
-
if connected is ...:
|
|
2639
|
-
connected = ([child_head.copy(), 1], [child_bone] if child_bone is not None else [])
|
|
2640
|
-
else:
|
|
2641
|
-
connected[0][0] += child_head
|
|
2642
|
-
connected[0][1] += 1
|
|
2643
|
-
if child_bone is not None:
|
|
2644
|
-
connected[1].append(child_bone)
|
|
2645
|
-
connect_ctx[1] = connected
|
|
2646
|
-
|
|
2647
|
-
def child_connect_finalize(par_bone, connect_ctx):
|
|
2648
|
-
force_connect_children, connected = connect_ctx
|
|
2649
|
-
# Do nothing if force connection is not enabled!
|
|
2650
|
-
if force_connect_children and connected is not None and connected is not ...:
|
|
2651
|
-
# Here again we have to be wary about zero-length bones!!!
|
|
2652
|
-
par_tail = connected[0][0] / connected[0][1]
|
|
2653
|
-
if (par_tail - par_bone.head).magnitude < 1e-2:
|
|
2654
|
-
par_bone_vec = (par_bone.tail - par_bone.head).normalized()
|
|
2655
|
-
par_tail = par_bone.head + par_bone_vec * 0.01
|
|
2656
|
-
par_bone.tail = par_tail
|
|
2657
|
-
for child_bone in connected[1]:
|
|
2658
|
-
if similar_values_iter(par_tail, child_bone.head):
|
|
2659
|
-
child_bone.use_connect = True
|
|
2660
|
-
|
|
2661
|
-
# Create the (edit)bone.
|
|
2662
|
-
bone = arm.bl_data.edit_bones.new(name=self.fbx_name)
|
|
2663
|
-
bone.select = True
|
|
2664
|
-
self.bl_obj = arm.bl_obj
|
|
2665
|
-
self.bl_data = arm.bl_data
|
|
2666
|
-
self.bl_bone = bone.name # Could be different from the FBX name!
|
|
2667
|
-
# Read EditBone custom props the NodeAttribute
|
|
2668
|
-
if settings.use_custom_props and self.fbx_data_elem:
|
|
2669
|
-
blen_read_custom_properties(self.fbx_data_elem, bone, settings)
|
|
2670
|
-
|
|
2671
|
-
# get average distance to children
|
|
2672
|
-
bone_size = 0.0
|
|
2673
|
-
bone_count = 0
|
|
2674
|
-
for child in self.children:
|
|
2675
|
-
if child.is_bone:
|
|
2676
|
-
bone_size += child.get_bind_matrix().to_translation().magnitude
|
|
2677
|
-
bone_count += 1
|
|
2678
|
-
if bone_count > 0:
|
|
2679
|
-
bone_size /= bone_count
|
|
2680
|
-
else:
|
|
2681
|
-
bone_size = parent_bone_size
|
|
2682
|
-
|
|
2683
|
-
# So that our bone gets its final length, but still Y-aligned in armature space.
|
|
2684
|
-
# 0-length bones are automatically collapsed into their parent when you leave edit mode,
|
|
2685
|
-
# so this enforces a minimum length.
|
|
2686
|
-
bone_tail = Vector((0.0, 1.0, 0.0)) * max(0.01, bone_size)
|
|
2687
|
-
bone.tail = bone_tail
|
|
2688
|
-
|
|
2689
|
-
# And rotate/move it to its final "rest pose".
|
|
2690
|
-
bone_matrix = parent_matrix @ self.get_bind_matrix().normalized()
|
|
2691
|
-
|
|
2692
|
-
bone.matrix = bone_matrix
|
|
2693
|
-
|
|
2694
|
-
force_connect_children = settings.force_connect_children
|
|
2695
|
-
|
|
2696
|
-
connect_ctx = [force_connect_children, ...]
|
|
2697
|
-
for child in self.children:
|
|
2698
|
-
if child.is_leaf and force_connect_children:
|
|
2699
|
-
# Arggggggggggggggggg! We do not want to create this bone, but we need its 'virtual head' location
|
|
2700
|
-
# to orient current one!!!
|
|
2701
|
-
child_head = (bone_matrix @ child.get_bind_matrix().normalized()).translation
|
|
2702
|
-
child_connect(bone, None, child_head, connect_ctx)
|
|
2703
|
-
elif child.is_bone and not child.ignore:
|
|
2704
|
-
child_bone = child.build_skeleton(arm, bone_matrix, settings, bone_size)
|
|
2705
|
-
# Connection to parent.
|
|
2706
|
-
child_connect(bone, child_bone, None, connect_ctx)
|
|
2707
|
-
|
|
2708
|
-
child_connect_finalize(bone, connect_ctx)
|
|
2709
|
-
|
|
2710
|
-
# Correction for children attached to a bone. FBX expects to attach to the head of a bone, while Blender
|
|
2711
|
-
# attaches to the tail.
|
|
2712
|
-
if force_connect_children:
|
|
2713
|
-
# When forcefully connecting, the bone's tail position may be changed, which can change both the bone's
|
|
2714
|
-
# rotation and its length.
|
|
2715
|
-
# Set the correction matrix such that it transforms the current tail transformation back to the original
|
|
2716
|
-
# head transformation.
|
|
2717
|
-
head_to_origin = bone.matrix.inverted_safe()
|
|
2718
|
-
tail_to_head = Matrix.Translation(bone.head - bone.tail)
|
|
2719
|
-
origin_to_original_head = bone_matrix
|
|
2720
|
-
tail_to_original_head = head_to_origin @ tail_to_head @ origin_to_original_head
|
|
2721
|
-
self.bone_child_matrix = tail_to_original_head
|
|
2722
|
-
else:
|
|
2723
|
-
self.bone_child_matrix = Matrix.Translation(-bone_tail)
|
|
2724
|
-
|
|
2725
|
-
return bone
|
|
2726
|
-
|
|
2727
|
-
def build_node_obj(self, fbx_tmpl, settings):
|
|
2728
|
-
if self.bl_obj:
|
|
2729
|
-
return self.bl_obj
|
|
2730
|
-
|
|
2731
|
-
if self.is_bone or not self.fbx_elem:
|
|
2732
|
-
return None
|
|
2733
|
-
|
|
2734
|
-
# create when linking since we need object data
|
|
2735
|
-
elem_name_utf8 = self.fbx_name
|
|
2736
|
-
|
|
2737
|
-
# Object data must be created already
|
|
2738
|
-
self.bl_obj = obj = bpy.data.objects.new(name=elem_name_utf8, object_data=self.bl_data)
|
|
2739
|
-
|
|
2740
|
-
fbx_props = (elem_find_first(self.fbx_elem, b'Properties70'),
|
|
2741
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
2742
|
-
|
|
2743
|
-
# ----
|
|
2744
|
-
# Misc Attributes
|
|
2745
|
-
|
|
2746
|
-
obj.color[0:3] = elem_props_get_color_rgb(fbx_props, b'Color', (0.8, 0.8, 0.8))
|
|
2747
|
-
obj.hide_viewport = not bool(elem_props_get_visibility(fbx_props, b'Visibility', 1.0))
|
|
2748
|
-
|
|
2749
|
-
obj.matrix_basis = self.get_matrix()
|
|
2750
|
-
|
|
2751
|
-
if settings.use_custom_props:
|
|
2752
|
-
blen_read_custom_properties(self.fbx_elem, obj, settings)
|
|
2753
|
-
|
|
2754
|
-
return obj
|
|
2755
|
-
|
|
2756
|
-
def build_skeleton_children(self, fbx_tmpl, settings, scene, view_layer):
|
|
2757
|
-
if self.is_bone:
|
|
2758
|
-
for child in self.children:
|
|
2759
|
-
if child.ignore:
|
|
2760
|
-
continue
|
|
2761
|
-
child.build_skeleton_children(fbx_tmpl, settings, scene, view_layer)
|
|
2762
|
-
return None
|
|
2763
|
-
else:
|
|
2764
|
-
# child is not a bone
|
|
2765
|
-
obj = self.build_node_obj(fbx_tmpl, settings)
|
|
2766
|
-
|
|
2767
|
-
if obj is None:
|
|
2768
|
-
return None
|
|
2769
|
-
|
|
2770
|
-
for child in self.children:
|
|
2771
|
-
if child.ignore:
|
|
2772
|
-
continue
|
|
2773
|
-
child.build_skeleton_children(fbx_tmpl, settings, scene, view_layer)
|
|
2774
|
-
|
|
2775
|
-
# instance in scene
|
|
2776
|
-
view_layer.active_layer_collection.collection.objects.link(obj)
|
|
2777
|
-
obj.select_set(True)
|
|
2778
|
-
|
|
2779
|
-
return obj
|
|
2780
|
-
|
|
2781
|
-
def link_skeleton_children(self, fbx_tmpl, settings, scene):
|
|
2782
|
-
if self.is_bone:
|
|
2783
|
-
for child in self.children:
|
|
2784
|
-
if child.ignore:
|
|
2785
|
-
continue
|
|
2786
|
-
child_obj = child.bl_obj
|
|
2787
|
-
if child_obj and child_obj != self.bl_obj:
|
|
2788
|
-
child_obj.parent = self.bl_obj # get the armature the bone belongs to
|
|
2789
|
-
child_obj.parent_bone = self.bl_bone
|
|
2790
|
-
child_obj.parent_type = 'BONE'
|
|
2791
|
-
child_obj.matrix_parent_inverse = Matrix()
|
|
2792
|
-
|
|
2793
|
-
# Blender attaches to the end of a bone, while FBX attaches to the start.
|
|
2794
|
-
# bone_child_matrix corrects for that.
|
|
2795
|
-
if child.pre_matrix:
|
|
2796
|
-
child.pre_matrix = self.bone_child_matrix @ child.pre_matrix
|
|
2797
|
-
else:
|
|
2798
|
-
child.pre_matrix = self.bone_child_matrix
|
|
2799
|
-
|
|
2800
|
-
child_obj.matrix_basis = child.get_matrix()
|
|
2801
|
-
child.link_skeleton_children(fbx_tmpl, settings, scene)
|
|
2802
|
-
return None
|
|
2803
|
-
else:
|
|
2804
|
-
obj = self.bl_obj
|
|
2805
|
-
|
|
2806
|
-
for child in self.children:
|
|
2807
|
-
if child.ignore:
|
|
2808
|
-
continue
|
|
2809
|
-
child_obj = child.link_skeleton_children(fbx_tmpl, settings, scene)
|
|
2810
|
-
if child_obj:
|
|
2811
|
-
child_obj.parent = obj
|
|
2812
|
-
|
|
2813
|
-
return obj
|
|
2814
|
-
|
|
2815
|
-
def set_pose_matrix_and_custom_props(self, arm, settings):
|
|
2816
|
-
pose_bone = arm.bl_obj.pose.bones[self.bl_bone]
|
|
2817
|
-
pose_bone.matrix_basis = self.get_bind_matrix().inverted_safe() @ self.get_matrix()
|
|
2818
|
-
|
|
2819
|
-
# `self.fbx_elem` can be `None` in cases where the imported hierarchy contains a mix of bone and non-bone FBX
|
|
2820
|
-
# Nodes parented to one another, e.g. "bone1"->"mesh1"->"bone2". In Blender, an Armature can only consist of
|
|
2821
|
-
# bones, so to maintain the imported hierarchy, a placeholder bone with the same name as "mesh1" is inserted
|
|
2822
|
-
# into the Armature and then the imported "mesh1" Object is parented to the placeholder bone. The placeholder
|
|
2823
|
-
# bone won't have a `self.fbx_elem` because it belongs to the "mesh1" Object instead.
|
|
2824
|
-
# See FbxImportHelperNode.find_fake_bones().
|
|
2825
|
-
if settings.use_custom_props and self.fbx_elem:
|
|
2826
|
-
blen_read_custom_properties(self.fbx_elem, pose_bone, settings)
|
|
2827
|
-
|
|
2828
|
-
for child in self.children:
|
|
2829
|
-
if child.ignore:
|
|
2830
|
-
continue
|
|
2831
|
-
if child.is_bone:
|
|
2832
|
-
child.set_pose_matrix_and_custom_props(arm, settings)
|
|
2833
|
-
|
|
2834
|
-
def merge_weights(self, combined_weights, fbx_cluster):
|
|
2835
|
-
indices = elem_prop_first(elem_find_first(fbx_cluster, b'Indexes', default=None), default=())
|
|
2836
|
-
weights = elem_prop_first(elem_find_first(fbx_cluster, b'Weights', default=None), default=())
|
|
2837
|
-
|
|
2838
|
-
for index, weight in zip(indices, weights):
|
|
2839
|
-
w = combined_weights.get(index)
|
|
2840
|
-
if w is None:
|
|
2841
|
-
combined_weights[index] = [weight]
|
|
2842
|
-
else:
|
|
2843
|
-
w.append(weight)
|
|
2844
|
-
|
|
2845
|
-
def set_bone_weights(self):
|
|
2846
|
-
ignored_children = tuple(child for child in self.children
|
|
2847
|
-
if child.is_bone and child.ignore and len(child.clusters) > 0)
|
|
2848
|
-
|
|
2849
|
-
if len(ignored_children) > 0:
|
|
2850
|
-
# If we have an ignored child bone we need to merge their weights into the current bone weights.
|
|
2851
|
-
# This can happen both intentionally and accidentally when skinning a model. Either way, they
|
|
2852
|
-
# need to be moved into a parent bone or they cause animation glitches.
|
|
2853
|
-
for fbx_cluster, meshes in self.clusters:
|
|
2854
|
-
combined_weights = {}
|
|
2855
|
-
self.merge_weights(combined_weights, fbx_cluster)
|
|
2856
|
-
|
|
2857
|
-
for child in ignored_children:
|
|
2858
|
-
for child_cluster, child_meshes in child.clusters:
|
|
2859
|
-
if not meshes.isdisjoint(child_meshes):
|
|
2860
|
-
self.merge_weights(combined_weights, child_cluster)
|
|
2861
|
-
|
|
2862
|
-
# combine child weights
|
|
2863
|
-
indices = []
|
|
2864
|
-
weights = []
|
|
2865
|
-
for i, w in combined_weights.items():
|
|
2866
|
-
indices.append(i)
|
|
2867
|
-
if len(w) > 1:
|
|
2868
|
-
# Add ignored child weights to the current bone's weight.
|
|
2869
|
-
# XXX - Weights that sum to more than 1.0 get clamped to 1.0 when set in the vertex group.
|
|
2870
|
-
weights.append(sum(w))
|
|
2871
|
-
else:
|
|
2872
|
-
weights.append(w[0])
|
|
2873
|
-
|
|
2874
|
-
add_vgroup_to_objects(indices, weights, self.bl_bone, [node.bl_obj for node in meshes])
|
|
2875
|
-
|
|
2876
|
-
# clusters that drive meshes not included in a parent don't need to be merged
|
|
2877
|
-
all_meshes = set().union(*[meshes for _, meshes in self.clusters])
|
|
2878
|
-
for child in ignored_children:
|
|
2879
|
-
for child_cluster, child_meshes in child.clusters:
|
|
2880
|
-
if all_meshes.isdisjoint(child_meshes):
|
|
2881
|
-
indices = elem_prop_first(elem_find_first(child_cluster, b'Indexes', default=None), default=())
|
|
2882
|
-
weights = elem_prop_first(elem_find_first(child_cluster, b'Weights', default=None), default=())
|
|
2883
|
-
add_vgroup_to_objects(indices, weights, self.bl_bone, [node.bl_obj for node in child_meshes])
|
|
2884
|
-
else:
|
|
2885
|
-
# set the vertex weights on meshes
|
|
2886
|
-
for fbx_cluster, meshes in self.clusters:
|
|
2887
|
-
indices = elem_prop_first(elem_find_first(fbx_cluster, b'Indexes', default=None), default=())
|
|
2888
|
-
weights = elem_prop_first(elem_find_first(fbx_cluster, b'Weights', default=None), default=())
|
|
2889
|
-
add_vgroup_to_objects(indices, weights, self.bl_bone, [node.bl_obj for node in meshes])
|
|
2890
|
-
|
|
2891
|
-
for child in self.children:
|
|
2892
|
-
if child.is_bone and not child.ignore:
|
|
2893
|
-
child.set_bone_weights()
|
|
2894
|
-
|
|
2895
|
-
def build_hierarchy(self, fbx_tmpl, settings, scene, view_layer):
|
|
2896
|
-
if self.is_armature:
|
|
2897
|
-
# create when linking since we need object data
|
|
2898
|
-
elem_name_utf8 = self.fbx_name
|
|
2899
|
-
|
|
2900
|
-
self.bl_data = arm_data = bpy.data.armatures.new(name=elem_name_utf8)
|
|
2901
|
-
|
|
2902
|
-
# Object data must be created already
|
|
2903
|
-
self.bl_obj = arm = bpy.data.objects.new(name=elem_name_utf8, object_data=arm_data)
|
|
2904
|
-
|
|
2905
|
-
arm.matrix_basis = self.get_matrix()
|
|
2906
|
-
|
|
2907
|
-
if self.fbx_elem:
|
|
2908
|
-
fbx_props = (elem_find_first(self.fbx_elem, b'Properties70'),
|
|
2909
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
2910
|
-
|
|
2911
|
-
if settings.use_custom_props:
|
|
2912
|
-
# Read Armature Object custom props from the Node
|
|
2913
|
-
blen_read_custom_properties(self.fbx_elem, arm, settings)
|
|
2914
|
-
|
|
2915
|
-
if self.fbx_data_elem:
|
|
2916
|
-
# Read Armature Data custom props from the NodeAttribute
|
|
2917
|
-
blen_read_custom_properties(self.fbx_data_elem, arm_data, settings)
|
|
2918
|
-
|
|
2919
|
-
# instance in scene
|
|
2920
|
-
view_layer.active_layer_collection.collection.objects.link(arm)
|
|
2921
|
-
arm.select_set(True)
|
|
2922
|
-
|
|
2923
|
-
# Add bones:
|
|
2924
|
-
|
|
2925
|
-
# Switch to Edit mode.
|
|
2926
|
-
view_layer.objects.active = arm
|
|
2927
|
-
is_hidden = arm.hide_viewport
|
|
2928
|
-
arm.hide_viewport = False # Can't switch to Edit mode hidden objects...
|
|
2929
|
-
bpy.ops.object.mode_set(mode='EDIT')
|
|
2930
|
-
|
|
2931
|
-
for child in self.children:
|
|
2932
|
-
if child.ignore:
|
|
2933
|
-
continue
|
|
2934
|
-
if child.is_bone:
|
|
2935
|
-
child.build_skeleton(self, Matrix(), settings)
|
|
2936
|
-
|
|
2937
|
-
bpy.ops.object.mode_set(mode='OBJECT')
|
|
2938
|
-
|
|
2939
|
-
arm.hide_viewport = is_hidden
|
|
2940
|
-
|
|
2941
|
-
# Set pose matrix and PoseBone custom properties
|
|
2942
|
-
for child in self.children:
|
|
2943
|
-
if child.ignore:
|
|
2944
|
-
continue
|
|
2945
|
-
if child.is_bone:
|
|
2946
|
-
child.set_pose_matrix_and_custom_props(self, settings)
|
|
2947
|
-
|
|
2948
|
-
# Add bone children:
|
|
2949
|
-
for child in self.children:
|
|
2950
|
-
if child.ignore:
|
|
2951
|
-
continue
|
|
2952
|
-
child_obj = child.build_skeleton_children(fbx_tmpl, settings, scene, view_layer)
|
|
2953
|
-
|
|
2954
|
-
return arm
|
|
2955
|
-
elif self.fbx_elem and not self.is_bone:
|
|
2956
|
-
obj = self.build_node_obj(fbx_tmpl, settings)
|
|
2957
|
-
|
|
2958
|
-
# walk through children
|
|
2959
|
-
for child in self.children:
|
|
2960
|
-
child.build_hierarchy(fbx_tmpl, settings, scene, view_layer)
|
|
2961
|
-
|
|
2962
|
-
# instance in scene
|
|
2963
|
-
view_layer.active_layer_collection.collection.objects.link(obj)
|
|
2964
|
-
obj.select_set(True)
|
|
2965
|
-
|
|
2966
|
-
return obj
|
|
2967
|
-
else:
|
|
2968
|
-
for child in self.children:
|
|
2969
|
-
child.build_hierarchy(fbx_tmpl, settings, scene, view_layer)
|
|
2970
|
-
|
|
2971
|
-
return None
|
|
2972
|
-
|
|
2973
|
-
def link_hierarchy(self, fbx_tmpl, settings, scene):
|
|
2974
|
-
if self.is_armature:
|
|
2975
|
-
arm = self.bl_obj
|
|
2976
|
-
|
|
2977
|
-
# Link bone children:
|
|
2978
|
-
for child in self.children:
|
|
2979
|
-
if child.ignore:
|
|
2980
|
-
continue
|
|
2981
|
-
child_obj = child.link_skeleton_children(fbx_tmpl, settings, scene)
|
|
2982
|
-
if child_obj:
|
|
2983
|
-
child_obj.parent = arm
|
|
2984
|
-
|
|
2985
|
-
# Add armature modifiers to the meshes
|
|
2986
|
-
if self.meshes:
|
|
2987
|
-
for mesh in self.meshes:
|
|
2988
|
-
(mmat, amat) = mesh.armature_setup[self]
|
|
2989
|
-
me_obj = mesh.bl_obj
|
|
2990
|
-
|
|
2991
|
-
# bring global armature & mesh matrices into *Blender* global space.
|
|
2992
|
-
# Note: Usage of matrix_geom (local 'diff' transform) here is quite brittle.
|
|
2993
|
-
# Among other things, why in hell isn't it taken into account by bindpose & co???
|
|
2994
|
-
# Probably because org app (max) handles it completely aside from any parenting stuff,
|
|
2995
|
-
# which we obviously cannot do in Blender. :/
|
|
2996
|
-
if amat is None:
|
|
2997
|
-
amat = self.bind_matrix
|
|
2998
|
-
amat = settings.global_matrix @ (Matrix() if amat is None else amat)
|
|
2999
|
-
if self.matrix_geom:
|
|
3000
|
-
amat = amat @ self.matrix_geom
|
|
3001
|
-
mmat = settings.global_matrix @ mmat
|
|
3002
|
-
if mesh.matrix_geom:
|
|
3003
|
-
mmat = mmat @ mesh.matrix_geom
|
|
3004
|
-
|
|
3005
|
-
# Now that we have armature and mesh in there (global) bind 'state' (matrix),
|
|
3006
|
-
# we can compute inverse parenting matrix of the mesh.
|
|
3007
|
-
me_obj.matrix_parent_inverse = amat.inverted_safe() @ mmat @ me_obj.matrix_basis.inverted_safe()
|
|
3008
|
-
|
|
3009
|
-
mod = mesh.bl_obj.modifiers.new(arm.name, 'ARMATURE')
|
|
3010
|
-
mod.object = arm
|
|
3011
|
-
|
|
3012
|
-
# Add bone weights to the deformers
|
|
3013
|
-
for child in self.children:
|
|
3014
|
-
if child.ignore:
|
|
3015
|
-
continue
|
|
3016
|
-
if child.is_bone:
|
|
3017
|
-
child.set_bone_weights()
|
|
3018
|
-
|
|
3019
|
-
return arm
|
|
3020
|
-
elif self.bl_obj:
|
|
3021
|
-
obj = self.bl_obj
|
|
3022
|
-
|
|
3023
|
-
# walk through children
|
|
3024
|
-
for child in self.children:
|
|
3025
|
-
child_obj = child.link_hierarchy(fbx_tmpl, settings, scene)
|
|
3026
|
-
if child_obj:
|
|
3027
|
-
child_obj.parent = obj
|
|
3028
|
-
|
|
3029
|
-
return obj
|
|
3030
|
-
else:
|
|
3031
|
-
for child in self.children:
|
|
3032
|
-
child.link_hierarchy(fbx_tmpl, settings, scene)
|
|
3033
|
-
|
|
3034
|
-
return None
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
def load(operator, context, filepath="",
|
|
3038
|
-
use_manual_orientation=False,
|
|
3039
|
-
axis_forward='-Z',
|
|
3040
|
-
axis_up='Y',
|
|
3041
|
-
global_scale=1.0,
|
|
3042
|
-
bake_space_transform=False,
|
|
3043
|
-
use_custom_normals=True,
|
|
3044
|
-
use_image_search=False,
|
|
3045
|
-
use_alpha_decals=False,
|
|
3046
|
-
decal_offset=0.0,
|
|
3047
|
-
use_anim=True,
|
|
3048
|
-
anim_offset=1.0,
|
|
3049
|
-
use_subsurf=False,
|
|
3050
|
-
use_custom_props=True,
|
|
3051
|
-
use_custom_props_enum_as_string=True,
|
|
3052
|
-
ignore_leaf_bones=False,
|
|
3053
|
-
force_connect_children=False,
|
|
3054
|
-
automatic_bone_orientation=False,
|
|
3055
|
-
primary_bone_axis='Y',
|
|
3056
|
-
secondary_bone_axis='X',
|
|
3057
|
-
use_prepost_rot=True,
|
|
3058
|
-
colors_type='SRGB',
|
|
3059
|
-
mtl_name_collision_mode="MAKE_UNIQUE"):
|
|
3060
|
-
|
|
3061
|
-
global fbx_elem_nil
|
|
3062
|
-
fbx_elem_nil = FBXElem('', (), (), ())
|
|
3063
|
-
|
|
3064
|
-
import os
|
|
3065
|
-
import time
|
|
3066
|
-
from bpy_extras.io_utils import axis_conversion
|
|
3067
|
-
|
|
3068
|
-
from . import parse_fbx
|
|
3069
|
-
from .fbx_utils import RIGHT_HAND_AXES, FBX_FRAMERATES
|
|
3070
|
-
|
|
3071
|
-
start_time_proc = time.process_time()
|
|
3072
|
-
start_time_sys = time.time()
|
|
3073
|
-
|
|
3074
|
-
perfmon = PerfMon()
|
|
3075
|
-
perfmon.level_up()
|
|
3076
|
-
perfmon.step("FBX Import: start importing %s" % filepath)
|
|
3077
|
-
perfmon.level_up()
|
|
3078
|
-
|
|
3079
|
-
# Detect ASCII files.
|
|
3080
|
-
|
|
3081
|
-
# Typically it's bad practice to fail silently on any error,
|
|
3082
|
-
# however the file may fail to read for many reasons,
|
|
3083
|
-
# and this situation is handled later in the code,
|
|
3084
|
-
# right now we only want to know if the file successfully reads as ascii.
|
|
3085
|
-
try:
|
|
3086
|
-
with open(filepath, 'r', encoding="utf-8") as fh:
|
|
3087
|
-
fh.read(24)
|
|
3088
|
-
is_ascii = True
|
|
3089
|
-
except Exception:
|
|
3090
|
-
is_ascii = False
|
|
3091
|
-
|
|
3092
|
-
if is_ascii:
|
|
3093
|
-
operator.report({'ERROR'}, rpt_("ASCII FBX files are not supported %r") % filepath)
|
|
3094
|
-
return {'CANCELLED'}
|
|
3095
|
-
del is_ascii
|
|
3096
|
-
# End ascii detection.
|
|
3097
|
-
|
|
3098
|
-
try:
|
|
3099
|
-
elem_root, version = parse_fbx.parse(filepath)
|
|
3100
|
-
except Exception as e:
|
|
3101
|
-
import traceback
|
|
3102
|
-
traceback.print_exc()
|
|
3103
|
-
|
|
3104
|
-
operator.report({'ERROR'}, rpt_("Couldn't open file %r (%s)") % (filepath, e))
|
|
3105
|
-
return {'CANCELLED'}
|
|
3106
|
-
|
|
3107
|
-
if version < 7100:
|
|
3108
|
-
operator.report({'ERROR'}, rpt_("Version %r unsupported, must be %r or later") % (version, 7100))
|
|
3109
|
-
return {'CANCELLED'}
|
|
3110
|
-
|
|
3111
|
-
print("FBX version: %r" % version)
|
|
3112
|
-
|
|
3113
|
-
if bpy.ops.object.mode_set.poll():
|
|
3114
|
-
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
|
3115
|
-
|
|
3116
|
-
# deselect all
|
|
3117
|
-
if bpy.ops.object.select_all.poll():
|
|
3118
|
-
bpy.ops.object.select_all(action='DESELECT')
|
|
3119
|
-
|
|
3120
|
-
basedir = os.path.dirname(filepath)
|
|
3121
|
-
|
|
3122
|
-
nodal_material_wrap_map = {}
|
|
3123
|
-
image_cache = {}
|
|
3124
|
-
|
|
3125
|
-
# Tables: (FBX_byte_id -> [FBX_data, None or Blender_datablock])
|
|
3126
|
-
fbx_table_nodes = {}
|
|
3127
|
-
|
|
3128
|
-
if use_alpha_decals:
|
|
3129
|
-
material_decals = set()
|
|
3130
|
-
else:
|
|
3131
|
-
material_decals = None
|
|
3132
|
-
|
|
3133
|
-
scene = context.scene
|
|
3134
|
-
view_layer = context.view_layer
|
|
3135
|
-
|
|
3136
|
-
# #### Get some info from GlobalSettings.
|
|
3137
|
-
|
|
3138
|
-
perfmon.step("FBX import: Prepare...")
|
|
3139
|
-
|
|
3140
|
-
fbx_settings = elem_find_first(elem_root, b'GlobalSettings')
|
|
3141
|
-
fbx_settings_props = elem_find_first(fbx_settings, b'Properties70')
|
|
3142
|
-
if fbx_settings is None or fbx_settings_props is None:
|
|
3143
|
-
operator.report({'ERROR'}, rpt_("No 'GlobalSettings' found in file %r") % filepath)
|
|
3144
|
-
return {'CANCELLED'}
|
|
3145
|
-
|
|
3146
|
-
# FBX default base unit seems to be the centimeter, while raw Blender Unit is equivalent to the meter...
|
|
3147
|
-
unit_scale = elem_props_get_number(fbx_settings_props, b'UnitScaleFactor', 1.0)
|
|
3148
|
-
unit_scale_org = elem_props_get_number(fbx_settings_props, b'OriginalUnitScaleFactor', 1.0)
|
|
3149
|
-
global_scale *= (unit_scale / units_blender_to_fbx_factor(context.scene))
|
|
3150
|
-
# Compute global matrix and scale.
|
|
3151
|
-
if not use_manual_orientation:
|
|
3152
|
-
axis_forward = (elem_props_get_integer(fbx_settings_props, b'FrontAxis', 1),
|
|
3153
|
-
elem_props_get_integer(fbx_settings_props, b'FrontAxisSign', 1))
|
|
3154
|
-
axis_up = (elem_props_get_integer(fbx_settings_props, b'UpAxis', 2),
|
|
3155
|
-
elem_props_get_integer(fbx_settings_props, b'UpAxisSign', 1))
|
|
3156
|
-
axis_coord = (elem_props_get_integer(fbx_settings_props, b'CoordAxis', 0),
|
|
3157
|
-
elem_props_get_integer(fbx_settings_props, b'CoordAxisSign', 1))
|
|
3158
|
-
axis_key = (axis_up, axis_forward, axis_coord)
|
|
3159
|
-
axis_up, axis_forward = {v: k for k, v in RIGHT_HAND_AXES.items()}.get(axis_key, ('Z', 'Y'))
|
|
3160
|
-
global_matrix = (Matrix.Scale(global_scale, 4) @
|
|
3161
|
-
axis_conversion(from_forward=axis_forward, from_up=axis_up).to_4x4())
|
|
3162
|
-
|
|
3163
|
-
# To cancel out unwanted rotation/scale on nodes.
|
|
3164
|
-
global_matrix_inv = global_matrix.inverted()
|
|
3165
|
-
# For transforming mesh normals.
|
|
3166
|
-
global_matrix_inv_transposed = global_matrix_inv.transposed()
|
|
3167
|
-
|
|
3168
|
-
# Compute bone correction matrix
|
|
3169
|
-
bone_correction_matrix = None # None means no correction/identity
|
|
3170
|
-
if not automatic_bone_orientation:
|
|
3171
|
-
if (primary_bone_axis, secondary_bone_axis) != ('Y', 'X'):
|
|
3172
|
-
bone_correction_matrix = axis_conversion(from_forward='X',
|
|
3173
|
-
from_up='Y',
|
|
3174
|
-
to_forward=secondary_bone_axis,
|
|
3175
|
-
to_up=primary_bone_axis,
|
|
3176
|
-
).to_4x4()
|
|
3177
|
-
|
|
3178
|
-
# Compute framerate settings.
|
|
3179
|
-
custom_fps = elem_props_get_number(fbx_settings_props, b'CustomFrameRate', 25.0)
|
|
3180
|
-
time_mode = elem_props_get_enum(fbx_settings_props, b'TimeMode')
|
|
3181
|
-
real_fps = {eid: val for val, eid in FBX_FRAMERATES[1:]}.get(time_mode, custom_fps)
|
|
3182
|
-
if real_fps <= 0.0:
|
|
3183
|
-
real_fps = 25.0
|
|
3184
|
-
scene.render.fps = round(real_fps)
|
|
3185
|
-
scene.render.fps_base = scene.render.fps / real_fps
|
|
3186
|
-
|
|
3187
|
-
# store global settings that need to be accessed during conversion
|
|
3188
|
-
settings = FBXImportSettings(
|
|
3189
|
-
operator.report, (axis_up, axis_forward), global_matrix, global_scale,
|
|
3190
|
-
bake_space_transform, global_matrix_inv, global_matrix_inv_transposed,
|
|
3191
|
-
use_custom_normals, use_image_search,
|
|
3192
|
-
use_alpha_decals, decal_offset,
|
|
3193
|
-
use_anim, anim_offset,
|
|
3194
|
-
use_subsurf,
|
|
3195
|
-
use_custom_props, use_custom_props_enum_as_string,
|
|
3196
|
-
nodal_material_wrap_map, image_cache,
|
|
3197
|
-
ignore_leaf_bones, force_connect_children, automatic_bone_orientation, bone_correction_matrix,
|
|
3198
|
-
use_prepost_rot, colors_type, mtl_name_collision_mode,
|
|
3199
|
-
)
|
|
3200
|
-
|
|
3201
|
-
# #### And now, the "real" data.
|
|
3202
|
-
|
|
3203
|
-
perfmon.step("FBX import: Templates...")
|
|
3204
|
-
|
|
3205
|
-
fbx_defs = elem_find_first(elem_root, b'Definitions') # can be None
|
|
3206
|
-
fbx_nodes = elem_find_first(elem_root, b'Objects')
|
|
3207
|
-
fbx_connections = elem_find_first(elem_root, b'Connections')
|
|
3208
|
-
|
|
3209
|
-
if fbx_nodes is None:
|
|
3210
|
-
operator.report({'ERROR'}, rpt_("No 'Objects' found in file %r") % filepath)
|
|
3211
|
-
return {'CANCELLED'}
|
|
3212
|
-
if fbx_connections is None:
|
|
3213
|
-
operator.report({'ERROR'}, rpt_("No 'Connections' found in file %r") % filepath)
|
|
3214
|
-
return {'CANCELLED'}
|
|
3215
|
-
|
|
3216
|
-
# ----
|
|
3217
|
-
# First load property templates
|
|
3218
|
-
# Load 'PropertyTemplate' values.
|
|
3219
|
-
# Key is a tuple, (ObjectType, FBXNodeType)
|
|
3220
|
-
# eg, (b'Texture', b'KFbxFileTexture')
|
|
3221
|
-
# (b'Geometry', b'KFbxMesh')
|
|
3222
|
-
fbx_templates = {}
|
|
3223
|
-
|
|
3224
|
-
def _():
|
|
3225
|
-
if fbx_defs is not None:
|
|
3226
|
-
for fbx_def in fbx_defs.elems:
|
|
3227
|
-
if fbx_def.id == b'ObjectType':
|
|
3228
|
-
for fbx_subdef in fbx_def.elems:
|
|
3229
|
-
if fbx_subdef.id == b'PropertyTemplate':
|
|
3230
|
-
assert(fbx_def.props_type == b'S')
|
|
3231
|
-
assert(fbx_subdef.props_type == b'S')
|
|
3232
|
-
# (b'Texture', b'KFbxFileTexture') - eg.
|
|
3233
|
-
key = fbx_def.props[0], fbx_subdef.props[0]
|
|
3234
|
-
fbx_templates[key] = fbx_subdef
|
|
3235
|
-
_()
|
|
3236
|
-
del _
|
|
3237
|
-
|
|
3238
|
-
def fbx_template_get(key):
|
|
3239
|
-
ret = fbx_templates.get(key, fbx_elem_nil)
|
|
3240
|
-
if ret is fbx_elem_nil:
|
|
3241
|
-
# Newest FBX (7.4 and above) use no more 'K' in their type names...
|
|
3242
|
-
key = (key[0], key[1][1:])
|
|
3243
|
-
return fbx_templates.get(key, fbx_elem_nil)
|
|
3244
|
-
return ret
|
|
3245
|
-
|
|
3246
|
-
perfmon.step("FBX import: Nodes...")
|
|
3247
|
-
|
|
3248
|
-
# ----
|
|
3249
|
-
# Build FBX node-table
|
|
3250
|
-
def _():
|
|
3251
|
-
for fbx_obj in fbx_nodes.elems:
|
|
3252
|
-
# TODO, investigate what other items after first 3 may be
|
|
3253
|
-
assert(fbx_obj.props_type[:3] == b'LSS')
|
|
3254
|
-
fbx_uuid = elem_uuid(fbx_obj)
|
|
3255
|
-
fbx_table_nodes[fbx_uuid] = [fbx_obj, None]
|
|
3256
|
-
_()
|
|
3257
|
-
del _
|
|
3258
|
-
|
|
3259
|
-
# ----
|
|
3260
|
-
# Load in the data
|
|
3261
|
-
# http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html?url=
|
|
3262
|
-
# WS73099cc142f487551fea285e1221e4f9ff8-7fda.htm,topicNumber=d0e6388
|
|
3263
|
-
|
|
3264
|
-
perfmon.step("FBX import: Connections...")
|
|
3265
|
-
|
|
3266
|
-
fbx_connection_map = {}
|
|
3267
|
-
fbx_connection_map_reverse = {}
|
|
3268
|
-
|
|
3269
|
-
def _():
|
|
3270
|
-
for fbx_link in fbx_connections.elems:
|
|
3271
|
-
c_type = fbx_link.props[0]
|
|
3272
|
-
if fbx_link.props_type[1:3] == b'LL':
|
|
3273
|
-
c_src, c_dst = fbx_link.props[1:3]
|
|
3274
|
-
fbx_connection_map.setdefault(c_src, []).append((c_dst, fbx_link))
|
|
3275
|
-
fbx_connection_map_reverse.setdefault(c_dst, []).append((c_src, fbx_link))
|
|
3276
|
-
_()
|
|
3277
|
-
del _
|
|
3278
|
-
|
|
3279
|
-
perfmon.step("FBX import: Meshes...")
|
|
3280
|
-
|
|
3281
|
-
# ----
|
|
3282
|
-
# Load mesh data
|
|
3283
|
-
def _():
|
|
3284
|
-
fbx_tmpl = fbx_template_get((b'Geometry', b'KFbxMesh'))
|
|
3285
|
-
|
|
3286
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3287
|
-
fbx_obj, blen_data = fbx_item
|
|
3288
|
-
if fbx_obj.id != b'Geometry':
|
|
3289
|
-
continue
|
|
3290
|
-
if fbx_obj.props[-1] == b'Mesh':
|
|
3291
|
-
assert(blen_data is None)
|
|
3292
|
-
fbx_item[1] = blen_read_geom(fbx_tmpl, fbx_obj, settings)
|
|
3293
|
-
_()
|
|
3294
|
-
del _
|
|
3295
|
-
|
|
3296
|
-
perfmon.step("FBX import: Materials & Textures...")
|
|
3297
|
-
|
|
3298
|
-
# ----
|
|
3299
|
-
# Load material data
|
|
3300
|
-
def _():
|
|
3301
|
-
fbx_tmpl = fbx_template_get((b'Material', b'KFbxSurfacePhong'))
|
|
3302
|
-
# b'KFbxSurfaceLambert'
|
|
3303
|
-
|
|
3304
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3305
|
-
fbx_obj, blen_data = fbx_item
|
|
3306
|
-
if fbx_obj.id != b'Material':
|
|
3307
|
-
continue
|
|
3308
|
-
assert(blen_data is None)
|
|
3309
|
-
fbx_item[1] = blen_read_material(fbx_tmpl, fbx_obj, settings)
|
|
3310
|
-
_()
|
|
3311
|
-
del _
|
|
3312
|
-
|
|
3313
|
-
# ----
|
|
3314
|
-
# Load image & textures data
|
|
3315
|
-
def _():
|
|
3316
|
-
fbx_tmpl_tex = fbx_template_get((b'Texture', b'KFbxFileTexture'))
|
|
3317
|
-
fbx_tmpl_img = fbx_template_get((b'Video', b'KFbxVideo'))
|
|
3318
|
-
|
|
3319
|
-
# Important to run all 'Video' ones first, embedded images are stored in those nodes.
|
|
3320
|
-
# XXX Note we simplify things here, assuming both matching Video and Texture will use same file path,
|
|
3321
|
-
# this may be a bit weak, if issue arise we'll fallback to plain connection stuff...
|
|
3322
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3323
|
-
fbx_obj, blen_data = fbx_item
|
|
3324
|
-
if fbx_obj.id != b'Video':
|
|
3325
|
-
continue
|
|
3326
|
-
fbx_item[1] = blen_read_texture_image(fbx_tmpl_img, fbx_obj, basedir, settings)
|
|
3327
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3328
|
-
fbx_obj, blen_data = fbx_item
|
|
3329
|
-
if fbx_obj.id != b'Texture':
|
|
3330
|
-
continue
|
|
3331
|
-
fbx_item[1] = blen_read_texture_image(fbx_tmpl_tex, fbx_obj, basedir, settings)
|
|
3332
|
-
_()
|
|
3333
|
-
del _
|
|
3334
|
-
|
|
3335
|
-
perfmon.step("FBX import: Cameras & Lamps...")
|
|
3336
|
-
|
|
3337
|
-
# ----
|
|
3338
|
-
# Load camera data
|
|
3339
|
-
def _():
|
|
3340
|
-
fbx_tmpl = fbx_template_get((b'NodeAttribute', b'KFbxCamera'))
|
|
3341
|
-
|
|
3342
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3343
|
-
fbx_obj, blen_data = fbx_item
|
|
3344
|
-
if fbx_obj.id != b'NodeAttribute':
|
|
3345
|
-
continue
|
|
3346
|
-
if fbx_obj.props[-1] == b'Camera':
|
|
3347
|
-
assert(blen_data is None)
|
|
3348
|
-
fbx_item[1] = blen_read_camera(fbx_tmpl, fbx_obj, settings)
|
|
3349
|
-
_()
|
|
3350
|
-
del _
|
|
3351
|
-
|
|
3352
|
-
# ----
|
|
3353
|
-
# Load lamp data
|
|
3354
|
-
def _():
|
|
3355
|
-
fbx_tmpl = fbx_template_get((b'NodeAttribute', b'KFbxLight'))
|
|
3356
|
-
|
|
3357
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3358
|
-
fbx_obj, blen_data = fbx_item
|
|
3359
|
-
if fbx_obj.id != b'NodeAttribute':
|
|
3360
|
-
continue
|
|
3361
|
-
if fbx_obj.props[-1] == b'Light':
|
|
3362
|
-
assert(blen_data is None)
|
|
3363
|
-
fbx_item[1] = blen_read_light(fbx_tmpl, fbx_obj, settings)
|
|
3364
|
-
_()
|
|
3365
|
-
del _
|
|
3366
|
-
|
|
3367
|
-
# ----
|
|
3368
|
-
# Connections
|
|
3369
|
-
def connection_filter_ex(fbx_uuid, fbx_id, dct):
|
|
3370
|
-
return [(c_found[0], c_found[1], c_type)
|
|
3371
|
-
for (c_uuid, c_type) in dct.get(fbx_uuid, ())
|
|
3372
|
-
# 0 is used for the root node, which isn't in fbx_table_nodes
|
|
3373
|
-
for c_found in (() if c_uuid == 0 else (fbx_table_nodes.get(c_uuid, (None, None)),))
|
|
3374
|
-
if (fbx_id is None) or (c_found[0] and c_found[0].id == fbx_id)]
|
|
3375
|
-
|
|
3376
|
-
def connection_filter_forward(fbx_uuid, fbx_id):
|
|
3377
|
-
return connection_filter_ex(fbx_uuid, fbx_id, fbx_connection_map)
|
|
3378
|
-
|
|
3379
|
-
def connection_filter_reverse(fbx_uuid, fbx_id):
|
|
3380
|
-
return connection_filter_ex(fbx_uuid, fbx_id, fbx_connection_map_reverse)
|
|
3381
|
-
|
|
3382
|
-
perfmon.step("FBX import: Objects & Armatures...")
|
|
3383
|
-
|
|
3384
|
-
# -- temporary helper hierarchy to build armatures and objects from
|
|
3385
|
-
# lookup from uuid to helper node. Used to build parent-child relations and later to look up animated nodes.
|
|
3386
|
-
fbx_helper_nodes = {}
|
|
3387
|
-
|
|
3388
|
-
def _():
|
|
3389
|
-
# We build an intermediate hierarchy used to:
|
|
3390
|
-
# - Calculate and store bone orientation correction matrices. The same matrices will be reused for animation.
|
|
3391
|
-
# - Find/insert armature nodes.
|
|
3392
|
-
# - Filter leaf bones.
|
|
3393
|
-
|
|
3394
|
-
# create scene root
|
|
3395
|
-
fbx_helper_nodes[0] = root_helper = FbxImportHelperNode(None, None, None, False)
|
|
3396
|
-
root_helper.is_root = True
|
|
3397
|
-
|
|
3398
|
-
# add fbx nodes
|
|
3399
|
-
fbx_tmpl = fbx_template_get((b'Model', b'KFbxNode'))
|
|
3400
|
-
for a_uuid, a_item in fbx_table_nodes.items():
|
|
3401
|
-
fbx_obj, bl_data = a_item
|
|
3402
|
-
if fbx_obj is None or fbx_obj.id != b'Model':
|
|
3403
|
-
continue
|
|
3404
|
-
|
|
3405
|
-
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
|
3406
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
3407
|
-
|
|
3408
|
-
transform_data = blen_read_object_transform_preprocess(fbx_props, fbx_obj, Matrix(), use_prepost_rot)
|
|
3409
|
-
# Note: 'Root' "bones" are handled as (armature) objects.
|
|
3410
|
-
# Note: See T46912 for first FBX file I ever saw with 'Limb' bones - thought those were totally deprecated.
|
|
3411
|
-
is_bone = fbx_obj.props[2] in {b'LimbNode', b'Limb'}
|
|
3412
|
-
fbx_helper_nodes[a_uuid] = FbxImportHelperNode(fbx_obj, bl_data, transform_data, is_bone)
|
|
3413
|
-
|
|
3414
|
-
# add parent-child relations and add blender data to the node
|
|
3415
|
-
for fbx_link in fbx_connections.elems:
|
|
3416
|
-
if fbx_link.props[0] != b'OO':
|
|
3417
|
-
continue
|
|
3418
|
-
if fbx_link.props_type[1:3] == b'LL':
|
|
3419
|
-
c_src, c_dst = fbx_link.props[1:3]
|
|
3420
|
-
parent = fbx_helper_nodes.get(c_dst)
|
|
3421
|
-
if parent is None:
|
|
3422
|
-
continue
|
|
3423
|
-
|
|
3424
|
-
child = fbx_helper_nodes.get(c_src)
|
|
3425
|
-
if child is None:
|
|
3426
|
-
# add blender data (meshes, lights, cameras, etc.) to a helper node
|
|
3427
|
-
fbx_sdata, bl_data = p_item = fbx_table_nodes.get(c_src, (None, None))
|
|
3428
|
-
if fbx_sdata is None:
|
|
3429
|
-
continue
|
|
3430
|
-
if fbx_sdata.id not in {b'Geometry', b'NodeAttribute'}:
|
|
3431
|
-
continue
|
|
3432
|
-
parent.bl_data = bl_data
|
|
3433
|
-
if bl_data is None:
|
|
3434
|
-
# If there's no bl_data, add the fbx_sdata so that it can be read when creating the bl_data/bone
|
|
3435
|
-
parent.fbx_data_elem = fbx_sdata
|
|
3436
|
-
else:
|
|
3437
|
-
# set parent
|
|
3438
|
-
child.parent = parent
|
|
3439
|
-
|
|
3440
|
-
# find armatures (either an empty below a bone or a new node inserted at the bone
|
|
3441
|
-
root_helper.find_armatures()
|
|
3442
|
-
|
|
3443
|
-
# mark nodes that have bone children
|
|
3444
|
-
root_helper.find_bone_children()
|
|
3445
|
-
|
|
3446
|
-
# mark nodes that need a bone to attach child-bones to
|
|
3447
|
-
root_helper.find_fake_bones()
|
|
3448
|
-
|
|
3449
|
-
# mark leaf nodes that are only required to mark the end of their parent bone
|
|
3450
|
-
if settings.ignore_leaf_bones:
|
|
3451
|
-
root_helper.mark_leaf_bones()
|
|
3452
|
-
|
|
3453
|
-
# What a mess! Some bones have several BindPoses, some have none, clusters contain a bind pose as well,
|
|
3454
|
-
# and you can have several clusters per bone!
|
|
3455
|
-
# Maybe some conversion can be applied to put them all into the same frame of reference?
|
|
3456
|
-
|
|
3457
|
-
# get the bind pose from pose elements
|
|
3458
|
-
for a_uuid, a_item in fbx_table_nodes.items():
|
|
3459
|
-
fbx_obj, bl_data = a_item
|
|
3460
|
-
if fbx_obj is None:
|
|
3461
|
-
continue
|
|
3462
|
-
if fbx_obj.id != b'Pose':
|
|
3463
|
-
continue
|
|
3464
|
-
if fbx_obj.props[2] != b'BindPose':
|
|
3465
|
-
continue
|
|
3466
|
-
for fbx_pose_node in fbx_obj.elems:
|
|
3467
|
-
if fbx_pose_node.id != b'PoseNode':
|
|
3468
|
-
continue
|
|
3469
|
-
node_elem = elem_find_first(fbx_pose_node, b'Node')
|
|
3470
|
-
node = elem_uuid(node_elem)
|
|
3471
|
-
matrix_elem = elem_find_first(fbx_pose_node, b'Matrix')
|
|
3472
|
-
matrix = array_to_matrix4(matrix_elem.props[0]) if matrix_elem else None
|
|
3473
|
-
bone = fbx_helper_nodes.get(node)
|
|
3474
|
-
if bone and matrix:
|
|
3475
|
-
# Store the matrix in the helper node.
|
|
3476
|
-
# There may be several bind pose matrices for the same node, but in tests they seem to be identical.
|
|
3477
|
-
bone.bind_matrix = matrix # global space
|
|
3478
|
-
|
|
3479
|
-
# get clusters and bind pose
|
|
3480
|
-
for helper_uuid, helper_node in fbx_helper_nodes.items():
|
|
3481
|
-
if not helper_node.is_bone:
|
|
3482
|
-
continue
|
|
3483
|
-
for cluster_uuid, cluster_link in fbx_connection_map.get(helper_uuid, ()):
|
|
3484
|
-
if cluster_link.props[0] != b'OO':
|
|
3485
|
-
continue
|
|
3486
|
-
fbx_cluster, _ = fbx_table_nodes.get(cluster_uuid, (None, None))
|
|
3487
|
-
if fbx_cluster is None or fbx_cluster.id != b'Deformer' or fbx_cluster.props[2] != b'Cluster':
|
|
3488
|
-
continue
|
|
3489
|
-
|
|
3490
|
-
# Get the bind pose from the cluster:
|
|
3491
|
-
tx_mesh_elem = elem_find_first(fbx_cluster, b'Transform', default=None)
|
|
3492
|
-
tx_mesh = array_to_matrix4(tx_mesh_elem.props[0]) if tx_mesh_elem else Matrix()
|
|
3493
|
-
|
|
3494
|
-
tx_bone_elem = elem_find_first(fbx_cluster, b'TransformLink', default=None)
|
|
3495
|
-
tx_bone = array_to_matrix4(tx_bone_elem.props[0]) if tx_bone_elem else None
|
|
3496
|
-
|
|
3497
|
-
tx_arm_elem = elem_find_first(fbx_cluster, b'TransformAssociateModel', default=None)
|
|
3498
|
-
tx_arm = array_to_matrix4(tx_arm_elem.props[0]) if tx_arm_elem else None
|
|
3499
|
-
|
|
3500
|
-
mesh_matrix = tx_mesh
|
|
3501
|
-
armature_matrix = tx_arm
|
|
3502
|
-
|
|
3503
|
-
if tx_bone:
|
|
3504
|
-
mesh_matrix = tx_bone @ mesh_matrix
|
|
3505
|
-
helper_node.bind_matrix = tx_bone # overwrite the bind matrix
|
|
3506
|
-
|
|
3507
|
-
# Get the meshes driven by this cluster: (Shouldn't that be only one?)
|
|
3508
|
-
meshes = set()
|
|
3509
|
-
for skin_uuid, skin_link in fbx_connection_map.get(cluster_uuid):
|
|
3510
|
-
if skin_link.props[0] != b'OO':
|
|
3511
|
-
continue
|
|
3512
|
-
fbx_skin, _ = fbx_table_nodes.get(skin_uuid, (None, None))
|
|
3513
|
-
if fbx_skin is None or fbx_skin.id != b'Deformer' or fbx_skin.props[2] != b'Skin':
|
|
3514
|
-
continue
|
|
3515
|
-
skin_connection = fbx_connection_map.get(skin_uuid)
|
|
3516
|
-
if skin_connection is None:
|
|
3517
|
-
continue
|
|
3518
|
-
for mesh_uuid, mesh_link in skin_connection:
|
|
3519
|
-
if mesh_link.props[0] != b'OO':
|
|
3520
|
-
continue
|
|
3521
|
-
fbx_mesh, _ = fbx_table_nodes.get(mesh_uuid, (None, None))
|
|
3522
|
-
if fbx_mesh is None or fbx_mesh.id != b'Geometry' or fbx_mesh.props[2] != b'Mesh':
|
|
3523
|
-
continue
|
|
3524
|
-
for object_uuid, object_link in fbx_connection_map.get(mesh_uuid):
|
|
3525
|
-
if object_link.props[0] != b'OO':
|
|
3526
|
-
continue
|
|
3527
|
-
mesh_node = fbx_helper_nodes[object_uuid]
|
|
3528
|
-
if mesh_node:
|
|
3529
|
-
# ----
|
|
3530
|
-
# If we get a valid mesh matrix (in bone space), store armature and
|
|
3531
|
-
# mesh global matrices, we need them to compute mesh's matrix_parent_inverse
|
|
3532
|
-
# when actually binding them via the modifier.
|
|
3533
|
-
# Note we assume all bones were bound with the same mesh/armature (global) matrix,
|
|
3534
|
-
# we do not support otherwise in Blender anyway!
|
|
3535
|
-
mesh_node.armature_setup[helper_node.armature] = (mesh_matrix, armature_matrix)
|
|
3536
|
-
meshes.add(mesh_node)
|
|
3537
|
-
|
|
3538
|
-
helper_node.clusters.append((fbx_cluster, meshes))
|
|
3539
|
-
|
|
3540
|
-
# convert bind poses from global space into local space
|
|
3541
|
-
root_helper.make_bind_pose_local()
|
|
3542
|
-
|
|
3543
|
-
# collect armature meshes
|
|
3544
|
-
root_helper.collect_armature_meshes()
|
|
3545
|
-
|
|
3546
|
-
# find the correction matrices to align FBX objects with their Blender equivalent
|
|
3547
|
-
root_helper.find_correction_matrix(settings)
|
|
3548
|
-
|
|
3549
|
-
# build the Object/Armature/Bone hierarchy
|
|
3550
|
-
root_helper.build_hierarchy(fbx_tmpl, settings, scene, view_layer)
|
|
3551
|
-
|
|
3552
|
-
# Link the Object/Armature/Bone hierarchy
|
|
3553
|
-
root_helper.link_hierarchy(fbx_tmpl, settings, scene)
|
|
3554
|
-
|
|
3555
|
-
# root_helper.print_info(0)
|
|
3556
|
-
_()
|
|
3557
|
-
del _
|
|
3558
|
-
|
|
3559
|
-
perfmon.step("FBX import: ShapeKeys...")
|
|
3560
|
-
|
|
3561
|
-
# We can handle shapes.
|
|
3562
|
-
blend_shape_channels = {} # We do not need Shapes themselves, but keyblocks, for anim.
|
|
3563
|
-
|
|
3564
|
-
def _():
|
|
3565
|
-
fbx_tmpl = fbx_template_get((b'Geometry', b'KFbxShape'))
|
|
3566
|
-
|
|
3567
|
-
# - FBX | - Blender equivalent
|
|
3568
|
-
# Mesh | `Mesh`
|
|
3569
|
-
# BlendShape | `Key`
|
|
3570
|
-
# BlendShapeChannel | `ShapeKey`, but without its `.data`.
|
|
3571
|
-
# Shape | `ShapeKey.data`, but also includes normals and the values are relative to the base Mesh
|
|
3572
|
-
# | instead of being absolute. The data is sparse, so each Shape has an "Indexes" array too.
|
|
3573
|
-
# | FBX 2020 introduced 'Modern Style' Shapes that also support tangents, binormals, vertex
|
|
3574
|
-
# | colors and UVs, and can be absolute values instead of relative, but 'Modern Style' Shapes
|
|
3575
|
-
# | are not currently supported.
|
|
3576
|
-
#
|
|
3577
|
-
# The FBX connections between Shapes and Meshes form multiple many-many relationships:
|
|
3578
|
-
# Mesh >-< BlendShape >-< BlendShapeChannel >-< Shape
|
|
3579
|
-
# In practice, the relationships are almost never many-many and are more typically 1-many or 1-1:
|
|
3580
|
-
# Mesh --- BlendShape:
|
|
3581
|
-
# usually 1-1 and the FBX SDK might enforce that each BlendShape is connected to at most one Mesh.
|
|
3582
|
-
# BlendShape --< BlendShapeChannel:
|
|
3583
|
-
# usually 1-many.
|
|
3584
|
-
# BlendShapeChannel --- or uncommonly --< Shape:
|
|
3585
|
-
# usually 1-1, but 1-many is a documented feature.
|
|
3586
|
-
|
|
3587
|
-
def connections_gen(c_src_uuid, fbx_id, fbx_type):
|
|
3588
|
-
"""Helper to reduce duplicate code"""
|
|
3589
|
-
# Rarely, an imported FBX file will have duplicate connections. For Shape Key related connections, FBX
|
|
3590
|
-
# appears to ignore the duplicates, or overwrite the existing duplicates such that the end result is the
|
|
3591
|
-
# same as ignoring them, so keep a set of the seen connections and ignore any duplicates.
|
|
3592
|
-
seen_connections = set()
|
|
3593
|
-
for c_dst_uuid, ctype in fbx_connection_map.get(c_src_uuid, ()):
|
|
3594
|
-
if ctype.props[0] != b'OO':
|
|
3595
|
-
# 'Object-Object' connections only.
|
|
3596
|
-
continue
|
|
3597
|
-
fbx_data, bl_data = fbx_table_nodes.get(c_dst_uuid, (None, None))
|
|
3598
|
-
if fbx_data is None or fbx_data.id != fbx_id or fbx_data.props[2] != fbx_type:
|
|
3599
|
-
# Either `c_dst_uuid` doesn't exist, or it has a different id or type.
|
|
3600
|
-
continue
|
|
3601
|
-
connection_key = (c_src_uuid, c_dst_uuid)
|
|
3602
|
-
if connection_key in seen_connections:
|
|
3603
|
-
# The connection is a duplicate, skip it.
|
|
3604
|
-
continue
|
|
3605
|
-
seen_connections.add(connection_key)
|
|
3606
|
-
yield c_dst_uuid, fbx_data, bl_data
|
|
3607
|
-
|
|
3608
|
-
# XXX - Multiple Shapes can be assigned to a single BlendShapeChannel to create a progressive blend between the
|
|
3609
|
-
# base mesh and the assigned Shapes, with the percentage at which each Shape is fully blended being stored
|
|
3610
|
-
# in the BlendShapeChannel's FullWeights array. This is also known as 'in-between shapes'.
|
|
3611
|
-
# We don't have any support for in-between shapes currently.
|
|
3612
|
-
blend_shape_channel_to_shapes = {}
|
|
3613
|
-
mesh_to_shapes = {}
|
|
3614
|
-
for s_uuid, (fbx_sdata, _bl_sdata) in fbx_table_nodes.items():
|
|
3615
|
-
if fbx_sdata is None or fbx_sdata.id != b'Geometry' or fbx_sdata.props[2] != b'Shape':
|
|
3616
|
-
continue
|
|
3617
|
-
|
|
3618
|
-
# shape -> blendshapechannel -> blendshape -> mesh.
|
|
3619
|
-
for bc_uuid, fbx_bcdata, _bl_bcdata in connections_gen(s_uuid, b'Deformer', b'BlendShapeChannel'):
|
|
3620
|
-
# Track the Shapes connected to each BlendShapeChannel.
|
|
3621
|
-
shapes_assigned_to_channel = blend_shape_channel_to_shapes.setdefault(bc_uuid, [])
|
|
3622
|
-
shapes_assigned_to_channel.append(s_uuid)
|
|
3623
|
-
for bs_uuid, _fbx_bsdata, _bl_bsdata in connections_gen(bc_uuid, b'Deformer', b'BlendShape'):
|
|
3624
|
-
for m_uuid, _fbx_mdata, bl_mdata in connections_gen(bs_uuid, b'Geometry', b'Mesh'):
|
|
3625
|
-
# Blenmeshes are assumed already created at that time!
|
|
3626
|
-
assert(isinstance(bl_mdata, bpy.types.Mesh))
|
|
3627
|
-
# Group shapes by mesh so that each mesh only needs to be processed once for all of its shape
|
|
3628
|
-
# keys.
|
|
3629
|
-
if bl_mdata not in mesh_to_shapes:
|
|
3630
|
-
# And we have to find all objects using this mesh!
|
|
3631
|
-
objects = []
|
|
3632
|
-
for o_uuid, o_ctype in fbx_connection_map.get(m_uuid, ()):
|
|
3633
|
-
if o_ctype.props[0] != b'OO':
|
|
3634
|
-
continue
|
|
3635
|
-
node = fbx_helper_nodes[o_uuid]
|
|
3636
|
-
if node:
|
|
3637
|
-
objects.append(node)
|
|
3638
|
-
shapes_list = []
|
|
3639
|
-
mesh_to_shapes[bl_mdata] = (objects, shapes_list)
|
|
3640
|
-
else:
|
|
3641
|
-
shapes_list = mesh_to_shapes[bl_mdata][1]
|
|
3642
|
-
# Only the number of shapes assigned to each BlendShapeChannel needs to be passed through to
|
|
3643
|
-
# `blen_read_shapes`, but that number isn't known until all the connections have been
|
|
3644
|
-
# iterated, so pass the `shapes_assigned_to_channel` list instead.
|
|
3645
|
-
shapes_list.append((bc_uuid, fbx_sdata, fbx_bcdata, shapes_assigned_to_channel))
|
|
3646
|
-
# BlendShape deformers are only here to connect BlendShapeChannels to meshes, nothing else to do.
|
|
3647
|
-
|
|
3648
|
-
# Iterate through each mesh and create its shape keys
|
|
3649
|
-
for bl_mdata, (objects, shapes) in mesh_to_shapes.items():
|
|
3650
|
-
for bc_uuid, keyblocks in blen_read_shapes(fbx_tmpl, shapes, objects, bl_mdata, scene).items():
|
|
3651
|
-
# keyblocks is a list of tuples (mesh, keyblock) matching that shape/blendshapechannel, for animation.
|
|
3652
|
-
blend_shape_channels.setdefault(bc_uuid, []).extend(keyblocks)
|
|
3653
|
-
_()
|
|
3654
|
-
del _
|
|
3655
|
-
|
|
3656
|
-
if settings.use_subsurf:
|
|
3657
|
-
perfmon.step("FBX import: Subdivision surfaces")
|
|
3658
|
-
|
|
3659
|
-
# Look through connections for subsurf in meshes and add it to the parent object
|
|
3660
|
-
def _():
|
|
3661
|
-
for fbx_link in fbx_connections.elems:
|
|
3662
|
-
if fbx_link.props[0] != b'OO':
|
|
3663
|
-
continue
|
|
3664
|
-
if fbx_link.props_type[1:3] == b'LL':
|
|
3665
|
-
c_src, c_dst = fbx_link.props[1:3]
|
|
3666
|
-
parent = fbx_helper_nodes.get(c_dst)
|
|
3667
|
-
if parent is None:
|
|
3668
|
-
continue
|
|
3669
|
-
|
|
3670
|
-
child = fbx_helper_nodes.get(c_src)
|
|
3671
|
-
if child is None:
|
|
3672
|
-
fbx_sdata, bl_data = fbx_table_nodes.get(c_src, (None, None))
|
|
3673
|
-
if fbx_sdata.id != b'Geometry':
|
|
3674
|
-
continue
|
|
3675
|
-
|
|
3676
|
-
preview_levels = elem_prop_first(elem_find_first(fbx_sdata, b'PreviewDivisionLevels'))
|
|
3677
|
-
render_levels = elem_prop_first(elem_find_first(fbx_sdata, b'RenderDivisionLevels'))
|
|
3678
|
-
if isinstance(preview_levels, int) and isinstance(render_levels, int):
|
|
3679
|
-
mod = parent.bl_obj.modifiers.new('subsurf', 'SUBSURF')
|
|
3680
|
-
mod.levels = preview_levels
|
|
3681
|
-
mod.render_levels = render_levels
|
|
3682
|
-
boundary_rule = elem_prop_first(elem_find_first(fbx_sdata, b'BoundaryRule'), default=1)
|
|
3683
|
-
if boundary_rule == 1:
|
|
3684
|
-
mod.boundary_smooth = "PRESERVE_CORNERS"
|
|
3685
|
-
else:
|
|
3686
|
-
mod.boundary_smooth = "ALL"
|
|
3687
|
-
|
|
3688
|
-
_()
|
|
3689
|
-
del _
|
|
3690
|
-
|
|
3691
|
-
if use_anim:
|
|
3692
|
-
perfmon.step("FBX import: Animations...")
|
|
3693
|
-
|
|
3694
|
-
# Animation!
|
|
3695
|
-
def _():
|
|
3696
|
-
# Find the number of "ktimes" per second for this file.
|
|
3697
|
-
# Start with the default for this FBX version.
|
|
3698
|
-
fbx_ktime = FBX_KTIME_V8 if version >= 8000 else FBX_KTIME_V7
|
|
3699
|
-
# Try to find the value of the nested elem_root->'FBXHeaderExtension'->'OtherFlags'->'TCDefinition' element
|
|
3700
|
-
# and look up the "ktimes" per second for its value.
|
|
3701
|
-
if header := elem_find_first(elem_root, b'FBXHeaderExtension'):
|
|
3702
|
-
# The header version that added TCDefinition support is 1004.
|
|
3703
|
-
if elem_prop_first(elem_find_first(header, b'FBXHeaderVersion'), default=0) >= 1004:
|
|
3704
|
-
if other_flags := elem_find_first(header, b'OtherFlags'):
|
|
3705
|
-
if timecode_definition := elem_find_first(other_flags, b'TCDefinition'):
|
|
3706
|
-
timecode_definition_value = elem_prop_first(timecode_definition)
|
|
3707
|
-
# If its value is unknown or missing, default to FBX_KTIME_V8.
|
|
3708
|
-
fbx_ktime = FBX_TIMECODE_DEFINITION_TO_KTIME_PER_SECOND.get(timecode_definition_value,
|
|
3709
|
-
FBX_KTIME_V8)
|
|
3710
|
-
|
|
3711
|
-
fbx_tmpl_astack = fbx_template_get((b'AnimationStack', b'FbxAnimStack'))
|
|
3712
|
-
fbx_tmpl_alayer = fbx_template_get((b'AnimationLayer', b'FbxAnimLayer'))
|
|
3713
|
-
stacks = {}
|
|
3714
|
-
|
|
3715
|
-
# AnimationStacks.
|
|
3716
|
-
for as_uuid, fbx_asitem in fbx_table_nodes.items():
|
|
3717
|
-
fbx_asdata, _blen_data = fbx_asitem
|
|
3718
|
-
if fbx_asdata.id != b'AnimationStack' or fbx_asdata.props[2] != b'':
|
|
3719
|
-
continue
|
|
3720
|
-
stacks[as_uuid] = (fbx_asitem, {})
|
|
3721
|
-
|
|
3722
|
-
# AnimationLayers
|
|
3723
|
-
# (mixing is completely ignored for now, each layer results in an independent set of actions).
|
|
3724
|
-
def get_astacks_from_alayer(al_uuid):
|
|
3725
|
-
for as_uuid, as_ctype in fbx_connection_map.get(al_uuid, ()):
|
|
3726
|
-
if as_ctype.props[0] != b'OO':
|
|
3727
|
-
continue
|
|
3728
|
-
fbx_asdata, _bl_asdata = fbx_table_nodes.get(as_uuid, (None, None))
|
|
3729
|
-
if (fbx_asdata is None or fbx_asdata.id != b'AnimationStack' or
|
|
3730
|
-
fbx_asdata.props[2] != b'' or as_uuid not in stacks):
|
|
3731
|
-
continue
|
|
3732
|
-
yield as_uuid
|
|
3733
|
-
for al_uuid, fbx_alitem in fbx_table_nodes.items():
|
|
3734
|
-
fbx_aldata, _blen_data = fbx_alitem
|
|
3735
|
-
if fbx_aldata.id != b'AnimationLayer' or fbx_aldata.props[2] != b'':
|
|
3736
|
-
continue
|
|
3737
|
-
for as_uuid in get_astacks_from_alayer(al_uuid):
|
|
3738
|
-
_fbx_asitem, alayers = stacks[as_uuid]
|
|
3739
|
-
alayers[al_uuid] = (fbx_alitem, {})
|
|
3740
|
-
|
|
3741
|
-
# AnimationCurveNodes (also the ones linked to actual animated data!).
|
|
3742
|
-
curvenodes = {}
|
|
3743
|
-
for acn_uuid, fbx_acnitem in fbx_table_nodes.items():
|
|
3744
|
-
fbx_acndata, _blen_data = fbx_acnitem
|
|
3745
|
-
if fbx_acndata.id != b'AnimationCurveNode' or fbx_acndata.props[2] != b'':
|
|
3746
|
-
continue
|
|
3747
|
-
cnode = curvenodes[acn_uuid] = {}
|
|
3748
|
-
items = []
|
|
3749
|
-
for n_uuid, n_ctype in fbx_connection_map.get(acn_uuid, ()):
|
|
3750
|
-
if n_ctype.props[0] != b'OP':
|
|
3751
|
-
continue
|
|
3752
|
-
lnk_prop = n_ctype.props[3]
|
|
3753
|
-
if lnk_prop in {b'Lcl Translation', b'Lcl Rotation', b'Lcl Scaling'}:
|
|
3754
|
-
# n_uuid can (????) be linked to root '0' node, instead of a mere object node... See T41712.
|
|
3755
|
-
ob = fbx_helper_nodes.get(n_uuid, None)
|
|
3756
|
-
if ob is None or ob.is_root:
|
|
3757
|
-
continue
|
|
3758
|
-
items.append((ob, lnk_prop))
|
|
3759
|
-
elif lnk_prop == b'DeformPercent': # Shape keys.
|
|
3760
|
-
keyblocks = blend_shape_channels.get(n_uuid, None)
|
|
3761
|
-
if keyblocks is None:
|
|
3762
|
-
continue
|
|
3763
|
-
items += [(kb, lnk_prop) for kb in keyblocks]
|
|
3764
|
-
elif lnk_prop == b'FocalLength': # Camera lens.
|
|
3765
|
-
from bpy.types import Camera
|
|
3766
|
-
fbx_item = fbx_table_nodes.get(n_uuid, None)
|
|
3767
|
-
if fbx_item is None or not isinstance(fbx_item[1], Camera):
|
|
3768
|
-
continue
|
|
3769
|
-
cam = fbx_item[1]
|
|
3770
|
-
items.append((cam, lnk_prop))
|
|
3771
|
-
elif lnk_prop == b'FocusDistance': # Camera focus.
|
|
3772
|
-
from bpy.types import Camera
|
|
3773
|
-
fbx_item = fbx_table_nodes.get(n_uuid, None)
|
|
3774
|
-
if fbx_item is None or not isinstance(fbx_item[1], Camera):
|
|
3775
|
-
continue
|
|
3776
|
-
cam = fbx_item[1]
|
|
3777
|
-
items.append((cam, lnk_prop))
|
|
3778
|
-
elif lnk_prop == b'DiffuseColor':
|
|
3779
|
-
from bpy.types import Material
|
|
3780
|
-
fbx_item = fbx_table_nodes.get(n_uuid, None)
|
|
3781
|
-
if fbx_item is None or not isinstance(fbx_item[1], Material):
|
|
3782
|
-
continue
|
|
3783
|
-
mat = fbx_item[1]
|
|
3784
|
-
items.append((mat, lnk_prop))
|
|
3785
|
-
print("WARNING! Importing material's animation is not supported for Nodal materials...")
|
|
3786
|
-
for al_uuid, al_ctype in fbx_connection_map.get(acn_uuid, ()):
|
|
3787
|
-
if al_ctype.props[0] != b'OO':
|
|
3788
|
-
continue
|
|
3789
|
-
fbx_aldata, _blen_aldata = fbx_alitem = fbx_table_nodes.get(al_uuid, (None, None))
|
|
3790
|
-
if fbx_aldata is None or fbx_aldata.id != b'AnimationLayer' or fbx_aldata.props[2] != b'':
|
|
3791
|
-
continue
|
|
3792
|
-
for as_uuid in get_astacks_from_alayer(al_uuid):
|
|
3793
|
-
_fbx_alitem, anim_items = stacks[as_uuid][1][al_uuid]
|
|
3794
|
-
assert(_fbx_alitem == fbx_alitem)
|
|
3795
|
-
for item, item_prop in items:
|
|
3796
|
-
# No need to keep curvenode FBX data here, contains nothing useful for us.
|
|
3797
|
-
anim_items.setdefault(item, {})[acn_uuid] = (cnode, item_prop)
|
|
3798
|
-
|
|
3799
|
-
# AnimationCurves (real animation data).
|
|
3800
|
-
for ac_uuid, fbx_acitem in fbx_table_nodes.items():
|
|
3801
|
-
fbx_acdata, _blen_data = fbx_acitem
|
|
3802
|
-
if fbx_acdata.id != b'AnimationCurve' or fbx_acdata.props[2] != b'':
|
|
3803
|
-
continue
|
|
3804
|
-
for acn_uuid, acn_ctype in fbx_connection_map.get(ac_uuid, ()):
|
|
3805
|
-
if acn_ctype.props[0] != b'OP':
|
|
3806
|
-
continue
|
|
3807
|
-
fbx_acndata, _bl_acndata = fbx_table_nodes.get(acn_uuid, (None, None))
|
|
3808
|
-
if (fbx_acndata is None or fbx_acndata.id != b'AnimationCurveNode' or
|
|
3809
|
-
fbx_acndata.props[2] != b'' or acn_uuid not in curvenodes):
|
|
3810
|
-
continue
|
|
3811
|
-
# Note this is an infamous simplification of the compound props stuff,
|
|
3812
|
-
# seems to be standard naming but we'll probably have to be smarter to handle more exotic files?
|
|
3813
|
-
channel = {
|
|
3814
|
-
b'd|X': 0, b'd|Y': 1, b'd|Z': 2,
|
|
3815
|
-
b'd|DeformPercent': 0,
|
|
3816
|
-
b'd|FocalLength': 0,
|
|
3817
|
-
b'd|FocusDistance': 0
|
|
3818
|
-
}.get(acn_ctype.props[3], None)
|
|
3819
|
-
if channel is None:
|
|
3820
|
-
continue
|
|
3821
|
-
curvenodes[acn_uuid][ac_uuid] = (fbx_acitem, channel)
|
|
3822
|
-
|
|
3823
|
-
# And now that we have sorted all this, apply animations!
|
|
3824
|
-
blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, settings.anim_offset, global_scale,
|
|
3825
|
-
fbx_ktime)
|
|
3826
|
-
|
|
3827
|
-
_()
|
|
3828
|
-
del _
|
|
3829
|
-
|
|
3830
|
-
perfmon.step("FBX import: Assign materials...")
|
|
3831
|
-
|
|
3832
|
-
def _():
|
|
3833
|
-
# link Material's to Geometry (via Model's)
|
|
3834
|
-
processed_meshes = set()
|
|
3835
|
-
for helper_uuid, helper_node in fbx_helper_nodes.items():
|
|
3836
|
-
obj = helper_node.bl_obj
|
|
3837
|
-
if not obj or obj.type != 'MESH':
|
|
3838
|
-
continue
|
|
3839
|
-
|
|
3840
|
-
# Get the Mesh corresponding to the Geometry used by this Model.
|
|
3841
|
-
mesh = obj.data
|
|
3842
|
-
processed_meshes.add(mesh)
|
|
3843
|
-
|
|
3844
|
-
# Get the Materials from the Model's connections.
|
|
3845
|
-
material_connections = connection_filter_reverse(helper_uuid, b'Material')
|
|
3846
|
-
if not material_connections:
|
|
3847
|
-
continue
|
|
3848
|
-
|
|
3849
|
-
mesh_mats = mesh.materials
|
|
3850
|
-
num_mesh_mats = len(mesh_mats)
|
|
3851
|
-
|
|
3852
|
-
if num_mesh_mats == 0:
|
|
3853
|
-
# This is the first (or only) model to use this Geometry. This is the most common case when importing.
|
|
3854
|
-
# All the Materials can trivially be appended to the Mesh's Materials.
|
|
3855
|
-
mats_to_append = material_connections
|
|
3856
|
-
mats_to_compare = ()
|
|
3857
|
-
elif num_mesh_mats == len(material_connections):
|
|
3858
|
-
# Another Model uses the same Geometry and has already appended its Materials to the Mesh. This is the
|
|
3859
|
-
# second most common case when importing.
|
|
3860
|
-
# It's also possible that a Model could share the same Geometry and have the same number of Materials,
|
|
3861
|
-
# but have different Materials, though this is less common.
|
|
3862
|
-
# The Model Materials will need to be compared with the Mesh Materials at the same indices to check if
|
|
3863
|
-
# they are different.
|
|
3864
|
-
mats_to_append = ()
|
|
3865
|
-
mats_to_compare = material_connections
|
|
3866
|
-
else:
|
|
3867
|
-
# Under the assumption that only used Materials are connected to the Model, the number of Materials of
|
|
3868
|
-
# each Model using a specific Geometry should be the same, otherwise the Material Indices of the
|
|
3869
|
-
# Geometry will be out-of-bounds of the Materials of at least one of the Models using that Geometry.
|
|
3870
|
-
# We wouldn't expect this case to happen, but there's nothing to say it can't.
|
|
3871
|
-
# We'll handle a differing number of Materials by appending any extra Materials and comparing the rest.
|
|
3872
|
-
mats_to_append = material_connections[num_mesh_mats:]
|
|
3873
|
-
mats_to_compare = material_connections[:num_mesh_mats]
|
|
3874
|
-
|
|
3875
|
-
for _fbx_lnk_material, material, _fbx_lnk_material_type in mats_to_append:
|
|
3876
|
-
mesh_mats.append(material)
|
|
3877
|
-
|
|
3878
|
-
mats_to_compare_and_slots = zip(mats_to_compare, obj.material_slots)
|
|
3879
|
-
for (_fbx_lnk_material, material, _fbx_lnk_material_type), mat_slot in mats_to_compare_and_slots:
|
|
3880
|
-
if material != mat_slot.material:
|
|
3881
|
-
# Material Slots default to being linked to the Mesh, so a previously processed Object is also using
|
|
3882
|
-
# this Mesh, but the Mesh uses a different Material for this Material Slot.
|
|
3883
|
-
# To have a different Material for this Material Slot on this Object only, the Material Slot must be
|
|
3884
|
-
# linked to the Object rather than the Mesh.
|
|
3885
|
-
# TODO: add an option to link all materials to objects in Blender instead?
|
|
3886
|
-
mat_slot.link = 'OBJECT'
|
|
3887
|
-
mat_slot.material = material
|
|
3888
|
-
|
|
3889
|
-
# We have to validate mesh polygons' ma_idx, see #41015!
|
|
3890
|
-
# Some FBX seem to have an extra 'default' material which is not defined in FBX file.
|
|
3891
|
-
for mesh in processed_meshes:
|
|
3892
|
-
if mesh.validate_material_indices():
|
|
3893
|
-
print("WARNING: mesh '%s' had invalid material indices, those were reset to first material" % mesh.name)
|
|
3894
|
-
_()
|
|
3895
|
-
del _
|
|
3896
|
-
|
|
3897
|
-
perfmon.step("FBX import: Assign textures...")
|
|
3898
|
-
|
|
3899
|
-
def _():
|
|
3900
|
-
material_images = {}
|
|
3901
|
-
|
|
3902
|
-
fbx_tmpl = fbx_template_get((b'Material', b'KFbxSurfacePhong'))
|
|
3903
|
-
# b'KFbxSurfaceLambert'
|
|
3904
|
-
|
|
3905
|
-
def texture_mapping_set(fbx_obj, node_texture):
|
|
3906
|
-
assert(fbx_obj.id == b'Texture')
|
|
3907
|
-
|
|
3908
|
-
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
|
3909
|
-
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
|
3910
|
-
loc = elem_props_get_vector_3d(fbx_props, b'Translation', (0.0, 0.0, 0.0))
|
|
3911
|
-
rot = tuple(-r for r in elem_props_get_vector_3d(fbx_props, b'Rotation', (0.0, 0.0, 0.0)))
|
|
3912
|
-
scale = tuple(((1.0 / s) if s != 0.0 else 1.0)
|
|
3913
|
-
for s in elem_props_get_vector_3d(fbx_props, b'Scaling', (1.0, 1.0, 1.0)))
|
|
3914
|
-
clamp = (bool(elem_props_get_enum(fbx_props, b'WrapModeU', 0)) or
|
|
3915
|
-
bool(elem_props_get_enum(fbx_props, b'WrapModeV', 0)))
|
|
3916
|
-
|
|
3917
|
-
if (loc == (0.0, 0.0, 0.0) and
|
|
3918
|
-
rot == (0.0, 0.0, 0.0) and
|
|
3919
|
-
scale == (1.0, 1.0, 1.0) and
|
|
3920
|
-
clamp == False):
|
|
3921
|
-
return
|
|
3922
|
-
|
|
3923
|
-
node_texture.translation = loc
|
|
3924
|
-
node_texture.rotation = rot
|
|
3925
|
-
node_texture.scale = scale
|
|
3926
|
-
if clamp:
|
|
3927
|
-
node_texture.extension = 'EXTEND'
|
|
3928
|
-
|
|
3929
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3930
|
-
fbx_obj, blen_data = fbx_item
|
|
3931
|
-
if fbx_obj.id != b'Material':
|
|
3932
|
-
continue
|
|
3933
|
-
|
|
3934
|
-
material = fbx_table_nodes.get(fbx_uuid, (None, None))[1]
|
|
3935
|
-
for (fbx_lnk,
|
|
3936
|
-
image,
|
|
3937
|
-
fbx_lnk_type) in connection_filter_reverse(fbx_uuid, b'Texture'):
|
|
3938
|
-
|
|
3939
|
-
if fbx_lnk_type.props[0] == b'OP':
|
|
3940
|
-
lnk_type = fbx_lnk_type.props[3]
|
|
3941
|
-
|
|
3942
|
-
ma_wrap = nodal_material_wrap_map[material]
|
|
3943
|
-
|
|
3944
|
-
if lnk_type in {b'DiffuseColor', b'3dsMax|maps|texmap_diffuse'}:
|
|
3945
|
-
ma_wrap.base_color_texture.image = image
|
|
3946
|
-
texture_mapping_set(fbx_lnk, ma_wrap.base_color_texture)
|
|
3947
|
-
elif lnk_type in {b'SpecularColor', b'SpecularFactor'}:
|
|
3948
|
-
# Intensity actually, not color...
|
|
3949
|
-
ma_wrap.specular_texture.image = image
|
|
3950
|
-
texture_mapping_set(fbx_lnk, ma_wrap.specular_texture)
|
|
3951
|
-
elif lnk_type in {b'ReflectionColor', b'ReflectionFactor', b'3dsMax|maps|texmap_reflection'}:
|
|
3952
|
-
# Intensity actually, not color...
|
|
3953
|
-
ma_wrap.metallic_texture.image = image
|
|
3954
|
-
texture_mapping_set(fbx_lnk, ma_wrap.metallic_texture)
|
|
3955
|
-
elif lnk_type in {b'TransparentColor', b'TransparencyFactor'}:
|
|
3956
|
-
ma_wrap.alpha_texture.image = image
|
|
3957
|
-
texture_mapping_set(fbx_lnk, ma_wrap.alpha_texture)
|
|
3958
|
-
if use_alpha_decals:
|
|
3959
|
-
material_decals.add(material)
|
|
3960
|
-
elif lnk_type == b'ShininessExponent':
|
|
3961
|
-
# That is probably reversed compared to expected results? TODO...
|
|
3962
|
-
ma_wrap.roughness_texture.image = image
|
|
3963
|
-
texture_mapping_set(fbx_lnk, ma_wrap.roughness_texture)
|
|
3964
|
-
# XXX, applications abuse bump!
|
|
3965
|
-
elif lnk_type in {b'NormalMap', b'Bump', b'3dsMax|maps|texmap_bump'}:
|
|
3966
|
-
ma_wrap.normalmap_texture.image = image
|
|
3967
|
-
texture_mapping_set(fbx_lnk, ma_wrap.normalmap_texture)
|
|
3968
|
-
"""
|
|
3969
|
-
elif lnk_type == b'Bump':
|
|
3970
|
-
# TODO displacement...
|
|
3971
|
-
"""
|
|
3972
|
-
elif lnk_type in {b'EmissiveColor'}:
|
|
3973
|
-
ma_wrap.emission_color_texture.image = image
|
|
3974
|
-
texture_mapping_set(fbx_lnk, ma_wrap.emission_color_texture)
|
|
3975
|
-
elif lnk_type in {b'EmissiveFactor'}:
|
|
3976
|
-
ma_wrap.emission_strength_texture.image = image
|
|
3977
|
-
texture_mapping_set(fbx_lnk, ma_wrap.emission_strength_texture)
|
|
3978
|
-
else:
|
|
3979
|
-
print("WARNING: material link %r ignored" % lnk_type)
|
|
3980
|
-
|
|
3981
|
-
material_images.setdefault(material, {})[lnk_type] = image
|
|
3982
|
-
|
|
3983
|
-
# Check if the diffuse image has an alpha channel,
|
|
3984
|
-
# if so, use the alpha channel.
|
|
3985
|
-
|
|
3986
|
-
# Note: this could be made optional since images may have alpha but be entirely opaque
|
|
3987
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
3988
|
-
fbx_obj, blen_data = fbx_item
|
|
3989
|
-
if fbx_obj.id != b'Material':
|
|
3990
|
-
continue
|
|
3991
|
-
material = fbx_table_nodes.get(fbx_uuid, (None, None))[1]
|
|
3992
|
-
image = material_images.get(material, {}).get(b'DiffuseColor', None)
|
|
3993
|
-
# do we have alpha?
|
|
3994
|
-
if image and image.depth == 32:
|
|
3995
|
-
if use_alpha_decals:
|
|
3996
|
-
material_decals.add(material)
|
|
3997
|
-
|
|
3998
|
-
ma_wrap = nodal_material_wrap_map[material]
|
|
3999
|
-
ma_wrap.alpha_texture.use_alpha = True
|
|
4000
|
-
ma_wrap.alpha_texture.copy_from(ma_wrap.base_color_texture)
|
|
4001
|
-
|
|
4002
|
-
# Propagate mapping from diffuse to all other channels which have none defined.
|
|
4003
|
-
# XXX Commenting for now, I do not really understand the logic here, why should diffuse mapping
|
|
4004
|
-
# be applied to all others if not defined for them???
|
|
4005
|
-
# ~ ma_wrap = nodal_material_wrap_map[material]
|
|
4006
|
-
# ~ ma_wrap.mapping_set_from_diffuse()
|
|
4007
|
-
|
|
4008
|
-
_()
|
|
4009
|
-
del _
|
|
4010
|
-
|
|
4011
|
-
perfmon.step("FBX import: Cycles z-offset workaround...")
|
|
4012
|
-
|
|
4013
|
-
def _():
|
|
4014
|
-
# Annoying workaround for cycles having no z-offset
|
|
4015
|
-
if material_decals and use_alpha_decals:
|
|
4016
|
-
for fbx_uuid, fbx_item in fbx_table_nodes.items():
|
|
4017
|
-
fbx_obj, blen_data = fbx_item
|
|
4018
|
-
if fbx_obj.id != b'Geometry':
|
|
4019
|
-
continue
|
|
4020
|
-
if fbx_obj.props[-1] == b'Mesh':
|
|
4021
|
-
mesh = fbx_item[1]
|
|
4022
|
-
|
|
4023
|
-
num_verts = len(mesh.vertices)
|
|
4024
|
-
if decal_offset != 0.0 and num_verts > 0:
|
|
4025
|
-
for material in mesh.materials:
|
|
4026
|
-
if material in material_decals:
|
|
4027
|
-
blen_norm_dtype = np.single
|
|
4028
|
-
vcos = MESH_ATTRIBUTE_POSITION.to_ndarray(mesh.attributes)
|
|
4029
|
-
vnorm = np.empty(num_verts * 3, dtype=blen_norm_dtype)
|
|
4030
|
-
mesh.vertex_normals.foreach_get("vector", vnorm)
|
|
4031
|
-
|
|
4032
|
-
vcos += vnorm * decal_offset
|
|
4033
|
-
|
|
4034
|
-
MESH_ATTRIBUTE_POSITION.foreach_set(mesh.attributes, vcos)
|
|
4035
|
-
break
|
|
4036
|
-
|
|
4037
|
-
for obj in (obj for obj in bpy.data.objects if obj.data == mesh):
|
|
4038
|
-
obj.visible_shadow = False
|
|
4039
|
-
_()
|
|
4040
|
-
del _
|
|
4041
|
-
|
|
4042
|
-
perfmon.level_down()
|
|
4043
|
-
|
|
4044
|
-
perfmon.level_down("Import finished.")
|
|
4045
|
-
return {'FINISHED'}
|