【Unity3D】表面着色器
1 前言
固定管线着色器一、固定管线着色器二 中介绍了 ShaderLib 的基本用法,本文将接着讲解表面着色器(Surface Shader)的用法。固定管线着色器基于 ShaderLib 命令实现,表面着色器基于 CG 语言实现。目前主流的 Shader 编程语言主要有 GLSL、HLSL、CG,如下:
- GLSL:OpenGL Shading Language,基于 OpenGL 接口,跨操作系统,依赖硬件,可以在 Windows 、Linux、Mac、Web、移动端跑,这种跨平台是由于 OpenGL 没有提供编译器,由显卡驱动完成着色器的编译工作,即显卡驱动支持 OpenGL,它就可以运行;
- HLSL:High Level Shading Language,基于 DirectX 接口,由微软研发,不依赖硬件,就算有不同的硬件,同一个着色器编译结果是一样的;
- CG:C for Graphic,由 NVIDIA(英伟达)研发,跨操作系统,不依赖硬件,它会根据平台的不同编译成相应的中间语言,CG 语言的跨平台性很大程度取决于与微软的合作,这也导致 CG 和 HLSL 非常相似,CG 可以无缝移植到 HLSL 平台上,但是缺点是无法完全发挥 OpenGL 的新特性。
2 CG 语言基础
1)基本数据类型
float // 32位浮点数, 精度: 小数点后6位, 适用: 模型坐标、纹理uv坐标
half // 16位浮点数, 精度: 小数点后3位, 适用: 模型坐标、纹理uv坐标
fixed // 12位浮点数, 精度: 1/256, 适用: 光照计算、颜色
int // 32位整数
bool // 8位布尔数
string // 字符串
sampler1D, sampler2D, sampler3D, samplerCUBE, samplerRECT // 纹理对象
补充:对于 float、half、int、fixed、bool 类型,可以在其后添加 2、3、4,以扩充维度,如:float2、int3、fixed4。
2)Input
struct Input
{float3 worldPos; // 世界坐标float3 screenPos; // 屏幕坐标half3 viewDir; // 观察方向, 顶点指向相机float4 color : COLOR; // 顶点颜色, 后面的COLOR是语义绑定fixed2 uv_MainTex; // 纹理uv坐标(命名方式必须是uv_纹理变量名称)fixed2 uv_NormTex; // 法线纹理uv坐标(命名方式必须是uv_法线纹理变量名称)
};
说明:Input 结构体需要自定义,里面的变量可以根据需要添加。
3)SurfaceOutput
struct SurfaceOutput
{half3 Albedo; // 反射率, 即颜色纹理rgbhalf3 Normal; // 法向量half3 Emission; // 自发光颜色rgbhalf Alpha; // 透明度half Specular; // 镜面反射度half Gloss; // 光泽度
};
说明:SurfaceOutput 结构体是系统自定义的结构体,不需要用户定义。
4)常用函数
saturate(var, min, max) // 将变量var约束在min和max之间, 超过边界就取边界值
dot(vec1, vec2) // 向量点乘
cross(vec1, vec2) // 向量叉乘
normalize(vec) // 向量归一化
tex2D(sampler2D, uv_Tex) // 查询纹理坐标对应的纹理值
UnpackNormal(color) // 根据法线纹理解析法线向量
3 光照
在 Assets 窗口右键,依次选择【Create→Shader→Standard Surface Shader】创建 Shader 脚本,实现光照效果代码如下:
SurfaceShader.shader
Shader "MyShader/SurfaceShaderTest" {Properties{// 属性名 ("面板显示名称", 类型) = 默认值_DiffuseColor ("漫反射颜色", Color) = (1, 0, 0, 0.5)}SubShader{CGPROGRAM // CG语言的开始// 编译指令 着色器类型 函数名称 光照模型 开启透明度#pragma surface surf Lambert Alpha// 声明属性变量, 必须与外部属性变量名称一致fixed4 _DiffuseColor;struct Input{float4 color : COLOR; // 顶点颜色, 后面的COLOR是语义绑定};void surf (Input IN, inout SurfaceOutput o) // 表面着色器函数{o.Albedo = _DiffuseColor.rgb; // 像素颜色o.Alpha = _DiffuseColor.a; // 像素透明度}ENDCG // CG语言的结束}FallBack "Diffuse"
}
创建一个Material,并将 ShaderTest 绑定到该 Material 上,如下:
将该 Material 拖拽到一个 Cube 和 Sphere 游戏对象上。选中绑定的 Material,在 Inspector 窗口调整 Shader 中光照颜色,显示效果如下:
4 贴图
SurfaceShader.shader
Shader "MyShader/SurfaceShaderTest" {Properties{// 属性名 ("面板显示名称", 类型) = 默认值_MainTex ("2阶贴图", 2D) = "white" {}}SubShader{CGPROGRAM // CG语言的开始// 编译指令 着色器类型 函数名称 光照模型#pragma surface surf Lambert// 声明属性变量, 必须与外部属性变量名称一致sampler2D _MainTex;struct Input{fixed2 uv_MainTex; // 纹理uv坐标(命名方式必须是uv_纹理变量名称)};void surf (Input IN, inout SurfaceOutput o) // 表面着色器函数{o.Albedo = tex2D(_MainTex, IN.uv_MainTex); // 像素颜色}ENDCG // CG语言的结束}FallBack "Diffuse"
}
选中绑定的 Material,在 Inspector 窗口选择贴图图片,显示效果如下:
5 法线贴图
光照的漫反射、镜面反射都是通过法线向量计算得到,法线向量经 PackNormal 函数处理后,值域映射到 [0, 1],由于颜色与处理后的法向量维度(3维)和值域([0, 1])一样,因此可以用颜色描述法线向量,即用一张法线图描述原图片每个像素位置的法线,取出法线图中某位置的颜色,再通过 UnpackNormal 函数映射,即可得到对应像素位置的法线向量。
如下,是一张原图和对应的法线图,可以看到,原图和法线图的轮廓很相似,因此美工可以通过调整原图的色相得到法线图。法线的 (x, y, z) 分量对应颜色的 (r, g, b) 分量,z 值越大,法线越偏向观察方向,法线图越偏向蓝色,这也是正视图一般偏向蓝色的原因。Unity3D 中,用户可以通过修改图片的 Texture Type 为 Normal map 生成法线图。
SurfaceShader.shader
Shader "MyShader/SurfaceShaderTest" {Properties{// 属性名 ("面板显示名称", 类型) = 默认值_MainTex ("2阶贴图", 2D) = "white" {}_NormTex ("法线贴图", 2D) = "white" {}}SubShader{CGPROGRAM // CG语言的开始// 编译指令 着色器类型 函数名称 光照模型#pragma surface surf Lambert// 声明属性变量, 必须与外部属性变量名称一致sampler2D _MainTex;sampler2D _NormTex;struct Input{fixed2 uv_MainTex; // 纹理uv坐标(命名方式必须是uv_纹理变量名称)fixed2 uv_NormTex; // 法线纹理uv坐标(命名方式必须是uv_法线纹理变量名称)};void surf (Input IN, inout SurfaceOutput o) // 表面着色器函数{o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb; // 像素颜色o.Normal = UnpackNormal(tex2D(_NormTex, IN.uv_NormTex)); // 像素法线}ENDCG // CG语言的结束}FallBack "Diffuse"
}
选中绑定的 Material,在 Inspector 窗口选择贴图和法线图,并将该 Material 拖拽到一个 Cube 对象上,再新建一个 Cube 对象(作为对比),绑定普通的 Material,显示效果如下:
说明:左边是法线贴图,右边是普通贴图,左边图片明显比右边更有质感。
6 自发光
本节在法线贴图的基础上,在物体凹凸边缘添加高亮效果。物体凹凸边缘是指物体表面法线与观察方向近似垂直的地方。
SurfaceShader.shader
Shader "MyShader/SurfaceShaderTest" {Properties{// 属性名 ("面板显示名称", 类型) = 默认值_MainTex ("2阶贴图", 2D) = "white" {}_NormTex ("法线贴图", 2D) = "white" {}_RimColor ("自发光颜色", Color) = (1, 1, 1, 1)_RimStrength ("自发光强度", Range(0, 5)) = 0.5}SubShader{CGPROGRAM // CG语言的开始// 编译指令 着色器类型 函数名称 光照模型#pragma surface surf Lambert// 声明属性变量, 必须与外部属性变量名称一致sampler2D _MainTex;sampler2D _NormTex;fixed4 _RimColor;half _RimStrength;struct Input{fixed2 uv_MainTex; // 纹理uv坐标(命名方式必须是uv_纹理变量名称)fixed2 uv_NormTex; // 法线纹理uv坐标(命名方式必须是uv_法线纹理变量名称)half3 viewDir; // 观察方向, 顶点指向相机};void surf (Input IN, inout SurfaceOutput o) // 表面着色器函数{o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb; // 像素颜色o.Normal = UnpackNormal(tex2D(_NormTex, IN.uv_NormTex)); // 像素法线half rimPower = 1 - saturate(dot(normalize(IN.viewDir), normalize(o.Normal))); // 计算自发光系数// o.Emission = _RimColor * _RimStrength * rimPower;o.Emission = _RimColor * pow(rimPower, _RimStrength); // 自发光颜色}ENDCG // CG语言的结束}FallBack "Diffuse"
}
选中绑定的 Material,在 Inspector 窗口选择贴图和法线图,并调整自发光颜色和自发光强度,将该 Material 拖拽到一个 Cube 对象上,显示效果如下:
【Unity3D】表面着色器相关推荐
- 【Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...
- Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)
本文主要讲解了Unity中SurfaceShader的具体写法,以及几个常用的CG函数的用法. 在这里先说明一下,表面着色器将分为两次讲解,本文介绍表面着色器的基本概念和一些写法,用内置的兰伯特光照模 ...
- 【Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42611531 作者:毛星云(浅墨) ...
- 【Unity3D Shader编程】之七 静谧之秋篇 表面着色器的写法 二 —— 自定义光照模式
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...
- Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42611531 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42611531 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)——自定义光照模式
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/plus/view.php?aid=183 作者:毛星云(浅墨) 微博:http://weibo ...
- 【Unity3D Shader编程】之六 暗黑城堡篇 表面着色器 Surface Shader 的写法 一
分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 本系列文章由@浅墨 ...
最新文章
- NIPS2018 | 腾讯AI Lab入选20篇论文,含2篇Spotlight
- 2017c语言考核册答案,2017年最新C语言考题带答案
- 深入浅出javascript(二)函数和this对象
- Nginx 0.8.5版本access.log日志分析shell命令
- HDU - 2222 Keywords Search(AC自动机)
- 删除mysql数据库中所有表
- Enterprise Library 2.0 Hands On Lab 翻译(3):数据访问程序块(三)
- 第44课 角谷猜想 动动脑 第3题 完善程序
- 总结@ 在C# 中的用法
- ASP.NET Web开发框架之八 所有ERP部分的源代码全部开放下载
- rsyslogd以及日志轮替logrotate的梳理
- Spring注解原理详解
- 由虚短、虚断分析集成运放电路
- vscode任务栏图标突然不显示
- Flixel横板游戏制作教程(十一)—JetPack(飞行背包)
- UVA10529 Dumb Bones
- DIY树莓派Raspberry Pi
- 增强低频和高频 matlab,实验名称高斯低频滤波及高频增强滤波.doc
- 多态性(一)——静态多态性
- 控制系统Matlab仿真——数学模型
热门文章
- 一位台校长震动所有中国人的演讲【转贴】_大不如
- php var报错,php异常parse error: syntax error, unexpected t_var错误怎么解决
- 数据透视表数据空白_更改数据透视表中的空白标签
- CAN/CANFD数据记录及实时传输
- SSRF攻击原理、作用、具体操作
- 01-为什么要学爬虫-python小白爬虫入门教程
- SQL优化篇--SQL TUNNING ADVICER使用
- js 日期转换为农历
- Apache IoTDB社区Meetup讲师征集!
- Java(Eclipse,JDK)最新全套下载安装教程