——介绍HLSL常用函数,API的使用。

想要成为合格的技术美术,一定要具备Shader开发能力,满足性能的需求,无论是技术美术的哪一个方向,HLSL都是需要点满的技能点。

参考

微软官方HLSL库:HLSL 参考 - Win32 apps | Microsoft Docs

《DirectX 3D HLSL高级实例精讲》我看的是实体书:GitHub - ljb1672/DirectX-3D-HLSL-Senior-instance-succinctly: code for DirectX 3D HLSL Senior instance succinctly


HLSL 语言

在渲染管线和介绍主流API的博客中,都提到了“可编程渲染管线”,其核心就是HLSL语言,正是因为HLSL才能对渲染管线可编程(针对微软的DX而言,当然还有Cg和OpenGL)。

HLSL语言和C++很相似,但是除了bool、int、float、double等标准型变量外,还有texture纹理变量、float、vec等向量类型等等。

本篇博客就根据技术美术百人计划的进度,主要介绍介绍HLSL的常用函数,秉持着不单纯copy老师PPT的原则,惯例会加入自己的理解。

HLSL的函数

HLSL的核心函数是由显卡驱动程序提供的函数库,用于向量及图形的计算,有了此函数库,程序的重点是将物理现象和光照模型转化成数学算法,算法则是由核心函数表达的代码,HLSL常用的函数大概有以下几种。

图形计算器

推荐了一个很方便的、图形相关数学函数实施验证的网站:Graphtoy

当然,其他的例如dmsmos也可以: Desmos | 图形计算器

把HLSL函数输进去,可以实时看到函数的数学表达形式,无需写Shader才能可视化。

1 基本数学运算

10个常用的数学运算

max(a,b) 返回较大的一个
min(a,b) 返回较小的一个
mul(a,b) 两变量相乘,常用于矩阵运算
abs(value a) 返回a的绝对值
round(x) 返回与x最近的整数
sqrt(x) 返回x的平方根
rsqrt(x) 返回x的平方根的倒数
degrees(x) 弧度转换成角度
redians(x) 角度转换成弧度
noise(x) 噪声函数,传入二维坐标返回[0,1]随机值

2 幂指对函数

常用的幂指对函数

pow(x,y) x的y次幂
exp(x) 返回以e为底的指数函数
exp2(value x) 返回以2为底,x为指数的幂
ldexp(x,exp) 返回x与2的exp次方乘积
log(x) 返回以e为底的对数 ln x
log2(x) 返回以2为底的对数
log10(x) 返回以10为底的对数
frexp(x,out exp) 把浮点数x分解成尾数和指数,返回值是尾数ret,exp参数返回的是指数,如果x为0,则exp和ret均0

in/out/inout关键字

frexp(x,out exp)中出现了out,是个关键字,一起的还有in、inout:

  • in——默认的,可不加,表必须传递参数值
  • out——表该参数是函数的一个返回值,仅用作输出,不能用作输入
  • inout——可输入也可输出

关于out具体点的解释:指定实参应该在函数返回时被拷贝给型参,这样可以通过参数返回值。out关键字是必须的,因为HLSL不允许传递一个引用或一个指针。如果实参标记为out,在函数开始前,型参就不拷贝给实参了。换句话说,out实参仅可以被用于输出数据——它不能用于输入。

3  三角函数和双曲函数

三角函数

sin(x) 求正弦,下划线前x均为弧度
cons(x) 求余弦
tan(x) 求正切
sincos(x,out s,out c) 返回x的正弦值s和余弦值c
tan(y,x) 返回y/x的正切值
asin(x) 返回输入值的反正弦值
acos(x) 返回输入值的反余弦值
atan(x) 返回输入值的反正切值
atan2(y,x) 返回y/x的反正切值

双曲函数

sinh(x) 返回x的双曲正弦值
cosh(x) 返回x的双曲余弦值
tanh(x) 返回x的双曲正切值

双曲函数——悬链线

