05/30/2020
06/13/2020 HLSL 数学库
HLSL 语法
- HLSL
- 数据类型
- 标量
- 向量
- vector
- float4,int3..
- 初始化
- 访问方式-读写
- swizzles赋值
- 矩阵Matrix
- 类型声明
- 初始化
- 赋值
- HLSL与着色器结合
- hlsli声明文件
- 顶点着色器
- 像素着色器
- HLSL数学库
- 向量与矩阵相乘或者矩阵之间相乘(mul函数)
- 规矩
- float4,float3,float2与C++的结构体相似
- 分量乘法(*)
HLSL
HLSL是一个着色器语言,独立于WIndows平台,只能供微软Direct3D使用。HLSL不能与OpenGL抗衡,用来抗衡GLSL产品1
数据类型
标量
- bool 32位(4字节)整数值用于存放逻辑值true和false
- int 32位(4字节)有符号整数
- uint 32位(4字节)无符号整数
- half 16位(2字节)浮点数(仅提供用于向后兼容)
- float 32位(4字节)浮点数
- double 64位(6字节)浮点数
向量
向量类型可以支持2到4个同类元素
vector
vector<float,4> vec1;
vector<int,2> vec2;
vector vec3; //== float4 vec3 包含4个float元素
float4,int3…
float4 vec1;
int2 vec2;
初始化
float2 vec1 = {0.0f,1.0f}; //花括号
float3 vec2 = float3(0.0f,1.0f,0.0f); //小括号
float4 vec3 = float4(vec1,0.0f);
访问方式-读写
float4 vec;
float x = vec.x; // 坐标访问x,y,z,w
float r = vec.r; // 颜色访问r,g,b,a
float i = vec[2]; //下标访问0,1,2,3
vec.a = 2.0f;
swizzles赋值
float4 vec;
float3 a = vec.xyz;
float2 b = vec.rg;
float4 c = vec.zzyx; //!!
vec3.xyzw = c;
vec3.yy = a.zz;
矩阵Matrix
类型声明
//类型
float1x1 float1x2 float1x3 float1x4
float2x1 float2x2 float2x3 float2x4
float3x1 float3x2 float3x3 float3x4
float4x1 float4x2 float4x3 float4x4
matrix<float, 2, 2> mat1; // float2x2
matrix mat1; // float4x4
初始化
float2x2 mat1 = {
1.0f, 2.0f, // 第一行
3.0f, 4.0f // 第二行
};
float3x3 TBN = float3x3(T, B, N); // T, B, N都是float3
赋值
matrix M;
// ...
float f0 = M._m00; // 第一行第一列元素(索引从0开始)
float f1 = M._12; // 第一行第二列元素(索引从1开始)
float f2 = M[0][1]; // 第一行第二列元素(索引从0开始)
float4 f3 = M._11_12; // Swizzles
HLSL与着色器结合
hlsli声明文件
//.hlsli 声明文件可以写到hlsli文件中,不进行编译
//HLSL结构体进行声明
struct VertexIn
{
float3 pos:POSITION; //描述坐标系
float4 color:COLOR; //描述颜色
};
struct VertexOut
{
float4 posH:SV_POSITION; //说明改顶点的位置从顶点着色器输出后,后续不能改变它了
float4 color:COLOR;
};
//常量缓冲区
//cbuffer 用于声明一个常量缓冲区
//matrix 等于float4*4
//HLSL默认为列主矩阵
//register(b0)该常量缓冲区位于寄存器索引为0的缓冲区
cbuffer ConstantBuffer:register(b0)
{
matrix gWorld;
matrix gView;
matrix gProjection;
}
顶点着色器
#include "Triangle.hlsli"
//返回值,与参数在hlsli声明过了
//VS 函数名表示入口函数名
VertexOut VS(VertexIn vIn)
{
VertexOut vOut;
vOut.posH = float4(vIn.pos,1.0f);
vOut.color = vIn.color;
return vOut;
}
像素着色器
#include "Triangle.hlsli"
float4 PS(vertexOut pIn):SV_Target //SV_Target 说明输出的颜色将会直接保存到渲染目标视图的后备缓冲区对应位置
{
return pIn.color; //pIn的值由 顶点着色器传递而来
}
HLSL数学库
向量与矩阵相乘或者矩阵之间相乘(mul函数)
matrix g_View; //matrix 数据类型 是 4x4矩阵
matrix g_Proj;
matrix viewProj = mul(g_View,g_Proj); //矩阵之间的相乘
float4 PosL;
float4 PosW = mul(PosL,viewProj); //向量与矩阵的相乘
- 用于矩阵相乘和向量变换等问题
- matrix 和 float4x4 是一样的,但是用的是列主序矩阵
- 可以使用row_major 强行把列主序矩阵转为行主序矩阵
规矩
- 行向量×行主序向量
- 列主序向量×列向量
- matrix 中列主序矩阵会发生转置
但是由于汇编dp4运算可以直接取列主序矩阵的行,从而避免大量转置,所以可以采用行向量×列主序向量
- C++代码端不进行转置,HLSL中使用row_major matrix(行主序矩阵),mul函数让向量放在左边(行向量),这样实际运算就是(行向量 X 行主序矩阵) 。这种方法易于理解,但是这样做dp4运算取矩阵的列很不方便,在HLSL中会产生用于转置矩阵的大量指令,性能上有损失。
- **C++代码端进行转置,HLSL中使用matrix(列主序矩阵) ,mul函数让向量放在左边(行向量),这样就是(行向量 X 列主序矩阵),但C++这边需要进行一次矩阵转置,HLSL内部不产生转置 。**这是官方例程所使用的方式,这样可以使得dp4运算可以直接取列主序矩阵的行,从而避免内部产生大量的转置指令。后续我会将教程的项目也使用这种方式。
- **C++代码端不进行转置,HLSL中使用matrix(列主序矩阵),mul函数让向量放在右边(列向量),**实际运算是(列主序矩阵 X 列向量)。这种方法的确可行,取列矩阵的行也比较方便,效率上又和2等同,就是HLSL那边的矩阵乘法都要反过来写,然而DX本身就是崇尚行主矩阵的,把OpenGL的习惯带来这边有点。。。
- C++代码端进行转置,HLSL中使用row_major matrix(行主序矩阵),mul函数让向量放在右边(列向量),实际运算是(行主序矩阵 X 列向量)。 就算这种方法也可以绘制出来,但还是很让人难受,比第2点还难受,我甚至不想去说它。
float4,float3,float2与C++的结构体相似
//float4 有4个分量,每个分量是float型的
float4 posL;
float temp = posL.x * posL.y * posL.z * posL.w;
//C++ 中
struct float4
{
float x;
float y;
float z;
float w;
};
分量乘法(*)
float3 color1;
float3 color2;
float3 blend = color1 * color2; // blend.x = color1.x * color2.x;
- 可以用于灯光,颜色混合,纹理颜色混合等等
X_Jun HLSL mul函数讲解
X_Jun HLSL 语法入门
- 百度百科介绍 ↩︎