在Unity3D中使用Projector实现动态阴影

  无意中看见一篇博客叙述使用Projector实现动态阴影可以在移动平台拥有非常好的性能,遂按照其想法实现了一遍,发现其中竟有许多细节,写下这篇博客记录以供将来参考。

Projector

  

  从上图中我们发现Projector中的参数参数Camera的参数非常的相似,那Projector是做什么的呢?

  官方解释:A Projector allows you to project a Material onto all objects that intersect its frstum.也就是Projector是把一个材质投影到与Projector视锥体相交的物体上,这个描述比较抽象,我们可以用以前的胶片电影来类比一下:Projector就是胶片放映机,被投影的材质就是胶片,Projector投影就像胶片放映机把胶片内容投影到电影幕布一样。

  按照这个理解,我们发现这个与平时在OpenGL中提到的摄像机投影有点不一样,OpenGL的投影矩阵干的事是把三维物体投影到摄像机的近平面,也就是三维到二维的一个改变,但Projector投影确是相反,把一个纹理投影到三维物体的表面。

原理

  按照上述Projector的理解,我们可以设想一个产生阴影的方法:先把要产生阴影的物体绘制到纹理中,然后把这个纹理投影到要接收阴影的物体表面上(注意与产生阴影的物体区分开),这样就有了阴影,而这就是Projector产生阴影的原理。

实现细节

  首先是要生成要被投影的阴影,因为这个阴影要与物体完美衔接,所以我们需要用Projector的参数来生成这个纹理,在Unity3D中我们的做法是:

  1.创建一个新Camera,Camera的参数与Projector的一致;

  2.设置Camera的Culling Mask为要产生阴影的物体所在的LayerMask,Projector的ignore Layers同样设置为这个LayerMask,同时把要产生阴影的物体的Layer设置为这个LayerMask;

  3.设置Camera渲染使用的shader,即camera.setReplaceShader;

  4.创建RenderTexture,使用的分辨率视自己需求而定,分辨率越高,阴影越精细;

  5.设置新建的Camera的TargetTexture为新建的RenderTexture;

  6.新建Projector所需材质,可以使用standard assets中的“ProjectorMultipy”shader创建,设置材质的_ShadowTex为新建的RenderTexture;

  7.运行即可看到效果。

  需要注意的是:

  1.传递给Projector材质的RenderTexture必须是clamp模式,但是如果阴影到了RenderTexture边缘的像素,因为是Clamp的原因,地板就会出现整个长条形的阴影,解决方案可以通过给projector材质添加mask图来处理边缘的像素;

  2.RenderTexture其实我们只需要表示产生阴影物体的位置,所以Camera使用的ReplaceShader可以使用最简单的shader,只写入一个通道值就可以了;

效果

ProjectorMultiply.Shader

   被投影的材质需要特殊的shader,其实主要是要计算阴影的uv坐标。因为我们使用的是新建的一个纹理,这个纹理如何应用到物体的表面,需要使用Projector定义的一个投影矩阵,也就是通过这个矩阵来计算投影后的uv坐标。比较人性化的是Unity3D已经帮我们计算好了,直接在shader中声明float4x4 unity_Projector就可以使用了。shader中还用到了falloff的一个texture,通常是一张左白右黑的贴图,用于控制阴影的强弱。Falloff左边为白色,alpha值为1,对应投影距离最近时最亮,右边接近全黑,alpha值为0,表示投影距离变远时投影会渐渐接近透明甚至看不见。具体代码如下:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

// Upgrade NOTE: replaced '_Projector' with 'unity_Projector'
// Upgrade NOTE: replaced '_ProjectorClip' with 'unity_ProjectorClip' Shader "Projector/Multiply" {
Properties {
_ShadowTex ("Cookie", 2D) = "black"{}
_FalloffTex ("FallOff", 2D) = "white" {}
}
Subshader {
Tags {"Queue"="Transparent"}
Pass {
ZWrite Off
ColorMask RGB
Blend DstColor Zero
Offset -1, -1 CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc" struct v2f {
float4 uvShadow : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 pos : SV_POSITION;
}; float4x4 unity_Projector; v2f vert (float4 vertex : POSITION)
{
v2f o;
o.pos = UnityObjectToClipPos (vertex);
o.uvShadow = mul (unity_Projector, vertex);
UNITY_TRANSFER_FOG(o,o.pos);
return o;
} sampler2D _ShadowTex;
sampler2D _FalloffTex; fixed4 frag (v2f i) : SV_Target
{
fixed4 texS = tex2Dproj (_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
fixed4 texF = tex2Dproj (_FalloffTex, UNITY_PROJ_COORD(i.uvShadow));
fixed ratio = texF.r * texS.a;
fixed4 res = fixed4(1,1,1,1) * (1 - ratio);
UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1,1,1,1));
return res;
}
ENDCG
}
}
}

  

优缺点

  优点:

    1.可控性强。可以看出我们可以控制在哪个区域、哪些物体、什么时间产生或更新阴影,也可以对阴影的质量进行控制(使用不同分辨率的RenderTexture);

    2.可以很方便的是实现模糊和软阴影(这个还没实践,不过因为我们可以取得阴影的rendertexture,所以完全可以实现);

  缺点:

    1.很明显,产生阴影的物体不能接收阴影;

    2.Unity3D 的Betch无法使用(因为要分层);

