您的位置:首页 > 其它

Shader学习的基础知识(三)基础光照

2019-03-05 01:39 302 查看
版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ww1351646544/article/details/88145440

一直以来学程序除做出什么效果以外,大多数时候还是觉得程序挺枯燥的。
之前为了面试游戏公司在家苦学了Lua一个多月,结果一些很简单的题都答不上来。
很多人和我说Lua一个月能学完,而Shader一个月只能学些皮毛,但可能本身对做效果特别感兴趣,学起Shader来如有神助,兴奋点特别多。个人觉得进步也特别快…下面是个人觉得必需要记下来的点了,已经是经过极度压缩的,请一个字一个字慢慢的研读清楚,如有疑问和错误请给我留言,谢谢。

辐照度

在光学里,我们使用辐照度来量化光。

吸收和散射

散射只改变光的方向,但不改变光的密度和颜色。而吸收只改变光线的密度和颜色,但不改变光线的方向。

名词

高光反射表示物体表面是如何反射光线的,而漫反射部分则表示有多少光线会被折射、吸收和散射出表面。出射度是指光源上每单位面积向半个空间内发出的光通量。

着色

是指根据材质属性(如漫反射属性等)、光源信息(如光源方向、辐照度等),使用一个等式去沿某个观察射出度的过程叫着色。也叫照光照模型。

计算机图形学第一定律

如果它看起来是对的,那么它就是对的。

标准光照模型的4个部分

环境光用于描述其他所有的间接光照。

自发光这个用于描述当给定一个方向 时,一个身会向该方向发射多少辐射度。

漫反射 漫反射中视角位置不重要,因为反射完全是随机的,它符合兰伯特定律。
漫反射光照=(漫反射颜色*灯光颜色)Max(0,点乘(顶点表面单位法向量,光源位置单位向量))
max用是取正值,点乘部分的含义是:法向量与光源投影(即越相同)数值越大。
如果使用半兰伯特模型的话公式如下:
漫反射光照=(漫反射颜色灯光颜色)*Max(0,点乘(顶点表面单位法向量,光源位置单位向量)*0.5+0.5)
目的是让阴暗面内容更丰富。

高光反射 它是完全 符合真实世界的高光反射。公式如下:
光泽度越大亮点就越小
反射公式=高光反射颜色光源颜色Max(0,点乘(单位射出角度,单位摄像机指向顶点位置))
(公式解释:即顶点射出角度与顶点指身摄像机越像,投影值就越高就越亮)

中线(h)=顶点至向摄像机的向量(v) 顶点指向光i源的向量(l) 这两个值平增均值再归一化
反射公式=高光反射颜色光源颜色Max(0,点乘(单位法向量,中线))
(中线越接近法线说明射的角度越正,中线与法线的点乘值就越大,就越亮)

漫反射例子(非常经典,静下心来查看每一个字)

逐顶点光照模型 逐顶点计算量小,但如顶点数量不够,效果会不好。

Shader "Custom/TestShader6" {
Properties{
_Diffuse("Diffuse",Color)=(1,1,1,1)
}
SubShader{
Pass{
//定义了这个才能得到一些内置的光照变量
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"

fixed4 _Diffuse;
//Appction To Vertex
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//Vertex To Fragment
struct v2f{
float4 pos:SV_POSITION;
fixed3 color:COLOR;
};

v2f vert(a2v v){
v2f o;

//把顶点从模型坐标放在齐次坐标中
o.pos=UnityObjectToClipPos(v.vertex);

//取得环境光部分
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

//把模型上的法线放在世界坐标空间中
//为什么是乘以WorldToObject呢,因为是ObjectToWorld的逆矩阵
//normalize是归一化
fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));

//取得灯光源“位置”信息的单位长度
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

//saturate是把结果截取到0~1
//点乘"世界坐标下法线量单位向量"与"世界坐标下灯光位置的单位向量",方向越相同数值越大,这里限制了0~1
//再用受光面的大小来乘上灯光颜色[0~1],即可以得到各个分量的大小
//同里再乘以物体本身的颜色得到最终颜色
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));

