Adds a C++ based FBX importer, using 3rd party ufbx library (design task: #131304). The old Python based importer is still there; the new one is marked as "(experimental)" in the menu item. Drag-and-drop uses the old Python importer; the new one is only in the menu item. The new importer is generally 2x-5x faster than the old one, and often uses less memory too. There's potential to make it several times faster still. - ASCII FBX files are supported now - Binary FBX files older than 7.1 (SDK 2012) version are supported now - Better handling of "geometric transform" (common in 3dsmax), manifesting as wrong rotation for some objects when in a hierarchy (e.g. #131172) - Some FBX files that the old importer was failing to read are supported now (e.g. cases 47344, 134983) - Materials import more shader parameters (IOR, diffuse roughness, anisotropy, subsurface, transmission, coat, sheen, thin film) and shader models (e.g. OpenPBR or glTF2 materials from 3dsmax imports much better) - Importer now creates layered/slotted animation actions. Each "take" inside FBX file creates one action, and animated object within it gets a slot. - Materials that use the same texture several times no longer create duplicate images; the same image is used - Material diffuse color animations were imported, but they only animated the viewport color. Now they also animate the nodetree base color too. - "Ignore Leaf Bones" option no longer ignores leaf bones that are actually skinned to some parts of the mesh. - Previous importer was creating orphan invisible Camera data objects for some files (mostly from MotionBuilder?), new one properly creates these cameras. Import settings that existed in Python importer, but are NOT DONE in the new one (mostly because not sure if they are useful, and no one asked for them from feedback yet): - Manual Orientation & Forward/Up Axis: not sure if actually useful. FBX file itself specifies the axes fairly clearly. USD/glTF/Alembic also do not have settings to override them. - Use Pre/Post Rotation (defaults on): feels like it should just always be on. ufbx handles that internally. - Apply Transform (defaults off, warning icon): not sure if needed at all. - Decal Offset: Cycles specific. None of other importers have it. - Automatic Bone Orientation (defaults off): feels like current behavior (either on or off) often produces "nonsensical bones" where bone direction does not go towards the children with either setting. There are discussions within I/O and Animation modules about different ways of bone visualizations and/or different bone length axes, that would solve this in general. - Force Connect Children (defaults off): not sure when that would be useful. On several animated armatures I tried, it turns armature animation into garbage. - Primary/Secondary Bone Axis: again not sure when would be useful. Importer UI screenshots, performance benchmark details and TODOs for later work are in the PR. Pull Request: https://projects.blender.org/blender/blender/pulls/132406
357 lines
6.2 KiB
C++
357 lines
6.2 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup pythonintern
|
|
*/
|
|
|
|
#include <Python.h>
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "bpy_app_build_options.hh"
|
|
|
|
static PyTypeObject BlenderAppBuildOptionsType;
|
|
|
|
static PyStructSequence_Field app_builtopts_info_fields[] = {
|
|
/* names mostly follow CMake options, lowercase, after `WITH_` */
|
|
{"bullet", nullptr},
|
|
{"codec_avi", nullptr},
|
|
{"codec_ffmpeg", nullptr},
|
|
{"codec_sndfile", nullptr},
|
|
{"compositor_cpu", nullptr},
|
|
{"cycles", nullptr},
|
|
{"cycles_osl", nullptr},
|
|
{"freestyle", nullptr},
|
|
{"image_cineon", nullptr},
|
|
{"image_dds", nullptr},
|
|
{"image_hdr", nullptr},
|
|
{"image_openexr", nullptr},
|
|
{"image_openjpeg", nullptr},
|
|
{"image_tiff", nullptr},
|
|
{"image_webp", nullptr},
|
|
{"input_ndof", nullptr},
|
|
{"audaspace", nullptr},
|
|
{"international", nullptr},
|
|
{"openal", nullptr},
|
|
{"opensubdiv", nullptr},
|
|
{"sdl", nullptr},
|
|
{"coreaudio", nullptr},
|
|
{"jack", nullptr},
|
|
{"pulseaudio", nullptr},
|
|
{"wasapi", nullptr},
|
|
{"libmv", nullptr},
|
|
{"mod_oceansim", nullptr},
|
|
{"mod_remesh", nullptr},
|
|
{"collada", nullptr},
|
|
{"io_wavefront_obj", nullptr},
|
|
{"io_ply", nullptr},
|
|
{"io_stl", nullptr},
|
|
{"io_fbx", nullptr},
|
|
{"io_gpencil", nullptr},
|
|
{"opencolorio", nullptr},
|
|
{"openmp", nullptr},
|
|
{"openvdb", nullptr},
|
|
{"alembic", nullptr},
|
|
{"usd", nullptr},
|
|
{"fluid", nullptr},
|
|
{"xr_openxr", nullptr},
|
|
{"potrace", nullptr},
|
|
{"pugixml", nullptr},
|
|
{"haru", nullptr},
|
|
/* Sentinel (this line prevents `clang-format` wrapping into columns). */
|
|
{nullptr},
|
|
};
|
|
|
|
static PyStructSequence_Desc app_builtopts_info_desc = {
|
|
/*name*/ "bpy.app.build_options",
|
|
/*doc*/ "This module contains information about options blender is built with",
|
|
/*fields*/ app_builtopts_info_fields,
|
|
/*n_in_sequence*/ ARRAY_SIZE(app_builtopts_info_fields) - 1,
|
|
};
|
|
|
|
static PyObject *make_builtopts_info()
|
|
{
|
|
PyObject *builtopts_info;
|
|
int pos = 0;
|
|
|
|
builtopts_info = PyStructSequence_New(&BlenderAppBuildOptionsType);
|
|
if (builtopts_info == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
#define SetObjIncref(item) \
|
|
PyStructSequence_SET_ITEM(builtopts_info, pos++, (Py_IncRef(item), item))
|
|
|
|
#ifdef WITH_BULLET
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
/* AVI */
|
|
SetObjIncref(Py_False);
|
|
|
|
#ifdef WITH_FFMPEG
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_SNDFILE
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
/* Compositor. */
|
|
SetObjIncref(Py_True);
|
|
|
|
#ifdef WITH_CYCLES
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_CYCLES_OSL
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IMAGE_CINEON
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
/* DDS */
|
|
SetObjIncref(Py_True);
|
|
|
|
/* HDR */
|
|
SetObjIncref(Py_True);
|
|
|
|
#ifdef WITH_IMAGE_OPENEXR
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IMAGE_OPENJPEG
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
/* TIFF */
|
|
SetObjIncref(Py_True);
|
|
|
|
#ifdef WITH_IMAGE_WEBP
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_INPUT_NDOF
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_AUDASPACE
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_INTERNATIONAL
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_OPENAL
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_OPENSUBDIV
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_SDL
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_COREAUDIO
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_JACK
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_PULSEAUDIO
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_WASAPI
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_LIBMV
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_OCEANSIM
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_MOD_REMESH
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_COLLADA
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IO_WAVEFRONT_OBJ
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IO_PLY
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IO_STL
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IO_FBX
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_IO_GREASE_PENCIL
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_OCIO
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef _OPENMP
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_OPENVDB
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_ALEMBIC
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_USD
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_FLUID
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_XR_OPENXR
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_POTRACE
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_PUGIXML
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#ifdef WITH_HARU
|
|
SetObjIncref(Py_True);
|
|
#else
|
|
SetObjIncref(Py_False);
|
|
#endif
|
|
|
|
#undef SetObjIncref
|
|
|
|
return builtopts_info;
|
|
}
|
|
|
|
PyObject *BPY_app_build_options_struct()
|
|
{
|
|
PyObject *ret;
|
|
|
|
PyStructSequence_InitType(&BlenderAppBuildOptionsType, &app_builtopts_info_desc);
|
|
|
|
ret = make_builtopts_info();
|
|
|
|
/* prevent user from creating new instances */
|
|
BlenderAppBuildOptionsType.tp_init = nullptr;
|
|
BlenderAppBuildOptionsType.tp_new = nullptr;
|
|
/* Without this we can't do `set(sys.modules)` #29635. */
|
|
BlenderAppBuildOptionsType.tp_hash = (hashfunc)_Py_HashPointer;
|
|
|
|
return ret;
|
|
}
|