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】表面着色器相关推荐

  1. 【Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...

  2. Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...

  3. 【浅墨Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本文主要讲解了Unity中SurfaceShader的具体写法,以及几个常用的CG函数的用法. 在这里先说明一下,表面着色器将分为两次讲解,本文介绍表面着色器的基本概念和一些写法,用内置的兰伯特光照模 ...

  4. 【Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42611531 作者:毛星云(浅墨) ...

  5. 【Unity3D Shader编程】之七 静谧之秋篇 表面着色器的写法 二 —— 自定义光照模式

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  6. Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42611531 作者:毛星云(浅墨) ...

  7. 【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42611531 作者:毛星云(浅墨) ...

  8. 【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)——自定义光照模式

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/plus/view.php?aid=183 作者:毛星云(浅墨)    微博:http://weibo ...

  9. 【Unity3D Shader编程】之六 暗黑城堡篇 表面着色器 Surface Shader 的写法 一

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 本系列文章由@浅墨 ...

最新文章

  1. NIPS2018 | 腾讯AI Lab入选20篇论文,含2篇Spotlight
  2. 2017c语言考核册答案,2017年最新C语言考题带答案
  3. 深入浅出javascript(二)函数和this对象
  4. Nginx 0.8.5版本access.log日志分析shell命令
  5. HDU - 2222 Keywords Search(AC自动机)
  6. 删除mysql数据库中所有表
  7. Enterprise Library 2.0 Hands On Lab 翻译(3):数据访问程序块(三)
  8. 第44课 角谷猜想 动动脑 第3题 完善程序
  9. 总结@ 在C# 中的用法
  10. ASP.NET Web开发框架之八 所有ERP部分的源代码全部开放下载
  11. rsyslogd以及日志轮替logrotate的梳理
  12. Spring注解原理详解
  13. 由虚短、虚断分析集成运放电路
  14. vscode任务栏图标突然不显示
  15. Flixel横板游戏制作教程(十一)—JetPack(飞行背包)
  16. UVA10529 Dumb Bones
  17. DIY树莓派Raspberry Pi
  18. 增强低频和高频 matlab,实验名称高斯低频滤波及高频增强滤波.doc
  19. 多态性(一)——静态多态性
  20. 控制系统Matlab仿真——数学模型

热门文章

  1. 一位台校长震动所有中国人的演讲【转贴】_大不如
  2. php var报错,php异常parse error: syntax error, unexpected t_var错误怎么解决
  3. 数据透视表数据空白_更改数据透视表中的空白标签
  4. CAN/CANFD数据记录及实时传输
  5. SSRF攻击原理、作用、具体操作
  6. 01-为什么要学爬虫-python小白爬虫入门教程
  7. SQL优化篇--SQL TUNNING ADVICER使用
  8. js 日期转换为农历
  9. Apache IoTDB社区Meetup讲师征集!
  10. Java(Eclipse,JDK)最新全套下载安装教程