工程源代码:https://github.com/xin-lover/ProjectorShadow

Unity3D AssetStore中有一个使用这种方法生成阴影的插件,做的比较完善,可以参考使用:Dynamic Shadow Projector.

参考博客:

  1.https://yrsc.github.io/2018/03/Projector%E5%AE%9E%E7%8E%B0%E4%BC%AA%E5%8A%A8%E6%80%81%E9%98%B4%E5%BD%B1/

Unity3D中使用Projector生成阴影的更多相关文章

  1. 在Unity3D中实现安卓平台的本地通知推送

    [前言] 对于手游来说,什么时候需要推送呢?玩过一些带体力限制的游戏就会发现,我的体力在恢复满后,手机会收到一个通知告诉我体力已完全恢复了.这类通知通常是由本地的客户端发起的,没有经过服务端. 在安卓 ...

  2. Json数据解析在Unity3d中的应用

    最近做项目过程中因为Json文件名写错了一个字母Unity报错,找错误找到半夜,当时为了验错,写了一个小Demo,正好借此总结一下Json. 1.什么是Json JSON(JavaScript Obj ...

  3. UE4/Unity3D中同时捕获多高清摄像头的高效插件

    本文主要讲实现过程的一些坑. 先说下要实现的目标,主要功能在UE4/Unity中都要用,能同时捕获多个摄像头,并且捕获的图片要达到1080p25桢上,并且需要经过复杂的图片处理后丢给UE4/Unity ...

  4. Unity3D中的shader基础知识

    1.Unity中配备了强大的阴影和材料的语言工具称为ShaderLab,以程式语言来看,它类似于CgFX和Direct3D的效果框架语法,它描述了材质所必须要的一切咨询,而不仅仅局限于平面顶点/像素着 ...

  5. 【转】Unity3D中脚本的执行顺序和编译顺序

    支持原文,原文请戳: Unity3D中脚本的执行顺序和编译顺序 在Unity中可以同时创建很多脚本,并且可以分别绑定到不同的游戏对象上,它们各自都在自己的生命周期中运行.与脚本有关的也就是编译和执行啦 ...

  6. unity3d中的自定义模型的顶点法线和建模软件中的术语“软硬边”和立方体

    在unity3d中我是想用Mesh生成一个正方体,直到遇到了法线的问题. 我是想显示如下图所示的正方体,却发现法线设置上的问题. 这里我先使用了8个顶点 按照每个顶点一个法线的结果,只能是这样:(也就 ...

  7. 在Unity中实现屏幕空间阴影(2)

    参考文章: https://www.imgtec.com/blog/implementing-fast-ray-traced-soft-shadows-in-a-game-engine/ 完成的工程: ...

  8. Unity3D系列教程--使用免费工具在Unity3D中开发2D游戏 第一节

    声明:   本博客文章翻译类别的均为个人翻译,版权全部.出处: http://blog.csdn.net/ml3947,个人博客:http://www.wjfxgame.com. 译者说明:这是一个系 ...

  9. Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现

    喜欢我的博客请记住我的名字:秦元培,我的博客地址是:http://qinyuanpei.com 转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanp ...

随机推荐

  1. ZOJ 1586 QS Network Kruskal求最小生成树

    QS Network Sunny Cup 2003 - Preliminary Round April 20th, 12:00 - 17:00 Problem E: QS Network In the ...

  2. 过滤asp.net页面每次发出请求之前访问

    public class PageFiltert : System.Web.UI.Page { public PageFiltert() { // //TODO: 在此处添加构造函数逻辑 // } p ...

  3. 数据库路由中间件MyCat - 源代码篇(6)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.3 AbstractConnection: 3.3.2 NIOHandler NIOHa ...

  4. window.onerror 捕捉所有的前端error

    //[捕捉所有前端error] window.onerror = function (errormessage, url, line, column, error) { console.log(&qu ...

  5. Keras输出每一层网络大小

    示例代码: model = Model(inputs=self.inpt, outputs=self.net) model.compile(loss='categorical_crossentropy ...

  6. nginx限制恶意IP处理方法

    思考了几种方案,最终考虑使用ip黑名单的方式: 处理方法: 一.nginx黑名单方式: 1.过滤日志访问API接口的IP,统计每10分钟调用超过100次的IP,直接丢进nginx的访问黑名单 2.具体 ...

  7. 洛谷P1829 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

    传送门 式子好麻烦orz……大佬好腻害orz->这里 //minamoto #include<iostream> #include<cstdio> #define ll ...

  8. 笔记-JavaWeb学习之旅19

    Redis:redis是一款高性能的NOSQL系列的非关系型数据库 NOSQL: Not Only SQL ,意即"不仅仅是SQL",是一项全新的数据库理念,泛指非关系型数据库 r ...

  9. Sql Server常用函数及技巧

    使用Sql Server好长时间了,今天特别想总结一下,算是回顾吧! 总结: 其实很多技巧,都是基于SQL Server自带的System Views,System Stored Procedures ...

  10. 在双系统(Win7和Ubuntu Kylin)中卸载Ubuntu

    由于以前学习Linux相关的知识,所以在win7的基础上装了ubuntu系统,最近在使用中老是出现一些问题,想将其卸载,于是在网上找了些相关方法. 我每次开机时,都会出现GRUB界面(我需要选择要进入 ...