Skip to content
V0.27.0.0 Release Note

V0.27.0.0 Release Note

特别提醒

亲爱的创作者:

您好!本次0.27.0.0版本更新是一次具有里程碑意义的更新,主要包含材质优化和API重构两个大模块。在首次打开项目时,编辑器将自动升级绝大部分的版本升级内容。以下为项目升级注意事项:

  1. 自动升级前,会自动备份项目至相对路径下:\MetaWorldSaved\Saved\MetaWorld\Project\Backup
  2. 自动升级过程根据项目规模不同可能会持续较长时间(3-20分钟不等),请升级过程中不要关闭编辑器。
  3. 如果升级失败请先删除该项目,然后将备份项目复制到工程目录下重新打开再次进行升级。
  4. 自动升级包含大部分API和资源的替换,但并不是能处理好所有的API和资源,因此升级完成后项目可能残留部分错误的API和资源,这部分需要您根据更新日志的指引进行手动替换。

对于此次升级给您造成不便我们感到非常抱歉。口袋方舟一直在以一站式解决游戏创作者的全链路需求、协助创作者将最大精力释放到创意层面的目标而努力。我们致力于通过技术,让所有人能平等普惠的获得丰富多样的体验,让创作回归创作本身;

感谢各位对口袋方舟的信任,未来我们共同进步!

升级必看(重要!!!):

027版本更新手册:‌⁡⁤⁤⁢⁣⁤‍‌⁢⁤‌⁣⁣‍‍⁡⁢⁢‍‬‬‬⁡‌⁢⁡⁡⁡⁤⁤⁣⁡⁣027版本更新手册

所有API变动列表:API变动列表

注意事项

1. 为了避免新上手的同学们产生误解,027上调整了新建空工程的默认UI,调整内容有:

  • 摇杆和摄像机滑动区都开启了【允许被鼠标控制】,这带来的变化是——PC端鼠标左键将能操作摇杆和摄像机滑动区(鼠标右键仍能通过按键绑定控制摄像机滑动区),移动端上的效果不变
  • 移除了攻击按钮对于鼠标左键的绑定
  • 删除了原有的点赞按钮以及脚本中的相关逻辑,只保留两个按钮,并且重新摆放了一下位置
  • 攻击动画改为异步加载,防止每隔一段时间后被清理掉(新增下载资源3分钟不使用自动卸载的规则,目的是优化资源内存使用情况,如需内存中一直存在的资源可使用优先加载)

img

2. PC关闭游戏窗口快捷键修改:

027版本编辑器点击运行后,关闭游戏窗口的快捷键由ESC修改为:Shift+F5。

3. 在安装360(或其他杀毒软件)的前提下打开/运行编辑器时有可能出现风险提示

解决方案:将编辑器所在的目录添加至对应信任区

20231109-150229

4. 游戏功能对象:点光源暂时删除

受编辑器改动影响,点光源出现效果和性能问题。针对该问题编辑器对点光源做暂时下架处理,并重构对象内部实现和接口功能。由此027版本资源库将暂时下架点光源对象,若项目中有使用该对象需要将其删除。同时建议在代码中也不要使用该对象,以免游戏产生异常的效果或性能损失。我们会尽快在后续版本上架全新的点光源,敬请期待。

新增功能

[新增]碰撞属性:仅查询碰撞

  • 碰撞属性新增:仅开启查询碰撞
  • 剔除物理碰撞,仅针对空间查询返回“阻挡”结果
  • 针对【角色】具备与“开启碰撞”相同的阻挡效果
  • 针对“物理模拟”对象不产生碰撞反馈
  • 对比“开启碰撞”节约部分物理计算的性能

img

[新增]房间踢人功能

  • 开发者可在服务端调用RoomService.kick()控制房间内某一玩家断开与服务器的连接

    • TypeScript
      if(SystemUtil.isServer()) {
          let cheater = Player.getAllPlayers()[0];
          RoomService.kick(cheater, "系统检测您有作弊行为,已将您与服务器断开连接");
      }
      if(SystemUtil.isServer()) {
          let cheater = Player.getAllPlayers()[0];
          RoomService.kick(cheater, "系统检测您有作弊行为,已将您与服务器断开连接");
      }
  • 客户端收到被强制断开链接消息时,弹窗默认提示玩家「您已与服务器断开连接」

img

  • API调用时第二个参数作为窗口文本告知玩家掉线原因或信息(信息最大128Byte)

img

[新增]指定客户端同步属性

  • 新增一个【PlayerState】基类,可以通过继承PlayerState实现不同结构的数据同步类。

    • 对于频繁调用的且不追求可靠性的RPC,可以用PlayerState的属性同步来代替,避免频繁调用rpc导致的栈溢出断线。
    • 单个PlayerState只能同步给Player自身客户端。
TypeScript
// 创建一个TestPlayerState类,设置需要同步的数据结构
@Component
class TestPlayerState extends PlayerState {
    // 同步属性specialData。
    @Property({replicated: true, onChanged: "OnRep"})
    specialData: String;
    // 同步属性specialData变化的回调函数OnRep,当属性值变化时打印最新值。
    OnRep() {
        console.log("specialData " + this.specialData);
    }
}
// 创建一个TestPlayerState类,设置需要同步的数据结构
@Component
class TestPlayerState extends PlayerState {
    // 同步属性specialData。
    @Property({replicated: true, onChanged: "OnRep"})
    specialData: String;
    // 同步属性specialData变化的回调函数OnRep,当属性值变化时打印最新值。
    OnRep() {
        console.log("specialData " + this.specialData);
    }
}
  • 每个玩家链接到服务端后自动给每个玩家创建PlayerState实例
  • 可以通过Player.getPlayerState()拿到指定的数据同步类的实例
TypeScript
// 通过player,获取到TestPlayerState对应PlayerState实例对象.
let instance = player.getPlayerState(TestPlayerState);
// 修改TestPlayerState实例对象的specialData,改变化仅同步给player对应的客户端。
instance.specialData = Date.now().toString();
// 通过player,获取到TestPlayerState对应PlayerState实例对象.
let instance = player.getPlayerState(TestPlayerState);
// 修改TestPlayerState实例对象的specialData,改变化仅同步给player对应的客户端。
instance.specialData = Date.now().toString();
  • 通过操作指定Player对象的PlayerState实例,可以实现属性同步给指定客户端
TypeScript
// 获取房间内所有的Player,并对每一个player执行定点同步。
Player.getAllPlayers().forEach((v,i) => {
    // 该写法与普通的同步属性效果一致。
    v.getPlayerState(TestPlayerState).specialData = Date.now().toString();
});
// 获取房间内所有的Player,并对每一个player执行定点同步。
Player.getAllPlayers().forEach((v,i) => {
    // 该写法与普通的同步属性效果一致。
    v.getPlayerState(TestPlayerState).specialData = Date.now().toString();
});
  • 完整使用示例如下:按下按键1,属性仅同步给发送事件的客户端;按下按键2,属性同步给所有客户端。

    img

TypeScript
// 创建一个TestPlayerState类,设置需要同步的数据结构
@Component
class TestPlayerState extends PlayerState {
    // 同步属性specialData。
    @Property({replicated: true, onChanged: "OnRep"})
    specialData: String;
    // 同步属性specialData变化的回调函数OnRep,当属性值变化时打印最新值。
    OnRep() {
        console.log("specialData " + this.specialData);
    }
}

@Component
export default class NewScript extends Script {
    // 同步属性regularData。
    @Property({replicated: true, onChanged: "OnRep"})
    regularData: string;
    // 同步属性regularData变化的回调函数OnRep,当属性值变化时打印最新值。
    OnRep() {
        console.log("regularData " + this.regularData);
    }
    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isServer()) {
            // 添加客户端事件ChangeSpecialData的监听器
            Event.addClientListener("ChangeSpecialData", (player) => {
                console.log("ChangeSpecialData");
                // 通过player,获取到TestPlayerState对应PlayerState实例对象.
                let instance = player.getPlayerState(TestPlayerState);
                // 修改TestPlayerState实例对象的specialData,改变化仅同步给player对应的客户端。
                instance.specialData = Date.now().toString();
            });
            // 添加客户端事件ChangeRegularData的监听器
            Event.addClientListener("ChangeRegularData", () => {
                console.log("ChangeRegularData");
                // 修改脚本同步属性regularData,改变化会同步给所有客户端。
                this.regularData = Date.now().toString();
            });
        }
        if(SystemUtil.isClient()) {
            // 添加按键方法:按下按键1,给服务端发送事件ChangeSpecialData。
            InputUtil.onKeyDown(Keys.One, () => {
                Event.dispatchToServer("ChangeSpecialData");
            });
            // 添加按键方法:按下按键2,给服务端发送事件ChangeRegularData
            InputUtil.onKeyDown(Keys.Two, () => {
                Event.dispatchToServer("ChangeRegularData");
            });
        }
    }
}
// 创建一个TestPlayerState类,设置需要同步的数据结构
@Component
class TestPlayerState extends PlayerState {
    // 同步属性specialData。
    @Property({replicated: true, onChanged: "OnRep"})
    specialData: String;
    // 同步属性specialData变化的回调函数OnRep,当属性值变化时打印最新值。
    OnRep() {
        console.log("specialData " + this.specialData);
    }
}

