标签:ogr express protected string pac continue css nts sig
原文:[HLSL]HLSL 入门参考 (dx11龙书附录B译文)
HLSL 高级着色语言 参考文档
龙书DirectX12现已推出中文版,其附录B的高级着色器语言参考的翻译质量比本文更高,有条件的读者可以去支持一下。
Note: 一些平台可能不支持 int, half, 或 double. 这些平台会使用 float 来模拟.
Note: 可以将 float 替换成其他标量类型以组成新的矢量. 比如 int2, half3, bool4.
??可以通过像给数组或结构体初始化那样初始化矢量:
float3 v = {1.0f, 2.0f, 3.0f};
float2 w = float2(x, y);
float4 u = float4(w, 3.0f, 4.0f);
// u= (w.x, w.y, 3.0f, 4.0f)
??可以通过数组下标的语法访问矢量元素. 比如访问矢量 vec 的第i个元素,可以这样写:
vec[i] = 2.0f;
??另外,可以通过定义好了的元素名 x, y, z, w, r, g, b 和 a 像访问结构体那样访问矢量元素.
vec.x = vec.r = 1.0f;
vec.y = vec.g = 2.0f;
vec.z = vec.b = 3.0f;
vec.w = vec.a = 4.0f;
?? 名称 r, g, b 和 a 与名称 x, y, z 和 w 引用的元素完全一样. 当用矢量表示颜色时,使用符号RGBA会更好一些,因为这强调了矢量储存的是颜色的事实.
??有时候会要使用矢量 的元素来填充矢量 .最直接的方法就是分别引用每个元素来分别赋值.不过 HLSL 提供了一种叫 Swizzles 的特殊的语法来进行这种仅仅变换次序的赋值:
float4 u = {1.0f, 2.0f, 3.0f, 4.0f};
float4 v = {0.0f, 0.0f, 5.0f, 6.0f};
v = u.wyyx;
//v = {4.0f, 2.0f, 2.0f, 1.0f}
??另一个例子:
float4 u = {1.0f, 2.0f, 3.0f, 4.0f};
float4 v = {0.0f, 0.0f, 5.0f, 6.0f};
v = u.wzyx;
// v = {4.0f, 3.0f, 2.0f, 1.0f}
??如果只需要复制部分元素的话可以这样子:
float4 u = {1.0f, 2.0f, 3.0f, 4.0f};
float4 v = {0.0f, 0.0f, 5.0f, 6.0f};
v.xy = u;
// v = {1.0f, 2.0f, 5.0f, 6.0f}
??可以使用下列语法定义 m × n 的矩阵,其中 n 和 m 必须在 1 到 4 之间:
floatmxn matmxn;
??例如:
Note: 可以将 float 替换成其他标量类型以组成新的矩阵. 比如 int2x2, half3x3, bool4x4.
??可以使用两个数组下表的语法访问矩阵元素.例如访问 i 行 j 列元素:
M[i][j] = value;
??另外还可以像结构体那样访问矩阵元素:
// One-Based Indexing:
// 索引从1起计数
M._11 = M._12 = M._13 = M._14 = 0.0f;
M._21 = M._22 = M._23 = M._24 = 0.0f;
M._31 = M._32 = M._33 = M._34 = 0.0f;
M._41 = M._42 = M._43 = M._44 = 0.0f;
// Zero-Based Indexing:
// 索引从0起计数
M._m00 = M._m01 = M._m02 = M._m03 = 0.0f;
M._m10 = M._m11 = M._m12 = M._m13 = 0.0f;
M._m20 = M._m21 = M._m22 = M._m23 = 0.0f;
M._m30 = M._m31 = M._m32 = M._m33 = 0.0f;
??有时候会需要引用矩阵的行矢量出来.可以只用一个数组下标来引用行矢量.比如从 3 × 3 矩阵 中提出第i行的行矢量可以这样子:
float3 ithRow = M[i];
// 获取第i行行矢量
??下面的例子演示了向矩阵中插入三个矢量:
float3 N = normalize(pIn.normalW);
float3 T = normalize(pIn.tangentW - dot(pIn.tangentW, N)*N);
float3 B = cross(N,T);
float3x3 TBN;
TBN[0] = T; // 设置第 1 行行矢量
TBN[1] = B; // 设置第 2 行行矢量
TBN[2] = N; // 设置第 3 行行矢量
??还可以从行矢量生成矩阵:
float3 N = normalize(pIn.normalW);
float3 T = normalize(pIn.tangentW - dot(pIn.tangentW, N)*N);
float3 B = cross(N,T);
float3x3 TBN = float3x3(T, B, N);
Note:四维矢量和 4 × 4 矩阵除了可以用 float4 和 float4x4 表示,还可以直接用 vector 和 matrix 表示:
vector u = {1.0f, 2.0f, 3.0f, 4.0f};
matrix M; // 4 x 4 矩阵
??可以用熟悉的 C++ 语法声明一个数组,例如:
float M[4][4];
half p[4];
float3 v[12]; // 12 个三维矢量
??结构体同样可以像 C++ 那样定义.不过 HLSL 的话就不允许有成员函数.这是一个结构体的例子:
struct SurfaceInfo {
float3 pos;
float3 normal;
float4 diffuse;
float4 spec;
};
SurfaceInfo v;
litColor += v.diffuse;
dot(lightVec, v.normal);
float specPower = max(v.spec.a, 1.0f);
??HLSL 的 typedef 跟 C++ .的几乎完全一样.例如给 vector<float,3>
一个别名可以这样:
typedef float3 point;
??然后可以将这样子的写法:
float3 myPoint;
改写成:
point myPoint;
??这是另外一个将 const 关键字(用起来跟C++一样的)进行 typedef 的演示:
typedef const float CFLOAT;
??以下关键字可以添加到变量前面作为前缀:
static: 本质上讲是 extern 的反义词;这个关键字表示该变量不会暴露给 C++ ,是仅着色器程序内部可见的变量.
static float3 v = {1.0f, 2.0f, 3.0f};
uniform: 表示变量不改变每一个顶点或像素—使得变量对于所有顶点和像素都是常量,只能在 C++ 改变其值.变量只能在着色器程序外部初始化(例如从 C++)
extern: 表示变量在 C++ 可见(例如 C++ 程序可在着色器程序外部访问这个变量).这里的全局变量默认为 uniform 和 extern.
const: 该关键字与 C++ 的 const 关键字一样.表示该变量为常量,不可改变.
const float pi = 3.14f;
??HLSL 允许数据进行类型转换,而且类型检查非常宽松.HLSL的类型转换跟 C 语言的相似.例如,转换 matrix 为 float 可以这样:
float f = 5.0f;
float4x4 m = (float4x4)f;
// 给 m 的每一个元素赋 f
??标量到矩阵的类型转换会将标量给矩阵的的每一个元素都用这个标量赋值.看看下面的例子:
float3 n = float3(...);
float3 v = 2.0f*n - 1.0f;
?? 2.0f*n
是标量与矩阵的数乘,没有问题.然而要使式子成立,标量 1.0f 会扩充成矢量 (1.0f, 1.0f, 1.0f)
.因此式子相当于:
float3 v = 2.0f*n - float3(1.0f, 1.0f, 1.0f);
??这里的例子都能容易地推断出类型转换的情况.不过完整的类型转换规则还是得参阅 SDK 参考文档,搜索 “Casting and Conversion”.
??为了方便参考,现在列出 HLSL 所有的关键字:
- | - | - | - |
---|---|---|---|
asm | float | pass | true |
bool | for | pixelshader | typedef |
compile | half | return | uniform |
const | if | sampler | vector |
decl | in | shared | vertexshader |
do | inline | static | void |
double | inout | string | volatile |
else | int | struct | while |
extern | matrix | technique | |
false | out | texture |
??下面的关键字保留且未使用,未来可能成为正式关键字.
- | - | - | - |
---|---|---|---|
auto | dynamic_cast | private | template |
break | enum | protected | this |
case | explicit | public | throw |
catch | friend | register | try |
char | goto | reinterpret_cast | typename |
class | long | short | union |
const_cast | mutable | signed | unsigned |
continue | namespace | sizeof | using |
default | new | static_cast | virtual |
delete | operator | switch | - |
??HLSL支持很多熟悉的 C++ 关键字. 除了下面要提到的少数的相异点,这些算符用起来跟 C++ 一毛一样.下表列出了所有的 HLSL 的算符.
- | - | - | - | - | - |
---|---|---|---|---|---|
[ ] | . | > | < | <= | >= |
!= | == | ! | && | || | ? : |
+ | += | - | -= | * | *= |
/ | /= | % | %= | ++ | – |
= | ( ) | , |
??虽然这些算符用起来跟 C++ 很像,但是还是有相异点.
Note:像是在 C++ 里的一样,这些算符的行为可从它对标量的运算里猜出来.
float4 u = {1.0f, 0.0f, -3.0f, 1.0f};
float4 v = {-4.0f, 2.0f, 1.0f, 0.0f};
// 矢量分量加法(各元素相加)
float4 sum = u + v; // sum = (-3.0f, 2.0f, -2.0f, 1.0f)
??矢量分量自增(各元素自增)
// 自增前: sum = (-3.0f, 2.0f, -2.0f, 1.0f)
sum++;
// 自增后: sum = (-2.0f, 3.0f, -1.0f, 2.0f)
??矢量分量乘法
float4 u = {1.0f, 0.0f, -3.0f, 1.0f};
float4 v = {-4.0f, 2.0f, 1.0f, 0.0f};
// 矢量分量乘法(各元素相乘)
float4 product = u * v; // product = (-4.0f, 0.0f, -3.0f, 0.0f)
Warning: 对于两个矩阵
float4x4 A;
float4x4 B;
操作 A*B
会进行分量乘法,而非矩阵乘法,矩阵乘法需要用函数 mul 进行.
??比较算符同样会对每个元素进行,并且返回由 bool 型值组成的(布尔)矢量或矩阵. bool 型值会填充整个作为运算结果的矢量或矩阵.例如:
float4 u = { 1.0f, 0.0f, -3.0f, 1.0f};
float4 v = {-4.0f, 0.0f, 1.0f, 1.0f};
float4 b = (u == v);
// b = (false, true, false, true)
??最后,对二元算符可以做如下断定的结论:
(x + y)
操作时, x 会被类型转换为 float3 型矢量,表达式最终结果的类型为 float3 型,其中 float 型的 x 类型会 提升 成 float3(x, x, x),这也是因为标量到矢量的类型转换预定好的.注意:对于未有定义类型转换的 提升 将会失败.例如, float2 到 float3 的 提升 将会失败,因为不存在矢量 float2 到矢量 float3 的类型转换.(x + y)
操作时, x 会被 提升 为 half 型,表达式最终结果的类型为 half.??HLSL 支持许多熟悉的 C++ if 语句,循环语句及其他常见的控制流程的语句.这些流程语句的语法跟 C++ 超像.
return (expression);
if(condition) {
statement(s);
}
if(condition) {
statement(s);
} else {
statement(s);
}
for(initial; condition; increment) {
statement(s);
}
while(condition) {
statement(s);
}
do {
statements(s);
}while(condition);
??HLSL 的函数有以下特点:
??并且 HLSL 还添加了给自定义函数用的额外的关键字.比如下面这个函数:
bool foo(
in const bool b, // input bool
out int r1, // output int
inout float r2 // input/output float
) {
if(b) { // 试探输入的数据
r1 = 5;
// 通过 r1 输出
} else {
r1 = 1;
// 通过 r1 输出
}
// 因为 r2 为 inout 所以可以用它作为 输入, 即读取数据
// 也可通过 r2 输出
r2 = r2 * r2 * r2;
return true;
}
??函数几乎就跟 C++ 的一样除了 in, out 和 inout 关键字.
float square(in float x) {
return x * x;
}
??去掉 in :
float square(float x) {
return x * x;
}
void square(in float, out float) {
y = x * x;
}
??通过 x 输入一个要被平方的数,并用 x 自乘得到平方并通过 y 返回值.
void square(inout float x) {
x = x * x;
}
??通过 x 输入一个存有要被平方的数的变量,并用 x 自乘得到平方并通过 x 返回值.
??HLSL 有用于 3D 图形编程的丰富的内建函数.下面列出部分内建函数:
Note: 很多函数都根据它应该能处理的数据重载了,使之能处理所有应该能处理的内建类型的参数.例如 abs 应当能处理所有标量数据,因故重载了对所有标量类型的操作.另外就是外积 cross 函数应当只能处理三维矢量,所以它就只重载了对所有标量类型的三维矢量的操作(例如 int3, float3, double3 等).还有就是线性插值函数 lerp 应该能处理所有标量,二维矢量,三维矢量和四维矢量的数据,所以它重载了这些所有类型的操作.
Note: 如果给"标量"函数(例如 cos(x))一个非标量的参数,该函数会遍历所有元素,对所有元素都调用该函数.例如:
float3 v = float3(0.0f, 0.0f, 0.0f);
v = cos(v);
会对所有元素都调用 cos 函数.
Note: 关于更多参考文档,完整的内建函数清单请查阅 DirectX 参考文档,搜索 “HLSL Intrinsic Functions.”
Parameters are always passed by value. ??
标签:ogr express protected string pac continue css nts sig
原文地址:https://www.cnblogs.com/lonelyxmas/p/10807273.html