这部分参考了:可能是最好的讲解双曲函数的文章 - 知乎 (zhihu.com)

双曲函数的起源是悬链线。双曲函数是一条有点像二次抛物线又不完全是的曲线,这条曲线与两端固定的绳子(铁链)在均匀引力作用下下垂的弧度相似,因此这条曲线也直接被叫做悬链线。具体的直接看上面的参考文章把,讲得非常不错!

一图展示三角函数和双曲函数的关系:

4  数据范围类

接下来是10个求数据范围的常用函数。

数据范围相关常用函数

ceil(x) 返回≥x的最小整数
floor(x) 返回≤x的最大整数
step(x,y) x≤y为1,否则为0
saturate(x) 钳制x在0到1之间,返回
clamp(x,min,max) 把x限制在[min,max]内,小于返回min大于返回max,是saturate()的升级版
fmod(x,y) 返回x/y的浮点部分(取余的余数部分)
frac(x) 返回输入x的小数部分
modf(x,out ip) 将x分为小数和整数部分,ip返回整数整体返回小数
lerp(x,y,s) 按照s在x到y之间插值,可以看成按照s分段,即x*(1-s)+y*s
smoothstep(min,max,x) 如果x在[min,max]范围内,则返回介于0和1之间的平滑Hermite插值,使用smoothstep在两个值之间创建平滑过渡,例如平滑的混合两种颜色值

smoothstep函数应用之-产生距离场

这部分参考了:GLSL函数smoothstep讲解 - 简书 (jianshu.com)

Shader实验室: smoothstep函数 - 知乎 (zhihu.com)

min --> edge0下界,max --> edge1上界,x插值输入,三者不仅可以是float,还可以是vec2/vec3/vec4变量,其用法:

float smoothstep(float edge0, float edge1, float x)
vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x)
vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x)
vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x)
vec2 smoothstep(float edge0, float edge1, vec2 x)
vec3 smoothstep(float edge0, float edge1, vec3 x)
vec4 smoothstep(float edge0, float edge1, vec4 x)

如果想要创建一个能够输出平滑过渡的函数,就可以用smoothstep,它其实又等同于:

genType t;
t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return (3.0 - 2.0 * t) * t * t;

可以用来干什么?——产生距离场(Distance Field)效果,下图是参考文章Shader实验室: smoothstep函数 - 知乎 (zhihu.com)中实现的效果:

5 类型判断类

给出了6个与数据类型判断相关的函数:

类型判断函数

all(x) 可以传入矢量,所有分量均为非0返回true,否则false
any(x) 只要传入的x有任何一个分量非0返回true,否则false
clip(x)

如果输入值小于0,丢弃该像素值,不进行渲染

(像素值为负->没有颜色)

sign(x) 返回x的正负,x<0返回-1,x=0返回0,x>0返回1
isinf(x)

如果x参数为+INF或-INF,返回true,否则false

isinite(x) 判断x参数是否有限(有界),与isinf(x) 相反
isnan(x)

x为NAN(非数字),返回true

x为数字,则返回false

clip函数应用之-透明度测试

这部分参考自《入门精要》

在片元着色器中使用clip函数进行透明度测试,如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色,它相当于:

void clip(float4 x){if(any(x<0))//一个discard指令以剔除片元discard;
}

通常透明度测试会给定一个材质参数_Cutoff,当前像素颜色为texColor.a,通过clip函数配合discard指令来实现:

//Alpha Test
clip(texColor.a - _Cutoff);

当然除了透明度测试外,还可以用来模拟间切平面、颜色渐渐消失的效果等等。

6 向量与矩阵类

举出了7个与向量、矩阵计算有关的函数。

向量与矩阵计算函数

length(v) 返回向量的长度
normalize(v) 向量归一化,x/length(x)
distance(a,b) 向量各分量之差的平方和
dot(a,b) a在b上的投影长,|a||b|cosθ,返回值是标量
cross(a,b)

a,b向量的叉积,例如计算TBN矩阵等等,返回值是个向量,与a,b均垂直