@Component
export default class NewScript extends Script {
    // 同步属性regularData。
    @Property({replicated: true, onChanged: "OnRep"})
    regularData: string;
    // 同步属性regularData变化的回调函数OnRep,当属性值变化时打印最新值。
    OnRep() {
        console.log("regularData " + this.regularData);
    }
    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isServer()) {
            // 添加客户端事件ChangeSpecialData的监听器
            Event.addClientListener("ChangeSpecialData", (player) => {
                console.log("ChangeSpecialData");
                // 通过player,获取到TestPlayerState对应PlayerState实例对象.
                let instance = player.getPlayerState(TestPlayerState);
                // 修改TestPlayerState实例对象的specialData,改变化仅同步给player对应的客户端。
                instance.specialData = Date.now().toString();
            });
            // 添加客户端事件ChangeRegularData的监听器
            Event.addClientListener("ChangeRegularData", () => {
                console.log("ChangeRegularData");
                // 修改脚本同步属性regularData,改变化会同步给所有客户端。
                this.regularData = Date.now().toString();
            });
        }
        if(SystemUtil.isClient()) {
            // 添加按键方法:按下按键1,给服务端发送事件ChangeSpecialData。
            InputUtil.onKeyDown(Keys.One, () => {
                Event.dispatchToServer("ChangeSpecialData");
            });
            // 添加按键方法:按下按键2,给服务端发送事件ChangeRegularData
            InputUtil.onKeyDown(Keys.Two, () => {
                Event.dispatchToServer("ChangeRegularData");
            });
        }
    }
}

[新增]二次元形象新增描边

  • 二次元形象在角色编辑器和客户端根据画质分级(7级及以上)开启描边效果。
    • img
    • img
  • 描边效果在编辑器中无开关且不可编辑,不会暴露接口给开发者。可以通过 setOutline 修改描边效果, setPostProcessOutline 无法修改该描边。
  • 描边效果根据Mesh的变化自动适配,使用Mask材质的Mesh不开启描边功能。

[新增]角色编辑器挂件功能优化

  1. 支持特效挂件。

  1. 支持运行时自动生成挂件。

在角色编辑器中,设置菜单中包含选项*“默认显示挂件”,*勾选后,启动客户端时,在角色编辑器内设置的挂件将结合相关数据,自动插在对应插槽上。

img

  1. 支持在编辑器场景中自动生成挂件。

工程内容中的角色数据文件或资源库中的高级人形形象资源中包含挂件数据,则在主视口生成该角色时结合挂件数据生成挂件。

img

[优化]去掉工具栏中的新建控件

由于使用人数较少,且为了保持工具栏的简洁,因此去掉工具栏中的新建控件。

img

[优化]角色编辑器保存规则优化

  • 在角色编辑器的工程菜单中点击保存使用快捷键Ctrl+S时,将弹出角色数据保存弹窗,可以自由选择要保存的部位数据。
  • 点击保存选中项时,将当前选中的角色数据覆盖到该角色数据文件中。
    • img
  • 新增不再提示选项,若在保存时勾选该选项,则在重新打开该工程前,都不再进行保存弹窗提示,触发保存时,默认保存所有角色数据(角色身上的所有数据)。

[优化]新建角色优化为先文件后窗口的形式

  • 将新建角色文件的流程优化为:先文件后窗口的形式。

  • 点击主编辑器或角色编辑器工程内容中的新建形象时,在工程内容中创建一个空的角色文件。文件默认命名为“新建形象”。

    img

    img

  • 双击该文件,打开角色编辑器进行角色编辑。

  • 新建角色文件中不包含角色形象数据,点击预览时,预览窗口中不显示任何资源,也不允许直接拖入主视口使用。

    img

[优化]隐藏二次元前后发的高光颜色调节项

在角色编辑器中隐藏二次元前后发的【高光颜色】调节项,同时废弃(setHighlightColor,getHighlightColor) TS接口。

img

[新增]未命名资源处理

服务器设置英文为默认语言,拉取资源列表时检测资源默认语言的名称字段

  1. 该字段不为空,资源正常发给编辑器
  2. 该字段为空,资源将无法使用

编辑器当前语言环境检测资源对应语言的名称字段(比如当前编辑器语言是中文,检查该资源的中文名称字段)

  1. 该字段为空,展示默认语言名称
  2. 该字段不为空,展示该名称

[优化]属性栏资源名称显示优化

属性栏中的资源名称将正确展示资源的配置名称,而非资源本身的文件名

img

img

[调整]移除文件名搜索逻辑

移除搜索功能中对资源文件名相关配置信息的搜索逻辑

img

img

[新增]搜索排序功能

搜索后展示的资源将会根据搜索内容在资源名称中的占比进行排序,优先展示相关性高的资源

img

img

[新增]向聊天框发送快捷语消息

支持向游戏聊天框区域发送编辑的快捷语消息内容,发送时将自动显示发送者名称;

可用于制作游戏内NPC或玩家快捷语在聊天框展示等功能;

注意:用户233乐园版本过低,会导致快捷语发送失败

API示例

TypeScript
@Component
export default class messageExample extends Script {
   protected onStart(): void {
        let content = " MetaWorld is funny";
        if (SystemUtil.isClient()) {
            /**客户端调用生效*/
            ChatService.asyncSendMessage(content);
        }
    }
 }
@Component
export default class messageExample extends Script {
   protected onStart(): void {
        let content = " MetaWorld is funny";
        if (SystemUtil.isClient()) {
            /**客户端调用生效*/
            ChatService.asyncSendMessage(content);
        }
    }
 }

[新增]允许创建多个摄像机对象,并在主视口展示模型及弹簧臂

  • 摄像机系统由弹簧臂和摄像机组成,实际挂点是弹簧臂负责,而摄像机挂载在弹簧臂尾端。

    新增SpringArm弹簧臂对象,每个Camera都有一个SpringArm对象,可通过Camera.springArm调整弹簧臂的参数,如下所示:

    typescript
    protected onStart(): void {   
         /**摄像机碰撞 */
         Camera.currentCamera.springArm.collisionEnabled = false;
         /**摄像机从碰撞状态恢复为非碰撞状态的插值速度 */
         Camera.currentCamera.springArm.collisionInterpSpeed = 0;
         /**弹簧臂长度 */
         Camera.currentCamera.springArm.length = 180;
         /**使用控制器的旋转作为摄像机的旋转*/
         Camera.currentCamera.springArm.useControllerRotation = true;
         Camera.currentCamera.springArm.localTransform
         Camera.currentCamera.springArm.worldTransform
    }
    protected onStart(): void {   
         /**摄像机碰撞 */
         Camera.currentCamera.springArm.collisionEnabled = false;
         /**摄像机从碰撞状态恢复为非碰撞状态的插值速度 */
         Camera.currentCamera.springArm.collisionInterpSpeed = 0;
         /**弹簧臂长度 */
         Camera.currentCamera.springArm.length = 180;
         /**使用控制器的旋转作为摄像机的旋转*/
         Camera.currentCamera.springArm.useControllerRotation = true;
         Camera.currentCamera.springArm.localTransform
         Camera.currentCamera.springArm.worldTransform
    }
  • 与026版本相同,新建项目的【对象管理器-世界对象】中会有一个自带的无法被删除的摄像机对象;游戏开始时,会默认展示这个摄像机所看到的画面

  • 从027开始,可以从【资源库-游戏功能对象】中拖出或者在脚本中动态创建任意个摄像机对象。摄像机的模型及弹簧臂(红色细线)会展示在场景中,便于大家理解摄像机对象的各项参数。修改世界对象-摄像机的模型的接口也将在后续版本中暴露出来。注意:从游戏功能对象中拖出来的弹簧臂长度为0,这时红色细线为一个点

  • 世界对象-摄像机与游戏功能对象-摄像机都可以通过脚本中Camera类的属性/接口来调整效果,用法详见 摄像机 | 产品手册

imgimg

img

  • 可通过Camera.switch在多个摄像机之间相互切换,此外switch方法提供参数自定义缓动动画,目前存在以下几种缓动函数枚举:

    img

    Camera.switch中的第三个参数blendExp在混合函数为LinearCubic时不生效。

    Camera中存在onSwitchComplete回调,当切换摄像机并且切换的缓动动画结束,对应主控摄像机会触发回调(在缓动动画进行时切换摄像机,上次切换摄像机的回调不会触发)。

    typescript
    @Component
    export default class SwitchCamera extends Script {
        public sceneCamera: Camera;
        public baseCamera: Camera;
        private _isMainCamera: boolean = true;
        /** 当脚本被实例后,会在第一帧更新前调用此函数 */
        protected onStart(): void {
            if (SystemUtil.isClient()) {
                this.baseCamera = Camera.currentCamera;
                this.sceneCamera = GameObject.findGameObjectById("0FAA2322") as Camera;
                this.baseCamera.onSwitchComplete.add(() => {
                    console.log("切换为默认摄像机")
                })
                this.sceneCamera.onSwitchComplete.add(() => {
                    console.log("切换为场景中摄像机")
                })
                InputUtil.onKeyDown(Keys.Q, () => {
                    if (this._isMainCamera) {
                       Camera.switch(this.sceneCamera, 5, CameraSwitchBlendFunction.EaseOut, 3);
                    } else {
                       Camera.switch(this.baseCamera);
                    }
                    this._isMainCamera = !this._isMainCamera;
                });
            }
        }
    }
    @Component
    export default class SwitchCamera extends Script {
        public sceneCamera: Camera;
        public baseCamera: Camera;
        private _isMainCamera: boolean = true;
        /** 当脚本被实例后,会在第一帧更新前调用此函数 */
        protected onStart(): void {
            if (SystemUtil.isClient()) {
                this.baseCamera = Camera.currentCamera;
                this.sceneCamera = GameObject.findGameObjectById("0FAA2322") as Camera;
                this.baseCamera.onSwitchComplete.add(() => {
                    console.log("切换为默认摄像机")
                })
                this.sceneCamera.onSwitchComplete.add(() => {
                    console.log("切换为场景中摄像机")
                })
                InputUtil.onKeyDown(Keys.Q, () => {
                    if (this._isMainCamera) {
                       Camera.switch(this.sceneCamera, 5, CameraSwitchBlendFunction.EaseOut, 3);
                    } else {
                       Camera.switch(this.baseCamera);
                    }
                    this._isMainCamera = !this._isMainCamera;
                });
            }
        }
    }

