【Unity3D】顶点和片元着色器
1 前言
上文介绍了渲染管线、固定管线着色器和表面着色器,如下:
固定管线着色器通过命令方式实现光照和贴图等效果,表面着色器通过给 SurfaceOutput 赋值实现光照、贴图和法线贴图等效果,它们都不用关注光照算法是如何实现的,只需要传值就行。
顶点和片元着色器给用户提供了更灵活的用法,但使用也更困难。另外,顶点着色器可以通过控制 MVP 矩阵变换实现对模型位置和姿态的控制。
2 固定颜色
在 Assets 窗口右键,依次选择【Create→Shader→Standard Surface Shader】创建 Shader 脚本,实现固定颜色 Shader 代码如下:
VFShader.shader
Shader "MyShader/VFShaderTest" {
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_MainColor ("显示颜色", Color) = (1, 0, 0, 1)
}
SubShader
{
Pass
{
CGPROGRAM // CG语言的开始
// 编译指令 着色器名称 函数名称
#pragma vertex vert // 顶点着色器, 每个顶点执行一次
#pragma fragment frag // 片段着色器, 每个像素执行一次
// 导入头文件
#include "UnityCG.cginc"
// 声明属性变量, 必须与外部属性变量名称一致
fixed4 _MainColor;
// 顶点着色器
float4 vert(float4 vertex: POSITION) : SV_POSITION
{
// 将局部坐标系下坐标转换为裁剪坐标系下坐标
return UnityObjectToClipPos(vertex); // 等价于: mul(UNITY_MATRIX_MVP, vertex)
}
// 片元着色器
fixed4 frag(): COLOR
{
return _MainColor;
}
ENDCG // CG语言的结束
}
}
FallBack "Diffuse"
}
创建一个 Material,并将 ShaderTest 绑定到该 Material 上,如下:

将该 Material 拖拽到一个 Cube 和 Sphere 游戏对象上。选中绑定的 Material,在 Inspector 窗口调整 Shader 中固定颜色,显示效果如下:

3 光照
1)光照原理
Phong 光照模型和 Blinn Phong 光照模型是应用比较广泛的光照模型,两者区别在与镜面反射光的计算,Phong 光照模型根据反向量和观察向量计算镜面反射光,Blinn Phong 光照模型根据半向量和法向量计算镜面反射光。

光照计算如下:
// 模型自身颜色
fixed4 albedo = tex2D(_MainTex, i.uv) * _ModelColor;
// 环境光
fixed4 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
// 漫反射光
fixed4 diffuse = _LightColor0 * albedo * max(0, dot(normal, lightDir));
// 镜面反射光(Phong光照模型)
// fixed4 specular = _LightColor0 * _Specular * pow(max(0, dot(reflectDir, viewDir)), _Gloss);
// 镜面反射光(Blinn Phong光照模型)
fixed4 specular = _LightColor0 * _Specular * pow(max(0, dot(normal, halfDir)), _Gloss);
// 合成颜色
fixed4 finalColor = fixed4(ambient + diffuse + specular, 1.0);
2)代码实现
VFShader.shader
Shader "MyShader/VFShaderTest" {
Properties {
_ModelColor ("Model Color", Color) = (1, 1, 1, 1) // 模型颜色
_Specular ("Specular Color", Color) = (1, 1, 1, 1) // 镜面反射颜色
_Gloss ("Gloss", Range(8.0, 256)) = 20 // 镜面反射光泽度
}
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _ModelColor; // 模型颜色
fixed4 _Specular; // 镜面反射颜色
float _Gloss; // 镜面反射光泽度
struct a2v {
float4 vertex : POSITION; // 模型空间顶点坐标
float3 normal : NORMAL; // 模型空间顶点法线向量
};
struct v2f {
float4 pos : SV_POSITION; // 裁剪空间顶点坐标
float3 normal : Normal; // 世界空间顶点法线向量
float3 worldPos : TEXCOORD0; // 世界空间顶点坐标
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
o.normal = UnityObjectToWorldNormal(v.normal); // 将模型空间法线向量变换到世界空间
o.worldPos = mul(unity_ObjectToWorld, v.vertex); // 将模型空间顶点坐标变换到世界空间
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 normal = normalize(i.normal); // 世界空间法线向量
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // 世界空间灯光向量
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // 世界空间观察向量
fixed3 halfDir = normalize(lightDir + viewDir); // 半向量
fixed3 albedo = _ModelColor; // 模型自身颜色
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo; // 环境光
fixed3 diffuse = _LightColor0 * albedo * max(0, dot(normal, lightDir)); // 漫反射光
fixed3 specular = _LightColor0 * _Specular * pow(max(0, dot(normal, halfDir)), _Gloss); // 镜面反射光(Blinn Phong光照模型)
return fixed4(ambient + diffuse + specular, 1);
}
ENDCG
}
}
FallBack "Specular"
}
选中绑定的 Material,在 Inspector 窗口调整 Shader 中光照颜色,显示效果如下:

4 贴图
VFShader.shader
Shader "MyShader/VFShaderTest" {
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_MainTex ("2阶贴图", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM // CG语言的开始
// 编译指令 着色器名称 函数名称
#pragma vertex vert // 顶点着色器, 每个顶点执行一次
#pragma fragment frag // 片段着色器, 每个像素执行一次
// 导入头文件
#include "UnityCG.cginc"
// 声明属性变量, 必须与外部属性变量名称一致
sampler2D _MainTex;
struct a2v // 顶点着色器输入结构体
{
float4 vertex : POSITION; // 模型空间顶点坐标
half2 texcoord : TEXCOORD0; // 纹理uv坐标
};
struct v2f // 顶点着色器输出结构体
{
float4 pos : SV_POSITION; // 裁剪空间顶点坐标
half2 uv : TEXCOORD0; // 纹理uv坐标
};
// 顶点着色器
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); // 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
o.uv = v.texcoord;
return o;
}
// 片元着色器
fixed4 frag(v2f i) : SV_Target
{
return tex2D(_MainTex, i.uv);
}
ENDCG // CG语言的结束
}
}
FallBack "Diffuse"
}
选中绑定的 Material,在 Inspector 窗口选择贴图图片,显示效果如下:

声明:本文转自【Unity3D】顶点和片元着色器
【Unity3D】顶点和片元着色器的更多相关文章
- 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- Unity3D学习笔记(三十五):Shader着色器(2)- 顶点片元着色器
Alpha测试 AlphaTest Great:大于 AlphaTest Less:小于 AlphaTest Equal:等于 AlphaTest GEqual:大于等于 AlphaTest LEqu ...
- 片元着色器(Fragment Shader)被称为像素着色器(Pixel Shader),但
片元着色器(Fragment Shader)被称为像素着色器(Pixel Shader),但片元着色器是一个更合适的名字, 因为此时的片元并不是一个真正意义上的像素.
- 《shader入门精要》13.2再谈运动模糊中片元着色器的世界坐标的计算
具体在书p275页 这里为啥需要除D.w呢. 首先我们得到的NDC的坐标是已经归一化的,但是CurrenViewProjectionMatrix的作用,是把世界空间转化为尚未归一化的裁剪空间. 这里看 ...
- OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)
OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...
- OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)
OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...
- OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围
OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章) 所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符. ...
- OpenGL ES着色器语言之静态使用(static use)和预处理
OpenGL ES着色器语言之静态使用(static use) 在OpenGL ES中有一个术语叫静态使用(static use),什么叫静态使用呢? 在写代码中,对于一个变量可能具有以下三种情况: ...
- OpenGLES2.0着色器语言glsl
OpenGLES2.0中是强制使用可编程的渲染管线的,使用的是glsl着色器语言,因为着色器语言是使用的GPU,即图形处理单元,而不是CPU,这样可以使CPU从繁重的几何计算和像素的处理中解脱出来了. ...
随机推荐
- 问题--flask无法发邮件,无法登录
1.问题 早上测试项目的时候,一直无法正确发送邮件,无法接收,但是查不出原因是什么 2.解决 改变了一下思路,去登录了不需要邮件验证码的用户,发现错误 这个错误提示是一个数据库连接错误,表明应用程序无 ...
- JS - console多个值
Promise.all([p1, p2]).then( (res) => { let [p1, p2] = res; console.l ...
- DDP运行报错(单卡无错):ERROR:torch.distributed.elastic.multiprocessing.api:failed (exitcode: 1)
使用DDP时出现错误,但是单卡跑无错误. 错误记录如下: RuntimeError: Expected to have finished reduction in the prior iteratio ...
- [转帖]tidb-lightning 逻辑模式导入
https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-configuration 本文档介绍如何编写逻辑导入模式的配置文件,如何进行性能调优等内 ...
- [转帖]CPU缓存行
https://www.jianshu.com/p/e338b550850f CPU缓存 执行程序是靠运行CPU执行主存中代码,但是CPU和主存的速度差异是非常大的,为了降低这种差距,在架构中使用了C ...
- [转帖]模拟enq: TX - row lock contention争用
https://www.modb.pro/db/623036 enq: TX - row lock contention它表示一个事务正在等待另一个事务释放被锁定的行.这种等待事件通常发生在并发访问数 ...
- Docker 运行 Redis Rabbitmq seata-server ftp 的简单办法
公司里面用到了很多组件, 发现安装二进制太麻烦了, 所以想用Docker 进行安装. 这里面简单给总结一下就不在折腾了.. 1. redis docker run -d -p 6379:6379 -- ...
- 关于SSL证书的学习与总结
关于证书 证书是用来实现https通信加密的基础, 有证书才能够进行相关的TLS层的加密处理. 本文简要讲解一下证书的申请,创建以及使用等. 第一部分: PKI 公共密钥基础 其实有很多家企业在做PK ...
- Raid卡在Write back 与Write through 时的性能差异
还是读姜老师的 mysql技术内核innodb存储引擎这本书里面的内容. 之前知道raid卡的设置会影响性能, 预计也是十几倍的性能差距, 但是从来没有用数据库进行过验证 书中有针对不通raid卡的设 ...
- KubeSphere2.1踩坑记
至少两台机器.推荐4X16.(完全安装KubeSphere会吃掉10G+内存) k8s安装(略1.14.8)可参考我上一篇文章或者基于kubeadmin快速安装 KubeSphere2.1前置条件 1 ...