determinant(m) 返回矩阵m按行列式方式计算的值
transpose(m)

返回m的转置矩阵

7 光线运算类

介绍4个与光照计算相关的函数。

光照计算相关函数

reflect(i,n) i为入射向量,n为法向量,返回反射向量
refract(i,n,ri) i为入射向量,n为法向量,ri为入射和折射介质的折射率比值,返回折射向量
n为法向量,l为光向量,h为半角向量,m为镜面反射系数,返回光照向量(环境光,漫反射光,镜面高光反射,1)
faceforward(n,i,ng) n得到面向视图方向的曲面法向量,返回值-n*sign(dot(i,ng))

lit函数到底返回了什么

官方文档参考:lit - Win32 apps | Microsoft Docs

 懂了吧!传出的其实就是Blinn-Phong反射模型计算环境光项La、漫反射项Ld、高光项Ls需要用到的一些值,简单的补充一下

  • 环境光—— 
  • 漫反射——
  • 高光项——

(其中高光项的p相当于lit函数里输入的m——越大代表着高光点越小,到这里一脸懵的话快去101补课!!!)

标红的部分就分别对应着lit函数返回的vector->(环境光,漫反射光,镜面高光反射,1)

faceforward函数

仍旧放上官方:faceforward - Win32 apps | Microsoft Docs

注意,返回的n的方向肯定会朝着入射向量i的相反方向。

8 纹理映射函数(纹理查找)

须知,纹理从一维、二维到三维都可进行查询。低维(一维或二维)的纹理例如法线纹理、渐变纹理、遮罩纹理等等,一维类比一维数组,二维的类比二维数组,很好理解。三维的相当于二维的叠加,还有立方体纹理查找。

所有的纹理查找函数都可以分为普通的、微分的和投影的三类方式。关于每一个查找函数细节一点的解释,我都放在了2D纹理查找函数介绍中进行说明。

8.1 1D纹理查找(几乎不用)

tex1D(s,t) 普通1D纹理查找,s是纹理采样器,t是位置,返回颜色值
tex1D(s,t,ddx,ddy) 带微分的1D纹理查找值,即使用导数查找纹理
tex1Dbias(s,t) 使用t.w决定某个MIP层的1D纹理查找
tex1Dgrad(s,t,ddx,ddy) 使用微分(梯度)并指定MIP层的1D纹理查找
tex1Dlod(s,t)

使用LOD方式的1D纹理查找

tex1Dproj(s,t) 使用投影方式的1D纹理查找,把纹理当作一张图片投影到场景中,先使用投影纹理技术计算出投影纹理坐标t(做了透视除法的t.w),然后使用投影纹理坐标进行查询

8.2 2D纹理查找

tex2D(s,t) 普通2D纹理查找,s是纹理采样器,t是vector,返回颜色
tex2D(s,t,ddx,ddy) 带微分的2D纹理查找值,t和ddxy都是vector,ddx和ddy的作用是取屏幕上相邻采样点的差值(本身偏导的作用就是表示方向上变化的快慢),ddxddy越大差值越大,采样像素越少,结果越模糊
tex2Dbias(s,t)

使用t.w决定某个MIP层的偏移量,把计算出来的纹理层全部偏移某个指定的值

例如tex2Dbias(_Texture, float4(uv,0,1));则是将MIPMAP的level提高一个等级,可用于对图像采样结果进行模糊or锐化

tex2Dgrad(s,t,ddx,ddy) 使用微分(梯度)并指定MIP层的2D纹理查找
tex2Dlod(s,t)

使用LOD方式的2D纹理查找,查找t.w纹理、t.uv位置处的color4

tex2Dproj(s,t) 使用投影方式的2D纹理查找,把纹理当作一张图片投影到场景中,先使用投影纹理技术计算出投影纹理坐标t(做了透视除法的t.w),然后使用投影纹理坐标进行查询

8.3 3D纹理查找

3D纹理可以理解成多个2D纹理叠加的结果,因此在查找时除了指定uv还需要指定3D纹理的层数。