[优化]摄像机物体透明功能效果升级

【摄像机物体透明】功能解决了此前版本中与模型合批功能的冲突问题,在027上可以正常使用了;并且将透明效果升级为新材质编辑中打孔半透明效果

摄像机触发物体透明的要求是:物体挡在摄像机和弹簧臂挂点之间,处于一条直线上

启用该功能首先要关闭摄像机弹簧臂的碰撞,其次再开启透明

imgimg

[优化]二次元捏脸效果优化

二次元新旧捏脸对比

本次优化二次元的捏脸效果,会对老项目角色的捏脸效果产生影响,在使用新版捏脸参数测试部分项目后,发现大部分调节项影响效果比较小,但由于眼睛上下缩放目前支持了闭眼效果,若有角色的该调节项数值调整较大,需要核查一下效果是否正确。

img

[新增]资源自动回收

  • 资源自动回收是为了自动管理资源的生命周期,未使用的资源都会在一段时候后进行释放。通过统计资源引用的对象数量(资源引用计数)能够发现未被使用的资源,及时释放从而减少对内存的占用。
TypeScript
// 生成一个音效,此时音频资源"178802"被该对象引用
let sound = await GameObject.asyncSpawn("178802");
// 切换一个音频资源,"178803"被该对象引用,经过一定时间后“178802”会被卸载
sound.setSoundAsset("178803");

// 按下按键1,切换音频资源然后播放,此时若“178802”被卸载,则播放效果会延迟一小段时间(重新加载资源)
InputUtil.onKeyDown(Keys.One, () => {
    sound.setSoundAsset("178802");
    sound.play();
});
// 生成一个音效,此时音频资源"178802"被该对象引用
let sound = await GameObject.asyncSpawn("178802");
// 切换一个音频资源,"178803"被该对象引用,经过一定时间后“178802”会被卸载
sound.setSoundAsset("178803");

// 按下按键1,切换音频资源然后播放,此时若“178802”被卸载,则播放效果会延迟一小段时间(重新加载资源)
InputUtil.onKeyDown(Keys.One, () => {
    sound.setSoundAsset("178802");
    sound.play();
});
  • 处于优先加载列表中的资源被认定为是必须资源,不在资源自动回收管理范围内,不会被卸载。

img

  • 如果需要确保对象资源加载完成,可以使用【AssetUtil】类中的方法对资源进行判断后使用:
TypeScript
// 生成一个音效,此时音频资源"178802"被该对象引用
let sound = await GameObject.asyncSpawn("178802");
// 切换一个音频资源,"178803"被该对象引用,经过一定时间后“178802”会被卸载
sound.setSoundAsset("178803");

// 按下按键1,切换音频资源然后播放
InputUtil.onKeyDown(Keys.One, () => {
    sound.setSoundAsset("178802");
    // 若资源已加载,则直接播放
    if(AssetUtil.assetLoaded("178802")) {
        sound.play();
    } else {
        // 若资源未加载,调用资源下载(含加载)方法,异步播放
        AssetUtil.asyncDownloadAsset("178802").then(() => {
            sound.play();
        });
    }
});
// 生成一个音效,此时音频资源"178802"被该对象引用
let sound = await GameObject.asyncSpawn("178802");
// 切换一个音频资源,"178803"被该对象引用,经过一定时间后“178802”会被卸载
sound.setSoundAsset("178803");

// 按下按键1,切换音频资源然后播放
InputUtil.onKeyDown(Keys.One, () => {
    sound.setSoundAsset("178802");
    // 若资源已加载,则直接播放
    if(AssetUtil.assetLoaded("178802")) {
        sound.play();
    } else {
        // 若资源未加载,调用资源下载(含加载)方法,异步播放
        AssetUtil.asyncDownloadAsset("178802").then(() => {
            sound.play();
        });
    }
});
  • 如果希望确保对象资源完成再使用它,请使用asyncSpawn并在回调中操作该对象。

[优化]UI创建相关性能优化

  • 027版本上通过反序列化调用和属性读取方面的优化,如果各UI控件的属性使用的是默认值,将不再会记录在UI文件中,缩短了UI创建相关函数35%左右的耗时;此优化对已经创建完成UI的每帧耗时没有影响
  • 为了应用这一优化,UI导出脚本工具导出的_generate脚本写法发生了变化,大家需要重新导出一次脚本后本次优化才能生效;下左图为UI导出脚本工具在027自动生成的脚本,下右图为026自动生成的脚本

img

img

  • 为了兼容此前的项目,标记UI控件的UIMarkPath装饰器功能仍然保留(在027上,旧装饰器由UIMarkPath改名为UIWidgetBind),大家可以自行选择是否更新_generate脚本,但推荐大家在后续项目开发中不再使用旧装饰器,这样创建UI的性能会更好一些
  • UI导出脚本功能的用法详见产品手册:

创建游戏界面 (UI) | 产品手册 (ark.online)

[新增]主编辑器增加寻路构建提示,可直接检测超大地形寻路构建完成

在主编辑器视口中增加寻路区域构建提示信息,对超大地形进行寻路构建时,可通过观察提示信息来判断寻路是否构建完成。

img

[新增]游泳区增加进入与离开的回调接口

TypeScript
let swimmingVolumeMain = this.gameObject as mw.SwimmingVolume;
swimmingVolumeMain.onEnter.add(()=>{
    //进入游泳区域
});
swimmingVolumeMain.onLeave.add(()=>{
    //离开游泳区域
});
let swimmingVolumeMain = this.gameObject as mw.SwimmingVolume;
swimmingVolumeMain.onEnter.add(()=>{
    //进入游泳区域
});
swimmingVolumeMain.onLeave.add(()=>{
    //离开游泳区域
});

[优化]角色功能重构

角色功能以及API部分进行重构,包括角色基础功能、角色形象换装功能、角色动画功能等方面。详细请见新产品手册:

重点内容介绍

1.角色对象合并

为消除角色对象之间的区别,统一使用Character类代表场景中的角色对象,将原先CharacterBase代表角色基础能力的接口迁移进Character

  • 判断角色是玩家还是NPC:Character对象继承Pawn对象新增player属性,玩家角色的player为控制玩家,NPC角色的player为null。

  • 切换玩家角色:player对象可以在服务端通过control接口控制未被其他玩家控制的角色对象。

    • TypeScript
      /**
      * @description 控制一个Pawn对象
      * @effect 只在服务端调用生效
      * @precautions 在服务端上立即更新控制对象。客户端由于网络延迟会有时间差。只能控制当前没有被玩家控制的角色。对其他玩家控制的角色使用该接口不会生效。返回本次控制的结果。
      * @param pawn usage:目标控制对象
      * @returns 操纵结果
      */
      control(pawn: mw.Pawn): boolean;
      /**
      * @description 控制一个Pawn对象
      * @effect 只在服务端调用生效
      * @precautions 在服务端上立即更新控制对象。客户端由于网络延迟会有时间差。只能控制当前没有被玩家控制的角色。对其他玩家控制的角色使用该接口不会生效。返回本次控制的结果。
      * @param pawn usage:目标控制对象
      * @returns 操纵结果
      */
      control(pawn: mw.Pawn): boolean;

2.去除rpc同步

  • 玩家角色只有Transform属性(position, rotation, scale)在主控端修改会同步。服务端修改会通知主控端执行移动。非玩家角色NPC仅在服务端修改会同步。
  • 在客户端修改玩家角色移动相关的属性,例如移动速度,跳跃高度等,在其他端表现一致。由于移动是主控端为权威端,所以即使与服务端属性不一样,仍不影响其他端表现。
  • 其他属性027后在客户端修改不会同步,需要在服务端修改,例如动画,姿态,头顶名字displayName,布娃娃状态ragdollEnabled,胶囊体偏移meshOffset等。

