# 闪烁的灯光 ## 通用工作流程 闪烁的光源对象由多个组件组成。
Object Type |
命名模板 |
说明 |
|---|---|---|
| Base RendInst | industrial_lamp_steel_wall_a.lod**.dag | 这是用作创建闪烁灯的基础的模型。在某些情况下,它可能不是必需的,特别是当您从头开始设计具有内置闪烁功能的灯时。 |
| RendInst without Emissive | industrial_lamp_steel_wall_a_base.lod**.dag | 对象的分离部分,没有任何自发光属性,导出为单独的渲染实例。 这对于以下各项是必需的: - 投射阴影(渲染实例阴影的计算成本明显低于动态模型阴影)。 - 销毁光源(当其边界框包含光源中心的渲染实例被销毁时,灯光消失)。 - 在视觉上销毁对象(渲染实例很容易 [通过析构函数销毁](../about-assets/customizing_asset_destructions.md)。 处理动态模型更复杂,因此我们按照光源规则让它们消失 - 它们的枢轴必须位于已销毁渲染实例的边界框内。 简单地说,当渲染实例被销毁时,动态模型会消失,光源会被移除,渲染实例会通过析构函数分解。 |
| DynModel with Emissive | industrial_lamp_steel_wall_a_flicker_dynmodel.lod**.dag | 整个模型的分离部分,使用动态发光着色器导出。从本质上讲,这是会发光和闪烁的部分。 |
| AnimChar | industrial_lamp_steel_wall_a_flicker_char.animChar.blk | 一个简单的 .blk 文件,其中包含对动态模型及其骨架的引用。从技术上讲,这是必要的,因为我们不能将动态模型直接放置在地图上,因为它不是静态对象。但是,可以放置 animChar。 例如: - dynModel:t="industrial_lamp_steel_wall_a_flicker_dynmodel" - skeleton:t="industrial_lamp_steel_wall_a_flicker_skeleton" |
| GameObj (Flickering Light) | industrial_lamp_steel_wall_a_flicker_8m_light.gameObj.blk | 一个 .blk 文件,其中包含 |
| GameObj (Flickering DynModel) | industrial_lamp_steel_wall_a_flicker_8m_mesh.gameObj.blk | 一个 .blk 文件,其中包含 |
| Composite | industrial_lamp_steel_wall_a_flicker_8m_cmp.composit.blk | 此 composite.blk 文件包括: - 基础渲染实例: industrial_lamp_steel_wall_a_base.lod**.dag - 闪烁的灯光游戏对象: industrial_lamp_steel_wall_a_flicker_8m_light.gameObj.blk - 闪烁的动态模型游戏对象: industrial_lamp_steel_wall_a_flicker_8m_mesh.gameObj.blk |
| 闪烁和光源模板
(所有模板都位于 |
industrial_lamp_steel_wall_a_flicker_8m_template | 闪烁模板。定义闪烁参数。 |
| industrial_lamp_steel_wall_a_flicker_8m_light | 闪烁光源模板。将光源链接到闪烁行为(您可以使用现成的光源或制作自己的光源)。该文件与 industrial_lamp_steel_wall_a_flicker_8m_light.gameObj.blk 文件同名。 | |
| industrial_lamp_steel_wall_a_flicker_8m_mesh | 闪烁的动态模型模板。将动态模型链接到闪烁行为(通过 AnimChar)。 该文件与 industrial_lamp_steel_wall_a_flicker_8m_mesh.gameObj.blk 文件同名。 |
```{important}
为了防止动态模型的矩阵和渲染实例之间的不同步,它们的枢轴点必须对齐(在导出到 `.dag` 文件之前在场景中正确定位)。在上图中,它们并排显示仅用于演示目的。
```
### 导出对象的命名
对于最初命名为`industrial_lamp_steel_wall_a.lod**.dag`的对象,split 渲染实例和动态模型应按如下方式命名:
- **RendInst**: `industrial_lamp_steel_wall_a_base.lod**.dag` – Non emissive base(非自发光基),其余部分将添加到该基底。
- **Dynamic Model**: `industrial_lamp_steel_wall_a_flicker_dynmodel.lod**.dag` – 闪烁的动态模型。
### Shaders
- **RendInst**: 使用基于资产创建技术的标准着色器。
- **Dynamic Model**: 使用动态自发光着色器,通常是 [dynamic_emissive](../shaders/dng-shaders/rendinst_emissive.md) 着色器。
### Destructions
如前所述,销毁仅适用于 render 实例。由于销毁动态模型更复杂,因此当关联的渲染实例被销毁时,只要动态模型和光源位于其边界框内,它们就会消失。
```{important}
光源和动态模型的“自动”销毁将仅在以下情况下发生:
1. 它们的枢轴必须位于已销毁的渲染实例的边界框内。如果它们只是触碰边缘,则不会发生破坏。
2. 必须在其模板中指定属性`destroyable_with_rendinst:tag{}`。大多数光源 (99%) 从其基本模板继承此属性,因此通常不需要手动添加。但是,对于每个新的动态模型,您必须在模板中包含此属性,例如在 `industrial_lamp_steel_wall_a_flicker_8m_mesh` 中。
```
要正确配置析构,您只需:
1. 为渲染实例创建标准`_destr`。
2. 根据标准准则在 `rendinst_dmg.blk` 中定义渲染实例析构。
```{important}
销毁渲染实例时,整个模型必须受到影响,这意味着销毁过程必须同时涵盖静态和动态部分。否则,动态模型将突然消失,在剩余渲染实例的几何体中留下间隙。
```
以下是正确的销毁过程:
Render Instance |
Dynamic Model |
Render Instance Dynamic Model Destruction |
Render Instance Dynamic Model Destruction DMG(optional) |
|---|
## 使用纹理和材质
一些关键注意事项:
- 自发光遮罩,存储在基于[rendinst_emissive/dynamic_emissive](../shaders/dng-shaders/rendinst_emissive.md)着色器系统,则只能针对动态模型中包含的模型部分进行烘焙。渲染实例不支持闪烁。
- 因此,渲染实例不应使用自发光着色器,除非艺术设计特别要求(例如,在科幻设置中)。
- 请记住,闪烁的光源不考虑材质中的光色或自发光色。您必须手动调整自发光颜色以匹配所需的灯光颜色(如果要创建新灯光,则反之亦然)。它们之间没有自动同步。
- 除非艺术设计要求,否则请避免将彩色光烘焙到albedo纹理中。这样做将限制模型的自发光颜色选项(如果其他人希望将其与不同的颜色一起使用)。自发光效果的颜色和强度在 [rendinst_emissive/dynamic_emissive](../shaders/dng-shaders/rendinst_emissive.md) 着色器设置。
- 因此,如果需要两个具有不同发射颜色(例如白色和红色)的相同灯,则必须创建两个具有不同自发光材质设置的单独动力学模型。如果自发光颜色被烘焙到albedo中,则无法做到这一点。
- Be aware that the [*Asset Viewer*](../../dagor-tools/asset-viewer/asset-viewer/asset_viewer.md) does not accurately display emissive color and intensity. All testing should be done in-game. Do not rely on the *Asset Viewer* for accurate results.
## 配置 .folder.blk
如果您不确定系统如何处理`.dag` 文件以及区分动态模型和渲染实例,请参阅以下文档:
- [.blk](../../dagor-tools/blk/blk.md)
- [.folder.blk](../all-about-blk/folder_blk.md)
- [Assets Philosophy](../about-assets/about_assets.md)
### 静态几何体处理
像往常一样,请遵循处理静态几何体的标准过程。唯一需要注意的是,如果您在 `.folder.blk` 的开头处理静态几何体,请确保 **排除动态模型**。否则,将导致它们被错误地处理。
**例:**
```
virtual_res_blk{
find:t="^(.*)\.lod00\.dag$"
exclude:t = "_destr\.lod00\.dag$"
exclude:t = "_dynmodel\.lod00\.dag$"
className:t="rendInst"
contents{
lod{range:r=12;}
lod{range:r=30;}
lod{range:r=80;}
allowProxyMat:b=yes
}
}
```
如果首先处理动态模型,则以后不需要排除(因为不会再次处理处理资源)。请记住删除不必要的 `stopProcessing:b=false`标志。
### 动态几何处理
在 Dagor Engine 的逻辑中,如果满足以下条件,则动态模型被视为动态模型:
1. 它使用动态着色器。
2. 它有一个骨架。
我们已经在材质中分配了动态着色器,所以现在我们需要创建骨架:
```
virtual_res_blk{ // 骨架创建块
find:t="^((.*)_dynmodel)\.lod00\.dag$" // 查找所有带有 _dynmodel 后缀的 LOD00
stopProcessing:b=false // 允许在下一个块中重新处理这些 .dag 文件
className:t="skeleton" // 将找到的资产视为骨架(提取数据以构建骨架资产)
name:t="$2_skeleton" // 使用动态模型名称 ($2) 和 _skeleton 后缀命名骨架
contents{ // 其他数据处理规则
addSkinNodes:b=yes
reduceNodes:b=yes
}
}
virtual_res_blk{ // 动态模型创建模块
find:t="^((.*)_dynmodel)\.lod00\.dag$" // 找到所有带有 _dynmodel 后缀的 LOD00 (由于前一个块的 stopProcessing:b=false)
stopProcessing:b=false // 这可能是一个多余的参数。
className:t="DynModel" // 将找到的资产作为动态模型进行处理(提取数据以构建动态模型资产)
name:t="$2_dynmodel" // 将动态模型命名为 $2_dynmodel(即带有 _dynmodel 后缀的动态模型名称)
contents{ // 其他数据处理规则
lod{range:r=12;} // LOD 距离
lod{range:r=30;}
lod{range:r=80;}
ref_skeleton:t="$2_skeleton" // 引用在上一个块中创建的骨架
}
}
```
```{important}
资产的命名可能会有一些混淆。我们处理带有`_dynmodel`后缀的对象,然后在 skeleton 和 dynamic model creation 模块中分配两个额外的后缀:
- `_skeleton`
- `_dynmodel`
这可能会导致预期名称如下:
- `_dynmodel_skeleton`
- `_dynmodel_dynmodel`
但是,*Asset Viewer* 显示正确的名称,而没有多余的`_dynmodel`。

这是由于 `find:t="^((.*)_dynmodel)\.lod00\.dag$"`语句中定义的搜索查询所致。
如果查询是 `find:t="^(.*_dynmodel)\.lod00\.dag$"`,则整个动态模型名称(包括 `_dynmodel`)将被视为对象名称 ($2)。我们使用的查询确保只有最内部的组(即没有 `_dynmodel` 的核心对象名称)被视为对象名称。
```
### 碰撞处理
正如我们所知,冲突现在通过文件包含(如 `include "#/develop/assets/_ri_collision_lod1.blk"`)来处理。默认情况下,此 include 也会影响动态模型,因为它不会排除它们。一种合乎逻辑的方法是首先包含动态模型碰撞块,但动态模型处理碰撞的方式不同——它们是通过损伤模型 (DM) 处理的。
因此,需要一种混合处理解决方案:
```
include "#/develop/assets/_ri_collision_lod1.blk" // 包括 RenderInst 碰撞处理。
"@override-last"{ // 覆盖包含文件中的参数。
"@override:find":t="^(.*)_dynmodel\.lod01\.dag$" // 查找专门用于动态模型的 LOD01。
"@override:contents"{gameResPack:t="game_logic.grp"; defCollidable:b=no;} // 为动态模型碰撞设置装配体参数。
stopProcessing:b=no // 这可能是一个多余的参数。
}
include "#/develop/assets/_ri_collision_lod1.blk" // 重复 RenderInst 碰撞处理 include。
```
这种混合方法可确保渲染实例和动态模型
在碰撞管道中得到适当处理。
### AnimChar
从技术上讲,我们不能直接在地图上放置动态模型,也不能在我们需要的闪烁模板中使用它。但是,我们可以使用 animChar(动画角色)来实现这一点。尽管名称抽象,但它允许我们有效地管理动态资源。
实质上,animChar 文件列出了应应用于特定动画模型的动态资源(闪烁的灯光只是动画的另一种形式)。
例如,`industrial_lamp_steel_wall_a_flicker_char.animChar.blk`包含以下两行:
```
dynModel:t="industrial_lamp_steel_wall_a_flicker_dynmodel" // 动态模型
skeleton:t="industrial_lamp_steel_wall_a_flicker_skeleton" // 关联的骨架
```
将 animChar 文件放在动态模型旁边,以模型命名,后缀为`_char.animChar.blk`。不需要额外的`.folder.blk`处理。
### GameObjects
[*Game Objects*](../about-assets/gameobjects/gameobjects.md) 本质上是与相关模板同名的占位符、容器或虚拟对象。
它们用于在环境中定位对象或将其添加到模板合成中。游戏对象提供触发声音 (SFX)、视觉效果 (VFX)、游戏触发器和光源等效果所需的矩阵信息。
通常,游戏对象与其他游戏对象一起存储在公共目录中。
例如,在基于 daNetGame 的项目中,它位于:
`/