但我其实不是很分得开三维纹理和MIPMAP的区别?或许三维纹理对每一层的纹理可控性更高吗?因为MIPMAP层次是有规律的,而3D纹理我可以按照喜好存放每一层纹理的大小。

tex3D(s,t) 普通3D纹理查找
tex3D(s,t,ddx,ddy) 带微分的3D纹理查找值
tex3Dbias(s,t) 使用t.w决定某个MIP层的3D纹理查找
tex3Dgrad(s,t,ddx,ddy) 使用微分(梯度)并指定MIP层的3D纹理查找
tex3Dlod(s,t)

使用LOD方式的3D纹理查找

tex3Dproj(s,t) 使用投影方式的3D纹理查找,把纹理当作一张图片投影到场景中,先使用投影纹理技术计算出投影纹理坐标t(做了透视除法的t.w),然后使用投影纹理坐标进行查询

8.4 立方体纹理查找

除了低维的纹理查找,和3维的纹理(2维纹理的叠加)查找,还有更复杂一点的立方体纹理(Cubemap),立方体纹理一般用以实现环境映射来模拟物体周围的环境。

立方体纹理一共包含了6张图像,每张图像对应立方体的六个面,那么如何进行查询(采样)呢?三维纹理坐标——从立方体中心出发,向外部延伸并和六个面之一相交,采样得到的结果就是由这个交点计算而来的。

texCUBE(s,t) 立方体环境贴图
texCUBE(s,t,ddx,ddy) 带微分的立方体纹理查找值
texCUBEbias(s,t) 使用t.w决定某个MIP层的立方体纹理查找
texCUBEgrad(s,t,ddx,ddy) 使用微分(梯度)并指定MIP层的立方体纹理查找
texCUBElod(s,t)

使用LOD方式的立方体纹理查找

texCUBEproj(s,t) 使用投影方式的立方体纹理查找,把纹理当作一张图片投影到场景中,先使用投影纹理技术计算出投影纹理坐标t(做了透视除法的t.w),然后使用投影纹理坐标进行查询

作业

1.写出你觉得最常用的5个函数

常用的话,感觉是涉及到向量计算的一些函数还有随机取值的一些:

  • mul(a,b)——变量相乘
  • dot(a,b)——向量点乘,光照计算里再普遍不过了
  • cross(a,b)——叉积,求垂直向量的时候经常用到,比如TBN矩阵那里
  • normalize(v)——向量归一化
  • clamp(x,min,max)——限制数的范围

2.ddx和ddy的实际使用测试

后续再填坑。