3.动画姿态解耦

  • 动画,姿态与二级姿态分别由Animation, Stance, Substance控制,通过loadAnimation()loadStance()loadSubStance()加载。调用对应的对象来实现动画、姿态的播放和控制。
  • 可以通过Character的currentAnimation, currentStance, currentSubStance获取到当前角色的动画或姿态对象。
  • 客户端加载动画/姿态不会同步。
  • 删除角色动画模式animationMode,用户不再需要手动切换。动画模式会根据角色类型:人形 -> Auto(自带动画状态机),四足 -> Custom(手动播动画),由编辑器自动切换。

4.换装重构

  • 原角色外观对象替换为CharacterDescription。通过character.description进行调用。

    • TypeScript
      /**新角色换装示例:*/
      let myCharacter=Player.localPlayer.character;
      // 修改角色style头部:头大小为1.5倍
      myCharacter.description.advance.headFeatures.head.headOverallScale = 1.5;
      // 修改角色style体型:身高为1.2倍
      myCharacter.description.advance.bodyFeatures.body.height = 1.2;
      // 修改角色style化妆:腮红为75674
      myCharacter.description.advance.makeup.blush.blushStyle = "75674";
      // 修改角色style头发:前发为57731,后发为63910
      myCharacter.description.advance.hair.frontHair.style = "57731";
      myCharacter.description.advance.hair.backHair.style = "63910";
      // 修改角色style:上衣为58694,下衣为58700,手套为60384,鞋子为58696
      myCharacter.description.advance.clothing.upperCloth.style = "58694";
      myCharacter.description.advance.clothing.lowerCloth.style = "58700";
      myCharacter.description.advance.clothing.gloves.style = "60384";
      myCharacter.description.advance.clothing.shoes.style = "58696";
      /**新角色换装示例:*/
      let myCharacter=Player.localPlayer.character;
      // 修改角色style头部:头大小为1.5倍
      myCharacter.description.advance.headFeatures.head.headOverallScale = 1.5;
      // 修改角色style体型:身高为1.2倍
      myCharacter.description.advance.bodyFeatures.body.height = 1.2;
      // 修改角色style化妆:腮红为75674
      myCharacter.description.advance.makeup.blush.blushStyle = "75674";
      // 修改角色style头发:前发为57731,后发为63910
      myCharacter.description.advance.hair.frontHair.style = "57731";
      myCharacter.description.advance.hair.backHair.style = "63910";
      // 修改角色style:上衣为58694,下衣为58700,手套为60384,鞋子为58696
      myCharacter.description.advance.clothing.upperCloth.style = "58694";
      myCharacter.description.advance.clothing.lowerCloth.style = "58700";
      myCharacter.description.advance.clothing.gloves.style = "60384";
      myCharacter.description.advance.clothing.shoes.style = "58696";
    • TypeScript
        相关接口:
      /**
      * @description 设置外观数据
      * @effect 调用端生效
      * @precautions setStyle设置角色的外观,可以传入CharacterDescription对象 / 角色外观文件的数组 / 挂件数据文件的guid。
      * @param data usage:外观数据
      * @networkStatus usage:双端
      */
      setDescription(data: mw.CharacterDescription | Array<string> | string): void;
      
      /**
      * @description 获取外观数据
      * @effect 调用端生效
      * @precautions 该接口获取角色当前外观数据的拷贝
      * @returns 角色外观数据的拷贝
      * @networkStatus usage:双端
      */
      getDescription(): mw.CharacterDescription;
      /**
      * @description 清空外观数据
      * @effect 调用端生效
      * @precautions 清空角色外观数据,此时角色不具备任何视觉表现。
      * @param appearance usage:是否清空形象数据 default:true
      * @param slotAndDecoration usage:是否清空插槽和物品数据 default:true
      * @networkStatus usage:双端
      */
      clearDescription(appearance?: boolean, slotAndDecoration?: boolean): void;
      /**
      * @description 同步外观数据
      * @effect 只在客户端调用生效
      * @precautions 角色在客户端设置外观后只会更换本地角色的外观,其他客户端角色外观未修改。通过该接口可以将本地外观广播至其他客户端。
      * @param appearance usage:角色同步 default:true
      * @param slotAndDecoration usage:插槽和装饰同步 default:true
      * @networkStatus usage:客户端
      */
      syncDescription(appearance?: boolean, slotAndDecoration?: boolean): void;
        相关接口:
      /**
      * @description 设置外观数据
      * @effect 调用端生效
      * @precautions setStyle设置角色的外观,可以传入CharacterDescription对象 / 角色外观文件的数组 / 挂件数据文件的guid。
      * @param data usage:外观数据
      * @networkStatus usage:双端
      */
      setDescription(data: mw.CharacterDescription | Array<string> | string): void;
      
      /**
      * @description 获取外观数据
      * @effect 调用端生效
      * @precautions 该接口获取角色当前外观数据的拷贝
      * @returns 角色外观数据的拷贝
      * @networkStatus usage:双端
      */
      getDescription(): mw.CharacterDescription;
      /**
      * @description 清空外观数据
      * @effect 调用端生效
      * @precautions 清空角色外观数据,此时角色不具备任何视觉表现。
      * @param appearance usage:是否清空形象数据 default:true
      * @param slotAndDecoration usage:是否清空插槽和物品数据 default:true
      * @networkStatus usage:双端
      */
      clearDescription(appearance?: boolean, slotAndDecoration?: boolean): void;
      /**
      * @description 同步外观数据
      * @effect 只在客户端调用生效
      * @precautions 角色在客户端设置外观后只会更换本地角色的外观,其他客户端角色外观未修改。通过该接口可以将本地外观广播至其他客户端。
      * @param appearance usage:角色同步 default:true
      * @param slotAndDecoration usage:插槽和装饰同步 default:true
      * @networkStatus usage:客户端
      */
      syncDescription(appearance?: boolean, slotAndDecoration?: boolean): void;
  • getDescription()会获取当前外观数据的拷贝,修改这个拷贝值并不会影响当前角色外观。使用场景:将当前角色外观数据应用于其他角色时(例如领奖台的实现)。

  • 角色换装完成委托统一整合为onDescriptionComplete

    • 注意:同步外观数据syncDescription后会再次调用onDescriptionComplete。避免在onDescriptionComplete委托方法中执行外观数据同步,造成无限循环。

    • TypeScript
      /** 错误写法*/
      this.localPlayer.character.onDescriptionComplete.add(()=>{
          this.localPlayer.character.syncDescription();
      })
      
      /** 正确写法*/
      this.localPlayer.character.setDescription([appearanceGuid]);
      this.localPlayer.character.syncDescription();
      /** 错误写法*/
      this.localPlayer.character.onDescriptionComplete.add(()=>{
          this.localPlayer.character.syncDescription();
      })
      
      /** 正确写法*/
      this.localPlayer.character.setDescription([appearanceGuid]);
      this.localPlayer.character.syncDescription();
  • 服务端的外观属性可以看作一个整体,如果修改了部分属性,会将所有的属性进行同步。如果存在不需要同步的外观属性,可以RPC到客户端进行修改。

5.角色挂载方式

  • character.attachToSlot(go, HumanoidSlotType.Root)可以将物体挂载到角色对应插槽上(这时被挂载的对象并不在角色的子级,而是在对应插槽的子级)。
  • go.parent = character通过设置parent为character将物体父级设置为角色。027之前mwactor和character是没有父子关系的,027将actor组件化后,可以为character设置父子级关系。

[优化]ISM 3.0

  • 为了支持去除动静态功能,以及优化部分渲染差异效果,研发的底层功能。

  • 核心的技术是使用图形API的IndirectDraw技术,在CPU端绑定网格体,材质等资源,在GPU端设置绘制参数,从而实现在GPU端完成视锥体剔除,距离剔除,遮挡剔除,从而优化DrawCall开销。

    img

[优化]角色形象属性与角色编辑器资源同步

  • 我们在角色面板中支持调整角色自定义形象,功能上与角色编辑器一致,所以我们将角色面板的形象设置的属性与角色编辑器内部的形象属性同步。无论是修改面板属性还是角色编辑器的属性,另一个属性设置都会进行同步调整,进而保证两者的一致性。

[优化]调整胶囊体大小,更加贴合角色的模型

  • 调整角色的胶囊体大小,吻合角色模型的实际身高。解决部分建筑无法通过的问题。

    img

img

[新增]默认工程新增脚步声等音效

  • 编辑器内置角色音效,在角色执行相关功能时,会自动播放音效。内置音效包括:起跳音效、落地音效、落水特效、游泳特效、跑步特效。
    • 起跳音效:角色在执行跳跃功能时,播放的音效。
    • 落地音效:角色下落状态后碰触到地面时,播放的音效。
    • 落水特效:角色下落状态后碰触到水面时,播放的音效。
    • 游泳特效:角色在执行游泳功能时,播放的音效。
    • 跑步特效:角色在执行跑步功能时,播放的音效。
  • 角色属性面板中新增【角色音效】属性,用户可以通过属性面板调整相关的音效(只能通过角色面板控制修改音效,未提供API修改)。

image-20230928155831983

[新增]角色简单移动策略

  • 我们提供了简单移动策略,在该移动模式下,摩擦力、加速度等参数会失效,并且不会进行浮空检测,同时角色动画模式将会变为自定义动画模式,方便开发者自定义移动效果和角色表现(角色简单移动开启后角色没有碰撞)
  • 简单移动策略可以做什么?
    • 站桩npc可以0移动消耗(因为关闭了复杂的移动逻辑,忽略重力摩擦力等外力因素)
    • 用户可以自定义移动(广场里npc固定点巡逻)
  • 相关接口:
