KeyLine系统
介绍
在许多情况下根据时间或其它的情况(例如光照条件),需要动态改变某些“处于游戏中”的参数。例如基于时间需要改变某些参数;可将参数动画保存为动画帧的序列:值和动画帧的时间。要在任意时刻计算参数值,需要找到上一个键和下一个键并在这两种值之间进行插值。
KeyLine系统处理键的顺序并负责键值之间的插值同时也为数据操作提供GUI。其为某种数据驱动系统,元信息以XML格式进行保存。
KeyLine脚本位于Unigine SDK的 data/scripts/keyline目录下。
实体
Param(参数)
Param(参数)是原子参数的一种类型,原子参数值需要动态改变(参看ParamBase类)。 参数可被序列化成XML与也可使用元数据(ParamDef)将其反序列化。 存在与参数相关联的方法,这些方法指定在某些环境中使用参数值的方式(setter)或从中进行检索(getter)。
存在一套预定义“基本”参数类型,此类型在ParamFloat, ParamInt, ParamVec4 类的盒子外可用。
ParamDef
ParamDef 是一种参数的定义。(类型,ParamEditor, 最小/最大值,默认值,setter/getter 方法)。 ParamDef 类通过其定义用来创建参数实例。
ParamEditor
ParamEditor是一种GUI编辑器类型的定义,用来对参数值进行编辑。(参看ParamEditorBase类)。
Key(键)
Key(键)是一组由某个面向对象进行分组的参数 (参看 KeyBase类)。
KeyDef
KeyDef是一种键的定义(其参数定义的集合)。 KeyDef类通过其定义被用来创建键的实例。
KeyLine
KeyLine是一系列的键 (这些键具有相同的类型),每个键通过其位置进行识别。 KeyLine负责在键之间进行平滑插值。 如果KeyLine的光标位置(当前位置)位于结尾键的后面,KeyLine就会在结尾键和第一个键之间进行插值(参看KeyLine类)。
KeyLineManager
KeyLineManager处理一系列的KeyLines (参看 KeyLineManager)。 其也负责最小/最大位置的全局设置。
文件格式
keyman
*.keyman文件包含以XMLKeyLineManager为格式的设置。
keyline_manager节点必须为节点分级的根。此节点具有下列强制性整数属性:min (针对KeyLineManager内所有KeyLines的最小位置)和max (用于所有KeyLines的最大位置)。除此之外,整数属性的持续时间 指定一个时间段,在此时间段期间KeyLineManager将从最小位置处传递到最大位置处。
keyline_manager节点可包含0个或更多的子keyline节点,每个节点都包含file属性,此属性指向 *.keyline文件。例如:
<?xml version="1.0" encoding="utf-8"?>
<keyline_manager min="0" max="86399" duration="1440">
<keyline file="demos/tropics/tropics_sky.keyline"/>
<keyline file="demos/tropics/tropics_render.keyline"/>
</keyline_manager>
keyline
*.keyline文件包含以XML为格式的keyline数据。 文件内仅能保存一个keyLine。
keyline节点必须为节点分级的根。此节点具有强制性name属性: min 和 max属性与 keyline_manager属性具有相同的意义,当会忽略这些属性的值因为KeyLineManager对其进行覆盖。 keyline必须拥有 key_def节点并将其作为后代。
key_def节点可通过两种不同的方式进行定义:
<!--
key_def (键定义) 节点: 基准格式。
(所需)文件 - 用来指定文件,此文件包含使用下列格式的键定义。
-->
<key_def file="demos/tropics/tropics_timeline.keydef"/>
<!--
key_def 节点 - 完全格式化。
attributes:
keyline (所需,如果key_def被放置到单独文件中且为可选选项,如果key_def被放置到keyline节点内)。
用来识别 key_def。
-->
<key_def keyline="scattering">
<!--
在此放置参数的定义
-->
<!--
param_def (参数定义) 节点。
属性:
type (必需) - 参数类型的字符串识别器。通过其名称用来创建参数实例。
name (必需) - 唯一的参数名。用来识别键中的参数。
editor (必需) 参数编辑器类型的字符串识别器。用来生成GUI从而用于对键进行编辑。
-->
<param_def type="float" name="energy" editor="float_slider">
<!--
用于参数的getter 方法名 (可选)
-->
<getter>engine.render.getScatteringEnergy</getter>
<!--
用于参数的gsetter方法名 (可选)
-->
<setter>engine.render.setScatteringEnergy</setter>
<!--
用于参数的最小值(可选)
-->
<min name="energy">0</min>
<!--
用于参数的最大值(可选)
-->
<max name="energy">40</max>
<!--
用于参数的默认值(可选)
-->
<default_value name="energy">15</default_value>
</param_def>
</key_def>
keyline节点有后代key节点,此节点包含键的数据。 如果在keyline内不存在键,将自动创建一个键。 将使用参数对此键进行填充,此参数通过环境中的getter方法得到检索(当从先前调整的非序列参数开始时,这种做法很有用)。
key节点拥有下列格式:
<!--
关键节点。包括一系列参数值。
属性:
pos (必需且唯一) -帧在 keyline上的位置。
-->
<key pos="43200">
<!--
param 节点。包含参数数据。
属性:
name (必需且唯一) - 参数名,此参数名同样也被系统作为参数辨识器进行使用
-->
<param name="areal">30</param>
<param name="greenstein">0.9</param>
<param name="mie_color">1 0.972549 0.858824 1</param>
</key>
keydef
*.keydef文件包含以XML为格式用于键类型的定义。
definition节点必须为节点分级的根。 version 属性用于将来的使用。 definition 节点包含一套使用完整格式的key_def节点,在keyline文件定义内进行描述。
例如:
<?xml version="1.0" encoding="utf-8"?>
<definitions version="1.0">
<key_def keyline="scattering">
<!-- ... -->
</key_def>
<key_def keyline="sky">
<!-- ... -->
</key_def>
<key_def keyline="render">
<!-- ... -->
</key_def>
</definitions>
使用方式
开始
第一步。准备用于参数的getter和setters方法
namespace Foo {
void setterFunc(DataType v) {
// 设置参数的一些操作
}
DataType getterFunc() {
// 检索参数值
}
}
第二步。准备keyline文件管理器
创建keyline文件管理器(例如test.keyman)。 定义keylines:
<?xml version="1.0" encoding="utf-8"?>
<keyline_manager min="0" max="86399" duration="2160">
<keyline file="test.keyline"/>
</keyline_manager>
创建keyline 文件(例如test.keyline):
<?xml version="1.0" encoding="utf-8"?>
<keyline name="test keyline">
<key_def>
<param_def type="float" name="param 1" editor="float_editline">
<getter>Foo::getterFunc</getter>
<setter>Foo::setterFunc</setter>
</param_def>
</key_def>
</keyline>
第三步。将keyline管理器的标头包括到脚本中
// 包括所有必需的keyline管理器标头:
#include <keyline.h>
// 如果要使用浮点型, vec4 或整型参数类型及其编辑器,需包括基本参数(可选):
#include <params_basic.h>
第四步。初始化keyline管理器
KeyLineManager manager;
void init() {
// 将基本参数注册从而允许通过名称来创建(从文件中进行加载时需要)
KeyLine::registerBasicParams();
// 创建并加载keyline
manager = new KeyLine::KeyLineManager();
manager.load("test.keyman");
}
第五步。在需要时,更新位置并调用应用
int update() {
if(play_mode) {
manager.play(); // 更新位置
}
manager.apply(); // 提交参数(在管理器内为每个参数调用setter方法)
}
将GUI用于编辑
KeyLine提供GUI编辑器,这样用户可以操纵键并更改参数值。 参考下列内容在项目中使用GUI编辑器。
第一步。包括标头
#include <keyline/keyline_window.h>
第二步。编写初始化,关机及更新代码
void init() {
Gui gui = engine.getGui();
KeylineWindow::init(gui);
KeyEditorWindow::init(gui);
}
void shutdown() {
KeylineWindow::shutdown();
KeyEditorWindow::shutdown();
}
void update() {
KeylineWindow::update();
KeyEditorWindow::update();
}
第三步。显示窗口
void show_window() {
// 设置回调(可选)
KeylineWindow::setOnSaveCallback("on_save_manager");
KeylineWindow::setOnResetCallback("on_reset_manager");
KeylineWindow::setOnHideCallback("on_editor_closed");
KeylineWindow::setOnSetCaptionCallback("gen_pos_caption");
// 显示窗口
KeylineWindow::show(manager);
}
/* 回调(可选)
*/
void on_save_manager() {
/* 用户若想将keyline管理器保存到文件中,暂时中断 */
}
void on_reset_manager() {
/* 用户若想撤销更改并重新加载keyline管理器,暂时中断 */
}
void on_editor_closed(int is_changed) {
/* 编辑器窗口关闭时,暂时中断。如果keyline管理器内存在未保存的更改,is_changed == 1*/
}
string gen_pos_caption(float pos) {
/* 生成用于keyline窗口GUI的位置标题。返回一个格式化的字符串 */
}
使用自定义参数
如果基本参数未能满足所有需求,可编写自己的参数类型。
要完成这样的操作,必须继承来自KeyLine::ParamBase的类并覆盖或至少加载,保存并复制方法。 来创建继承自 KeyLine::ParamEditorBase类的参数编辑器。 接着必须编写用于创建参数的方法:
/* 用于自定义参数的creation方法
*/
ParamBase createCustomParam() {
// 在有需要的情况下,在此处添加一些额外的初始化
return new CustomParam("foo");
}
/* 用于自定义参数编辑器的creation方法
*/
ParamEditorBase createCustomParamEditor(ParamDef def,Gui gui) {
// 在有需要的情况下,在此处添加一些额外的初始化
return new CustomParamEditor(gui);
}
addParamType("foo","createCustomParam");
addEditorType("foo_editor","createCustomParamEditor");
GUI
KeyLine系统会自动生成GUI用于对键进行编辑。