版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载。

  阴影在现实生活中扮演着非常重要的角色,通过阴影我们能直观的感受到光源位置、光源强弱、物体离地面高度、
物体轮廓等,在大脑中构建环境空间信息。阴影的产生与光源密切相关,阴影的产生也与环境光密切相关。阴影还影响人对空间环境的判断,是构建立体空间信息的重要参考因素。

  与真实世界一样,在数字世界中阴影的生成也需要光源,同时,在AR中阴影生成与 VR 相比有很大不同,VR是纯数字世界,在其环境中肯定能找到接受阴影的对象,但 AR 中却不一定有这样的对象,如将一个AR虚拟物体放置在真实桌面上,这时虚拟物体投射的阴影没有接受物体(桌面并不是数字世界中的对象,无法直接接受来自虚拟物体的阴影),因此就不能生成阴影。为使虚拟物体产生阴影,我们的思路是在虚拟物体下方放置一个接受阴影的对象,这个对象需要能接受阴影但又不能有任何材质表现,即除了阴影部分,其他地方需要透明,这样才不会遮挡现实世界中的物体。

(一) ShadowMap技术原理

  在Unity中,实现实时阴影混合了多种阴影生成算法,根据要求可以是shadowmap、screen space shadowmap、Cascaded Shadow等,shadowmap按技术又可以分为Standard Shadow Mapping、PCF、PSM、LISPSM、VSM、CSM / PSSM等等。之所以分这么多阴影生成算法,最主要的目的是平衡需求与复杂度。阴影生成的理论本身并不复杂,有光线照射的地方就是阳面(没有阴影),没有被光照射的地方就是阴面(有阴影),但现实环境光照非常复杂,阴影千差万别,有在太阳光直射下棱角特别分明的阴影,有在只有环境光照下界线特别不分明的超软阴影,也有介于这两者之间的阴影,目前没有一种统一的算法可以满足各种阴影生成要求,因此发展了各类阴影算法处理在特定情况下阴影的生成问题。

  ShadowMap技术需要进行两次渲染,第一次从灯光的视角渲染一张RenderTexture,将深度值写入到纹理中,这张深度纹理称之为深度图,第二次从正常的摄像机视角渲染场景,在渲染场景时需要将当前像素到灯光的距离与第一次渲染后的深度图中对应的深度信息作比较,如果距离比深度图中取出的值大就说明该点处于阴影中,如下图所示。

  在第一次渲染中,从灯光视角出发,渲染的是灯光位置可见的像素,记录这些深度信息到深度图中;第二次从摄像机视角渲染场景,这次渲染的是摄像机位置可见的像素,如E点,计算E点到灯光的距离L2,将L2与深度图中对应的深度值作比较,从图中可以看到,在第一次渲染时,与E点对应的深度信息是L1,并且L1<L2,这说明从灯光的视角看,E点被其他点挡住了,因此E点不能被灯光照射到,即E点处于阴影中(特别需要注意的是距离比较一定要在同一坐标空间中才有意义)。

(二)使用实时阴影

  如前所述,阴影生成一方面需要有光源,另一方面还需要有一个接受并显示阴影的载体。本节中我们将采用Unity内置的阴影解决方案生成AR实时阴影,光源采用Directional Light,使用一个Plane做阴影授受对象。

  首先,我们制作一个接受阴影且透明的Plane,在Project窗口中新建一个Shader,命名为ARShadow,编写以下cg代码,该shader的功能就是显示阴影。