TypeScript
// 获取玩家
let chara = Player.localPlayer.character
// 关闭复杂移动策略,开启简单移动策略
chara.complexMovementEnabled = false;
// 获取玩家
let chara = Player.localPlayer.character
// 关闭复杂移动策略,开启简单移动策略
chara.complexMovementEnabled = false;
  • 示意图:

[新增] (带体积)的射线检测

  • 027之前MW仅支持宽度为0的LineTrace。本次新增SphereTrace,CapsuleTrace和BoxTrace,性能消耗依次增加。四种检测均返回hitResult对象用于进行进一步计算。其中BoxTrace相比另外两种还能单独指定盒体的旋转以实现不同的检测空间轨道。

img

  • (带体积)的射线检测可以做什么?

    • 适配不同形状的子弹/武器进行弹道/横扫区域检测

    • 使用区域检测获取精确信息例如接触点和法线向量(和overlap的区别)027上overlap性能比trace要好。

      imgimg

  • 示例代码可参照API文档:

https://api-docs.ark.online/classes/mw.QueryUtil.html

TypeScript
let boxResult = QueryUtil.boxTrace(new Vector(0,0,0), new Vector(300,0,0), new Vector(10,10,10), new Rotation(0,0,0), true, false, [], false, Player.localPlayer.character);
let boxResult = QueryUtil.boxTrace(new Vector(0,0,0), new Vector(300,0,0), new Vector(10,10,10), new Rotation(0,0,0), true, false, [], false, Player.localPlayer.character);

[优化] 交互物支持动画资源 & 减少交互延迟

交互物支持动画资源,交互后角色会播放循环动画。通过直接解析动画资源中角色插槽偏移,实现交互延迟的降低。此外使用姿态资源仍然支持正常交互,但无法获取延迟优化效果。

[优化] 逻辑对象:对象发射器

  • 【ProjectileLauncher】改名【ObjectLauncher】对象发射器。支持单端使用,并支持发射单端/双端对象。
  • 发射时制造的投掷物,形状由球体->水平胶囊体。

img

  • 使用发射器不再需要bindPlayerunbindPlayer,当客户端调用发射方法时,发射器会给制造的投掷物实例中owner属性赋值该客户端便于用户执行游戏逻辑。在服务端调用发射方法时owner为空。
  • 新增【ProjectileInst】投掷物实例:支持获取运动速度和发射人。发射器工作流程如下:
    • 发射器调用launch方法(传入发射对象),根据参数创建一个投掷物实例。
    • 根据调用端给投掷物实例owner属性赋值。
    • 将传入的发射对象挂载到投掷物实例上。
    • 投掷物实例开始运动。
    • 投掷物实例触发发射器对应事件执行绑定函数。
    • 投掷物停止运动,解绑子对象后自行销毁。

img_v2_24a4c672-0bc6-4ede-abc6-b5082f9ee70g

  • 无论碰撞结果是“重叠”或“阻挡”,统一使用onProjectileHit获取回调。

  • 支持追踪发射。投掷物通过追踪加速度和追踪目标进行跟踪运动。

  • 新增轨迹预测功能。发射器按照输入的预测时间和密度返回运动轨迹的路径点(直到首次碰撞为止)。

TypeScript
// 获取预测的所有轨迹点
let predictPoints = myLauncher.predictedTrajectory(new Vector(200, 0, 30), new Vector(1, 0, 1), 10, 10);
// 按轨迹点生成轨迹
predictPoints.forEach((v,i) => {
    console.error("loc " + v);
    GameObject.asyncSpawn("84121").then((obj: Model) => {
        obj.worldTransform.position = v;
        obj.worldTransform.scale = new Vector(0.1, 0.1, 0.1);
        obj.setCollision(CollisionStatus.Off);
    });
});
// 获取预测的所有轨迹点
let predictPoints = myLauncher.predictedTrajectory(new Vector(200, 0, 30), new Vector(1, 0, 1), 10, 10);
// 按轨迹点生成轨迹
predictPoints.forEach((v,i) => {
    console.error("loc " + v);
    GameObject.asyncSpawn("84121").then((obj: Model) => {
        obj.worldTransform.position = v;
        obj.worldTransform.scale = new Vector(0.1, 0.1, 0.1);
        obj.setCollision(CollisionStatus.Off);
    });
});

img

  • 对象发射器的使用场景(可以做什么)?
    • 基本可以覆盖绝大多数飞行道具的需求

扔球

火箭发射

  • 示例代码可参照API文档或示例工程:

https://arkimg.ark.online/ObjectLauncher.zip

https://arkimg.ark.online/ProjectileInst.zip

https://api-docs.ark.online/classes/mw.ObjectLauncher.html#onprojectilehomingfail

[新增] 投掷功能类

对象发射器为了实现编辑状态下支持拖拽使用,以【GameObject】形式进行封装。此外为了方便用户自定义碰撞形状,且能获取投掷物的速度和发射人,【对象发射器】会制造一个投掷物对象(继承【GameObject】)采用父子挂载方式携带对象运动。可能导致性能风险:一次发射实际存在两个actor:一个actor是投掷物,一个是对象。

  • 为满足项目的性能要求,提供一个最简版本的【投掷功能类】对象:ProjectileMovement。改对象不额外生成actor,仅在发射对象下生成投掷物移动组件,通过成员方法控制运动状态,回调以及投掷参数。工作流程如下:

    • 传入一个待发射【GameObject】创建【投掷功能类】。

    • 设置【投掷功能类】参数包括运动参数,持有人,回调函数等。

    • 发射对象,开始抛物线运动。

    • 触发【投掷功能类】对应事件执行绑定函数。

    • 投掷物停止运动,【投掷功能类】不销毁,可连续发射。

      img_v2_e02080b6-b7dd-41d8-b66c-d9b3f788b86g

  • 创建【投掷功能类】对象时需要传入一个【GameObject】,构造方法会将其转化成可投掷的对象。此外也可以通过成员方法去切换组件关联的对象。切换对象后,原对象失去投掷能力,新对象转化为可投掷的对象。

TypeScript
// 创建投掷物。将传入对象转化成可投掷的对象。
let projectile = new ProjectileMovement(balls[curBall]);

// 投掷功能类切换自己的关联对象,原对象失去投掷能力,新对象转化为可投掷的对象。
projectile.setRelatedGameObject(balls[curBall]);
// 创建投掷物。将传入对象转化成可投掷的对象。
let projectile = new ProjectileMovement(balls[curBall]);

// 投掷功能类切换自己的关联对象,原对象失去投掷能力,新对象转化为可投掷的对象。
projectile.setRelatedGameObject(balls[curBall]);
  • 支持和【对象发射器】类似的投掷参数(碰撞参数除外)。【对象发射器】本质是创建一个自定义碰撞形状的投掷物对象,携带【GameObject】运动。【投掷功能类】是将【GameObject】转化成可投掷对象,所以碰撞属性沿用对象自身碰撞(简单碰撞信息)。
TypeScript
// 下列两个碰撞状态会实现反弹效果
ball.setCollision(CollisionStatus.QueryCollisionOnly);
ball.setCollision(CollisionStatus.On);

// QueryOnly无法反弹,但是会触发hit检测
ball.setCollision(CollisionStatus.QueryOnly);

// Off无法反弹,也不会触发hit检测
ball.setCollision(CollisionStatus.Off);
// 下列两个碰撞状态会实现反弹效果
ball.setCollision(CollisionStatus.QueryCollisionOnly);
ball.setCollision(CollisionStatus.On);

// QueryOnly无法反弹,但是会触发hit检测
ball.setCollision(CollisionStatus.QueryOnly);

// Off无法反弹,也不会触发hit检测
ball.setCollision(CollisionStatus.Off);

  • 对象发射器的使用场景(可以做什么)?

    • 【对象发射器】和【投掷功能类】核心功能类似,覆盖使用场景相同。
    • 在需要大量飞行道具同时进行抛物线运动的场景,可以使用【投掷功能类】节约性能。
    • 对比【对象发射器】,【投掷功能类】可以控制投掷物的运动状态:暂停&继续。
  • 示例代码可参照API文档或示例工程:

    https://arkimg.ark.online/ProjectileMovement.zip

https://api-docs.ark.online/classes/mw.ProjectileMovement.html

材质效果上车内容

027版本中,将会对现有的材质效果进行全面升级,升级至材质2.0,优化美术表现效果,解决API易用性、光照效果调整难度高、维护困难的问题,为后续版本需求、性能优化、基础体验优化打好基础

1.场景材质2.0效果升级

1.0 API

  • 新的材质2.0的API还在研发,目前可以尝试用旧版API修改材质

setVectorParameterValue("Main_Diffuse_Color", 你的色调) 来设置材质颜色

setScalarParameterValue("Tone_Saturation", 你的饱和度) 来设置材质饱和度

setTextureParameterValue("Decal_Color_Texture", 你的贴图) 来设置材质贴图参数

  • 设置材质的漫反射颜色,参数名称可从材质的mat文件中获得

img

img

1.1 效果对比: 026 vs 027

  • 材质升级后,材质质感表现可以更细腻,在高画质下物体的高光和反射可以包含更多的细节,颜色更接近美术DCC软件(数字内容创造软件)输出颜色。

