DreamShaderLang
快速开始

项目结构

DShader/ 怎么组织、哪些目录归插件所有,以及决定什么会被编译的 Package 规则。

DreamShaderLang 的源文件放在项目根目录下的一个目录里 —— 默认是 DShader,由 Project Settings ▸ DreamPlugin ▸ Dream Shader ▸ Paths ▸ Source Directory 配置。相对路径相对项目 目录解析。

源目录、它的 Packages 子目录和生成 shader 目录都由插件在模块启动时创建,也就是编辑器第一次启动时, 无论你有没有写过任何源文件。

目录树

M_Sample.dsm
F_Tint.dsf
Common.dsh
Color.dsh
dreamshader.package.json
Noise.dsh
DreamShader.code-workspace
dreamshader.lock.json

各目录职责

目录归属内容
DShader/源文件根目录。下面怎么分都行,这里给的是约定而不是规则。
DShader/Materials/材质 .dsm,通常一个文件一个 Shader
DShader/Functions/可复用的 .dsf 函数文件。
DShader/Shared/项目内部的 .dsh header。
DShader/VirtualFunctions/编辑器Create Virtual Function 为已有 UMaterialFunction 写声明的位置。
DShader/Decompiled/编辑器Export DSM / Export DSF 的输出目录,分为 MaterialsFunctionsLayersLayerBlends
DShader/Packages/扩展已安装的共享库。永远是源根下那个字面量子目录 Packages,不能单独配置。
DShader/DreamShader.code-workspace插件每次执行 Open Dream Shader Workspace 都会整体重写。
DShader/dreamshader.lock.json扩展记录已安装 Package 的版本。插件既不读也不写。
Intermediate/DreamShader/GeneratedShaders/插件生成的 .ush helper include,挂载在 /DreamShaderGenerated

DreamShader.code-workspace 每次调用都从一个固定对象序列化而来 —— 从不读取、合并或保留原文件。手动 加的 launchtasksextensions 或额外 settings 都会被销毁。把个人配置放在 DShader/.vscode/settings.json,这个命令不会碰它。

命名约定

类型约定
材质文件M_*.dsm
材质函数文件F_*.dsf
共享 header按领域命名 —— Texture.dshColor.dsh
Package 入口Library/<Name>.dsh

扩展名比较是大小写不敏感的,所以 M_Water.DSM 也是材质文件。标识符则是另一回事:插件把命名空间和 函数名净化成 HLSL 与资产标识符时会替换掉非 ASCII 字符,所以这些名字请用 ASCII。

import

每个材质尽量只 import 少量稳定入口:

import "Shared/Common.dsh";
import "@typedreammoon/dream-noise/Library/Noise.dsh";

一个 specifier 会依次尝试三个根:导入方文件所在目录、源根、Package 根。第一个存在且没有跑出自己根 目录的候选胜出 —— Package 内部的文件不能用 ../ 爬出去。没有扩展名的 specifier 会被补上 .dsh, 所以 import "…/Noise" 永远不可能解析到 .dsf。完整规则见 import 与命名空间

import 保持浅层还有一个好处:源 hash 覆盖的是整段内联后的 import 闭包,改一个 header 会让所有引入它的 文件都失效。

什么会被编译,什么不会

插件有两个枚举器,它们排除的东西不一样。

枚举器扩展名排除使用者
全量源枚举.dsm.dsh.dsfDShader/Packages 下的全部文件启动时的内存生成、commandlet 的 compile -All、cook、Gen 页列表、VirtualFunction 同步
材质源枚举.dsm.dsfDShader/Packages 下的 .dsmRecompile DSM、自动编译队列、依赖图

Packages 排除对 .dsm 是完整的,对 .dsf 只是部分。Package 里的 .dsf 在交互式编辑器会话中 被编译 —— 文件监视器和 Recompile DSM 都会拾取它 —— 但 compile -All、cook 和 Gen 页 不会。也就是说,一个附带 .dsf 函数资产的 Package 在本地能用,在 headless 构建里会静默地什么都 不生成。库代码请以 .dsh header 形式分发,或者把 .dsfPackages 复制到自己的源码树里。

Package 内的 Examples/**/*.dsm 在任何路径下都不会被编译,也不会出现在 Gen 页。要用示例,把它从 DShader/Packages 复制到 DShader/ 下。

Package 的 .dsh header 完全可以被 import,但从不参与 VirtualFunction 声明扫描 —— Package 里带的 VirtualFunction 永远不会与它的资产做校验。

版本管理

内容是否提交
.dsm / .dsf / .dsh提交 —— 这就是材质逻辑本身
dreamshader.lock.json如果团队会安装 Package,提交
Config/DefaultEngine.ini提交 —— 项目设置存在这里,是共享的
DShader/Packages/团队自定:直接入库,或按 lock 文件重新安装
生成的 .uasset一般不提交 —— 默认 backend 下编辑器本来也不会写出它们
Intermediate/DreamShader/不提交

团队内统一 Source Directory,这样 import 在每台机器上的解析结果才一致。

下一步

本页目录