当使用认知控制器时,这些设置控制了 character studio 如何影响状态的变换。更多详细信息,请参阅设置并使用认知控制器。
变换的最主要原素是 MAXScript 条件脚本。这是一个与控制器相关的脚本,该脚本每帧执行一次,它能测试任何比例或场景的纵横比以决定是否需要变换,测试结果成功(为真或 1)或失败(为假或 0)决定了变换是否进行。
character studio 在每个指定代理的每帧上执行一次脚本,这样可以设置对象和效果的动画,而且代理仍旧可以精确地做出反应。
fn [FunctionName] del t = ( [MAXScript code] if [MAXScript conditional] then 1 else 0 )
开放部分含有“fn”(函数)接下来是函数名,这些函数名也必须出现在状态变换对话框中,然后是输入参数“del t”,最后是“= (”。接下来可以是任何 MAXScript 代码,也可以什么都不包含。
闭合部分含有必需的 MAXScript 条件,然后是“then 1 else 0”。这意味着:如果条件结果为真,那么返回 1(也就是说发生了变换),或者如果条件结果为假,那么返回 0(也就是说没发生变换)。可以反转数字 1 和 0 的顺序(“then 0 else 1”),这样条件为真就不发生变换,反之亦然。最后,函数必须以括号结束:“)”。
下面是一些可以在认知控制器中使用的脚本例子,并附有简要说明。可以在您自己的场景中修改并使用这些例子。
该示例脚本测试由粒子系统 Spray01 发射的粒子数目,并且当粒子数目为 100 时返回正数。
fn TestParticles del t = ( if (particleCount $Spray01) == 100 then 1 else 0 )
该示例脚本测试名为 Sphere03 的对象位置,并且当位置在范围(X>=150,Y>=0,Z>=70)中时返回正数。
fn PositionCheck del t = ( if ($sphere03.pos.x >= 150 and $sphere03.pos.y >=0 and $sphere03.pos.z >=70) then 1 else 0 )
该示例脚本测试雾效果的密度参数,并且当参数值为 50 时返回正数。
fn TestAtmos del t = ( atmos_fog = getAtmospheric 1 print atmos_fog.density -- to:debug if (atmos_fog.density == 50) then 1 else 0 )
请注意第二行,该行将雾的大气效果赋值给名为“atmos_fog”的变量。只有在使用大气效果时才需要这样;对大多数对象而言,只需要简单的在对象名前加上一个“$”,就像前面两个示例中演示的那样。getAtmospheric 命令后的“1”表示大气在“渲染效果”对话框 “效果”列表中的位置。
如果执行了此赋值操作,就可以通过在 MAXScript 监听器中输入下述命令来获得大气属性的列表:
ShowProperties atmos_fog
该示例脚本使用 MAXScript 的距离函数来获得某个代理和另一个场景对象间的距离,并且当结果小于 30 时返回正数。
fn TestDist del t = ( get_dist=distance $sphere01.pos $delegate02.simpos print (get_dist) if get_dist < 30 then 1 else 0 )
如同上一个示例一样,该示例使用了一个变量;这里使用变量的目的只是为了使脚本看起来更简单。在第二行中,使用距离函数来获取球体和代理间的距离,并将结果赋值给变量“get_dist”。如果想测试所有使用认知控制器的代理而不仅仅是特定的一个,可以通过用“del.simpos”替代“$delegate02.simpos”来实现。
在脚本的第三行,出于调试的目的将计算所得距离输出到监听器窗口。该行对模拟来说不是必需的,而且可以将其删除。最后,值与常数 30 相比较,如果值小于 30 那么脚本返回 1,表明需要进行变换。
可以基于该脚本来创建认知控制器,使得控制器使用多个查找行为/状态来在任意的对象值间沿特定路径移动代理。一旦代理在指定对象的给定距离中,那么就会发生变换并使代理移动到下一个查找状态,这样就可以移向下一对象。因为在每一帧中都对变换进行测试,所以可以按照自己的意愿随意移动目标对象,这样就如同实现了动态动画效果。
该示例脚本检测应用于圆柱体的弯曲修改器的角度参数,并且当角度在 70 到 -70 度之间(包括 70 和 -70 度)时返回真。
fn TestBend del t = ( if ($cylinder01.bend.angle <= 70 and $cylinder01.bend.angle >= -70) then 1 else 0 )
请注意在第二行中语句在文本外使用了圆括号是因为脚本同时测试两个条件:角度是否小于等于 70 度,和角度是否大于等于 -70 度。因为在这两个测试条件间使用了“and”,所以只有当两者同时为真时脚本返回为真。
可能想在变换脚本中决定哪些行为正在影响某个特定的脚本。群组提供了一种基于 MAXScript 的方法来实现这一目的。甚至可以检查某个特定的代理是否被指定为行为的一个目标。例如在一个鸡尾酒聚会场景上,如果 Harry 正在寻找 Sally 那么 Betty 就会回避 Harry。但是如果 Harry 正在回避 Sally 那么 Betty 将会寻找 Harry。
以下示例脚本中使用的场景条件比上一段的示例更为复杂。下面是大致的情况。
使用墙排斥行为将六个代理限制在由四个栅格定义的“房间”中。在模拟过程中代理 1、2、3 和 5 简单的随机漫步。但是代理 4 使用认知控制器(CC1),该控制器让代理开始漫步,并且如果代理的三个任意对之一中的成员间的距离小于 50 单位,那么就切换到三种回避行为之一。每种避免行为都将由三个代理组成的不同组作为目标,其中两个包括代理 2。代理 6 被指定为第二个认知控制器 (cc2),该控制器使用下面的脚本来通知它,如果代理 4 正在避免代理 2,则切换到避免行为。该脚本的核心是函数 transfunc4 中的下面行:
加载该文件,按 F11 打开监听器窗口,然后求解。当发现代理 4 在回避代理 2 时监听器窗口显示一条消息。
通过在上面的行中替换代理的名称,或是在 transfunc4 的列表中替换回避行为的名称,并通过添加或删除必要的行,可以如同在自己的模拟中一样,使用该脚本来检查一个代理是否正在避免另一个。
该示例脚本说明了第二个要点:认知控制器变换脚本可以含有多个函数。群组首先执行在“状态变换”对话框 “变换条件”字段中指定的功能,该功能将调用脚本中的一个或多个其他功能,这些功能当然还可以调用功能。在该示例中,transfunc4 调用第一个函数 isDelegateAvoiding,并传递其三个参数。
最后,脚本包含特定的函数 getBehaviorType,该函数将输入行为与已知行为列表相比较,如果存在匹配的话则返回已知行为。在该示例中,transfunc4 通过当前影响 Delegate04 的行为列表,使用 getBehaviorType 测试其中的每一个行为,并且如果一个回避行为已经在起作用,那么就继续检查 Delegate02 是否是该回避行为的一个障碍。与测试特定行为相比,尤其是当场景包含许多同类型的行为或经常编辑行为设置时,该函数可以更高效更灵活的使用。通过在 transfunc4 中删除下面一行开始部分的注释标志(双连字符),可以查看返回的行为。