【转载】Blender 源码学习 --- Modifier

250 阅读4分钟

原文链接

Blender 源码学习 --- Modifier

原文格式太乱了,我整理了一下

正文

Blender Modifier 的结构有点小复杂, 需要修改的部分有点多

需要修改的部分

1. properties_data_modifier.py

Modifier 的 UI 界面, 接口是 SCALING

2. DNA_modifier_types.h

这里有两个东西需要修改

  • a. 在这里添加 ModifierType 枚举类
  • b. 声明和 UI 交互的数据结构

3. RNA_access.h

添加 StructRNA 的声明, 而定义是自动生成的

4. rna_modifier.c

这里有三处需要修改

  • a. 这里添加的是 添加 Modifier 下拉列表 UI 的值, 同时指向 12.a
  • b. 修改 rna_Modifier_refine, 这里相当于定义了从 2.a3 的链接
  • c. 在 RNA_def_modifier 中创建 StructRNA, 然后由系统自动生成定义, 和 3 链接

5. 创建 Modifier 所需的文件 MOD_xxx.c

这个文件包含所有算法, 以及事件处理, 修改 cmakelists 加入编译列表

6. 在 MOD_modifiertypes.h 中声明 Modifier 所需要的类型

将会在 5 中定义

7. 在 MOD_util.c 创建 INIT_TYPE

相当于从 2.a6 的链接

这是一个简易的关系图:

image.png

具体代码解析

1. 首先是编写 UI

我们在 properties_data_modifier.py 添加这么行代码

class DATA_PT_modifiers(ModifierButtonsPanel, Panel): 
...
def SCALING(self, layout, ob, md):
    layout.prop(md, "scaleui")
...

SCALING 这个函数是有意义的, 在第 4.a 步会出现, 同时这里的 md 就是我们在第 4.c 步创建的 RNA_ScalingModifier

2. DNA_modifier_types.h: 修改两处

第一处

ModifierType 枚举类中创建 eModifierType_Scaling, 这是 blender 最顶层能够访问到的元素

typedef enum ModifierType {
    eModifierType_None = 0,
    ...
    ...
    eModifierType_Wireframe         = 48,
    eModifierType_Scaling           = 49, // 这里的编号是需要连续
    NUM_MODIFIER_TYPES
} ModifierType;

第二处

创建 struct ScalingModifierData, 这个 struct 会在两处用到, 一个是生成 RNA_ScalingModifier, 第二个是在 MOD_scaling.c 中用到

typedef struct ScalingModifierData {
    ModifierData modifier;
    float scale;
    int pad; // blender 为了保证兼容性的 8 byte 对齐
} ScalingModifierData;

3. RNA_access.h

声明 RNA_ScalingModifier ,其实际定义由在 4.c 步骤生成

extern StructRNA RNA_ScalingModifier

4. rna_modifier.c

修改三处

第一处

在这里可以看到各种被分类好了的 Modifier, 找到对应的位置插入以下代码:

EnumPropertyItem modifier_type_items[] = {
    ...
    {0, "", 0, N_("Deform"), ""},
    ...
    {eModifierType_Scaling, "SCALING", ICON_MAN_SCALE, "Scaling the mesh", ""},
    ...
};

这一步同时让系统知道 eModifierType_Scaling 对应了 Python 中的哪个函数来绘制 UI

第二处

在函数体 rna_Modifier_refine 中添加对应代码:

static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
{
    ...
    switch (md->type) {
        ...
        case eModifierType_Scaling:
            return &RNA_ScalingModifier;
    ...
}

这里让系统得知 eModifierType_Scaling 对应的 RNA

第三处

定义 RNA

static void rna_def_modifier_scaling(BlenderRNA *brna)
{
    StructRNA *srna;
    PropertyRNA *prop;

    srna = RNA_def_struct(brna, "ScalingModifier", "Modifier");
    RNA_def_struct_ui_text(srna, "Scaling Modifier", "Scaling effect modifier");
    RNA_def_struct_sdna(srna, "ScalingModifierData");
    RNA_def_struct_ui_icon(srna, ICON_MAN_SCALE);

    /* scaleui: name for "properties_data_modifier.py"*/
    prop = RNA_def_property(srna, "scaleui", PROP_FLOAT, PROP_NONE); 

    /*scale: name for "DNA_modifier_types.h"*/
    RNA_def_property_float_sdna(prop, NULL, "scale");

    RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
    RNA_def_property_ui_range(prop, -100, 100, 1, 3);
    RNA_def_property_ui_text(prop, "Scale", "Scale factor");
    RNA_def_property_update(prop, 0, "rna_Modifier_update");

}

......

void RNA_def_modifier(BlenderRNA *brna)
{
    ...
    rna_def_modifier_remesh(brna);
    rna_def_modifier_skin(brna);
    rna_def_modifier_scaling(brna);
}

5. 创建对应文件, 修改对应文件夹下的 cmakelists

set(SRC
    ...
    intern/MOD_scaling.c
    ...
)

6. OD_modifiertypes.h

添加 ModifierTypeInfo 的声明

extern ModifierTypeInfo modifierType_Scaling;

7. MOD_util.c

让 blender 能够通过 eModifierType_Scaling 获取 ModifierTypeInfo

#define INIT_TYPE(typeName) (types[eModifierType_##typeName] = &modifierType_##typeName)
...
    INIT_TYPE(Scaling);
#undef INIT_TYPE

8. MOD_util.c

核心代码部分, 关于 ModifierTypeInfo 的定义可以在 BKE_modifier.h 中看到非常详细的定义

/*
 * ***** BEGIN GPL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software  Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
 * All rights reserved.
 *
 * Contributor(s): Your name
 *
 * ***** END GPL LICENSE BLOCK *****
 *
 */

/** \file blender/modifiers/intern/MOD_scaling.c
 *  \ingroup modifiers
 */


#include "DNA_meshdata_types.h"

#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"

#include "MEM_guardedalloc.h"

#include "BKE_cdderivedmesh.h"
#include "BKE_particle.h"
#include "BKE_deform.h"

#include "MOD_modifiertypes.h"
#include "MOD_util.h"


static void initData(ModifierData *md)
{
    ScalingModifierData *smd = (ScalingModifierData *) md;
    smd->scale = 1.0f;
}

static void copyData(ModifierData *md, ModifierData *target)
{
    ScalingModifierData *smd = (ScalingModifierData *) md;
    ScalingModifierData *tsmd = (ScalingModifierData *) target;
    tsmd->scale = smd->scale;
}

static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
    ScalingModifierData *smd = (ScalingModifierData *) md;
    /* disable if modifier is 1.0 for scale*/
    if (smd->scale == 1.0f) return 1;
    return 0;
}

static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
    ScalingModifierData *smd = (ScalingModifierData *)md;
    CustomDataMask dataMask = 0;
    return dataMask;
}

static void ScalingModifier_do(
        ScalingModifierData *smd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
    int i;
    float scale;
    scale = smd->scale;

    for (i = 0; i < numVerts; i++) {
        vertexCos[i][0] = vertexCos[i][0] * scale;
        vertexCos[i][1] = vertexCos[i][1] * scale;
        vertexCos[i][2] = vertexCos[i][2] * scale;
    }
}

static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                        float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
{
    DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, 0);

    ScalingModifier_do((ScalingModifierData *)md, ob, dm,
                      vertexCos, numVerts);

    if (dm != derivedData)
        dm->release(dm);
}

static void deformVertsEM(
        ModifierData *md, Object *ob, struct BMEditMesh *editData,
        DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
    DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, 0);

    ScalingModifier_do((ScalingModifierData *)md, ob, dm,
                      vertexCos, numVerts);

    if (dm != derivedData)
        dm->release(dm);
}


ModifierTypeInfo modifierType_Scaling = {
    /* name */              "Scaling",
    /* structName */        "ScalingModifierData",
    /* structSize */        sizeof(ScalingModifierData),
    /* type */              eModifierTypeType_OnlyDeform,
    /* flags */             eModifierTypeFlag_AcceptsMesh |
                            eModifierTypeFlag_SupportsEditmode,

    /* copyData */          copyData,
    /* deformVerts */       deformVerts,
    /* deformMatrices */    NULL,
    /* deformVertsEM */     deformVertsEM,
    /* deformMatricesEM */  NULL,
    /* applyModifier */     NULL,
    /* applyModifierEM */   NULL,
    /* initData */          initData,
    /* requiredDataMask */  requiredDataMask,
    /* freeData */          NULL,
    /* isDisabled */        isDisabled,
    /* updateDepgraph */    NULL,
    /* dependsOnTime */     NULL,
    /* dependsOnNormals */  NULL,
    /* foreachObjectLink */ NULL,
    /* foreachIDLink */     NULL,
    /* foreachTexLink */    NULL,
};

  • RNA_access.h: 各种 StructRNA 声明的地方
  • BKE_modifier.h: 关于 ModifierTypeInfo 的定义