(注意:模型效果的表现不仅和材质有关,还和光影后处理有关)

  • 材质2.0增加了逆光时边缘光效果,可以提升模型的体积感

    材质1.0材质2.0
    imgimg
  • 高光反射的灰度过渡优化,避免了资源在浅色时出现过曝的情况。

材质1.0材质2.0
imgimg
  • 最低画质支持高光和金属反射。解决低画质手机金属材质球变没了的问题。
材质1.0高画质材质2.0高画质
imgimg
材质1.0低画质材质2.0低画质
imgimg
  • 各画质的最终效果差异变小,减少了各个画质间的颜色差异。

    材质1.0高画质材质2.0高画质
    imgimg
    材质1.0低画质材质2.0低画质
    imgimg
  • PBR材质皮肤效果升级,增强了皮肤的质感,增强了3S效果

材质1.0材质2.0
imgimg
  • 各项异性过滤,优化大平面使用四方连续贴图远处精度丢失的问题。
无各项异性过滤各项异性过滤
imgimg

1.2 设置材质颜色和饱和度(初版)

  • 新的材质2.0的API还在研发,目前可以尝试用旧版API:

setVectorParameterValue("Tone_Tint", 你的色调) 来设置材质颜色

img

setScalarParameterValue("Tone_Saturation", 你的饱和度) 来设置材质饱和度

1.3 地形材质(实验版,之后的升级可能导致地形材质效果失效)

目前地形材质、纹理还在完善,纹理是一个纹理数组,玩家将不再需要上传地形的纹理。

只需要设置纹理Id即可。

1.4 超分辨率TSR(实验版)

我们的TSR = FSR + TAA,

目前默认只开了TAA,关闭了FSR,后续会做到**“画面设置”**里,当前只能通过画质分级和命令行实现调用

如果觉得有些场合鬼影问题严重,想要关闭TAA,可以使用命令行:

mw.setAA 0

如果觉得锯齿严重,想要开启TAA,可以使用命令行:

mw.setAA 3

如果觉得清晰度不够,想要开启FSR,可以使用命令行:

FSR N,这里的N填【1~6】,整数,越高画质越高,FSR 0是关闭FSR

如果觉得TAA闪烁太厉害,可以使用命令行:

r.TemporalAADenoise N,这里的N填【-1.0~1.0】,浮点数,越低,Denoise越多。

2.材质半透功能(初版)

MW编辑器基于材质2.0迭代,提供材质半透效果调整功能,提供多语言翻译,提供Tips。

使用方法

img

选择想调整的模型,在细节面板选择想调整的材质,点击材质编辑器按钮,打开材质编辑器

img

打开材质编辑器后,选择模式选择分页,通过材质模式选项材质的半透表现方式

为了表现不同的美术效果,目前MW材质有三种模式

  1. 不透明模式(Blend_Opaque):指该材质没有透明效果,最常见的模式,也是最省性能的模式
  2. 镂空蒙版模式(Blend_Masked):多用于树叶、铁丝网等镂空表现。这种模式,是为了节省三角面,把模型表面上的镂空信息,做在贴图上。
  3. 半透明模式(Blend_Translucent):多用于玻璃、水面等大片、大区域的透明效果。透明效果更丝滑自然,但是两个半透的模型包围盒重叠时(或模型自身不是一个凸包时),容易出现排序错乱的问题

img

修改模式之后,选择半透明度分页,进行材质半透效果调整

img

注意事项

  • 半透效果做在材质上,调整材质半透效果时会影响所有使用该材质的资源
  • 半透效果对性能有较大影响,请谨慎使用

另外,场景物体挡住摄像机后的消隐效果已经实现,目前用的扎孔不透明度实现,这个扎孔不透明度当且仅当为**“镂空蒙版模式”“半透明模式”**时才生效。

3.Lighting模块修改说明

3.1天空光 & 平行光

合并对象

027版本删除原有【SkyLight】天空光对象与【DirectionalLight】平行光对象。新增【Lighting】光照对象承载它们之前的功能。优化合并后对象如所示:

光照 - Lighting

SkyLight属性:
立方体贴图

DirectionalLight属性:
朝向角度
俯仰角度
是否使用色温
色温
投射阴影
阴影距离

新增属性:
曝光补偿

合并属性:
光照强度(天空光强度 & 平行光强度)
偏色值 (天空光颜色 & 平行光颜色)
img
去除继承GameObject

【光照】对象不继承GameObject。

光照 - Lighting

变换(删除)
基础属性
Name
Guid(删除)
静态状态(删除)
网络状态(删除)
Tag(删除)
游戏性设置(删除)
场景设置(删除)
imgimg
API改动
  • 【SkyLight】天空光对象属性:光强intensity和光颜色lightColor,【DirectionalLight】平行光对象属性:光强intensity和光颜色lightColor,在【Lighting】对象中进行合并处理,由brightnesslightColor代替。
  • 删除【DirectionalLight】平行光对象角色模拟阴影baseShadowEnabled属性。
  • 不再继承【GameObject】对象去除冗余接口,静态封装原有接口

光照 - Lighting 优化后的API

属性含义属性名类型默认值取值范围说明读写可见
曝光值ev100number-1-6 - 6静态曝光偏移值Read / WriteScript & Editor
光照亮度brightnessnumber10-1预设偏移值,晚上->白天Read / WriteScript & Editor
偏色值lightColorLinearColorFFFFFFFF-Read / WriteScript & Editor
朝向角度yawAnglenumber-60-180-180朝向角度 (-180 ~ 180)只在客户端调用生效Read / WriteScript & Editor
俯仰角度pitchAnglenumber-60-90-90俯仰角度 (-90 ~ 90)只在客户端调用生效Read / WriteScript & Editor
是否开启阴影castShadowsEnabledbooleantrue-是否开启阴影只在客户端调用生效Read / WriteScript & Editor
阴影距离shadowDistancenumber2500-阴影距离只在客户端调用生效Read / WriteScript & Editor
是否开启色温temperatureEnabledbooleanfalse-是否开启色温只在客户端调用生效Read / WriteScript & Editor
色温temperaturenumber65001000-12000色温只在客户端调用生效Read / WriteScript & Editor

新旧API映射表

天空光 - SkyLight

API含义老API新API修改类型
天空光强度skyLight.intensityLighting.brightness使用新接口代替
天空光颜色skyLight.lightColorLighting.lightColor使用新接口代替

平行光 - DirectionLight

API含义老API新API修改类型
朝向角度directionalLight.yawAngleLighting.yawAngle使用新接口代替
俯仰角度directionalLight.pitchAngleLighting.pitchAngle使用新接口代替
光照强度directionalLight.intensityLighting.brightness使用新接口代替
光照颜色directionalLight.lightColorLighting.lightColor使用新接口代替
是否开启阴影directionalLight.shadowEnabledirectionalLight.shadowEnabled使用新接口代替
阴影距离directionalLight.shadowDistancedirectionalLight.shadowDistance使用新接口代替
是否开启色温directionalLight.temperatureEnabledirectionalLight.temperatureEnabled使用新接口代替
色温directionalLight.temperaturedirectionalLight.temperature使用新接口代替
功能展示

属性说明

  • 曝光值

静态曝光偏移值,调节该值修改场景曝光亮度,越小越亮。取值范围-6 ~ 6,默认值为 -1。

img

  • 光照亮度

预设光照偏移值,调节该值修改场景晚上->白天,越小越暗。取值范围0 ~ 1,默认值为 1。

img

  • 偏色值

光照颜色偏移值,调节该值修改场景中光照颜色。默认值为 FFFFFFFF 白色。

img

  • 朝向角度

光线的朝向角度,调节该值修改场景中光线来源的方向。取值范围-180 ~ 180,默认值为 -60。

img

  • 俯仰角度

光线的俯仰角度,调节该值修改场景中光线与地面的夹角。取值范围-90 ~ 90,默认值为 -60。

img

  • 是否开启阴影

光照是否可以照射出阴影,调节该值开启/关闭阴影。默认值为true。

img

  • 阴影距离

能看见阴影的最大距离,调节该值修改阴影可见距离。需注意阴影可见距离越远,阴影质量越低,细节越模糊。默认值为2500。

img

  • 是否开启色温

光照是否应用色温,调节该值开启/关闭色温。默认值为false。

img

  • 色温

光照色温值,需要开启色温才会生效。调节该值修改场景中光线色温。取值范围1000 ~ 12000,默认值为 6500。

img

示例代码

TypeScript
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            Lighting.brightness = 1;
            Lighting.yawAngle = -45;
            Lighting.pitchAngle = -30;
        }
    }
}
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            Lighting.brightness = 1;
            Lighting.yawAngle = -45;
            Lighting.pitchAngle = -30;
        }
    }
}

3.2后处理

【PostProcess】逻辑对象 -> 【PostProcess】世界对象

因后处理对象并不支持叠加使用,场景中有且仅有一份生效,故027版本将**【PostProcess】后处理对象从资源库逻辑对象中删除,放置到世界对象**以默认配置存在。

imgimg

【PostProcess】后处理对象新增preset属性提供7种后处理预设,降低用户使用门槛:

