Blender 源码解析(1)

        由于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是一种任何类型都定义成对象的语言,是也可能是反射的需要。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值