Cocos 3.x 阴影

参考
https://docs.cocos.com/creator/3.3/manual/zh/concepts/scene/shadow.html

在 3D 世界中,光与影一直都是极其重要的组成部分,它们能够丰富整个环境,质量好的阴影可以达到以假乱真的效果,并且使得整个世界具有立体感。

Creator 3.0 目前支持 Planar 和 ShadowMap 两种阴影类型。

关于ShadowMap理论部分,可以参考图形学笔记九 阴影 光追一 求交

一、Planar简介

参考
使用顶点投射的方法制作实时阴影
【Unity Shader】平面阴影(Planar Shadow)

1.概述

阴影是计算机图形学中一个很重要的部分,阴影的加入使得物体更加具有立体感,也有助于我们理解物体间的相互位置关系和大小。

实时阴影的实现方法有很多种,shadowMap适用性最好,但性能开销也大,有时候我们的项目其实并不需要那么通用的阴影,我们只需要一个“适用某些特定场合”的一个“看起来正确”的实时阴影。

本文所说的,就是一种利用顶点投射的方法实现的实时阴影技术,在一些阴影质量要求不高,地面平整的项目是一个非常合适的方案,现在很火的手游《王者荣耀》就用了类似的技术。

(经提醒,这个技术叫平面投影阴影(Planar Projected Shadows)技术,由Jim Blinn 1988年提出。http://www.twinklingstar.cn/2015/1717/tech-of-shadows/#21_Blinns)

2.推导

说到求投影,我当时首先想到的就是用投影矩阵,后来经群友提醒,其实可以更进一步简化为求相似三角形,这样理解起来似乎还更简单些,以下是推导过程,为了简化计算,我们在二维空间内进行推导。

根据已知条件,我们可以得到一个这样的题目:已知平面坐标系内一个单位向量L(Lx,Ly),坐标系内一点M(Mx,My),求点M沿着L方向 在y = h上的投影位置P,如下图所示:

image.png
3.优缺点

这种平面阴影的优点是性能消耗小,阴影品质较高,简单好实现,非常适合MOBA类、俯视视角类型的游戏(角色和相机有一定距离)。

但是此方法的局限性也很大,最明显的缺点是阴影只投影在特定平面上,会插到墙体等障碍物中。另外它模拟的并不是真实的物理阴影和实际差别很大,阴影边缘很硬,真实的边缘会有虚化,如果镜头距离较近的话缺陷就会比较明显。

image.png
二、Shadow Map简介

参考
Shadow Map阴影贴图小讲
作为目前绝大多数电子游戏使用的阴影技术,我们来看一下shadow mapping的原理,优缺点都有哪些。这篇文章主要讲解Directional Light平行光产生的阴影, Omnidirectional light(也就是点光源,具体分为point light和spot light)产生的阴影放在下一篇中。

我们先讲原理,拿OpenGL举例,不谈具体的代码,聊聊大概的框架和偏原理的数学,以及实现过程中出现的问题,问题产生的原因和相对应的优化方案。

1.Shadow Mapping的原理

对于比较了解实时渲染的同学们应该知道 实时渲染中z-buffer的概念。这里简单的讲一下z-buffer是什么。z,取于3D场景中xyz坐标中的z。在将一个3D场景空间的三角形转换在2D图形空间的过程中,保留每个像素点的深度值储存起来,这就是z-buffer,这个过程在vertex shader中完成。总结来说,zbuffer就是每个像素点在场景空间的深度,通过比较每个像素点的深度,可以确定哪些像素点被遮挡而不需要被渲染,可以很大的提高渲染的效率。

介绍完z-buffer,现在开始讲讲Shadow Mapping的原理。原理其实非常简单,在确定遮挡关系的时候, z-buffer的深度值是相对于摄像机镜头,也就是眼睛所见来确定物体是否被遮挡,这个很容易理解。眼睛能看不见的地方,当然被挡住了。那我们换个角度想想,阴影是如何产生的?

阴影其实就是光线看不见的地方。因此,如果我们把摄像机放到光源,那么光能看见的地方,亮度就会高;而光看不见的地方,就是阴影。所以,通过把摄像机放到光源出获得的每个像素点的深度值z-buffer保存起来得到一张类似于map的缓冲,就是Shadow Map。

当我们有了这一张Shadow Map以后,我们回到摄像机空间中,把每个点在光照空间的坐标求出来,获得每个点的深度值z,在fragment shader中通过blinn-phong光照模型来渲染场景。这就是Shadow Map的大概原理。

image.png

图片来自http://LearnOpenGL.com

这张图可以很好地帮助理解。我们通过矩阵T来获得每个点在光照空间的坐标。如左图,P点是摄像机可以看到的点,因此需要通过T(P)转化到光照空间中,从而获得深度值0.9。而C点摄像机捕捉不到,但是可以直接在光照空间中获得深度值0.4。通过比较两个点深度值,我们判断出P点处在阴影当中。

以下参考
7.2 Shadow Map
Shadow Map实现原理:首先将光源想像成一个相机对场景做第一次渲染,将光源所能看到的所有场景物体的深度写入z-buffer中,如果光源为定向光,如太阳,光源将对观察者所看到的视锥体内的所有物体投射阴影, 光源使用正交投影,投影的视图的宽(x),高(y)要设置得足够大来包含所有可视物体。如果光源为局部(Local)光源,也需要做类似调整,如果局部光源离投影阴影的物体足够远,一个视锥体就可以包含这些物体, 特别地,如果 局部光源是一盏聚光灯(spotlight),它本身与有一个视锥关联,视锥外的一切物体都认为是不会受光照影响

并不是场景中的所有物体都要渲染到shadow map中,只有投影阴影的物体才需要被渲染。例如,如果已知地面只接收阴影而不投影阴影,那么就不需要将其渲染到shadow map。

三、cocos中开启阴影
1.在 层级管理器 中选中 Scene,然后在 属性检查器 的 shadows 组件中勾选 Enabled 属性。
image.png
2.在 层级管理器 中选中需要显示阴影的 3D 节点,然后在 属性检查器 的 MeshRenderer 组件中将 ShadowCastingMode 属性设置为 ON。
image.png

若阴影类型是 ShadowMap,还需要将 MeshRenderer 组件上的 ReceiveShadow 属性设置为 ON。注意:Planar 类型的阴影只有投射在平面上才能正常显示,不会投射在物体上,也就是说 MeshRenderer 组件中的 ReceiveShadow 属性是无效的。

注意:如果阴影无法正常显示,需要调整一下方向光的照射方向。

3.Planar shadow

Planar 阴影类型一般用于较为简单的场景。


image.png
  • Enabled 是否开启阴影效果
  • Type 阴影类型
  • Saturation 调节阴影饱和度
  • ShadowColor 设置阴影颜色
  • Normal 垂直于阴影的法线,用于调整阴影的倾斜度
  • Distance 阴影在法线的方向上与坐标原点的距离
4.ShadowMap

ShadowMap 是以光源为视点来渲染场景的。从光源位置出发,场景中看不到的地方就是阴影产生的地方。


image.png
  • Enabled 是否开启阴影效果
  • Type 设置阴影类型
  • Saturation 调节阴影饱和度
  • Pcf 设置阴影边缘反走样等级,目前支持 HARD、SOFT、SOFT_2X,详情可参考下文 PCF 软阴影 部分的介绍。
  • MaxReceived 最多支持产生阴影的光源数量,默认为 4 个,可根据需要自行调整
  • Bias 设置阴影偏移值,防止 z-fiting
  • NormalBias 设置法线偏移值,防止曲面出现锯齿状
  • ShadowMapSize 设置阴影纹理大小,目前支持 Low_256x256、Medium_512x512、High_1024x1024、Ultra_2048x2048 四种精度的纹理
  • InvisibleOcclusionRange 设置 Camera 可见范围外的物体产生的阴影是否投射到可见范围内,若需要则调大该值即可
  • ShadowDistance 设置 Camera 可见范围内显示阴影效果的范围,阴影质量与该值的大小成反比
  • FixedArea 设置是否通过手动设置下列属性来控制 Camera 可见范围内显示阴影效果的范围,详情可参考下文 FixedArea 模式 部分的介绍
  • Near 设置主光源相机的近裁剪面
  • Far 设置主光源相机的远裁剪面
  • OrthoSize 设置主光源相机的正交视口大小

注意:从 v3.3 开始,属性检查器 中阴影的 LinearPacking 项被移除,Creator 将自动判断硬件能力,并选用最优方式进行阴影渲染。

ShadowMap 在开启了物体 MeshRenderer 组件上的 ReceiveShadow 后,就会接收并显示其它物体产生的阴影效果。

ShadowMap 一般用于要求光影效果比较真实,且较为复杂的场景。但不足之处在于如果不移动光源,那么之前生成的 Shadow Map 就可以重复使用,而一旦移动了光源,那么就需要重新计算新的 ShadowMap。

5.PCF 软阴影

百分比渐近过滤(PCF)是一个简单、常见的用于实现阴影边缘反走样的技术,通过对阴影边缘进行平滑处理来消除阴影贴图的锯齿现象。原理是在当前像素(也叫做片段)周围进行采样,然后计算样本跟片段相比更接近光源的比例,使用这个比例对散射光和镜面光成分进行缩放,然后再对片段着色,以达到模糊阴影边缘的效果。

目前 Cocos Creator 支持 硬采样4 倍采样(SOFT 模式)9 倍采样(SOFT_2X 模式),倍数越大,采样区域越大,阴影边缘也就越柔和。

6.FixedArea 模式

FixedArea 模式用于设置是否手动控制 Camera 可见范围内显示阴影效果的范围:

  • 若不勾选该项(默认),则引擎会使用和 CSM(级联阴影算法)相同的裁切流程和相机计算,根据 Camera 的方向和位置来计算阴影产生的范围。
  • 若勾选该项,则根据手动设置的 NearFarOrthoSize 属性来控制阴影产生的范围。
四、官方示例test-case-3d中的shadow-map
五、问题
1.关于3.0 ShadowMap的疑问

离灯很近的地方不产生阴影

2.一个bug,Creator3.0的地形Terrain 不能接收阴影,角色无法在地形上显示阴影

Planar只能在XOZ面上投,如果的地形的高度(Y轴坐标)超过了0,就看不到了。

3.请问游戏中如何关闭阴影
目前强行关闭了
let planarShadows = director.getRunningScene()._renderScene.planarShadows
planarShadows.enabled = false
planarShadows.onGlobalPipelineStateChanged()
planarShadows[’_pendingModels’].length = 0;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容