预设效果:默认,梦境,反差色,暖阳,老照片,夜幕,鲜暖色

用户自定义(自动):后处理设置,泛光,全局饱和度,全局对比度

imgimg
typescript
/**设置后处理预设模板 */
  PostProcess.preset = PostProcessPreset.Night;
/**设置后处理预设模板 */
  PostProcess.preset = PostProcessPreset.Night;

删除无效&易错的属性&去除继承GameObject

变换(删除)
基础属性
Name
Guid(删除)
静态状态(删除)
网络状态(删除)
Tag(删除)
游戏性设置(删除)
场景设置(删除)
后处理设置
后处理融合图(删除)
后处理融合度(删除)
后处理高级设置
色调映射(易错删除)
泛光
全局饱和度
全局对比度
全局伽马值
LDR饱和度(易错删除)
LDR对比度(易错删除)
LDR伽马值(易错删除)
HDR饱和度(易错删除)
HDR对比度(易错删除)
HDR伽马值(易错删除)
环境光遮蔽强度(无效删除)
环境光遮蔽半径(无效删除)
动态模糊(无效删除)
LDR与HDR阈值(易错删除)
色调映射斜率(易错删除)
色调映射地位阈值(易错删除)
色调映射高位阈值(易错删除)
色调映射暗部裁剪(易错删除)
色调映射亮部裁剪(易错删除)
曝光补偿(无效删除)
曝光最大亮度(无效删除)
曝光最小亮度(无效删除)
描边设置(删除)
描边颜色(删除)
描边宽度(删除)
被遮挡融合比例(删除)
img

新增后处理模板

【PostProcess】后处理对象新增preset属性提供7种后处理预设,降低用户使用门槛:

默认 Default = 0
梦境 Dreamy = 1
反差色 Contrast = 2
暖阳 WarmSunshine = 3
老照片 OldPhoto = 4
夜幕 Night = 5
鲜暖色 WarmContrast = 6
img

新增后处理配置类

新增【PostProcessConfig】后处理配置类,囊括后处理当前属性,解耦数据层和功能层。【PostProcess】后处理对象新增config属性。【PostProcessConfig】保证了外部接口的纯净,此外保留了后续可能需要暴露更多复杂的后处理参数的扩展性。

imgimg

API改动

  • 由于【PostProcess】后处理对象无法叠加使用。删除【PostProcess】逻辑对象,将其放置到世界对象。

  • 废弃【后处理】中的易错和失效属性,仅保留bloomIntensity、globalSaturation、globalContrast三个全局属性。新增preset属性,切换美术提供的七种后处理效果预设。

  • 新增【PostProcessConfig】后处理配置类,囊括后处理当前属性,解耦数据层和功能层。【PostProcess】后处理对象新增config属性。

    示例代码

    typescript
    @Component
    export default class SetPostProcess extends Script {
        /** 当脚本被实例后,会在第一帧更新前调用此函数 */
        protected onStart(): void {
            if (SystemUtil.isClient()) {
                 let config = new PostProcessConfig();
                /**全局泛光 */
                config.bloomIntensity = 0.5;
                /**全局饱和度 */
                config.globalSaturation = 0.5;
                /**全局对比度 */
                config.globalSaturation = 1;
                PostProcess.config = config;
            }
        }
    }
    @Component
    export default class SetPostProcess extends Script {
        /** 当脚本被实例后,会在第一帧更新前调用此函数 */
        protected onStart(): void {
            if (SystemUtil.isClient()) {
                 let config = new PostProcessConfig();
                /**全局泛光 */
                config.bloomIntensity = 0.5;
                /**全局饱和度 */
                config.globalSaturation = 0.5;
                /**全局对比度 */
                config.globalSaturation = 1;
                PostProcess.config = config;
            }
        }
    }

后处理 - PostProcess 优化后的API

属性含义属性名类型默认值取值范围说明读写可见
预设presetPostProcessPresetPostProcessPreset.Default-后处理预设Read / WriteVisible
配置configPostProcessConfig--后处理预设配置Read / WriteVisible
泛光bloomnumber1.50 - 8泛光Read / WriteVisible
饱和度saturationnumber1.20 - 2全局饱和度Read / WriteVisible
对比度contrastnumber10 - 5全局对比度Read / WriteVisible
LUT百分比lUTBlendstring--LUT百分比Read / WriteVisible
LUT贴图资源lUTTextureAssetByGuidstring--LUT贴图资源Read / WriteVisible

新旧API映射表

API含义老API新API修改类型
设置色调映射 (0 ~ 100)toneCurveAmount-删除
设置全局伽马值(0 ~ 5)globalGamma-删除
设置LDR饱和度(0 ~ 2)lDRSaturation-删除
设置LDR对比度Contrast (0.2 ~ 5.0)lDRContrast-删除
设置LDR伽马值 (0 ~ 5)lDRGamma-删除
设置HDR饱和度 (0 ~ 2)hDRSaturation-删除
设置HDR对比度 (0 ~ 5)hDRContrast-删除
设置HDR伽马值 (0 ~ 5)hDRGamma-删除
设置环境光遮蔽强度(0 ~ 1)ambientOcclusionIntensity-删除
设置环境光遮蔽半径(0.1 ~ 500.0)ambientOcclusionRadius-删除
设置动态模糊 (0 ~ 1)motionBlur-删除
设置LDR与HDR阈值 (-1 ~ 1)lDR2HDRThreshold-删除
设置色调映射斜率 (0 ~ 1)toneSlope-删除
设置色调映射低位阈值(0 ~ 1)toneToe-删除
设置色调映射高位阈值(0 ~ 1)toneShoulder-删除
设置色调映射暗部裁剪(0 ~ 1)toneBlackClip-删除
设置色调映射亮部裁剪(0 ~ 1)toneWhiteClip-删除
设置曝光补偿(-15 ~ 15)autoExposureBias-删除
设置曝光最小亮度(-10 ~ 20)autoExposureMinBrightness-删除
设置曝光最大亮度(-10 ~ 20)autoExposureMaxBrightness-删除
设置被遮挡部分高亮透明度(0 ~ 1)outlineCoveredAlpha-删除
设置被遮挡部分描边透明度(0 ~ 1)outlineCoveredEdgeAlpha-删除
设置未被遮挡部分高亮透明度(0 ~ 1)outlineNotCoveredAlpha-删除
设置未被遮挡部分描边透明度(0 ~ 1)outlineNotCoveredEdgeAlpha-删除
设置描边宽度 (0 ~ 4)setOutlineWidth-删除
设置被遮挡融合比例(0 ~ 1)setOccluderBlend-删除
添加一个描边颜色并返回对应的索引addOutLineColor()-删除
功能展示

属性说明

  • 预设效果
    • 后处理自身提供的7种预设模板,切换模板可以快速应用不同的后处理效果。默认值是Default=0。
    • 默认 Default = 0
    • img
    • 梦境 Dreamy = 1
    • img
    • 反差色 Contrast = 2
    • img
    • 暖阳 WarmSunshine = 3
    • img
    • 老照片 OldPhoto = 4
    • img
    • 夜幕 Night = 5
    • img
    • 鲜暖色 WarmContrast = 6
    • img
  • 泛光

修改该值可以调节镜头中泛光强度,取值范围0 ~ 8,默认值为 1.5。

img

  • 全局饱和度

修改该值可以调节镜头颜色的饱和度,取值范围0 ~ 2,默认值为 1.2。

img

  • 全局对比度

修改该值可以调节镜头颜色的对比度,取值范围0 ~ 5,默认值为 1。

img

示例代码

TypeScript
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            PostProcess.bloomIntensity = 1.5;
            PostProcess.globalSaturation = 1.1;
            PostProcess.globalContrast = 1;
        }
    }
}
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            PostProcess.bloomIntensity = 1.5;
            PostProcess.globalSaturation = 1.1;
            PostProcess.globalContrast = 1;
        }
    }
}

3.3天空盒

去除继承GameObject
API改动
  • 类名由【SkyBox】修改为【Skybox】
  • 接口调用方式修改为静态,去除对象与GameObject的继承关系
  • 按照竞品和英语规则重新命名属性

天空盒 - Skybox 优化后的API

属性