【技术美术图形部分】2.3 HLSL常用函数相关推荐

  1. 【技术美术图形部分】图形渲染管线3.0-光栅化和像素处理阶段

    写在前面 开始学习<入门精要>第八章透明效果后,接触到了渲染顺序.透明度测试这些概念,才发现之前的渲染管线总结忘掉了光栅化和像素处理这两个阶段的学习记录,怪不得没什么印象...赶紧写一篇补 ...

  2. 【技术美术图形部分】PBR全局光照:理论知识补充

    写在前面 最近做东西的流程是这样的,想实现一个风格化森林小场景,场景体现的主体是风格化树和交互草 --> 于是用了两天时间学SpeedTree做树模型 --> 用了两天时间SD做了树干贴图 ...

  3. 【技术美术图形部分】纹理基础1.0-纹理管线

    目录 1 纹理三大问 1.1 What--针对物体表面属性进行"建模" 纹理 Texture 纹理值 Texture Value 纹素 Texels 1.2 Why--降低建模工作 ...

  4. 【技术美术图形部分】图形渲染管线2.0-GPU管线概述几何阶段

    图形渲染管线1.0 [技术美术知识储备]图形渲染管线1.0-基本概念&CPU负责的应用阶段 在上一篇中,从渲染分类开始介绍了什么是渲染流水线.为什么要有流水线以及流水线如何进行的,还介绍了CP ...

  5. 【技术美术图形部分】图形渲染管线1.0-基本概念CPU负责的应用阶段

    渲染分类 谈渲染管线之前,我想有必要看看渲染的分类.渲染可以按不同的分类依据进行分类: 按照渲染时机可以分成实时渲染(除了用于3D游戏还多用于工业仿真方面,注重交互性和实时性)和离线渲染(离线渲染多用 ...

  6. 【技术美术图形部分】关于前向渲染和延迟渲染

    学习参考 [技术美术百人计划]图形 3.4 延迟渲染管线介绍 <Unity Shader 入门精要> 1 Unity的渲染路径 关于渲染路径,我在图形渲染管线1.0中就提过了,但只是初步的 ...

  7. 【技术美术图形部分】2.2 模型与材质基础

    记录之前膜拜一下这节课的大佬,才大三,我一个研二菜狗留下不学无术的泪水! May佬提到,这次课程安排的目的是给美术同学一个缓冲的空间,我的话在写这篇学习笔记就尽量加入一些自己的理解. 友情提示!才发现 ...

  8. 【技术美术图形部分】PBR直接光部分:Disney原则的BRDF和次表面散射模型

    写在前面 补充去年遗漏下的知识.很多叙述都是参考了众多大佬的文章!因为是作为个人学习总结的博客,所以直接卑微的借鉴过来了,后面会给出所有参考的文章. 另外,放上一个忘了在哪一篇知乎评论里的截图: 说的 ...

  9. 【技术美术图形部分】AO理论及优化 AO贴图如何参与渲染

    写在前面 昨天从美术的角度出发,对AO贴图参与到次世代建模流程中的过程进行了学习.今天从图形学角度学习环境光遮蔽. 封面图截取自实时渲染GI|Ambient Occlusion:AO.SSAO.HBA ...

最新文章

  1. java togglebutton_Java ToggleButton.setId方法代码示例
  2. 我所理解的OOP——UML六种关系
  3. String 方法中 replace 和 replaceAll 的区别详解(源码分析)
  4. web相关概念回顾|| 部署项目的方式
  5. Tomcat启动时卡在org.apache.catalina.startup.HostConfig
  6. 两张趣图助你理解状态码的含义~
  7. PHP实训笔记,【学习笔记19】实验吧 让我进去
  8. spring的钩子_模板方法模式——看看 JDK 和 Spring 是如何优雅复用代码的
  9. C/C++ list链表的理解以及使用
  10. (5)ZYNQ FPGA中断介绍
  11. jsx中如何解决{if…else…}的问题
  12. 英语12个月份名称的由来
  13. 迅捷PDF在线转换器将PDF增加密码的简单方法
  14. Rust本地化实现 —— fluent
  15. java ireport 打印_ireport客户端打印
  16. Java总结IO之总集篇
  17. php 正则车架号,正则判断工具类 - 我的开源中国 - OSCHINA - 中文开源技术交流社区...
  18. 给大家分享下仿QQ消息页面横向滑出菜单,Item内容较多的情况
  19. linux看磁带内容命令,Linux下磁带管理命令
  20. java solid设计原则_六大设计原则之里氏替换原则(LSP)

热门文章

  1. 自如_智能家居硬件测试
  2. 云展网教程 | 云展网电子杂志页面排版最佳尺寸,最佳字体,字号
  3. 比太阳还要明亮!天文学家发现使上最亮星体
  4. LeetCode 61-70题 这是动态规划合集啊?受宠若惊
  5. 如何魔改Xilinx Vivado 的MIG IP核
  6. 资讯_计算机屏幕_镜面屏;
  7. 《Java零基础入门到精通(集合,泛型,IO,反射,JVM, 源码)【渡一教育】》思维导图版笔记(完结)
  8. Umi部署pages多页面访问配置
  9. iOS 设置自定义间距的文字下划线
  10. 杭州 小学计算机比赛,【2019年第二十届全国中小学电脑制作活动】,乐博乐博学员强势晋级杭州市赛!...