Shader山下(二十七)平面阴影
以下摘录自《Unity 3D ShaderLab开发实战详解》,第10章。
转注:这是一个非常简单且廉价的实时假阴影,比较常用到,据我所知,王者荣耀中就使用了类似的手法。缺点就是比较假,只能投射到平面上,不能应对地面的凹凸,最明显的问题就是会插到墙里去。
转注:需要传给shader接受阴影的地面(平面)的worldToLocalMatrix和localToWorldMatrix。对应的变量分别为_World2Ground和_Ground2World。
Shader "Tut/Shadow/PlanarShadow_3" {
//转注:这里对原作里的平行光计算部分和阴影淡出部分做了整合,略去了点光源计算部分。Properties{_Intensity("atten",range(1,16))=1}SubShader {Pass {Tags {"LightMode" = "ForwardBase"}Material {Diffuce(1,1,1,1)}Lighting On}Pass {Tags {"LightMode" = "ForwardBase"}Cull FrontBlend DstColor SrcColorOffset -1,-1 //使阴影在平面之上CGPROGRAM#pragma vertex vert#pragma fragment frag#inlcude "UnityCG.cginc"float4x4 _World2Ground;float4x4 _Ground2World;float _Intensity;struct v2f{float4 pos:SV_POSITION;float atten:TEXCOORD0;};v2f vert(float4 vertex:POSITION){v2f o;float3 litDir;litDir = WorldSpaceLightDir(vertex);litDir = mul(float3x3(_World2Ground), litDir);//把光源方向转换到接受平面空间litDir = normalize(litDir);float4 vt;vt = mul(_Object2World, vertex);vt = mul(_World2Ground, vt);//将物体顶点转换到接受平面空间vt.xz=vt.xz-(vt.y/litDir.y)*litDir.xz;//用三角形相似计算沿光源方法投射后的xz//上面这行代码可拆解为如下的两行代码,这样可能在进行三角形相似计算时更好理解//vt.x=vt.x-(vt.y/litDir.y)*litDir.x;//vt.z=vt.z-(vt.y/litDir.y)*litDir.z;vt.y=0;//使阴影保持在接受平面上vt=mul(_Ground2World,vt);//返回到世界坐标空间vt=mul(_World2Object,vt);//将结果重新表达为Object Space坐标o.pos = mul(UNITY_MATRIX_MVP, vt);//经典的MVP变换,输出到Clip Spaceo.atten=distance(vertex,vt)/_Intensity;//根据前后定点的距离计算衰减return o;}float4 frag(void) : COLOR{return smoothstep(0,1,i.atten/2);}ENDCG}}
}
在此Shader中,我们首先使用固定管线对物体做了一个简单的照明。在计算阴影的ForwardBase中,首先使用一个可以叠加阴影的混合模式,然后使用z偏移保证出来的阴影在接受平面之上。_World2Ground和_Ground2World分别是我们自定义的两个进出阴影接受平面矩阵(转注:这里原作解释的不好,按字面意思理解即可)。在具体计算中,首先将光源方向和投影物体的顶点都转换到接受平面的空间(接受平面的物体空间),在它们都处于同一空间后,通过简单的三角形近似算法,来计算投影物体顶点沿光线投影后在接受平面上的新位置。因为这是一个Build In的(Built-in)Unity Plane,所以只计算其xz分量即可,并将y分量设为0,这样投影出来的阴影就出现在接受平面上了。投影计算完成后,返回世界空间,然后到投影物体本身的Object Space,之后的事情就如通常那样,一个经典的MVP变换即可。
这个方法还有一个显而易见的问题,那就是物体本身是立体的,不在一个平面,因此,这个计算前后的点的距离是包括物体本身厚度的,这个厚度就会表现在阴影上。
转注:使用Stencil可以解决这个问题,但是原作中并没有涉及,所以暂时略过。
算了,以下为原创:
如上图所示,Cube和Cylinder貌似没有什么问题,但是右边那个绳结形状的物体的阴影就出现了问题。解决方法,在第二个pass里CGPROGRAM之前,加入以下代码:
Stencil{Ref 1 //参考值为1,stencilBuffer值默认为0 Comp Greater //stencil比较方式是大于Pass replace //通过的处理是替换,就是拿1替换buffer 的值 Fail Keep //深度检测和模板检测双失败的处理是保持ZFail keep //深度检测失败的处理是保持}
结果:
效果略好,但是也并不太理想,那是因为原作并不是把绳结物体当成一整个物体对待,而是当做一个一个的顶点处理,用原顶点和对应的影子顶点计算距离明显有问题。另外有一种做法是传入对象的世界坐标,然后跟世界空间的影子顶点计算距离,但其实也略复杂了,最简单的就是把o.atten=distance(vertex,vt)/_Intensity;
这一段替换成:
o.atten=length(vt)/_Intensity;
其实就是计算影子顶点和物体的原点的距离。
效果如图:
这就需要在制作模型的时候把物体的原点设在y=0的平面上,这样这种影子才能达到较好的效果。
最后……需要提一句,原作中将物体和影子在一个shader里渲染,我认为这是有问题的,因为没法分别设置Queue,物体的Queue应该是Geometry,而影子的Queue应该是Transparent。所以正确的做法应该是,物体该怎么渲染就怎么渲染,影子做一个GameObject挂在物体上,添加MeshFilter和MeshRenderer使用相同的Mesh,然后MeshRenderer里使用阴影的材质。即上文中的Shader去掉第一个Pass,并修改Tags。Blend方法建议修改为Blend SrcAlpha OneMinusSrcAlpha,最后frag方法建议修改为:
float4 frag(v2f i) : COLOR {return float4(0,0,0, smoothstep(1, 0, i.atten / 2));}
综上所述,整合一下代码:
Shader "Tut/Shadow/PlanarShadow_Chaos" {Properties{_Intensity("atten",range(1,16))=1}SubShader {Tags{ "LightMode" = "ForwardBase""Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }pass {Cull FrontBlend SrcAlpha OneMinusSrcAlphaOffset -1,-1Stencil{Ref 1 //参考值为1,stencilBuffer值默认为0 Comp Greater //stencil比较方式是大于Pass replace //通过的处理是替换,就是拿1替换buffer 的值 Fail Keep //深度检测和模板检测双失败的处理是保持ZFail keep //深度检测失败的处理是保持}CGPROGRAM#pragma vertex vert #pragma fragment frag#include "UnityCG.cginc"float4x4 _World2Ground;float4x4 _Ground2World;float _Intensity;struct v2f{float4 pos:SV_POSITION;float atten:TEXCOORD0;};v2f vert(float4 vertex: POSITION){v2f o;float3 litDir;litDir=normalize(WorldSpaceLightDir(vertex)); litDir=mul(_World2Ground,float4(litDir,0)).xyz;float4 vt;vt= mul(unity_ObjectToWorld, vertex);vt=mul(_World2Ground,vt);vt.xz=vt.xz-(vt.y/litDir.y)*litDir.xz;vt.y=0;vt=mul(_Ground2World,vt);//back to worldvt=mul(unity_WorldToObject,vt);o.pos=UnityObjectToClipPos(vt);o.atten=length(vt)/_Intensity;return o;}float4 frag(v2f i) : COLOR {return float4(0,0,0, smoothstep(1, 0, i.atten / 2));}ENDCG }//}
}
Shader山下(二十七)平面阴影相关推荐
- Shader山下(十七)语义Semantic
当在编写Cg或者HLSL着色器程序的时候,我们需要使用语义(Semantic)来指明输入输出变量的"意图". 例如下面的这段Shader代码: Shader "Custo ...
- Shader山下(二十一)多重变体(Multiple Variants)
2019独角兽企业重金招聘Python工程师标准>>> Shader山下(二十)编译指令(Compilation Directives)介绍了如何使用编译指令,本文就专文介绍一下多重 ...
- 2d shader unity 阴影_【Unity Shader】平面阴影(Planar Shadow)
来介绍一种适用于移动平台的高性能实时阴影解决方案--平面阴影(Planar Shadow). 由于Unity内置的实时阴影实现方式是屏幕空间阴影贴图(Screen Space Shadow Map)非 ...
- Unity Shader - Planar Shadow - 平面阴影
文章目录 整体运行效果 思路 Shader 问题 Z-Fighting,解决:按法线方向偏移一丢丢 绘制 Alpha 混合重叠,解决:使用 stencil buffer 来规避 为何出现这个问题 解决 ...
- Shader山下(十二)材质属性绘制器
Unity5增加了一个叫MaterialPropertyDrawer的东西,可以使用它们标记在shader的Properties里面,扩充shader的一些参数在编辑器上的样式. 本文以Shader山 ...
- Shader山下(一)第一个Shader
学习Unity3D就得学Shader,然而新手学习Shader往往不知道从何处下手,没有找对门,谈何入门. 本系列主要介绍Shader的一些基础知识,希望可以带你找对门,然后入得了门. (本文作者也尚 ...
- 【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍
游戏开发笔记二十七 Direct3D 11入门级知识介绍 作者:毛星云 邮箱: happylifemxy@163.com 期待着与志同道合的朋友们相互交流 上一节里我们介绍了在迈入Dire ...
- 【Unity】Planar Shadows平面阴影的实现
Plannar Shadows,即平面阴影,是一个适用于平坦地形的假阴影技术.要求阴影的Receiver为平面,Occluder不与其他物体穿插. 实现效果 1.定向光源Planar Shadows ...
- 8.3实例程序:平面阴影
在场景中被灯光照射的地方会产生阴影,这将使场景变的更真实.在这一部分我们将演示怎样实现平面阴影,即在平面上的阴影(如图8.5). 使用这种阴影只是一种权宜之计,虽然它增强了场景的真实效果,但是这并不是 ...
- OpenCV C++案例实战二十七《角度测量》
OpenCV C++案例实战二十七<角度测量> 前言 一.鼠标响应事件 1.1功能源码 1.2功能效果 二.计算直线角度 2.1 计算直线斜率 2.2计算直线角度 2.3功能源码 三.绘制 ...
最新文章
- 【Java】 链表的回文结构
- 部署Symantec Antivirus 10.0网络防毒服务器之六
- Linux文件系统上的特殊权限 SUID, SGID, Sticky(粘之位)
- android输入法中的imeoption
- oracle让查出来的数据排序,Oracle数据库的查询排序
- 【计算机基础】存储器层次 Memory hierarchy
- linux 扩充db2表空间,如何扩充db2的表空间、加容器等表空间维护操作
- Python正则表达式如何进行字符串替换
- oracle监听服务无法启动不了,关于ORACLE监听服务无法启动的问题
- 由通项为In(1+1\n)的级数引申...
- tar命令压缩和解压缩
- matlab db5是什么小波,3、代码 - matlab小波分析步骤是什么
- php 绕不过的laravel,php – 为什么在Laravel中不能轻松下载大文件?
- 系统中 用户操作日志管理
- web项目连接阿里云云数据库RDS-MySQL8.0
- Smart-Link
- 虚拟机(VMware Workstation Pro15)及系统(Windows10)安装
- RecyclerView调用notifyDataSetChanged()不起作用
- LabWindows界面的程序控制
- 螺旋矩阵java_Java实现螺旋矩阵
热门文章
- python参数种类_python的参数类型
- mysql 中英按字母排序_利用MySQL数据库来处理中英文取首字母排序
- 数据结构实验一,第1题:基于顺序存储结构的图书信息表的创建和输出
- php 无级分类源代码,php+mysql无限级分类程序代码
- python为什么流行头上长草_头上“长草”真的可以实现吗?
- 我的.emacs(Ubuntu版)(二十二)
- android播放器如何获取音乐文件信息
- 创业团队最好的时代 - 上篇
- Fresco图片加载框架使用方法完全指南
- ppt播放影片时出现提示某些文件可能携带病毒,损害您的计算机,我的PPT没病毒—禁用PowerPoint的病毒提示...