属性含义属性名类型默认值取值范围说明读写可见
天空盒预设presetSkyPresetMorning2D = 0-天空球预设Read / WriteEditor & Script
天空球贴图IDskyDomeTextureIdstring--设置天空球贴图WriteEditor & Script
天空球亮度skyDomeIntensitynumber10-100天空球亮度Read / WriteEditor & Script
天空球颜色skyDomeBaseColorType.LinearColorFFFFFFFF天空球颜色Read / WriteEditor & Script
是否开启渐变效果gradientEnabledbooleantrue是否开启渐变效果Read / WriteEditor & Script
天空顶层颜色skyDomeTopColorType.LinearColor3B75C6FF天空球顶层颜色Read / WriteEditor & Script
天空中层颜色skyDomeMiddleColorType.LinearColor6DA2E1FF天空中层颜色Read / WriteEditor & Script
天空下层颜色skyDomeBottomColorType.LinearColorBAD0F3FF天空下层颜色Read / WriteEditor & Script
地平线渐出值fallOffnumber31-20地平线渐出值Read / WriteEditor & Script
是否开启星星starVisiblebooleanfalse是否开启星星Read / WriteEditor & Script
星星贴图IDstarTextureIdstring-设置星星贴图WriteEditor & Script
星星亮度starIntensitynumber10-1星星亮度Read / WriteEditor & Script
星星密度starDensitynumber100-100星星密度Read / WriteEditor & Script
是否开启太阳sunVisiblebooleantrue是否开启太阳Read / WriteEditor & Script
太阳贴图IDsunTextureIdstring-设置太阳贴图WriteEditor & Script
太阳光亮度starIntensitynumber400-2000太阳光亮度Read / WriteEditor & Script
太阳颜色sunColorType.LinearColorFFE2B6FF太阳颜色Read / WriteEditor & Script
太阳大小sunSizenumber90-100太阳大小Read / WriteEditor & Script
是否开启月亮moonVisiblebooleanfalse是否开启月亮Read / WriteEditor & Script
月亮贴图IDmoonTextureIdstring-设置月亮贴图WriteEditor & Script
月亮光亮度moonIntensitynumber10-2000月亮光亮度Read / WriteEditor & Script
月亮颜色moonColorType.LinearColorFFFFFFFF月亮颜色Read / WriteEditor & Script
月亮大小moonSizenumber100-100月亮大小Read / WriteEditor & Script
是否开启云cloudVisiblebooleanfalse是否开启云Read / WriteEditor & Script
云贴图IDcloudTextureIdstring-云贴图IDWriteEditor & Script
云透明度cloudOpacitynumber10-1云透明度Read / WriteEditor & Script
云颜色cloudColorType.LinearColorE4EAFFFF云颜色Read / WriteEditor & Script
云密度cloudDensitynumber10-1云密度Read / WriteEditor & Script
云速度cloudSpeednumber0.50-10云速度Read / WriteEditor & Script

方法

功能说明方法名返回类型输入说明输入值范围输出说明输出值范围使用域
刷新天空盒refresh(): voidvoid-void--Client Only
重置天空盒reset(): voidvoid-void--Client Only

新旧API映射表

API含义老API新API修改类型
天空盒SkyBoxSkybox使用新接口代替
天空球预设skyPresetpreset使用新接口代替
天空球贴图IDskyDomeTextureAssetByIDskyDomeTextureId使用新接口代替
天空球颜色skyDomeTintskyDomeBaseColor使用新接口代替
是否开启渐变效果skyDomeGradientEnableskyDomeGradientEnabled使用新接口代替
天空顶层颜色skyDomeTopTintskyDomeTopColor使用新接口代替
天空中层颜色skyDomeHorizontalTintskyDomeMiddleColor使用新接口代替
天空下层颜色skyDomeBotTintskyDomeBottomColor使用新接口代替
是否开启星星starEnablestarVisible使用新接口代替
星星贴图IDstarTextureAssetByIDstarTextureId使用新接口代替
星星密度starTilingstarDensity使用新接口代替
是否开启太阳sunEnablesunVisible使用新接口代替
太阳贴图IDsunTextureAssetByIDsunTextureId使用新接口代替
太阳颜色sunTintsunColor使用新接口代替
是否开启月亮moonEnablemoonVisible使用新接口代替
月亮贴图IDmoonTextureAssetByIDmoonTextureId使用新接口代替
月亮颜色moonTintmoonColor使用新接口代替
是否开启云cloudEnablecloudVisible使用新接口代替
云贴图IDcloudTextureAssetByIDcloudTextureId使用新接口代替
云颜色cloudTintcloudColor使用新接口代替
功能展示

属性说明

示例代码

TypeScript
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            Skybox.preset = SkyPreset.DuskLowPoly;
            Skybox.sunColor = LinearColor.red;
            Skybox.cloudColor = LinearColor.red;
        }
    }
}
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            Skybox.preset = SkyPreset.DuskLowPoly;
            Skybox.sunColor = LinearColor.red;
            Skybox.cloudColor = LinearColor.red;
        }
    }
}

3.4环境雾

去除继承GameObject

环境雾对象【ExponentialHeightFog】改名【Fog】且不再继承GameObject。

是否启用
环境雾预设
默认
近景雾
远景雾
地下雾
沙漠雾
雾密度
雾高度衰弱
雾高度
雾散射颜色
雾最大透明度
起始距离
太阳光散射指数
太阳光散射起始距离
太阳光散射颜色
img
API改动
  • 类名由【ExponentialHeightFog】修改为【Fog】
  • 接口调用方式修改为静态,去除对象与GameObject的继承关系
  • 修改命名中EnableEnabled
  • 去除属性中的fog前缀
  • setPresetByIndex修改为setPreset

环境雾 - Fog 优化后的API

属性

属性含义属性名类型默认值取值范围说明读写可见
启用fogEnablebooleanfalse-启用/禁用环境雾Read & WriteEditor & Script
密度densitynumber0.10 ~ 1雾密度Read & WriteEditor & Script
衰弱高度heightFalloffnumber10 ~ 1雾衰弱高度(控制密度如何随着高度的降低而增加.值越小,可见过渡越大)Read & WriteEditor & Script
高度heightnumber0-10000 ~ 10000雾高度Read & WriteEditor & Script
散射颜色inscatteringColorLinearColor#E2E8EBFF-雾散射颜色Read & WriteEditor & Script
最大透明度maxOpacitynumber10 ~ 1雾最大透明度(值为1表示雾可以在远处变得完全不透明并完全替换场景颜色,值为0表示根本不会考虑雾颜色)Read & WriteEditor & Script
起始距离startDistancenumber10000 ~ 10000雾起始距离(到摄像机的距离)Read & WriteEditor & Script
太阳光散射指数directionalInscatteringExponentnumber42 ~ 64太阳光散射指数,控制定向散射锥的大小,该圆锥用于近似来自太阳光的散射.Read & WriteEditor & Script
太阳光散射初始距离directionalInscatteringStartDistancenumber42 ~ 64太阳光散射初始距离,控制与定向散射查看器的起始距离,定向散射用于近似太阳光的散射.Read & WriteEditor & Script
太阳光散射颜色directionalInscatteringColorLinearColor000000FF-太阳光散射颜色,控制定向散射的颜色,该颜色用于近似太阳光的散射.Read & WriteEditor & Script

方法

功能说明方法名返回类型输入说明输入值范围输出说明输出值范围使用域
设置环境雾预设setPreset(presetIndex: FogPreset): voidvoidpresetIndex预设枚举值---Client Only

新旧API映射表

API含义老API新API修改类型
环境雾对象ExponentialHeightFogFog使用新对象代替
启用环境雾fogEnableenabled使用新接口代替
雾密度fogDensitydensity使用新接口代替
雾衰弱高度fogHeightFalloffheightFalloff使用新接口代替
雾高度fogHeightheight使用新接口代替
雾散射颜色fogInscatteringColorinscatteringColor使用新接口代替
雾最大透明度fogMaxOpacitymaxOpacity使用新接口代替
设置环境雾预设setPresetByIndexsetPreset使用新接口代替
功能展示

属性说明

  • 是否启用

是否启用环境雾的效果。

img

  • 环境雾预设
    • 默认 Default = 0:默认效果,距离和浓度适中
    • img
    • 近景雾 NearFog = 1:近处的环境雾,距离较短
    • img
    • 远景雾 FarFog = 2:远处的环境雾,距离较远
    • img
    • 地下雾 UndergroundFog = 3:黑暗的地下洞穴的环境效果
    • img
    • 沙漠雾 DesertFog = 4:沙漠地带的环境效果
    • img
  • 雾密度

整体密度系数,是可视雾层的厚度。取值范围0 ~ 1,默认值为 0.1。

img

  • 雾高度衰弱

雾效从高到低,雾效效果逐渐变浓,该值是控制雾效的过度效果,值越小效果越柔和。取值范围0 ~ 1,默认值为 1。

img

  • 雾高度

雾效的起始世界高度,也就是环境雾Z轴的位置,高度越低,雾的效果越淡,高度越高,雾的效果越浓。取值范围-10000 ~ 10000,默认值为 0。

img

  • 雾散射颜色

雾的内散射颜色,就是雾的主要颜色。默认值为#E2E8EBFF白色

img

  • 雾最大透明度

雾的最大不透明度。值为1时雾完全不透明,值为0时雾基本不可见。取值范围0 ~ 1,默认值为 1。

img

  • 起始距离

雾出现处与摄像机的距离。取值范围0 ~ 10000,默认值为 1000。

img

  • 太阳光散射指数

控制太阳光颜色影响的散射强弱,指数越强,散射的范围就越大。取值范围2 ~ 64,默认值为 4。

img

  • 太阳光散射起始距离

太阳光散射的初始距离。取值范围2 ~ 64,默认值为 4。

img

  • 太阳光散射颜色

设置在环境雾中太阳光的散射颜色,就是太阳光的主要颜色。默认值为#000000FF黑色

img

示例代码

TypeScript
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            Fog.enabled = true;
            Fog.setPreset = FogPreset.DesertFog;
            Fog.desity = 0.9;
        }
    }
}
@Component
export default class NewScript extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if(SystemUtil.isClient()) {
            Fog.enabled = true;
            Fog.setPreset = FogPreset.DesertFog;
            Fog.desity = 0.9;
        }
    }
}

修复BUG