您的位置:首页 > 移动开发 > Unity3D

Unity3D学习(六):《Unity Shader入门精要》——Unity的基础光照

2018-01-05 17:53 260 查看
前言 光学中,我们是用辐射度来量化光。 光照按照不同的散射方向分为:漫反射(diffuse)和高光反射(specular)。高光反射描述物体是如何反射光线的,漫反射则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们可以计算出射光线的数量和方向,通常使用出射度描述它。辐射度和出射度之间是线性关系的,它们之间的比值就是材质的漫反射和高光反射属性。 BRDF模型 早期的游戏引擎一般只有一个光照模型,BRDF模型,即标准光照模型(Bidirectional Reflectance Distribution Function),又称Phong模型。 它的基本方法是,把进入到摄像机内的光线分为4部分,每部分使用一种方法来计算它的贡献度。
  • 自发光  描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。注意,如果没有使用全局光照,这些自发光的表面并不会照亮周围的物体,只是他本体看起来更亮而已。
  • 高光反射(金属之类的)  描述当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
  • 漫反射  该表面会向四周散射多少辐射量
  • 环境光  描述其他所有的间接光照(就是其他物体的发射的光线)。 
兰伯特定律 发射光线的强度与表面法线和光源方向之间的夹角余弦值成正比。   漫发射的计算公式    C = (c * m) * max( 0 , n * l )。 小写c为光源颜色,m为漫反射颜色,n是表面法线,l是指向光源的单位矢量。需要注意应该防止发现和光源点乘的结果为负值(避免物体被从后面来的光源照亮),所以用max函数限制其为正数。   高光反射的计算公式
  •   r = 2(n * l)n - l
  •  C = (c * m) * (max(0,v * r)) ^ gloss
n,l代表意义与漫反射公式相同,r为光的反射方向矢量,m为高光反射颜色, v 为 视角方向矢量,gloss为材质的光泽度,gloss越大亮点就越小。     Blinn模型的高光反射计算公式   与上述Phong模型不同的是,Blinn模型引入了一个新矢量h,通过对 v 和 l的取平均后再归一化得到:h = ( v + l ) / | v + l |。   公式为:C = ( c * m) * (max( 0, n * h ))^gloss   逐像素与逐顶点光照  在片元着色器中计算,称为逐像素光照。在顶点着色器中计算,称为逐顶点光照(高罗德着色)。逐顶点光照是在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出成像素颜色。由于顶点数目小于像素数目,所以其计算量小于逐像素光照,因此在阴影交界处会出现锯齿,精细度不如逐像素光照。   Unity的环境光和自发光 环境光可以通过Shader的内置变量UNITY_LIGHTMODEL_AMBIENT访问 自发光只需要在片元着色器输出最后的颜色之前,把材质的自发光颜色添加到输出颜色上就行。   漫反射和高光反射的Shader实现 漫反射光照模型(逐顶点)
Shader "Unity Shader Book/Chapter6/Diffuse Vertex-Level"
{
Properties
{
_Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Tags { "LightMode"="ForwardBase" }

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "Lighting.cginc"

fixed4 _Diffuse;
struct appdata
{
float4 vertex : POSITION; //顶点在模型空间的坐标
float3 normal : NORMAL;  //法线
} ;

struct v2f
{
fixed3 color : COLOR;  //输出颜色
float4 pos : SV_POSITION;  //输出位置
} ;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);  //模型空间转换到裁剪空间

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;  //环境光

fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); //法线方向n

fixed3 worldLight  = normalize(_WorldSpaceLightPos0.xyz); //光源位置

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
}
}
}

 

高光反射模型(逐顶点)
Shader "Unity Shader Book/Chapter6/SpecularVertexLevel"
{
Properties
{
_Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
_Specular("Specular",Color) = (1.0,1.0,1.0,1.0)
_Gloss("Gloss",Range(8.0,256)) = 20 //size of specular area
}
SubShader
{
Tags { "LightMode"="ForwardBase" }   //Be careful ,The light direction will be opposite without this

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "Lighting.cginc"

fixed4 _Diffuse;
fixed4 _Specular;
float  _Gloss;
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
} ;

struct v2f
{
float3 color: COLOR;
float4 pos : SV_POSITION;
} ;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//equal to "o.pos = mul(UNITY_MATRIX_MVP,v.vertex);"

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
// or use UnityObjectToWorldNormal(v.normal)
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));

fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //反射方向矢量r

fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz); //视线方向

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
}
}
}

  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: