# 光度学光源 (IES) ## 概述 在基于 *daNetGame* 的项目中,除了聚光灯或泛光灯等传统光源外,您还可以使用 [IES 格式](https://blog.ansi.org/2020/02/standard-file-photometric-data-ies-lm-63-19/) 添加光度学光源。 IES 文件实质上是一个文本文件,它根据 3D 空间中的角度定义来自源的光强度分布。格式规范可以在 [这里](http://expertunion.ru/normyi-osvescheniya/iesna-lm-63-1995-opisanie-formata-ies.html)找到。 您可以从 Internet 下载现成的 IES 文件,因为大多数照明制造商都为其产品提供 IES 配置文件。此外,还有大量的 IES 库可用,其中包含数千个适合各种可视化需求的配置文件。 或者,您可以使用各种编辑器手动创建 IES 配置文件。我用过这个 [IES 生成器](https://lightonline.ru/documents/Other/IES_Generator.html),它使用起来很简单:你可以用鼠标在垂直平面上绘制光线轮廓。 然后,生成的轮廓将围绕垂直轴“旋转”(类似于 3ds Max* 中的 *Lathe* 修改器,它从样条线创建 3D 对象)。 但是,此工具无法沿两个轴创建非对称 IES 剖面,这意味着墙壁和地板上的光分布不能同时变化。 ![Photometric Light Sources](./_images/photometric_lights_01.jpg) 如果需要更复杂的 IES 配置文件,则必须查找并测试其他软件,或搜索现有的 IES 文件。对于更简单的任务,此工具就足够了。本文末尾提供了示例。 ## 在基于 daNetGame 的项目中集成 IES 文件 下载或创建 IES 文件后,将其放在以下目录中: ``` //develop/assets/manmade_common/textures/ies ``` 全局 `foled.blk` 文件中的以下块处理 IES 文件的处理: ``` virtual_res_blk{ find:t="^(.*)\.ies$" className:t="tex" contents{ addrU:t="clamp"; addrV:t="clamp" convert:b=yes buildIES:b=yes textureWidth:i=128 textureHeight:i=128 } } ``` 这意味着在构建过程中,每个 IES 文件都会转换为 L8 格式的简单 128x128 像素纹理。 有关引擎实现的详细信息,请参阅 [Photometry](./photometric_lights.md#photometry)部分。 ## 在光源中使用 IES 文件 要将特定的 IES 文件用作光源,只需在模板的 `light.texture_name` 变量下指定其名称并编译 vroms。 基于 *daNetGame* 的项目的轻量级模板位于: ``` //prog/gameBase/content/common/gamedata/templates/_lights.blk ``` 例如,带有两个灯的壁灯将如下所示: ``` light_sconce_medium{ _extends:t="omni_light" light.max_radius:r=3.5 light.offset:p3=0, 0, 0 light.color:c=255, 152, 70, 255 light.brightness:r=2.5 light.contact_shadows:b=false light.texture_name:t="ies_doublelamp_sconce_a" } ``` ## 关于 IES 和 Omni 灯的重要说明 光度学灯光只能应用于泛光灯,这意味着它们不会投射阴影。因此,它们不适合在灯、聚光灯或类似光源中使用。相反,它们应该保留用于艺术照明效果。 ## IES 使用示例 以下是一些示例 IES 配置文件(从左到右:[*Asset Viewer*](../../dagor-tools/asset-viewer/asset-viewer/asset_viewer.md)、在 *IESGen 4* 生成器中查看,并在游戏中查看): - `ies_doublelamp_sconce_a` - `ies_multilamp_sconce_a` - `ies_singlelamp_sconce_a` - `ies_singlelamp_sconce_b` - `ies_hand_lantern_a` (最初用于煤油灯,但最终用于紧急出口标志)。 在其中一个示例中,为了在天花板上获得不均匀的照明,我只需将光源水平旋转 90 度即可。 - `ies_monitor_a` 如上一个示例所示,即使在表格下方也有光,因为泛光灯不会投射阴影。但是,结果是可以接受的——肯定比将带有刺眼阴影的聚光灯放在那里要好。 ## IES 的局限性 请务必了解,单个 IES 配置文件无法完美地重现多源或基于表面的灯光的复杂灯光模式。光线总是从单个点辐射,而不是从多个光源或一个区域辐射。例如,使用单个 IES 配置文件表示具有许多小灯泡的壁灯始终是一种折衷方案。您会注意到光线是从中心发出的,而不是从每个单独的灯泡发出的。尽管如此,结果在视觉上仍然是可以接受的。 ![Limitations of IES](./_images/photometric_lights_20.jpg) ## 光度法 基于 *daNetGame* 的项目支持光度学文件来描述泛光灯的光分布。本文介绍了如何使用它们。 #### 支持的文件类型 - **IES** - 格式: [ANSI/IES LM-63-19](https://blog.ansi.org/2020/02/standard-file-photometric-data-ies-lm-63-19/) - 文件详情: [Lifewire 关于 .ies 文件的文章](https://www.lifewire.com/ies-file-2621816) #### 文件放置 光度法文件应放置在适当文件夹下的 `develop/assets/` 目录中。要导出这些资源,请将以下块添加到`.folder.blk`中: ``` virtual_res_blk{ find:t="^(.*)\.ies$" className:t="tex" contents{ convert:b=yes buildIES:b=yes textureWidth:i=128 textureHeight:i=128 blurRadius:r=3 phiMin:r=0 phiMax:r=360 thetaMin:r=0 thetaMax:r=180 edgeFadeout:r=-1 } } ``` 确保资产名称具有 `ies_` 前缀。没有它,它们将无法在游戏中被识别为光度纹理。 `textureWidth` 和 `textureHeight`组件全局定义生成的纹理的分辨率。虽然可以导出不同分辨率的光度法纹理,但游戏将无法加载它们。如果创建其他块来解析 '.ies' 文件或稍后添加其他类型,请确保所有光度法纹理保持相同的分辨率。 ### 聚光灯和特殊选项 对于聚光灯,光线集中在中心周围,从而提高纹理质量。IES 导出器支持将光强度限制为围绕视图方向的特定角度(例如,180 度以将光限制为向前方向)。 #### 如何使用 此选项必须单独应用于灯光: 1. 将`.ies` 文件放在适当的目录中(带有相应的`.folder.blk`进行处理)。 2. 打开[*Asset Viewer*](../../dagor-tools/asset-viewer/asset-viewer/asset_viewer.md)并选择 IES 资源。 - 检查右侧面板中的光度信息。 - 前三个值(模糊半径、缩放、旋转)显示当前配置。 - 底部的两个值表示计算出的最优值。 3. 创建一个虚拟资产`.blk`文件,例如`ies_flashlight_a.tex.blk`代表 `ies_flashlight_a.ies`。 4. 使用最佳值指定 `iesScale:r` 和 `iesRotation:b` 属性。(目前,此过程不是自动化的。 ![How to Use](./_images/photometry_01.jpg) rotation 值还会隐式调整缩放比例。这些指定的值应接近 *Asset Viewer* 中显示的最佳值。如果值太低,导致纹理质量下降,则 *daBuild* 将显示警告并建议最佳值。如果缩放无法正确存储纹理,则 daBuild 将产生错误。 ### 模糊 模糊有助于减少光照中的像素化或锯齿。`blurRadius` 以度为单位指定,而不是以像素为单位,并应用于整个球体以确保纹理边缘无缝对齐。 #### 用法 在 `.folder.blk` 或虚拟资产 `.blk` 文件中定义 `blurRadius:r` 参数,如示例中所示。默认值为 `3`。 ### 角度限制 光源的内容可以限制为两个轴上的特定角度范围。相关选项包括: ``` phiMin:r=0 phiMax:r=360 thetaMin:r=0 thetaMax:r=180 edgeFadeout:r=-1 ``` - `phiMin`-`phiMax`范围定义围绕前进方向的限制。 - `thetaMin`-`thetaMax`定义从向前(theta=`0`) 到向后 (theta=`180`)的限制。 光强度完全保留在指定区域内。在此区域之外,它会根据`edgeFadeout`淡出。默认情况下,`edgeFadeout:r=-1`会计算一个自动淡出,以确保光线不会在纹理上渗出多个像素(取决于分辨率)。如果 `edgeFadeout >= 0`,则将其视为度值,与纹理分辨率无关。 **示例**: 为防止背光透过墙壁泄漏,请使用`thetaMin:r=0` 和 `thetaMax:r=93`的垂直限制。您必须在 `.folder.blk` 中使用这些参数创建新的虚拟资源(例如`/develop/assets/manmade_common/textures/ies/.folder.blk`)。 ### 为 Omni Light 设置 Photometric 要设置泛光灯的光度计: 1. 将`.ies`文件添加到资产文件夹。 2. 在贴图的`.blk` 文件中定义泛光灯的光度计: ``` entity{ _template:t="omni_light" light.direction:p3=0, 1, 0 light.texture_name:t="asset_name" ... } ``` #### 自定义纹理注意事项 - 任何纹理都可以用作`light.texture_name`中的光度纹理,但对于自定义纹理(不是由 IES 转换器生成),请记住以下几点: - 红色通道用于着色器。 - 分辨率必须与`.folder.blk`中指定的光度分辨率匹配。 - 布局必须与映射算法 (球面或八面体) 匹配。 - 如果分辨率较低,则在光线强度下可能会看到折叠线。这可以通过模糊折叠线处的像素对以具有相似的值来缓解: - **Spherical mapping**: 左侧和右侧 `(0, y)` ↔ `(w-1, y)` - **Octahedral mapping**: 每侧的两半折叠在一起,例如,对于顶部: `(x, 0)` ↔ `(w-x-1, 0)` - 不建议将自定义纹理用于测试以外的目的,因为与分辨率和布局更改相关的维护开销。 - 游戏将根据 `ies_`前缀加载资产。 - 此外,由于光度测量不均匀,因此必须指定光源方向。默认情况下,光线指向下方,但这可能与 `.ies`文件中的光度法方向不匹配。虽然这适用于测试文件,但没有规则保证`.ies`文件中的特定方向。 - 为了获得更好的性能,光源不存储完整的方向,并且可以围绕其方向自由旋转。以下是如何处理光源方向的确切细节: - 光的 **方向** 对应于其 **Y 轴**。对光度数据进行采样时,此方向由`theta = 0` 表示,而`phi`在 `[0, 2*pi]`范围内变化。这通常反映了测量过程中光线指向的方向。 - **X 轴** 是 `(1, 0, 0)` 或 `(0, 0, 1)` — 无论哪个选项都会产生垂直于光线方向的向量。沿光源方向的 parallel 分量将被删除,以确保这种垂直度。选择离光源方向较远的轴。 - 如果未找到纹理,游戏将发出警告并继续,而不应用光度纹理。 - 在未指定或定位光度法纹理的情况下,灯光将像以前一样使用完全强度。 ### Mapping `.ies` 文件通常包含有限数量的非均匀间距样本。 这些贴图使用以下两种映射方法之一转换为纹理: - **Octahedral Mapping** (默认):提供更好的样本分布。 ![Octahedral Mapping](./_images/photometry_04.jpg) - **Spherical Mapping**: 虽然实现了,但由于性能稍差且样本分布不均匀(两极密集,侧面稀疏),因此未使用。 #### 更改映射算法 要启用球形映射: 1. 在 `/prog/gameLibs/publicInclude/render/renderLights.hlsl`中,注释或取消注释该行: ``` #define USE_OCTAHEDRAL_MAPPING ``` 2. 在 `prog/tools/sceneTools/assetExp/exporters/texExp.cpp`中,修改以下内容: ``` IesReader::ImageData img = ies.generateOctahedral(width, height); // IesReader::ImageData img = ies.generateSpherical(width, height) ``` #### 生成的纹理的技术细节 - 格式: **L8 (8-bit, 单通道)** - 文件类型: `.DDSX` - **Spherical Mapping**: 第一个和最后一个像素列几乎相同,以避免在折叠线处出现插值问题(冗余: h 像素)。 - **Octahedral Mapping**: 边缘像素与相应的折叠像素几乎匹配(冗余: h + w 像素)。 **示例:** - 测试文件: [photometry_file_test2.ies](./_images/photometry_file_test2.ies) - 真实数据: [photometry_file_t8_06nw.ies](./_images/photometry_file_t8_06nw.ies)