untiy 3d ShaderLab_第9章_2_球体阴影(一) 平行光对球体的投影
2016-10-21 11:06
357 查看
球形阴影
在平面阴影的讲述中,接收阴影的物体结构比较简单,因此我们可以有一个简单有效的算法来解决投射在平面上的阴影问题。同理,如果阴影投射物体的结构很简单,我们也可以设计出一个简单有效的算法来计算阴影,比如球体投影的阴影。其实不只是球体只要是能用能用一固定方程式表达的几何体,都适用于此概念。
9.1平行光对球体的投影
当我们知道一个球体的位置以及其半径的时候,就已经确切地掌握了这个球体在空间的儿何信息,此时就很容易算出这个球体的投影。首先是脚本SphereShadow.cs,这是一个设定球体位置和半径信息的脚本,需要附加到使用此材质接受球体阴影的脚本上,其代码如下:
9.1.2 使用相似三角形计算投影
然后,当我们需要计算一个点是否在球体的投影区域时,我们需要知道这个点到灯光的方向,到球体中心的方向以及距离,然后根据这两个方向的夹角,通过相似三角形的计算,考察透过这个方向在球体的此半径内能不能看到光源,如果可以,此点就不处于阴影之中,否则此点将被标记在阴影中。这个完整操作是在SphereShadow_l.shader中完成的,其完整代码如下:
这个Shader在vertex函数中计算了到光源和投影球体的矢量,在fragment函数中,把插值后的矢量进行normalize,同时计算到投影球体的距离,这个距离在解此点、球体中心以及到光源方向矢量的垂线所构造的三角形时要用到。通过这两个方向矢量的点积得出角度,然后解上面那个三角形,通过到光源矢量方向的垂线距离与球体半径的大小判定在此点能否看到光源。打开SphereShadow文件夹下面的SphereShadow-1场景,效果如图所示。
Scene:
Game:
在平面阴影的讲述中,接收阴影的物体结构比较简单,因此我们可以有一个简单有效的算法来解决投射在平面上的阴影问题。同理,如果阴影投射物体的结构很简单,我们也可以设计出一个简单有效的算法来计算阴影,比如球体投影的阴影。其实不只是球体只要是能用能用一固定方程式表达的几何体,都适用于此概念。
9.1平行光对球体的投影
当我们知道一个球体的位置以及其半径的时候,就已经确切地掌握了这个球体在空间的儿何信息,此时就很容易算出这个球体的投影。首先是脚本SphereShadow.cs,这是一个设定球体位置和半径信息的脚本,需要附加到使用此材质接受球体阴影的脚本上,其代码如下:
using UnityEngine; using System.Collections; [ExecuteInEditMode] public class SphereShadow : MonoBehaviour { public GameObject sphere; void Update () { Vector3 pos=sphere.transform.position; GetComponent<Renderer>().sharedMaterial.SetVector("_spPos",new Vector4(pos.x,pos.y,pos.z,1f)); GetComponent<Renderer>().sharedMaterial.SetFloat("_spR",sphere.transform.localScale.x/2); } }
9.1.2 使用相似三角形计算投影
然后,当我们需要计算一个点是否在球体的投影区域时,我们需要知道这个点到灯光的方向,到球体中心的方向以及距离,然后根据这两个方向的夹角,通过相似三角形的计算,考察透过这个方向在球体的此半径内能不能看到光源,如果可以,此点就不处于阴影之中,否则此点将被标记在阴影中。这个完整操作是在SphereShadow_l.shader中完成的,其完整代码如下:
Shader "Tut/Shadow/SphereShadow_1" { Properties { _spPos ("Sphere Position", vector) = (0,0,0,1)//投影球体位置 _spR ("Sphere Radius", float) = 1//投影球体半径 _Intensity("Intensity Of Shadow",range(0,1))=0.5//阴影浓度 } SubShader { pass{ Tags{"LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float4 _spPos; float _spR; float _Intensity; float4 _LightColor0; struct v2f{ float4 pos:SV_POSITION; float3 litDir:TEXCOORD0;//在世界坐标中的灯光方向矢量 float3 spDir:TEXCOORD1;//在世界坐标中的投影球体方向矢量 float4 vc:TEXCOORD2;//逐顶点计算的光照 }; v2f vert(appdata_base v) { v2f o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); o.litDir=WorldSpaceLightDir(v.vertex); o.spDir=(_spPos-mul(_Object2World,v.vertex)).xyz; //下面是对顶点光照的计算,与阴影的计算无关 float3 ldir=ObjSpaceLightDir(v.vertex); ldir=normalize(ldir); o.vc=_LightColor0*max(0,dot(ldir,v.normal)); return o; } float4 frag(v2f i):COLOR { float3 litDir=normalize(i.litDir); float3 spDir=i.spDir; float spDistance=length(spDir);//到球体的距离 spDir=normalize(spDir); float cosV=dot(spDir,litDir);//两个方向的夹角余弦值 float sinV=sin(acos(max(0,cosV))); float D=sinV*spDistance;//解三角形 float shadow=step(_spR,D);//spR>D 0,else 1 判断是否能透过此方向看到光源 float c=lerp(1-_Intensity,1,shadow);//0 is dark //*step(0,dot(i.N,litDir)) return i.vc*c; } ENDCG }//endpass } }
这个Shader在vertex函数中计算了到光源和投影球体的矢量,在fragment函数中,把插值后的矢量进行normalize,同时计算到投影球体的距离,这个距离在解此点、球体中心以及到光源方向矢量的垂线所构造的三角形时要用到。通过这两个方向矢量的点积得出角度,然后解上面那个三角形,通过到光源矢量方向的垂线距离与球体半径的大小判定在此点能否看到光源。打开SphereShadow文件夹下面的SphereShadow-1场景,效果如图所示。
Scene:
Game:
相关文章推荐
- untiy 3d ShaderLab_第9章_3_球体阴影(三) 点光源对球体的投影
- untiy 3d ShaderLab_第9章_2_球体阴影(二) 阴影的淡入/淡出
- untiy 3d ShaderLab_第9章_1_平面阴影(二) 点光源对平面的投影
- untiy 3d ShaderLab_第9章_1_平面阴影(三) 点光源对平面的投影
- untiy 3d ShaderLab_第9章_1_平面阴影(一)
- untiy 3d ShaderLab_第8章_4_ 单光照贴图在Deferred 渲染路径下的实时阴影
- untiy 3d ShaderLab_第6章_VertexLit渲染路径_2_顶点照明和Unity存放光源的第一种方式
- untiy 3d ShaderLab_第6章_VertexLit渲染路径_3_顶点照明和Unity存放光源的第二种方式
- untiy 3d ShaderLab_第8章_3_ 单光贴图和Forward 渲染路径
- untiy 3d ShaderLab_第7章_ Forward渲染路径_3_重要光源在ForwardAdd内的执行
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_1_Unity通过ShaderLab 来组织Shader
- untiy 3d ShaderLab_第8章_2_在效果和性能间进行权衡
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_2_Unity中Shader的3种形态
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_3_Shader的数据接口:属性和 uniform变量
- untiy 3d ShaderLab_第7章_ Forward渲染路径_4_Forward渲染路径总结
- untiy 3d ShaderLab_第4章_基本的光照模型
- ShaderLab学习小结(五)接收平行光阴影
- untiy 3d ShaderLab_第6章_VertexLit渲染路径_4_顶点照明和Unity存放光源的第三种方式
- untiy 3d ShaderLab_第5章_第一个被执行的Pass_1_不同LightMode 被选择的顺序
- untiy 3d ShaderLab_第7章_ Forward渲染路径_1_ForwardBase和ForwardAdd