3个不稳定版本
使用旧的Rust 2015
0.2.1 | 2019年1月19日 |
---|---|
0.2.0 | 2018年9月30日 |
0.1.0 | 2018年7月8日 |
#233 在 渲染
用于 spectra
65KB
1K SLoC
Cheddar GLSL超集语言
什么是Cheddar?
Cheddar是GLSL的超集。
该包在其文档中包含一个嵌入教程,它将为您提供足够的详细信息,以了解Cheddar是什么以及您应该如何使用它。
贡献
您可以通过分支项目并提供合并请求来贡献。目前需要特别关注的工作主要包括
- 核心类型和结构。
- 示例。
- 语义分析。
- 细分控制着色器。
- 细分评估着色器。
- 适当的公共API。
lib.rs
:
Cheddar着色语言。
前言
Cheddar是GLSL的超集,它增加了几个功能以增强GLSL。
- 在Cheddar中将一些非有效GLSL构造转换为有效,以简化某些着色阶段的编写。
- 一种更函数式的GPU着色编程方法。
- 结构、类型和GLSL特定构造的共享。
- 导入和模块。
该语言被表示为一个DSL。
函数式着色语言
Cheddar使用与GLSL相同的语法(对于大多数构造)。如果您已经编写了一段时间的GLSL,您可能需要大约二十分钟的时间来熟悉Cheddar并开始使用它。
与GLSL的最大不同之处在于Cheddar试图更函数化。它仍然是一种命令式语言;您仍然可以创建变量并更改其内容。但是,您不再写入全局变量(即顶点属性)或不再发射顶点和原语。
核心:语义函数
语义函数是您可以声明的函数,具有使它们特殊化的名称。每个程序员都知道至少一个语义函数:main
。如果一个代码单元导出一个名为main
的函数,该函数不接受任何参数并返回空值,则此函数将被视为您的二进制文件的入口点。Cheddar通过识别多个语义函数来使用此概念。
注意:可以更改链接器/编译器识别的作为
start
例程的函数的名称。尽管如此,目前使用Cheddar无法实现这一点。
大多数语义函数直接映射到着色器阶段。使用原始GLSL,如果你想编写一个顶点着色器,你必须提供一个导出main
函数的代码单元。这段代码通常会通过in
声明读取顶点属性,并将代码传递给下一个阶段(通常是片段着色器,但也可能是几何着色器等)。
这是一个典型、无聊的顶点着色器
layout (location = 0) in vec3 i_pos;
layout (location = 1) in vec4 i_col;
in vec4 o_col;
void main() {
gl_Position = vec4(i_pos, 1.);
o_col = i_col;
}
这个简单的顶点着色器只是将它的颜色传递到下一个阶段。
现在让我们尝试将这个代码段转换为Cheddar。首先,Cheddar没有着色器阶段的概念。一切都是一个函数。这使组合变得更好。映射到顶点着色器的语义函数是Cheddar中的map_vertex
函数。必须遵守一些规则和定律。
map_vertex
的签名是自由的,但- 它必须返回一个用户定义的类型,其名称是自由的。
- 它可以有任意多的参数(甚至零),这些参数代表顶点着色器的输入。然而,这些参数的类型必须与GLSL顶点属性兼容。
- 如果你想忽略一个参数,你只需省略其名称但保留其类型(例如,在C中)。
- 返回位置的类型必须至少有一个字段,其类型为
vec4
– 当前名称受限制,你必须将其称为chdr_Position
。该字段表示计算输出的实际顶点位置,你无法从中读取;你只能写入它。如果你需要在map_vertex
之后使用它,你需要为你的结构添加另一个字段。这个限制可能在未来的版本中取消。
Cheddar不关心函数和类型出现的顺序,它在编译时会重新组织它们。
上面的代码段对应的Cheddar可能是
struct V {
vec4 pos;
vec4 col;
};
V map_vertex(vec3 pos, vec4 col) {
return V(vec4(pos, 1.), col);
}
当编译为GLSL时,上面的Cheddar代码将看起来像前面的GLSL代码段。你可以看到一些有趣的属性
- 全局(即
in
)不再存在,现在是函数参数
。 - 你可以忽略函数参数 – 例如,
V map_vertex(vec3 pos, vec4)
。 - 你不再写入全局(即
out
),而是返回值
。
从这个意义上说,Cheddar比原始GLSL更函数式。
你将想要编写一个片段着色器来消耗那个color
值。原理是相同的:你需要编写一个接受这个V
类型作为单个参数
并返回用户定义的类型的语义函数。这个函数必须命名为map_frag_data
。
让我们编写一个片段着色器,它将使用顶点的颜色显示我们的顶点。
struct F {
vec4 col;
};
F map_frag_data(V v) {
return F(v.col);
}
就这样!最后,假设我们想在顶点着色器和片段着色器之间插入一个几何着色器。这是通过定义concat_map_prim
来完成的。这个函数很棘手,因为它不返回任何内容,充当一个生成器。它接受两个参数
- 输入补丁类型,形式为
in YourType[dimension] binding_name
。YourType
是您定义的顶点类型(在我们的例子中,将是V
)。dimension
是补丁中的顶点数量。1
将会使您映射点。2
将会使您映射线。3
将会使您映射三角形。
binding_name
是您希望参数调用的名称。
- 输出原语类型,形式为
layout (output_prim, max_vertices = nb) out YourOutputType
。output_prim
是要使用的输出原语。points
将输出简单点。line_strip
将输出带状线。triangle_strip
将输出带状三角形。
nb
是您将输出的最大顶点数。
以下是我们当前示例的示例。
struct GV {
vec4 pos;
vec4 col;
vec3 normal;
};
void concat_map_prim(in V[3] verts, layout (triangle_strip, max_vertices = 3) out GV) {
// …
}
接下来,您想了解的是您应该如何“生成”顶点和原语。这是通过一系列语义函数完成的
yield_vertex
,它接受一个正确类型的顶点作为单个参数(在我们的例子中为V
)。yield_primitive
,它不接受任何参数。
这两个函数都不返回任何内容。前者将 yield 您传递的顶点并将其发送到当前原语。带状原语将连接您发出的每个顶点,直到您调用 yield_primitive
函数,该函数将使用前面的点生成原语,并最终开始另一个原语,如果之后发出其他 yield_vertex
调用。
最后,这些函数应放在同一个代码单元中。Cheddar 不要求您为不同的 着色器阶段 提供不同的字符串,因为语义函数具有不同的签名和名称。
构造共享
Cheddar 的一个主要优势是启用 构造共享。也就是说,您使用的大多数全局符号都将在所有 着色器阶段 之间共享。这并不令人惊讶,因为我们到目前为止只定义了函数,那么我们为什么要重复使用每个类型呢?即使 GLSL 要求您重复 struct
、uniform
和 in
/ out
声明,Cheddar 也不会,它将在幕后执行所有操作。
如果您声明一个类型,例如
struct MySuperCoolType {
float a;
vec3 b;
mat4 c;
};
并在几个语义函数(比如 map_vertex
和 map_frag_data
)中使用它,Cheddar 将自动生成具有相同类型定义的 MySuperCoolType
的 顶点着色器 和 片段着色器。
这种共享对以下内容有效
struct
定义。- 全局
const
声明。您将喜欢定义PI
一次并永远。 uniform
(常规和 块)。- 您不必担心
in
和out
是否匹配,因为所有操作都在函数级别以及通过您定义的类型完成。 - 除了语义函数之外的所有函数。
模块和导入
定义
Cheddar 还提供了一些强制性的重构和组织代码的功能:模块。您所编写的任何代码都属于一个模块。目前,模块导出它们定义的所有符号。
模块有一个名称,并且必须是唯一的。名称的格式为:foo.bar.zoo
,并且有直接的文件系统表示。在这里,foo.bar.zoo
模块位于文件 foo/bar/zoo.chdr
中。
导入模块
可以使用 use
关键字导入模块——简单,就像 Rust 一样!——并且可以使用括号 ( )
来选择项目。
use foo.bar.zoo (PI)
在这里,我们从 foo.bar.zoo
导入 PI
。
免责声明:目前,导入列表 仅向程序员提供提示,并由 Cheddar 运行时使用。所有符号都被导入。这将在未来的版本中修复。
Cheddar 支持传递依赖关系,并且知道如何解决导入的 菱形问题。如果您遇到任何依赖循环,它也会正确捕获。
关于 warmy
的说明
Cheddar 使用 warmy
crate 为您提供模块和简单的依赖关系解决器。当前的情况是,如果您不要求 Cheddar 进行查找,它不会查找您模块的依赖关系。有关如何操作的更多信息,请参阅 Module::substitute_imports
函数。
由于使用了 warmy
,Cheddar 还支持自动重新加载阴影模块。
关于验证的说明
目前,Cheddar 在验证您的代码方面做了非常、非常少的验证工作。它主要检查
- 通过 glsl crate 的 GLSL 语法。
- 一些 Cheddar 构造,例如您提供的类型或顶点类型中的字段。
- 依赖模块循环。
**您的代码的语义不会被分析**。这意味着如果您做了类似 float x = true;
的操作,Cheddar 不会抱怨。
正在开发中,但非常欢迎贡献!
关于细分控制和平滑评估着色器的说明
这两个阶段尚未集成到 Cheddar 中。
依赖关系
~2–9.5MB
~84K SLoC