? ? ? ? 由于Blender代码量很大,涉及的业务面比较广,本人从目前的了解中大概说一下对Blener的认识,如有错误,请指正,十分感谢。
? ? ? ? Blender是一个的功能十分强大,并且跨平台,目前只是从window下对模型的处理过程中对其介绍,包括UI部分和数据部分。
? ? ?(一)、Blender的UI部分,Blender的UI是基于GHOST类库开发的主窗口以及一些弹出的子窗口,对于主窗口,GHOST的作用主要是创建主窗口界面、监听系统IO操作、提供GPU上下文、消息循环过程等。而对于主窗口内的布局、工作区、各种面板、小部件等UI以及UI的消息传递都是自定义的,主窗口中的UI都是使用Opengl绘制的,UI类的基础类库的封装是C++开发并对Python开放UI类库的操作接口,而每个界面的UI组织是通过python处理的(脚本便于业务组织)。
? ? (二)、Blender的数据部分,Blender的核心数据是DNA相关的数据结构,以及RNA基于DNA数据进行业务封装,本人感觉Blender对源码中的核心数据结构处理比较复杂,整个源码中会包含很对的预处理程序,像makesdna.exe、makesrna.exe等,其中makesdna.exe会将rna_*.h文件中的数据结构转换成内存结构,例如:DNA_listBase.h文件的处理,makesdna.exe会将该文件按照字符
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/** Generic - all structs which are put into linked lists begin with this. */
typedef struct Link {
struct Link *next, *prev;
} Link;
/** Simple subclass of Link. Use this when it is not worth defining a custom one. */
typedef struct LinkData {
struct LinkData *next, *prev;
void *data;
} LinkData;
/** Never change the size of this! dna_genfile.c detects pointer_size with it. */
typedef struct ListBase {
void *first, *last;
} ListBase;
/* 8 byte alignment! */
#ifdef __cplusplus
}
#endif
串进行解析,并将解析的结果存储到如下结构中:
typedef struct SDNA {
// 数据、数据长度
/** Full copy of 'encoded' data (when data_alloc is set, otherwise borrowed). */
// 全部的未编码的数据
const char *data;
/** Length of data. 数据长度*/
int data_len;
bool data_alloc; // 是否需要要自己维护堆
/** Total number of struct members. 结构体成员数量*/
int names_len, names_len_alloc;
/** Struct member names. 结构体成员变量的名称*/
const char **names;
/** Result of #DNA_elem_array_size (aligned with #names). */
// 每一个名字的字母个数,例如“*next”个数为5
short *names_array_len;
/** Size of a pointer in bytes. 指针大小*/
int pointer_size;
/** Type names. 所有的类型,包括结构体、普通类型(int\float\string等)*/
const char **types;
/** Number of basic types + struct types. 类型长度*/
int types_len;
/** Type lengths. */
short *types_size;
/** Information about structs and their members. 结构体和它们的成员的信息*/
SDNA_Struct **structs;
/** Number of struct types. */
int structs_len;
/** #GHash for faster lookups, requires WITH_DNA_GHASH to be used for now. */
struct GHash *structs_map;
/** Temporary memory currently only used for version patching DNA. */
// 临时内存当前仅用于版本修补DNA
struct MemArena *mem_arena;
/** Runtime versions of data stored in DNA, lazy initialized,
* only different when renaming is done. */
// DNA中存储的数据的运行时版本,延迟初始化,仅在重命名完成时不同
// 查找别名并存储在sdna->alias.types中于sdna->types位置上对应
struct {
/** Aligned with #SDNA.names, same pointers when unchanged. */
const char **names; // 名称别名数组
/** Aligned with #SDNA.types, same pointers when unchanged. */
const char **types; // 类型别名数组
/** A version of #SDNA.structs_map that uses #SDNA.alias.types for its keys. */
struct GHash *structs_map;
} alias;
} SDNA;
比如将ListBase这个类型名存储到SDNA中的types中,同时这个types中还存储着int、float、string等基本类型,还有将结构体的成员变量名称存储在SDNA中的names中,?SDNA_Struct **structs;中则存放当前Blender中所有的dna_*.h的结构体信息,SDNA_Struct代码如下:
// 结构体和它们的成员的信息
typedef struct SDNA_Struct {
/** This struct must not change, it's only a convenience view for raw data stored in SDNA. */
/** 这个结构不能改变, 只是方便查看 */
/** An index into SDNA->types. 结构体的类型(如link、baselist等) */
short type;
/** The amount of members in this struct.结构中的成员数量(如link、baselist等)成员变量的数量 */
short members_len;
/** "Flexible array member" that contains information about all members of this struct. */
// 结构体成员变量的信息(如link、baselist等的成员变量)
SDNA_StructMember members[];
} SDNA_Struct;
结构体的SDNA_Struct的type则是SDNA中types的索引,SDNA_Struct的SDNA_StructMember members[];中存储的是结构体的成员变量列表,SDNA_StructMember的代码如下:
// 结构体成员信息
typedef struct SDNA_StructMember {
/** This struct must not change, it's only a convenience view for raw data stored in SDNA. */
/** 这个结构不能改变, 只是方便查看 */
/** An index into SDNA->types. 类型 */
short type;
/** An index into SDNA->names. 名称 */
short name;
} SDNA_StructMember;
SDNA_StructMember的type是指向SDNA中types的索引,而SDNA_StructMember的name是指向SDNA中names的索引,Blender将很多的基础结构存储到SDNA的内存结构中,并将这个结构序列化成一个文件dna.c中,这个文件在工程目录下,是自动创建的。
? ? ? ? 而对于于RNA相关的处理是使用makesrna.exe处理的,例如:
// RNA中需要处理的文件( 文件名,对应的这个.c文件里的入口函数 )
static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_rna.c", NULL, RNA_def_rna}, // 文件名,对应的这个.c文件里的入口函数
{"rna_ID.c", NULL, RNA_def_ID}, // 定义ID
{"rna_texture.c", "rna_texture_api.c", RNA_def_texture}, // 定义纹理
{"rna_action.c", "rna_action_api.c", RNA_def_action}, // 定义动作
{"rna_animation.c", "rna_animation_api.c", RNA_def_animation}, // 定义动画
{"rna_animviz.c", NULL, RNA_def_animviz},
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, // 定义骨骼
{"rna_attribute.c", NULL, RNA_def_attribute},
{"rna_asset.c", NULL, RNA_def_asset},
{"rna_boid.c", NULL, RNA_def_boid}, // 定义实体
{"rna_brush.c", NULL, RNA_def_brush}, // 定义画刷
{"rna_cachefile.c", NULL, RNA_def_cachefile},
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera}, // 定义相机
{"rna_cloth.c", NULL, RNA_def_cloth}, // 定义布料
{"rna_collection.c", NULL, RNA_def_collections}, //
{"rna_color.c", NULL, RNA_def_color}, // 定义颜色
{"rna_constraint.c", NULL, RNA_def_constraint},
{"rna_context.c", NULL, RNA_def_context}, // 定义上下文
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve}, // 定义曲线
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint}, // 定义绘制
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_gpencil.c", NULL, RNA_def_gpencil}, // 定义油笔
#ifdef WITH_HAIR_NODES
{"rna_hair.c", NULL, RNA_def_hair}, // 定义毛发
#endif
{"rna_image.c", "rna_image_api.c", RNA_def_image}, // 定义图像
{"rna_key.c", NULL, RNA_def_key},
{"rna_light.c", NULL, RNA_def_light}, // 定义灯
{"rna_lattice.c", "rna_lattice_api.c", RNA_def_lattice}, // 定义栅格
{"rna_layer.c", NULL, RNA_def_view_layer}, // 定义视图层
{"rna_linestyle.c", NULL, RNA_def_linestyle}, // 定义线样式
{"rna_main.c", "rna_main_api.c", RNA_def_main},
{"rna_fluid.c", NULL, RNA_def_fluid},
{"rna_material.c", "rna_material_api.c", RNA_def_material}, // 定义材质
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh}, // 定义网格
{"rna_meta.c", "rna_meta_api.c", RNA_def_meta},
{"rna_modifier.c", NULL, RNA_def_modifier}, // 定义修改器
{"rna_gpencil_modifier.c", NULL, RNA_def_greasepencil_modifier},
{"rna_shader_fx.c", NULL, RNA_def_shader_fx}, // 定义特效
{"rna_nla.c", NULL, RNA_def_nla},
{"rna_nodetree.c", NULL, RNA_def_nodetree}, // 定义节点树
{"rna_object.c", "rna_object_api.c", RNA_def_object}, // 定义对象
{"rna_object_force.c", NULL, RNA_def_object_force},
{"rna_depsgraph.c", NULL, RNA_def_depsgraph}, // 定义依赖图
{"rna_packedfile.c", NULL, RNA_def_packedfile}, // 定义打包文件
{"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle}, // 定义粒子
#ifdef WITH_POINT_CLOUD
{"rna_pointcloud.c", NULL, RNA_def_pointcloud}, // 定义点云
#endif
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, // 定义骨骼姿态
{"rna_curveprofile.c", NULL, RNA_def_profile},
{"rna_lightprobe.c", NULL, RNA_def_lightprobe}, // 定义灯光探头
{"rna_render.c", NULL, RNA_def_render}, // 定义渲染
{"rna_rigidbody.c", NULL, RNA_def_rigidbody}, // 定义刚体
{"rna_scene.c", "rna_scene_api.c", RNA_def_scene}, // 定义场景
{"rna_screen.c", NULL, RNA_def_screen}, // 定义屏幕
{"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint}, // 定义雕刻绘制
{"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer},
#ifdef WITH_SIMULATION_DATABLOCK
{"rna_simulation.c", NULL, RNA_def_simulation}, // 定义仿真
#endif
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_speaker.c", NULL, RNA_def_speaker},
{"rna_test.c", NULL, RNA_def_test},
{"rna_text.c", "rna_text_api.c", RNA_def_text}, // 定义文本
{"rna_timeline.c", NULL, RNA_def_timeline_marker}, // 定义时间轴
{"rna_sound.c", "rna_sound_api.c", RNA_def_sound}, // 定义声音
{"rna_ui.c", "rna_ui_api.c", RNA_def_ui}, // 定义ui
{"rna_userdef.c", NULL, RNA_def_userdef},
{"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont}, // 定义字体
{"rna_volume.c", NULL, RNA_def_volume}, // 定义体积
{"rna_wm.c", "rna_wm_api.c", RNA_def_wm}, // 定义窗口管理
{"rna_wm_gizmo.c", "rna_wm_gizmo_api.c", RNA_def_wm_gizmo}, // 定义小部件
{"rna_workspace.c", "rna_workspace_api.c", RNA_def_workspace}, // 定义工作空间
{"rna_world.c", NULL, RNA_def_world}, // 定义世界
{"rna_movieclip.c", NULL, RNA_def_movieclip}, // 定义影视剪辑
{"rna_tracking.c", NULL, RNA_def_tracking},
{"rna_mask.c", NULL, RNA_def_mask},
{"rna_xr.c", NULL, RNA_def_xr}, // 定义混合现实
{NULL, NULL},
};
makesrna.exe会将这些列表中的文件按照后面的函数在内存中定义对SDNA数据的处理,因为SDNA中定义的都是数据结构,没有对数据的处理过程(函数),同时是按照Blender的业务需要生成rna_*_gen.c文件,这个封装过程会将c++的基本数据类型进行封装,例如float在Blender中会被重新封装成FloatPropertyRNA结构体,这些结构体按照业务需要会重新定义,例如矩阵的定义:
FloatPropertyRNA rna_Mesh_transform_matrix = {
{(PropertyRNA *)&rna_Mesh_transform_shape_keys, NULL,
-1, "matrix", 3, 0, 1, 0, 0, "",
"Matrix",
0, "*",
PROP_FLOAT, PROP_MATRIX | PROP_UNIT_NONE, NULL, 2, {4, 4, 0}, 16,
NULL, 0, NULL, NULL, rna_property_override_diff_default, rna_property_override_store_default, rna_property_override_apply_default,
0, -1, NULL},
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, 1.0f, 3, 0.0f, rna_Mesh_transform_matrix_default
};
感觉这个封装过程于使用脚本有很大的原因,因为python是一种任何类型都定义成对象的语言,是也可能是反射的需要。
|