• 回复@大雨582:社会人不可能像自然人一样自由,你还得尊重别人的意愿!不然咱随便生产啥都强行让你要,咱是自由了,你呢? 2019-10-12
  • 发改委每月首个工作日公布限制乘坐火车飞机人员名单 2019-10-12
  • 全国啦啦操联赛临汾站开幕 2019-10-08
  • 《爱疯音乐家》陈洁仪:不完美的美其实更美爱疯音乐家陈洁仪 2019-10-08
  • 中冶置业兴隆百万平米新城正式亮相 将打造全配套高铁康养小镇 2019-10-06
  • 以政府拟严打“乱拍摄”以军行为 最高10年监禁 2019-10-03
  • 图解:关于中国梦,习近平总书记这十句话直抵人心 2019-09-20
  • “舌尖”之后, “风味”能否再续辉煌? 2019-09-17
  • 腾讯要花32亿收购《绝地求生》开发商10%股份 2019-09-17
  • 涨知识!文字里的秘密 最全甲骨文书展来了 2019-09-13
  • 晋中市着力将“厕所革命”进行到底 2019-09-05
  • 供应链如何更“智慧” 2019-09-05
  • 红枣食疗效果好 6种吃法最滋补-美食资讯 2019-09-01
  • 党的十九大最重大的理论成就 2019-08-28
  • 余世存:阅读经典不仅是消费,也是责任 2019-08-20
  • 福建体彩31选号走势图: 士郎 在Unity中实现2D光照系统

    16
    回复
    1874
    查看
    打印 上一主题 下一主题
    [ 复制链接 ]
    排名
    1
    昨日变化

    福建36选7和值走势图 www.00-na.com 8235

    主题

    8793

    帖子

    3万

    积分

    Rank: 16

    UID
    1231
    好友
    186
    蛮牛币
    13057
    威望
    30
    注册时间
    2013-7-29
    在线时间
    4205 小时
    最后登录
    2019-10-19

    活力之星原创精华达人突出贡献奖财富之证游戏蛮牛QQ群会员蛮牛妹VIP

    马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

    您需要 登录 才可以下载或查看,没有帐号?注册帐号

    x


    一些2D游戏中引入实时光影效果能给游戏带来非常大的视觉效果提升,亦或是利用2D光影实现视线遮挡机制。例如Terraria,Starbound。





    2D光影效果需要一个动态光照系统实现,而通常游戏引擎所提供的实时光照系统仅限于3D场景,要实现图中效果的2D光影需要额外设计适用于2D场景的光照系统。虽然在Unity Assets Store上有不少2D光照系统插件,实际上实现一个2D光照系统并不复杂,并且可以借此机会熟悉Unity渲染管线开发。

    本文将介绍通过Command Buffer扩展Unity Built-in Render Pipeline实现一个简单的2D光照系统。所涉及到的前置技术栈包括Unity,C#,render pipeline,shader programming等。本文仅包含核心部分的部分代码,完整代码可以在我的GitHub上找到:

    SardineFish/Unity2DLightinggithub.com

    2D Lighting Model

    首先我们尝试仿照3D场景中的光照模型,对2D光照进行理论建模。

    在现实世界中,我们通过肉眼所观测到的视觉图像,来自于光源产生的光,经过物体表面反射,通过晶状体、瞳孔等眼球光学结构,投射在视网膜上导致视觉细胞产生神经冲动,传递到大脑中形成。而在照片摄影中,则是经过镜头后投射在感光元件上成像并转换为数字图像数据。而在图形渲染中,通常通过模拟该过程,计算摄像机所接收到的来自物体反射的光,从而渲染出图像。

    1986年,James T.Kajiya在论文THE RENDERING EQUATION[1]中提出了一个著名的渲染方程:



    3D场景中物体表面任意一面元所受光照,等于来自所有方向的光线辐射度的总和。这些光经过反射和散射后,其中一部分射向摄像机(观察方向)。(通常为了简化这一过程,我们可以假定这些光线全部射向摄像机)

    而在2D平面场景中,我们可以认为,该平面上任意一点所受的光照,等于来自所有方向的光线辐射度的总和,其中的一部分射向摄像机,为了简化,我们认为这些光线全部进入摄像机。这一光照模型可以用以下方程描述:



    即,平面上任意一点,或者说一个像素(x,y)的颜色,等于在该点处来自[0,2π]所有方向的光的总和。其中Light(x,y,θ)表示在点(x,y)处来自θ方向的光量。

    基于这一光照模型,我们可以实现一个2D空间内的光线追踪渲染器。去年我在这系列文章的启发下,基于js实现了一个简单的2D光线追踪渲染器demo

    Raytrace 2Dray-trace-2d.sardinefish.com

    关于该渲染器,我写过一篇Blog:2D光线追踪渲染,借用该渲染器渲染出来的2D光线追踪图像,我们可以对2D光照效果做出一定的分析和比较。



    2D Lighting System

    Light Source

    相较于3D实时渲染中的点光源、平行光源和聚光灯等多种精确光源,在2D光照中,通常我们只需要点光源就足以满足对2D光照的需求。

    由于精确光源的引入,我们不再需要对光线进行积分计算,因此上文中的2D光照方程就可以简化为:



    即空间每点的光照等于场景中所有点光源在(x,y)处光量的总和。为了使光照更加真实,我们可以对点光源引入光照衰减机制:



    其中d为平面上一点到光源的距离,t为可调节参数,取值范围[0,1]

    所得到的光照效果如图(t=0.3):



    光照衰减模型还有很多种,可以根据需求进行更改。

    Light Rendering

    在有了光源模型之后,我们需要将光照绘制到屏幕上,也就是光照的渲染实现。计算光照颜色与物体固有颜色的结合通常采用直接相乘的形式,即color=lightColor.rgb*albedo.rgb,与Photoshop等软件中的“正片叠底”是同样的。



    在3D光照中,通常有两种光照渲染实现:Forward Rendering和Deferred Shading。在2D光照中,我们也可以参考这两种光照实现:

    Forward:对场景中的每个Sprite设置自定义Shader材质,渲染每一个2D光源的光照,然而由于Unity渲染管线的限制,这一过程的实现相当复杂,并且对于具有N个Sprite,M个光源的场景,光照渲染的时间复杂度为O(MN)。

    Deferred:这一实现类似于屏幕后处理,在Unity完成场景渲染后,对场景中的每个光源,绘制到一张屏幕光照贴图上,将该光照贴图与屏幕图像相乘得到最终光照效果,过程类似于上图。

    显然在实现难度和运行效率上来说,选择Deferred的渲染方式更方便

    Render Pipeline

    在Unity中实现这样的一个光照渲染系统,一些开发者选择生成一张覆盖屏幕的Mesh,用该Mesh渲染光照,最终利用Unity渲染管线中的透明度混合实现光照效果。这样的实现具有很好的平台兼容性,但也存在可扩展性较差,难以进行更复杂的光照和软阴影生成等问题。

    因此我在这里选择使用CommandBuffer对Unity渲染管线进行扩展,设计一条2D光照渲染管线,并添加到Unity Built-in Render Pipeline中。对于使用Unity Scriptable Render Pipeline的开发者,本文提到的渲染管线亦有一定参考用途,SRP也提供了相应扩展其渲染管线的相关API。

    总结一下上文关于2D光照系统的建模,以及光照渲染的实现,我们的2D光照渲染管线需要实现以下过程:

    1.针对场景中每个需要渲染2D光照的摄像机,设置我们的渲染管线

    2.准备一张空白的Light Map

    3.遍历场景中的所有2D光源,将光照渲染到Light Map

    4.抓取当前摄像机目标Buffer中的图像,将其与Light Map相乘混合后输出到摄像机渲染目标

    Camera Script

    要使用CommandBuffer扩展渲染管线,一个CommandBuffer实例只需要实例化一次,并通过Camera.AddCommandBuffer方法添加到摄像机的某个渲染管线阶段。此后需要在每次摄像机渲染图像前,即调用OnPreRender方法时,清空该CommandBuffer并重新设置相关参数。

    这里还设置ExecuteInEditMode和ImageEffectAllowedInSceneView属性以确保能在编辑器的Scene视图中实时渲染2D光照效果。

    这里选择CameraEvent.BeforeImageEffects作为插入点,即在Unity完成了场景渲染后,准备渲染屏幕后处理前的阶段。
    [AppleScript] 纯文本查看 复制代码
    using System.Collections;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.Rendering;
    
    [ExecuteInEditMode]
    [ImageEffectAllowedInSceneView]
    [RequireComponent(typeof(Camera))]
    public class Light2DRenderer : MonoBehaviour
    {
        CommandBuffer cmd;
        // Init CommandBuffer & add to camera.
        void OnEnable()
        {
            cmd = new CommandBuffer();
            GetComponent<Camera>().AddCommandBuffer(CameraEvent.BeforeImageEffects, cmd);
        }
        void OnDisable()
        {
            GetComponent<Camera>().RemoveCommandBuffer(CameraEvent.BeforeImageEffects, cmd);
        }
        void OnPreRender()
        {
            // Setup CommandBuffer every frame before rendering.
            RenderDeffer(cmd);
        }
    }


    Setup CommandBuffer

    由于我们要绘制一张光照贴图,并将其与屏幕图像混合,我们需要一个临时的RenderTexture(RT),这里设置Light Map的贴图格式为ARGBFloat,原因是我们希望光照贴图中每个像素的RGB光照分量是可以大于1的,这样可以提供更精确的光照效果和更好的扩展性,而默认的RT会在混合前将缓冲区中每个像素的值裁剪到[0,1]。

    在临时RT使用完毕后,请务必Release!请务必Release!请务必Release?。ū鹞?,问就是显卡崩溃)
    [AppleScript] 纯文本查看 复制代码
    public void RenderDeffer(CommandBuffer cmd)
    {
        cmd.Clear();
    
        // Render light map
        var lightMap = Shader.PropertyToID("_LightMap");
        cmd.GetTemporaryRT(lightMap, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBFloat);
        cmd.SetRenderTarget(lightMap);
        cmd.ClearRenderTarget(true, true, Color.black);
        var lights = GameObject.FindObjectsOfType<Light2D>();
        foreach (var light in lights)
        {
            light.RenderLight(cmd);
        }
    
        var screen = Shader.PropertyToID("_ScreenImage");
        cmd.GetTemporaryRT(screen, -1, -1);
        // Grab screen
        cmd.Blit(BuiltinRenderTextureType.CameraTarget, screen);
        // Blend light map & screen image with custom shader
        cmd.Blit(screen, BuiltinRenderTextureType.CameraTarget, LightingMaterial, 0);
    
        // DONT FORGET to release the temp RT!!!
        // OR your graphic card may crash after a while due to the memory overflow (may be) :)
        cmd.ReleaseTemporaryRT(lightMap);
        cmd.ReleaseTemporaryRT(screen);
        cmd.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
    }


    最终用于光照混合的Shader代码非常简单,这里使用了UNITY_LIGHTMODEL_AMBIENT引入一个场景全局光照,全局光照可以在Lighting>Scene面板里设置:
    [AppleScript] 纯文本查看 复制代码
    fixed4 frag(v2f i) : SV_Target
    {
        float3 ambient = UNITY_LIGHTMODEL_AMBIENT;
        float3 light = ambient + tex2D(_LightMap, i.texcoord).rgb;
        float3 color = light * tex2D(_MainTex, i.texcoord).rgb;
        return fixed4(color, 1.0);
    }



    Render Lighting

    渲染光源光照贴图的过程,对于不同的光源类型有不同的实现方式,例如直接使用Shader程序式生成,亦或是使用一张光斑贴图。其核心部分就是:

    1.生成一张用于渲染的Mesh(通常就是一个简单的Quad)

    2.设置CommandBuffer将该Mesh绘制到Light Map

    Quad就是一个正方形,可以用以下代码生成:
    [AppleScript] 纯文本查看 复制代码
    Mesh = new Mesh();
    Mesh.vertices = new Vector3[]
    {
        new Vector3(-.5, -.5, 0),
        new Vector3(.5, -.5, 0),
        new Vector3(-.5, .5, 0),
        new Vector3(.5, .5, 0),
    };
    Mesh.triangles = new int[]
    {
        0, 2, 1,
        2, 3, 1,
    };
    Mesh.RecalculateNormals();
    Mesh.uv = new Vector2[]
    {
        new Vector2 (0, 0),
        new Vector2 (1, 0),
        new Vector2 (0, 1),
        new Vector2 (1, 1),
    };


    需要注意的是,Mesh资源不参与GC,也就是每次new出来的Mesh会永久驻留内存直到退出(导致Unity内存泄漏的一个主要因素)。因此不应该在每次渲染的时候new一个新的Mesh,而是在每次渲染时,调用Mesh.Clear()方法将Mesh清空后重新设置。

    这里生成的Mesh基于该GameObject的本地坐标系,在调用CommandBuffer.DrawMesh以渲染该Mesh,我们还需要设置相应的TRS变换矩阵,以确保渲染在屏幕上的正确位置。
    [AppleScript] 纯文本查看 复制代码
    public void RenderLight(CommandBuffer cmd)
    {
        if (!LightMaterial)
            LightMaterial = new Material(Shader.Find("Lighting2D/2DLight"));
        
        // You may want to set some properties for your lighting shader
        LightMaterial.SetTexture("_MainTex", LightTexture);
        LightMaterial.SetColor("_Color", LightColor);
        LightMaterial.SetFloat("_Attenuation", Attenuation);
        LightMaterial.SetFloat("_Intensity", Intensity);
        cmd.SetGlobalVector("_2DLightPos", transform.position);
        
        var trs = Matrix4x4.TRS(transform.position, transform.rotation, transform.localScale);
        cmd.DrawMesh(Mesh, trs, LightMaterial);
    }


    由于我们需要同时将多个光照绘制到同一张光照贴图上,根据光照物理模型,光照强度的叠加应当使用直接相加的方式,因此用于渲染光照贴图的Shader应该设置Blend属性为One One:

    [AppleScript] 纯文本查看 复制代码
    Tags { 
        "Queue"="Transparent" 
        "RenderType"="Transparent" 
        "PreviewType"="Plane"
        "CanUseSpriteAtlas"="True"
    }
    
    Lighting Off
    ZWrite Off
    Blend One One


    2D Shadow

    要在该光照系统中引入2D阴影,只需要在每次绘制光照贴图时,额外对每个阴影投射光源绘制一个阴影贴图(Shadow Map),并应用在渲染光照贴图的Shader中采样即可。
    [AppleScript] 纯文本查看 复制代码
    var lights = GameObject.FindObjectsOfType<Light2D>();
    foreach (var light in lights)
    {
        cmd.SetRenderTarget(shadowMap);
        cmd.ClearRenderTarget(true, true, Color.black);
        if (light.LightShadows != LightShadows.None)
        {
            light.RenderShadow(cmd, shadowMap);
        }
        cmd.SetRenderTarget(lightMap);
        light.RenderLight(cmd);
    }
    


    关于2D阴影贴图的生成,可以参考伪人的这篇文章:

    伪人:如何在unity实现足够快的2d动态光照zhuanlan.zhihu.com

    或者我有时间继续填坑再写一个。(FLAG)

    Source Code

    完整的project放在了GitHub上:https://github.com/SardineFish/Unity2DLighting

    截止本文,已实现的功能包括:

    ?2D光照系统框架

    o渲染管线扩展

    o全局光照设置

    ?2D光源

    o程序式光源,光照衰减

    o贴图光源

    ?2D阴影

    o硬阴影

    o软阴影(高斯模糊实现、体积光实现)

    阴影投射物体目前仅支持多边形,未来将加入对Box和Circle等2D碰撞体的阴影实现。

    Git Tag:https://github.com/SardineFish/Unity2DLighting/tree/v0.1.0

    References

    知乎@SardineFish

    2初来乍到
    116/150
    排名
    64937
    昨日变化

    0

    主题

    30

    帖子

    116

    积分

    Rank: 2Rank: 2

    UID
    259926
    好友
    0
    蛮牛币
    300
    威望
    0
    注册时间
    2017-12-16
    在线时间
    84 小时
    最后登录
    2019-10-19
    沙发
    2019-6-24 16:52:41 只看该作者
    66666666666666666
    2初来乍到
    116/150
    排名
    64937
    昨日变化

    0

    主题

    30

    帖子

    116

    积分

    Rank: 2Rank: 2

    UID
    259926
    好友
    0
    蛮牛币
    300
    威望
    0
    注册时间
    2017-12-16
    在线时间
    84 小时
    最后登录
    2019-10-19
    板凳
    2019-6-24 16:53:52 只看该作者
    支持大佬~~~~
    2初来乍到
    116/150
    排名
    64937
    昨日变化

    0

    主题

    30

    帖子

    116

    积分

    Rank: 2Rank: 2

    UID
    259926
    好友
    0
    蛮牛币
    300
    威望
    0
    注册时间
    2017-12-16
    在线时间
    84 小时
    最后登录
    2019-10-19
    地板
    2019-6-24 16:54:53 只看该作者
    支持大佬~~~~
    5熟悉之中
    940/1000
    排名
    10707
    昨日变化

    0

    主题

    663

    帖子

    940

    积分

    Rank: 5Rank: 5

    UID
    301976
    好友
    1
    蛮牛币
    1408
    威望
    0
    注册时间
    2018-10-31
    在线时间
    179 小时
    最后登录
    2019-9-30
    5#
    2019-6-24 20:13:11 只看该作者
    点赞大佬,感谢分享经验
    7日久生情
    2332/5000
    排名
    4093
    昨日变化

    0

    主题

    1578

    帖子

    2332

    积分

    Rank: 7Rank: 7Rank: 7Rank: 7

    UID
    254705
    好友
    1
    蛮牛币
    2097
    威望
    0
    注册时间
    2017-11-16
    在线时间
    392 小时
    最后登录
    2019-10-18
    6#
    2019-6-25 08:07:28 只看该作者
    66666666666666666666666666
    7日久生情
    4949/5000
    排名
    21
    昨日变化

    0

    主题

    256

    帖子

    4949

    积分

    Rank: 7Rank: 7Rank: 7Rank: 7

    UID
    29678
    好友
    1
    蛮牛币
    9627
    威望
    0
    注册时间
    2014-6-14
    在线时间
    1427 小时
    最后登录
    2019-10-19
    7#
    2019-6-25 08:25:28 只看该作者
    点赞大佬,感谢分享经验
    7日久生情
    1952/5000
    排名
    1192
    昨日变化

    1

    主题

    566

    帖子

    1952

    积分

    Rank: 7Rank: 7Rank: 7Rank: 7

    UID
    87577
    好友
    0
    蛮牛币
    8596
    威望
    0
    注册时间
    2015-3-31
    在线时间
    407 小时
    最后登录
    2019-10-19

    锦衣玉食

    8#
    2019-6-25 08:41:35 只看该作者
    too good too strong!

    0

    主题

    56

    帖子

    77

    积分

    Rank: 2Rank: 2

    UID
    321303
    好友
    0
    蛮牛币
    97
    威望
    0
    注册时间
    2019-5-6
    在线时间
    21 小时
    最后登录
    2019-7-11
    9#
    2019-6-25 08:57:53 只看该作者
    3偶尔光临
    171/300
    排名
    16220
    昨日变化

    0

    主题

    43

    帖子

    171

    积分

    Rank: 3Rank: 3Rank: 3

    UID
    292037
    好友
    0
    蛮牛币
    613
    威望
    0
    注册时间
    2018-8-1
    在线时间
    84 小时
    最后登录
    2019-10-18
    10#
    2019-6-25 09:51:17 只看该作者
    感谢楼主分享!
    6蛮牛粉丝
    1205/1500
    排名
    3617
    昨日变化

    5

    主题

    494

    帖子

    1205

    积分

    Rank: 6Rank: 6Rank: 6

    UID
    269155
    好友
    2
    蛮牛币
    2885
    威望
    0
    注册时间
    2018-2-22
    在线时间
    292 小时
    最后登录
    2019-10-12
    11#
    2019-6-25 09:52:30 只看该作者
    谢谢分线阿阿嘎
    6蛮牛粉丝
    1258/1500
    排名
    1815
    昨日变化

    8

    主题

    221

    帖子

    1258

    积分

    Rank: 6Rank: 6Rank: 6

    UID
    131585
    好友
    0
    蛮牛币
    2816
    威望
    0
    注册时间
    2015-12-13
    在线时间
    297 小时
    最后登录
    2019-9-19
    12#
    2019-6-26 09:56:12 只看该作者
    2初来乍到
    116/150
    排名
    64937
    昨日变化

    0

    主题

    30

    帖子

    116

    积分

    Rank: 2Rank: 2

    UID
    259926
    好友
    0
    蛮牛币
    300
    威望
    0
    注册时间
    2017-12-16
    在线时间
    84 小时
    最后登录
    2019-10-19
    13#
    2019-6-28 19:50:51 只看该作者
    66666666666厉害
    3偶尔光临
    228/300
    排名
    10466
    昨日变化

    2

    主题

    82

    帖子

    228

    积分

    Rank: 3Rank: 3Rank: 3

    UID
    21010
    好友
    0
    蛮牛币
    344
    威望
    0
    注册时间
    2014-4-11
    在线时间
    42 小时
    最后登录
    2019-7-16
    14#
    2019-7-10 12:24:12 只看该作者
    66666666666
    5熟悉之中
    699/1000
    排名
    5900
    昨日变化

    0

    主题

    329

    帖子

    699

    积分

    Rank: 5Rank: 5

    UID
    11484
    好友
    0
    蛮牛币
    6
    威望
    0
    注册时间
    2013-12-31
    在线时间
    134 小时
    最后登录
    2019-10-12
    15#
    2019-7-11 08:48:30 只看该作者
    感谢分享经验
    您需要登录后才可以回帖 登录 | 注册帐号

    本版积分规则

  • 回复@大雨582:社会人不可能像自然人一样自由,你还得尊重别人的意愿!不然咱随便生产啥都强行让你要,咱是自由了,你呢? 2019-10-12
  • 发改委每月首个工作日公布限制乘坐火车飞机人员名单 2019-10-12
  • 全国啦啦操联赛临汾站开幕 2019-10-08
  • 《爱疯音乐家》陈洁仪:不完美的美其实更美爱疯音乐家陈洁仪 2019-10-08
  • 中冶置业兴隆百万平米新城正式亮相 将打造全配套高铁康养小镇 2019-10-06
  • 以政府拟严打“乱拍摄”以军行为 最高10年监禁 2019-10-03
  • 图解:关于中国梦,习近平总书记这十句话直抵人心 2019-09-20
  • “舌尖”之后, “风味”能否再续辉煌? 2019-09-17
  • 腾讯要花32亿收购《绝地求生》开发商10%股份 2019-09-17
  • 涨知识!文字里的秘密 最全甲骨文书展来了 2019-09-13
  • 晋中市着力将“厕所革命”进行到底 2019-09-05
  • 供应链如何更“智慧” 2019-09-05
  • 红枣食疗效果好 6种吃法最滋补-美食资讯 2019-09-01
  • 党的十九大最重大的理论成就 2019-08-28
  • 余世存:阅读经典不仅是消费,也是责任 2019-08-20
  • 11选5彩票平台代理 网络广告联盟平台 广西体育11选五开奖结果 秒速时时彩在线预测 晨龙捕鱼 手机网站如何利用网盟赚钱 五子棋价格 乒乓球赛开始啦体育儿歌 pt电子游戏公司 足彩进球彩场次安排 欢乐升级游戏下载 博彩6码 手机赌博赢了几十万 广西快乐双彩基本走 白姐透码波色网