//再加上环境对他的影响
o.color = ambient + diffuse;

return o;
}

float4 frag(v2f i):COLOR{
//上面处理好了,这里直接输出即可
return fixed4(i.color,1);
}
ENDCG
}
}
}

逐像素着色 计算量会比逐顶点的大,效果也好,但是负担会比较大,区别在于把像素点的讲算放到了fragment方法中。上面例子看明白了,下面这个例子意思是一样的。

Shader "Custom/TestShader7" {
Properties{
_Diffuse("Diffuse",Color)=(1,1,1,1)
}
SubShader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"

fixed4 _Diffuse;
//Appction To Vertex
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//Vertex To Fragment
struct v2f{
float4 pos:SV_POSITION;
float3 worldnormal:TEXCOORD0;
};

v2f vert(a2v v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.worldnormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));

return o;
}

float4 frag(v2f i):SV_TARGET{

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldnormal);
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));

float3 color = ambient + diffuse;

return fixed4(color,1);
}
ENDCG
}
}
}

高光反射例子

逐顶点光照

Shader "Custom/TestShader8" {
Properties{
_Diffuse("Diffuse",Color)=(1,1,1,1)
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8,256))=20
}
SubShader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"

fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
//Appction To Vertex
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//Vertex To Fragment
struct v2f{
float4 pos:SV_POSITION;
float3 color:COLOR;
};

v2f vert(a2v v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);

//漫反射部分,和上面的例子一样
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
fixed3 worldLightDir = normalize(_WorldSpaceLi
20000
ghtPos0.xyz);
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));

//高光反射
//因为高光反射需要的方向是入射方向,所以需要对光线位置(worldLightDir)进行取反,得到入射方向
//函数reflect(i,n)计算可以反射方向 i:入射方向 n:法线方向
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));

//取摄像机的位置-顶点的位置=顶点指向摄像机的向量
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz);

//通过“点乘”“顶点指向摄像机向量”与“反射方向”得到这两向量的投影值
//函数pow(x,y) 返回x的y次方
//"单位点乘"的取值范围在-1~1所以部数越大,范围越小。
fixed3 specular = _LightColor0.rgb * _Specular.rgb *pow(saturate(dot(reflectDir,viewDir)),_Gloss);

//最后把颜色加起来
o.color = ambient+diffuse+specular;

return o;
}

float4 frag(v2f i):SV_TARGET{

return float4(i.color,1);
}
ENDCG
}
}
}

逐像素光照

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Custom/TestShader9" {
Properties{
_Diffuse("Diffuse",Color)=(1,1,1,1)
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8,256))=20
}
SubShader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"

fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
//Appction To Vertex
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//Vertex To Fragment
struct v2f{
float4 pos:POSITION;
float3 normal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
};

v2f vert(a2v v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
o.worldPos =mul(unity_ObjectToWorld,v.vertex);

return o;
}

float4 frag(v2f i):SV_TARGET{

//漫反射部分,和上面的例子一样
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(i.normal,worldLightDir));

//高光反射
//因为高光反射需要的方向是入射方向,所以需要对光线位置(worldLightDir)进行取反,得到入射方向
//函数reflect(i,n)计算可以反射方向 i:入射方向 n:法线方向
fixed3 reflectDir = normalize(reflect(-worldLightDir,i.normal));

//取摄像机的位置-顶点的位置=顶点指向摄像机的向量
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);

//通过“点乘”“顶点指向摄像机向量”与“反射方向”得到这两向量的投影值
//函数pow(x,y) 返回x的y次方
//"单位点乘"的取值范围在-1~1所以部数越大,范围越小。
fixed3 specular = _LightColor0.rgb * _Specular.rgb *pow(saturate(dot(reflectDir,viewDir)),_Gloss);

//最后把颜色加起来
float3 color = ambient+diffuse+specular;

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