使用 Morph 资源¶
变形将一个形状无缝转换为另一个形状。使用 Morph 资源在网格之间进行变形。
Kanzi 使用着色器来启用变形。请参阅 着色器 (Shaders)。
在您可以在 Kanzi 中进行网格变形之前,您需要在第三方工具中创建3D模型并将其导入到 Kanzi Studio。
当在第三方工具中创建网格以便在它们之间进行变形时,首先创建基础网格。从基础网格开始,塑造要变形到的网格。在创建网格时,请记住:
所有网格必须都具有相同数量的顶点和组合仪表。
请勿更改网格的拓扑。
添加变形¶
在您可以将变形添加到 Kanzi Studio 项目之前,需在第三方工具中创建带有变形的3D模型,并将其导出为gltf、glb、fbx或dae格式。
要在您的 Kanzi Studio 项目中添加变形:
在 Assets 中,单击 Import Assets 并导入使用变形网格的 3D 模型,该模型具有您希望在其间进行变形的变形目标。
每个变形目标都是变形基础形状的变形版本。
如果模型包含没有法线的网格,Kanzi Studio 提供生成法线的功能。Kanzi 在光照计算中使用法线。当您不让 Kanzi Studio 生成法线时,网格使用变形基网格的法线。请参阅 使用 morph target normals。
当 Kanzi Studio 导入变形时,它会创建:
在 Library > Meshes 中,来自 3D 模型的网格和使用导入网格的 Morph 资源。
在 Library > Materials and Textures 中,如果您的项目尚不包含此类材质类型,则需要支持变形的材质类型。
Kanzi Studio 创建使用此材质类型的材质,并将您的变形的基础网格设置为使用这些材质。
在材质类型中,Kanzi Studio 设置同时激活的变形目标的最大数量,以匹配导入变形中的网格数量。为了优化性能,您可以限制同时激活的变形目标的数量。请参阅 限制同时激活的变形目标的数量。
在 Prefabs 中,一个 Scene 预设包含使用 Morph 和 Mesh 资源的 Model 节点。
要在 Prefabs 中的 Preview 中显示 Scene 预设的内容,请双击该预设。
Kanzi Studio 在新的 Preview 选项卡中打开预设,并在 Preview 中显示该预设的内容。
在 Prefabs 中,选择一个显示 Morph 资源的 Model 节点。在 Morph Target Weights 属性中的 Properties 中,您可以调整 Morph 资源中每个网格的权重。
通过这种方式,您可以控制 Morph 的形状。
值越高,Morph 越接近该网格的形状。Kanzi 变形着色器设置基础变形形状的权重,使 Morph Target Weights 的总和为 1。这使得生成形状的比例保持与目标形状一致。
例如,可以使用关键帧动画来更改变形的形状。请参阅 创建变形权重动画。
将目标添加到 Morph 中¶
要添加您希望在其间变形的形状,请将网格添加到 Morph。
为了使变形正常工作,仅添加符合以下条件的网格:
由相同的基础网格塑造而成。
具有相同的拓扑结构以及相同数量的顶点和簇。
要将目标添加到 Morph:
在 Library > Meshes 中,创建或选择一个 Morph 资源。
在 Morph Target Weights 属性中的 Properties:
单击 Add。在下拉菜单中,选择要添加为 Morph 目标的网格,并调整网格的权重。值越高,Morph 越接近该网格的形状。
重复上一步以添加您要在其间进行变形的所有变形目标。
在 Library > Materials and Textures > Material Types 中,选择您的变形基网格使用的每个材质类型。在 Properties 的 Preprocessor Definitions 中,将 KANZI_SHADER_MORPH_TARGET_COUNT 设置为您希望 Kanzi 一次激活的变形目标数量。
如果您使用智能材质,Kanzi 会根据为材质设置的属性自动设置 Preprocessor Definitions。
当一个变形具有的目标多于 KANZI_SHADER_MORPH_TARGET_COUNT 的值时,Kanzi 会自动选择那些权重最大的变形目标进行激活。
(可选) 如果您的图形驱动程序不支持您设置的变形目标数量:
在 Properties 的 Preprocessor Definitions 中,将 KANZI_SHADER_USE_MORPH_DATA_TEXTURE 设置为 1。
通过这种方式,您可以启用材质类型使用变形数据纹理。数据纹理允许同时拥有任意数量的活动变形目标,但会带来性能成本。
在 Library > Meshes 中,选择您的 Morph 资源。在 Properties 中,添加并启用 Morph > Export as Data Texture 属性。
使用 morph target normals¶
当您将使用变形网格的3D模型导入到 Kanzi Studio 时,如果该模型中的某些网格没有法线,Kanzi Studio 会提供生成法线的选项。Kanzi 在光照计算中使用法线。当您在导入过程中不让 Kanzi Studio 生成缺失的法线时,变形目标会自动使用变形基础网格的法线。
小技巧
要手动生成网格的法线, 在 Library > Meshes 中右键单击该网格并选择 Generate Normals。
控制使用变形目标法线¶
要控制变形目标法线的使用:
在 Library > Materials and Textures > Materials Types 中,选择您的变形基网格使用的材质类型。
在 Properties 的 Preprocessor Definitions 中,将 KANZI_SHADER_USE_MORPH_TARGET_NORMALS 的值设置为:
0 将形变目标设置为使用形变基础网格的法线。
1 将每个变形目标设置为使用其自身的法线。
改进生成的变形目标法线¶
当 Kanzi Studio 为变形目标生成的法线与变形基础形状的法线不同时,随着您激活更多的变形目标,这种差异会累积。这可能导致法线的逐步视觉退化。
要改进生成的变形目标法线:
在 Library > Materials and Textures > Materials Types 中,选择您的变形基网格使用的材质类型。
在 Properties 的 Preprocessor Definitions 中,将 KANZI_SHADER_USE_MORPH_NORMAL_LIMIT 的值设置为 1。
这将限制法线的差异仅由单个目标形状引起。
限制同时激活的变形目标的数量¶
当您将包含变形的3D模型导入到 Kanzi Studio 时,Kanzi Studio 将该变形设置为使用支持同时激活所有变形目标的材质类型。如果您的变形包含大量目标,Kanzi 会将变形设置为在数据纹理中存储其变形目标的顶点属性。数据纹理允许同时拥有任意数量的活动变形目标,但会带来性能成本。一次激活的变形目标越多,处理顶点着色器所需的时间就越长。要优化性能,您可以:
限制一次可以激活的变形目标的数量。
禁用数据纹理的使用。
在没有数据纹理的情况下,同时激活的变形目标的最大数量是
在其中:
\(MaxChannels\) 是您的图形驱动程序支持的最大顶点属性通道数。
例如,16。
\(ConstantChannels\) 是包含所有变形目标相同属性数据的通道数量。
例如,纹理坐标、骨骼权重和骨骼索引对于所有变形目标都是相同的。
\(PerTargetChannels\) 是包含目标特定属性数据的通道数量。
例如,顶点位置、法线和切线可以在每个变形目标中有所不同。
要优化性能,当您不需要在您的变形中一次激活超过 \(N\) 个目标时,禁用数据纹理的使用。
当您的变形不使用数据纹理时,只有具有最大权重的 \(N\) 目标可以同时激活。
要限制同时激活的变形目标的数量:
在 Library > Materials and Textures > Material Types 中,选择您的变形基网格使用的每个材质类型。在 Properties 的 Preprocessor Definitions 中,将 KANZI_SHADER_MORPH_TARGET_COUNT 设置为您希望 Kanzi 一次激活的变形目标数量。
当一个变形具有的目标多于 KANZI_SHADER_MORPH_TARGET_COUNT 的值时,Kanzi 会自动选择那些权重最大的变形目标进行激活。
(可选) 如果您将 KANZI_SHADER_MORPH_TARGET_COUNT 设置为您的图形驱动程序在不使用数据纹理的情况下支持的值,请禁用数据纹理:
在 Library > Materials and Textures > Material Types 中,选择您的变形基网格使用的每个材质类型。在 Properties 的 Preprocessor Definitions 中,将 KANZI_SHADER_USE_MORPH_DATA_TEXTURE 设置为 0。
如果您这样做,请确保将 KANZI_SHADER_MORPH_TARGET_COUNT 设置为您的图形驱动程序在不使用数据纹理的情况下支持的值。否则,Kanzi Studio 会使用红色错误材质渲染您的模型,并在日志中打印警告。
在 Library > Meshes 中,选择 Morph 资源。在 Properties 中,禁用或移除 Export as Data Texture 属性。
创建变形权重动画¶
要更改变形的形状,使用关键帧动画。您可以从 gltf、glb、fbx 或 dae 文件中导入变形权重动画,或者在 Kanzi Studio 中创建动画。
要在 Kanzi Studio 中创建变形权重动画:
在 Library > Animations 中,按 Alt 并右键单击 Animation Clip 并选择 Animation。
例如,将动画命名为 Middle Animation,并在 Properties 中设置:
要将 Target Property 更改为 <Expression>,请单击
以添加 Morph Weight 属性,并将其设置为 <MorphWeight>[1]。Property Field 到 Whole property
您使用 Animation Clip 来存放变形中各网格的关键帧动画。每个动画以变形中的特定网格为目标,并定义该网格在不同时间点的权重。Middle Animation 是您要变形的第一个网格的关键帧动画。
根据您想在 Morph 中动画化的目标形状的数量重复上一步。对于 <MorphWeight>[n] 中的每个动画,将 n 设置为 Morph 中的网格,您希望通过动画更改其权重。不要为基础网格添加动画。
例如,要使用三个网格对变形进行动画化,请创建两个动画。将它们命名为 Middle Animation 和 Ready Animation,并设置:
Middle Animation Target Property 到 <Expression> <MorphWeight>[1]
Ready Animation Target Property 到 <Expression> <MorphWeight>[2]
使用 Middle Animation 设置变形中第二个网格的权重。使用 Ready Animation 在不同时间点设置变形中第三个网格的权重。Kanzi 变形着色器设置第一个网格的权重。
为您在上一步中创建的动画创建关键帧。请参阅 为目标属性字段创建关键帧动画。
您使用关键帧值在不同时间点设置变形中网格的 Weight 属性。
值越高,Morph 越接近该网格的形状。Kanzi 变形着色器设置基础变形形状的权重,使 Morph Target Weights 的总和为 1。这使得生成形状的比例保持与目标形状一致。
例如,要为包含三个网格的变形创建一秒钟的线性动画,请在 Library 中双击 Middle Animation,然后在 Animation Clip Editor 中创建以下关键帧:
Middle Animation:
第一个关键帧:
将 Time 设为 0。
Value 到 0
第二个关键帧:
Time 到 0.5
Value 到 1
第三个关键帧:
Time 到 1
Value 到 0
Ready Animation:
第一个关键帧:
将 Time 设为 0。
Value 到 0
第二个关键帧:
Time 到 0.5
Value 到 0
第三个关键帧:
Time 到 1
Value 到 1
使用您创建的关键帧动画对变形进行动画化:
在 Node Tree 中,选择其 Mesh 属性设置为您想要动画的 Morph 的 Model 节点。请参阅 添加变形。
在 Node Components 中,按 Alt 并右键单击 Animation 并选择 Animation Player。
在您创建的 Animation Player 中的 Node Components 中,将 Target Animation Timeline 属性设置为您在第一步中创建的 Animation Clip,并设置动画播放。请参阅 播放关键帧动画。
例如,设置:
将 Autoplay Enabled 设置为 enabled。
Playback Mode 到 Ping pong
将 Repeat Count Infinite 设置为 enabled。
在 API 中使用变形¶
要手动创建变形时间线并为时间线时钟创建回放:
// Create morph and add meshes (created beforehand) into it.
MorphSharedPtr morph = Morph::create(domain, "testMorph");
morph->add(mesh1, 0.0f);
morph->add(mesh2, 1.0f);
// Add node that will hold the morph, then add it to the scene graph (scene).
Model3DSharedPtr model = Model3D::create(domain, "testSphere");
model->setMesh(morph);
scene->addChild(model);
// Create float animation and add two keyframes.
FloatKeyframeAnimationSharedPtr animation = FloatKeyframeAnimation::create(domain);
animation->addLinearKeyframe(chrono::milliseconds(0), 0.0f);
animation->addLinearKeyframe(chrono::milliseconds(100), 1.0f);
// Create timeline and playback.
MorphWeightTimelineSharedPtr morphTimeline = MorphWeightTimeline::create(domain, "testSphere", 1, animation);
SceneGraphTimelinePlaybackContext context(*scene);
TimelinePlaybackSharedPtr playback = morphTimeline->createPlayback(context);
// Add playback to root clock
domain->getRootTimelineClock()->addTimelinePlayback(playback);
有关详细信息,请参阅 Morph 类。