文章目录
- 前言
- 一、开始学习Unity Shader
- 1.1 Unity Shader的基本结构:
- 1.2 一些介绍
- 1.3 总结:Unity内置变量
- 二、基础光照
- 2.1 视觉原理基础
- 2.2 标准光照模型
- 2.3 漫反射光照模型
- 2.4 半兰伯特模型
- 2.5 高光反射光照模型
- 2.6 布林冯模型
- 2.7 帮助函数
前言
从初级篇开始
一、开始学习Unity Shader
1.1 Unity Shader的基本结构:
1.2 一些介绍
很烦,一上来就是bug,一模一样得代码,我的球就是红色的,初步怀疑是target的问题:
这个bug的原因是frag()函数的输出不是fix而是fixed4
当时刚刚学大约是打错了
//shader名称
Shader "Custom/SimpleShader"{
SubShader{
pass{
CGPROGRAM
//定义顶点着色器和片元着色器函数
#pragma vertex vert
#pragma fragment frag
//输入:POSITION,定义为v, 输出到SV_POSITION 中
float4 vert(float4 v : POSITION): SV_POSITION{
return UnityObjectToClipPos(v);
}
// SV_TARGET,渲染目标,储存到一个帧缓存器中
fixed4 frag() : SV_Target{
return fixed4(1.0 , 1.0 ,1.0 , 1.0);
}
ENDCG
}
}
}
struct结构体
定义一个结构
综合使用
Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform fixed4 _Color;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR0;
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 c = i.color;
c *= _Color.rgb;
return fixed4(c, 1.0);
}
ENDCG
}
}
}
1.3 总结:Unity内置变量
二、基础光照
2.1 视觉原理基础
- 光线从光源中传播出来
- 光线被物体吸收,并且由物体发出散射到其他各个方向
- 摄像机接收到光纤,产生图像
几个名词:
- 辐照度(irradiance):量化光,光源方向和v表面法线n之间的夹角的余弦值来得到
- 高光反射:物体表面是如何反射光线的
- 漫反射:有多少光线会被折射吸收和散射
- 出射度:出射光线的数量和方向
- BRDF:双向散射分布模型,后续会有提到
2.2 标准光照模型
只关注直接光照
他把进入到摄像机内的光线分为四个部分
- 自发光,描述一个给定方向上的一个表面本身会向该方向发射多少辐射量
- 高光反射
- 漫反射
- 环境光,描述其他的所有间接光照
接下来是一些计算公式
- 环境光通常是一个全局变量,所有的物体都会使用它,用来模拟间接光照
- 自发光,直接使用该材质的自发光颜色
- 高光反射是经验模型
2.3 漫反射光照模型
逐顶点版本
Shader "Unity Shaders Book/Chapter 6/Diffuse Vertex-Level" {
Properties {
// 定义漫反射颜色,初始值白色
_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
}
SubShader {
Pass {
// 指定该pass的光照模式,定义该pass在unity的光照流水线中的角色
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//为了使用内置变量引入库
#include "Lighting.cginc"
// 使用properties的变量
fixed4 _Diffuse;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
v2f vert(a2v v) {
v2f o;
// Transform the vertex from object space to projection space
o.pos = UnityObjectToClipPos(v.vertex);
// Get ambient term
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// Transform the normal from object space to world space
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
// Get the light direction in world space
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
// Compute diffuse term
//内置变量lightcolor0 访问该pass处理的光源的颜色和强度信息
//光源方向可以由_WorldSpaceLightPos0
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
o.color = ambient + diffuse;
return o;
}
fixed4 frag(v2f i) : SV_Target {
return fixed4(i.color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
在逐像素版本中,顶点着色器将传递世界法线和裁切空间的位置信息,在片元着色器中完成fixed4 color的计算
2.4 半兰伯特模型
上面的模型有个问题
在光照无法到达的区域,模型是纯黑的,没有一点变化,看起来是个平面半兰伯特光照模型的公式如下
- 他把表面法线和入射光线的点积做了个映射,而不是取最大值,把负值部分完全抛掉
- 一般,映射到
效果长这样
2.5 高光反射光照模型
- 入射光线的颜色和强度
- 材质的高光反射系数
- 视角方向
- 反射方向
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level" {
Properties {
_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
_Specular ("Specular", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
v2f vert(a2v v) {
v2f o;
// Transform the vertex from object space to projection space
o.pos = UnityObjectToClipPos(v.vertex);
// Get ambient term
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// Transform the normal from object space to world space
//注意左乘右乘
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
// Get the light direction in world space
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
// Compute diffuse term
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
// 获得反射光线
fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
// 视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
// Compute specular term
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
o.color = ambient + diffuse + specular;
return o;
}
fixed4 frag(v2f i) : SV_Target {
return fixed4(i.color, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}
效果如图
2.6 布林冯模型
半程向量的使用
2.7 帮助函数