Shader "Davidwang/MobileARShadow"
{SubShader{Pass {Tags { "LightMode" = "ForwardBase" "RenderType" = "Opaque" "Queue" = "Geometry+1" "ForceNoShadowCasting" = "True"  }LOD 150Blend Zero SrcColorZWrite OnCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#pragma multi_compile_fwdbase#include "AutoLight.cginc"struct v2f{float4 pos : SV_POSITION;LIGHTING_COORDS(0,1)};v2f vert(appdata_base v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);TRANSFER_VERTEX_TO_FRAGMENT(o);return o;}fixed4 frag(v2f i) : COLOR {float attenuation = LIGHT_ATTENUATION(i);return fixed4(1.0,1.0,1.0,1.0) * attenuation;}ENDCG}}Fallback "VertexLit"}

  然后新建一个材质,亦命名为ARShadow,选择shader为刚才变编写的ARShadow.shader。在Hierarchy窗口中新建一个Plane,将其Scale改小一点,修改为(0.1,0.1,0.1),然后将ARShadow材质赋给它,并制作成Prefab,命名为ARPlane,删除Hierarchy窗口中的Plane,到此,接受阴影的平面制作完成。

  在Hierarchy窗口选择Directional Light,然后在Inspector窗口中进行设置。先测试一下硬阴影,将Shadow Type设置为Hard Shadows,其余参数设置如下图所示,详细参数后文会说明。

  在Unity菜单栏依次选择 Edit ->Project Settings,打开Project Settings对话框,选择Quality选项卡,点击其右侧Android下的黑色小三角图标,在下拉菜单中选择Very High或者Ultra,然后选择Shadows为Hard Shadows Only,选择Shadow Projection为Close Fit,如下图所示。


  在Project窗口中新建一个C#脚本,命名为AppController.cs,编写如下代码。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;[RequireComponent(typeof(ARRaycastManager))]
public class AppControler : MonoBehaviour
{public  GameObject spawnPrefab;public GameObject ARPlane;static List<ARRaycastHit> Hits;private ARRaycastManager mRaycastManager;private GameObject spawnedObject = null;private float mARCoreAngle = 180f;private void Start(){Hits = new List<ARRaycastHit>();mRaycastManager = GetComponent<ARRaycastManager>();}void Update(){if (Input.touchCount == 0)return;var touch = Input.GetTouch(0);if (mRaycastManager.Raycast(touch.position, Hits, TrackableType.PlaneWithinPolygon | TrackableType.PlaneWithinBounds)){var hitPose = Hits[0].pose;            if (spawnedObject == null){spawnedObject = Instantiate(spawnPrefab, hitPose.position, hitPose.rotation);spawnedObject.transform.Rotate(Vector3.up, mARCoreAngle);var p = Instantiate(ARPlane, hitPose.position, hitPose.rotation);p.transform.parent = spawnedObject.transform;}else{spawnedObject.transform.position = hitPose.position;}}}
}

  该脚本的主要功能在检测到的平面上放置虚拟对象,同时实例化了一个接受阴影的平面,并设置该平面为虚拟对象的子对象。将该脚本挂载在场景中的AR Session Origin对象上,并将虚拟物体与前面制作好的ARPlane赋给相应属性,如下图所示。


  运行后效果如下图所示。


  从上图中可以看到,这时生成的阴影锯齿非常严重,基本无法使用,其性能消耗基本保持在20ms-30ms之间,如下图所示。


  接下来我们测试软阴影,将Directional Light的Shadow Type设置为Soft Shadows,其余参数设置不变。然后在Unity菜单栏依次选择 Edit ->Project Settings,打开Project Settings对话框,选择Quality选项卡,设置选择Shadow Projection为Stable Fit,效果如下。



  在使用Soft Shadow并选择Shadow Projection为Stable Fit后,阴影的质量有了比较大的改观,也柔和了很多,但阴影与虚拟对象贴合得不紧密,同时性能消耗升到40ms-50ms之间。

  保持Directional Light属性Shadow Type为Soft Shadows,设置选择Shadow Projection为Close Fit,效果如下。


  在选择Shadow Projection为Close Fit后,阴影与虚拟对象贴合得非常好,整体效果也还不错,但边缘过渡还是比较生硬,性能消耗升到60ms-80ms之间。对比可以发现,Shadow Type 与 Shadow Projection选项对阴影质量影响很大,Stable Fit对Shadow map使用的是球形渐隐,Close Fit使用的是线性渐隐,Close Fit通常用于渲染较高分辨率的阴影,但在相机移动时阴影会轻微摆动,Stable Fit渲染的阴影分辨率较低,不过相机移动时不会发生摆动。另外也可以看出,阴影生成对性能影响还是比较大的,高分辨率的实时阴影可能导致性能消耗成倍增加。

(三)阴影参数详解

  Unity阴影系统非常强大复杂,在Directional Light属性中,与阴影相关的属性详细信息如下表所示:

属性 描述
Strength 阴影强度,值越大阴影越浓,越小阴影越淡,范围为[0,1],默认值为1。
Resolution 阴影分辨率,Use Quality Settings为使用Project Settings中的设置值,通常会选择该选项,因为Project Settings中可设置的参数更丰富,按分辨率从低到高依次为Low Resolution,Medium Resolution,High Resolution,Very High Resolution,分辨率越高,阴影边缘的锯齿效应就越平滑越不明显。
Bias 偏移量,范围为[0,2],默认值为0.05,阴影与模型的位置关系,值越大阴影与模型偏移越大,其与Normal Bias一并用来防止自阴影(Shadow acne)和阴影偏离(peter-panning)。
Normal Bias 法向偏移量,范围为[0,3],默认值为0.4,建议取值范围[0.3,0.7],该属性实际是用来调整表面坡度偏移量,坡度越大偏移量应该越大,但过大的偏移理又会导致阴影偏离(peter-panning),因此固定的偏移量需要法向偏移量来修正。
Near Plane 近平面,产生阴影的最小距离,范围为[0.1,10],调整该值可以调整近阴影裁减平面。

  在Project Settings对话框中,选择Quality选项卡,这里可以设置整体的质量表现,从左到右依次为台式电脑、iOS、Android、webGL,从上到下质量越来越高,在效果越来越好的同时性能消耗也会同步增加。

  在Project Settings对话框中与阴影相关的设置如下图所示。

  各属性详细说明见下表。

属性 描述
Shadowmask Mode 阴影遮罩模式,只在光源为Mix模式才有用,Shadowmask表示所有静态物体都使用烘焙阴影,Distance Shadowmask与Shadow Distance配合使用,在Shadow Distance范围内使用实时阴影,在范围外使用烘焙阴影。因此,Distance Shadowmask性能消耗比Shadowmask要高。
Shadows 阴影模式,分为Disable Shadows,Hard Shadows Only,Hard and Soft Shadows,分别为无阴影,硬阴影,软阴影。
Shadow Resolution 阴影分辨率,按分辨率从低到高依次为Low Resolution,Medium Resolution,High Resolution,Very High Resolution,分辨率越高,阴影边缘的锯齿效应就越平滑越不明显。
Shadow Projection 阴影投影,Directional Light的阴影投影方式。Close Fit渲染高分辨率的阴影,Stable Fit渲染低分辨率的阴影。
Shadow Distance 阴影可见距离,为提高性能,在此距离内渲染阴影,在此距离外的阴影不渲染。
Shadow Near Plane Offset 近平面阴影偏移,用于处理近平面处大三角形导致的阴影扭曲问题。
Shadow Cascades 层叠阴影,分为No Cascades,Two Cascades,Four Cascades,更高的层叠阴影带来更好的阴影边缘柔和效果,层叠阴影对性能消耗非常大。
Cascade Splits 层叠切片,用于调整层叠阴影叠加效果。

  Unity自带的阴影系统实现了shadowmap、screen space shadowmap、Cascaded Shadow等阴影效果,也可以控制阴影偏移量与法向偏移量,能普适于常见应用。

ARFoundation之路-AR阴影生成之一相关推荐

  1. ARFoundation之路-人脸检测增强之二

    版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载.   前节所述使用"标准模型"匹配人脸以检测人脸姿态是众多人脸姿态检测方法中的一种,实际上,人脸姿态估计 ...

  2. Unity3d 使用URP渲染管线实现AR阴影(阴影投射再透明地面)

    历经千辛万苦,对于一个不会写Shader的程序员,从内置渲染管线的AR阴影实现到URP渲染管线实现是多么艰辛.全网搜索资料,少的可怜. 不容易 感谢Unity 社区!!!!!!! unity-tech ...

  3. ARFoundation之路-光照估计

    版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载. (一)光照一致性   AR 与 VR 在光照上最大的不同在于 VR 世界是纯数字世界,有一套完整的数学模型,而 AR 则是 ...

  4. ARFoundation之路-环境配置(iOS)之二

    版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载. (一)AppController   在Project窗口Scripts文件夹下,空白处点击鼠标右键,在弹出的级联菜单中依 ...

  5. 3d 自动生成物体_Adobe发布3D建模、AR内容生成应用Scantastic

    10月27日消息,Adobe展示了一款支持3D AR扫描的全新移动应用原型Scantastic,该应用结合3D扫描.设计和AR技术,让你用手机就能将周围的物体扫描并生成3D模型. 据青亭网了解,Sca ...

  6. ARFoundation之路-平面管理

      平面检测是很多AR应用的基础,无论是ARKit还是ARCore,都提供平面检测功能.同时,平面也是可跟踪对象,在前几节中我们知道,ARFoundation使用ARPlaneManager管理器来管 ...

  7. ARFoundation之路-视频播放

    版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载.   在AR中播放视频也是一种常见的需求,如在一个展厅中放置的虚拟电视上播放宣传视频,或者在游戏中为营造氛围而设置的虚拟电视 ...

  8. ARFoundation之路-3D物体识别之一

    版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载.   3D物体跟踪技术,是指通过图像处理技术对摄像头中拍摄到的3D物体识别定位并对其姿态进行跟踪的技术.3D物体跟踪技术的基 ...

  9. python实现dem输出三维模型_python实现DEM数据的阴影生成的方法

    相关的依赖库在我的github网站上 首先贴出代码: import solar from gradient import * from shadows import * import numpy as ...

最新文章

  1. 3224: Tyvj 1728 普通平衡树
  2. struts2.1.6教程二、struts.xml配置及例程
  3. python 控件叠加_如何将图像应用于控件背景(叠加)
  4. CCNA网络小菜鸟笔记之(第十一章, 广域网协议)
  5. 比Redis快5倍的中间件,究竟为什么这么快?
  6. 浏览器关闭百度右侧的图片推荐---简洁就是美
  7. 读取cpu温度的api_温度读取vc++获取cpu温度
  8. 期刊论文插入参考文献(Word尾注插入法,简单适用)
  9. 【应用统计学】总体方差的假设检验
  10. android7.1索尼,Xperia 1
  11. 继被Twitter永久封杀后!Sci-Hub再遭英国网络运营商封禁!
  12. crmeb多商户公测版发布
  13. 发顶会论文,怎么就那么难?10个带你一起“收割”顶会论文的...
  14. HttpClient模块的HttpGet和HttpPost及Connection to refuse解决
  15. 【Java锁体系】ReadWriteLock读写锁是什么?什么是读写锁
  16. 在Tomcat下使用JavaBean
  17. iPhone开启的「查找」功能怎么操作
  18. java text to speech_Java TextToSpeech.speak方法代碼示例
  19. Java中间件-Elasticsearch
  20. java为什么用工厂模式_【Java】为什么建议没事不要随便用工厂模式创建对象?...

热门文章

  1. Vuetify 使用步骤
  2. 160个crakeme之cracking4all.1.exe
  3. Java中Hbase查询,复杂,条件范围,时间范围,精确查询等等
  4. 如何使用PDF编辑软件在PDF文件中添加背景图片
  5. 磁盘阵列RAID理解
  6. CSS3新增伪类有哪些?
  7. FFmpeg多音轨进行合并
  8. 用c#写一段获取邮箱后缀的代码
  9. NCL站点资料画中国区域气温散点图及分布图
  10. Nginx 符合域名跳转