Aura #01 (Unity 大气特效插件)

(施工中w)

老实说我也不知道该叫啥了这标题wwww

Aura是一个Unity的开源插件,可以实现较为出色的大气效果(如:体积光,体积雾等等):

传送门:
Asset store: https://assetstore.unity.com/packages/vfx/shaders/aura-volumetric-lighting-111664
Github: https://github.com/raphael-ernaelsten/Aura

大概的效果是这个样子的www:

(都是官方的图x)

那么www它到底是怎么实现的呢www?

(本来以为自己肯定什么都看不懂打算这个假期好好研究一下的x 结果在回来的飞机上就稍微弄明白了一点ww(虽然实现确实很直接简单www)果然还是比以前厉害了一点点的x(逃



在Aura的github页面(上面有链接)中提到了这样一张图,也就是实现的流程图:

首先第一部分,对应着Aura里的各种光源(平行(Directional)光、点光源等等)和各种Volume(一块雾)。(Aura这里光源不需要打在雾上(进行散射)从而产生体积光的效果,单一个光源就可以拥有体积光的效果w)
它们只是各种形式的数据结构(这块volume的形状,光源的参数等等)保存在内存中,等待随后的操作将它们打包发送到Compute Shader进行计算得到最终的光照结果。

简单概括一下的话,整个流程大概是:计算各点颜色,累加,应用到渲染结果上。

主要的光照计算过程发生在 Aura::Frustum::ComputeData() (Aura/Classes/Frustum.cs : 147)中。ComputeData() 函数在Aura的主类(Aura.cs)的 UpdateFrustrum()(更新视锥体)函数(Aura.cs : 351)中被调用,而 UpdateFrustrum() 函数又在同一类下的 OnRenderImage(RT, RT) 函数(Aura.cs : 174)中被调用。OnRenderImage 函数完成了绘制图像的操作,两个参数(都是RenderTexture - 两张纹理,就是在屏幕上要显示的当前帧)src和dest分别是这个函数的输入和输出。在函数 OnRenderImage() 中,用PostProcess的方式(使用一个PixelShader(Aura/Shaders/Shaders/PostProcessShader.shader),后述)把 ComputeShader 计算的最终光照结果(一个3D纹理,对应图上最下面的Integrated Volumetric Lighting,是 UpdateFrustrum() 的产物,后述)应用到 Unity 按照常规方法渲染出的图片上面,得到最终的结果。

↑ 输入图像(常规渲染结果)

↑ ComputeShader 计算得到的结果(3D纹理没找到合适的可视化方法,这是得到的3D纹理中的一"片"。可以看到由左上方照向右下的光束)

↑ 通过 PostProcessShader 把大气效果应用到渲染结果上,得到最终的图像。

(1)光照(大气效果)的计算:

首先,按照设置中的精细程度与渲染范围(在摄像机的Aura组件下有名为Resolution和Range的设置项),把当前 View Space 的视锥体(也就是摄像机眼前的这个锥体)按照精细度分成很多小块进行计算。

↑ 就这个椎体,就是Frustrum。

在把视锥体切成许多小块后,每一个小块就对应着最终3D纹理中的一个体素(是像素概念从2D到3D的延申),同时每个小块之间在这一阶段上没有计算,这个过程是高度并行化的(每个thread计算一个体素),交给了ComputeShader。每一个体素的计算过程在ComputeDataComputeShader.compute 中。

在这之前,还对当前的深度缓冲区做了一些处理( ComputeMaximumDepthComputeShader.compute ),得到了视锥体中的深度信息(在视锥体格子的某一条x,y轴上,摄像机最远能看到哪里):

(计算得到的深度图,主要是对原图的信息进行整合,得到在视锥体的3D纹理清晰度下合适的深度图像)

根据这样一张深度图,剔除掉一些没有作用的体素。(被场景物体遮挡住了)

回过来看光照的计算:

抛开前六万五千行(...)的宏定义(根据用户的设置不同(使用 / 忽略光源等)最多可以产生32768种设置组合,所以定义了这么多宏定义)不管,可以看到接下来的计算过程非常的直接:

(这里很多东西都不是很正确,只能当个大概理解一下ww(这里太菜还没搞懂orz)

1.  首先获得当前体素对应的世界空间坐标。在这里,这个位置是加了一些Jitter(扰动 / 噪声)的,让最终产生的结果更加的柔和(用噪声弥补清晰度上的不足,之后也有很多地方有这种处理)。

2.  计算每个 Volume 对该点的贡献。(带有 "密度" (相当于alpha) 的颜色)

3.  计算每个光源对该点颜色的贡献。首先通过该光源的 ShadowMap 计算自己是否在它的阴影中,如果在阴影中那么这个光源相当于不存在(+0);如果不在阴影中则被光源照亮,当前点的颜色加上光源的颜色(还有相应的衰减)。同时,如果有 Light Cookie 之类的东西也可以在这里计算出来。

4.  对这个点最终得到的颜色进行一些小处理,如非负性等;

5.  利用前一帧计算的结果和当前帧的结果进行混合,让最终得到的结果更加的柔和。这一步很关键,如果不重复利用前一帧的计算结果,最后渲染出的图像上可以看出非常明显的 artifact 。但在混合后,渲染质量有了很大提升。Aura给的默认值是前一帧占90%,当前帧的结果占10%,在60FPS下这是一个较为理想的参数。(怎么momentum都是0.9(x))在混合的过程中,由于摄像机位置的变化,导致前一帧的视锥体与当前帧的视锥体之间有着些许的位移,所以需要通过一系列矩阵变换,把当前帧在视锥内的位置变换到前一帧的视锥中,再对前一帧得到的结果进行取样。

到这里,我们得到了每个点的颜色。这里觉得可以浅显的理解为,这个颜色就是当前格大气被光照之后散射的颜色,相当于一个小光源(的颜色)。但到现在我们只得到了摄像机前每个格子的光源颜色,还没有计算这些光源照到摄像机中的效果。

就不贴代码了,太长而且零零散散(

所以第二步就是把每个光源的颜色进行累加啦。

对应的文件为 ComputeAccumulationComputeShader.compute (Accumulation就是累加的意思):

在累加的过程中,我们需要考虑到散射光源在传播路径上的衰减:使用exp(指数)函数作为衰减函数(因为 exp( ax ) 是 x = a * x‘ (经过单位距离衰减a, a < 1) 的解)。过程也很简单:

1.  每一个thread(threadIdx为x, y, z)计算由当前格子(x, y, z)开始,光线传播到摄像机(x, y, 0)后的最终颜色。这一过程同时考虑到了路上所有格子的光照(不单只有起始点一个格子)。

2.  通过循环计算光从远端传递到摄像机的过程。Aura代码里的循环写得有些绕,是从摄像机(z = 0)循环到当前格的z (从摄像机到当前格方向),然而在计算的时候反过来算衰减,实际上就是从当前格衰减、传播到摄像机的过程。

half4 Accumulate(half4 colorAndDensityFront, half4 colorAndDensityBack)
{
    half transmittance = exp(colorAndDensityBack.w * layerDepth);
    half4 accumulatedLightAndTransmittance = half4(colorAndDensityFront.xyz + colorAndDensityBack.xyz * (1.0f - transmittance) * colorAndDensityFront.w, colorAndDensityFront.w * transmittance);
    // 注意这里 Front + Back * (1.0f - transmittance), 也就是反过来计算。

    return accumulatedLightAndTransmittance;
}

[numthreads(NUM_THREAD_X,NUM_THREAD_Y,NUM_THREAD_Z)]
void RayMarchThroughVolume(uint3 id : SV_DispatchThreadID)
{
    // 获得当前点坐标
    half3 normalizedLocalPos = GetNormalizedLocalPositionWithDepthBias(id);

    #if ENABLE_OCCLUSION_CULLING
    // 遮挡剔除
    [branch]
    if(IsNotOccluded(normalizedLocalPos.z, id.xy)) // TODO : MAYBE COULD BE OPTIMIZED BY USING A MASK VALUE IN THE DATA TEXTURE
    #endif
    {
        // 设置初值
        half4 currentSliceValue = half4(0, 0, 0, 1);
        half4 nextValue = 0;          

        // 循环计算衰减
        [loop]
        for(uint z = 0; z < id.z; ++z)
        {
            nextValue = SampleLightingTexture(uint3(id.xy, z));
            currentSliceValue = Accumulate(currentSliceValue, nextValue);
        }

        half4 valueAtCurrentZ = SampleLightingTexture(id);
        currentSliceValue = Accumulate(currentSliceValue, valueAtCurrentZ);

        // 将最终得到的结果写入3D纹理
        WriteInOutputTexture(id, currentSliceValue);
    }
}

最后一步就是根据最后得到的衰减累加3D纹理,用 PostProcessShader.shader 给图像做最后的上色。方法也很简单,获得当前位置的深度,转换到对应的 View Space (视锥体)坐标,从3D纹理中采样,加入一些噪声之后把当前颜色(计算得到的颜色)叠加到原有图像上面,就得到了最终的结果:

float4 Aura_GetFogValue(float3 screenSpacePosition)
{
    // Aura_VolumetricLightingTexture: 衰减累加得到的3D纹理(ComputeShader的最终结果)
    return tex3Dlod(Aura_VolumetricLightingTexture, float4(screenSpacePosition.xy, Aura_RescaleDepth(screenSpacePosition.z), 0));
}

void Aura_ApplyFog(inout float3 colorToApply, float3 screenSpacePosition)
{
    // 加入一些噪声
    screenSpacePosition.xy += GetBlueNoise(screenSpacePosition.xy, 3).xy;

    float4 fogValue = Aura_GetFogValue(screenSpacePosition);

    // 再加一点噪声
    float4 noise = GetBlueNoise(screenSpacePosition.xy, 4);

    // 叠加颜色
    colorToApply = colorToApply * (fogValue.w + noise.w) + (fogValue.xyz + noise.xyz);
}

fixed4 frag (v2f psIn) : SV_Target
{
    // 转换深度坐标
    float depth = tex2D(_CameraDepthTexture, psIn.uv);
    depth = LinearEyeDepth(depth);

    // _MainTex 为普通渲染得到的最终图像
    float4 backColor = tex2D(_MainTex, psIn.uv);
    Aura_ApplyFog(backColor.xyz, float3(psIn.uv, depth));
    // 见上面的函数定义

    return backColor;
}

(过几天更新几张gif图,更加直观一点www)

然后我把它随便丢到了一个场景里面www效果还可以ww?因为还没有细调www(所以就看看玩玩(x

因为整个操作是在 View Space 的一定范围里做的,所以场景多大都可以,也算是一个比较让人满意的点www?嘛x

以上ww

原文地址:https://www.cnblogs.com/betairy-linkzeldagg/p/9527315.html

时间: 2024-11-04 00:46:31

Aura #01 (Unity 大气特效插件)的相关文章

Unity的NGUI插件篇——入场效果

Unity的NGUI插件篇--入场效果 入场效果 入场效果需要借助于NGUI提供的TweenPosition类来完成,为了说明此类的使用方法,本节将使会讲解两个示例.本文选自  大学霸 <NGUI使用手册>  一书 匀速入场 将游戏主菜单看作一个整体,本小节会令其自上而下匀速入场,具体的实现过程如下: (1)在Project视图里,新建一个C#脚本,命名为AppearFromAbove,为其添加下面的代码: 01     using UnityEngine; 02     using Syst

[译]为Unity制作WP8插件

前言: 在用Unity发布WP8应用时候,经常会遇到一些API不能用的情况,例如弹出MessageBox,无法使用string.Compare(string,string,bool)等等之类的问题.那么如何解决这些问题呢?解决方案之一就是制作插件.在Unity Manual中有这样一篇文章:http://docs.unity3d.com/Manual/wp8-plugins-guide-csharp.html 讲的就是如何制作Unity的WP8插件.小弟我用中文将这个过程描述一遍.由于能力有限,

unity编辑器和插件的制作(四.1)

好久没有更新,有些急事终于处理完了,接着更新博客! 废话不多说,接着上面的讲,今天我们来接着讲述. 前面说到 怎么去建立一个自己 ,用代码绘制一个色块,今天我们来讲述下,怎么绘制一个图片在场景里面. 首先 我们先做下图片的功课. 在unity中图片的种类分了很多,默认是:Texture, 还有其他的一些属性. 有些人可以会遇到 我放进去的素材为什么编译之后会变模糊那,这是由于,在unity中你没有修改图片的属性,导致的. 在 texture模式下, 我们来分析下这种图片的属性, wrap mod

unity 编辑器和插件制作(五)

接着前面的继续前行,默默的fighting. 前面讲了,怎么使用摄像机发射线到物体,来触发事件.今天我们 来讲述下怎么去实现一个label. 这个就相对比较简单了,其实我们可以直接使用unity自带得textmesh来实现一个字体,但大多数时候,需要改一些设置,字体大小,材质等等 一些得问题所以我们,最好还是自己写一个脚本来实现一些简单的操作,方便简洁嘛.其实很简单 ,下面我们就开始来实现这些方法. 代码 : using UnityEngine; using System.Collections

CSDN开源夏令营 基于Compiz的switcher插件设计与实现之compiz特效插件介绍及特效实现

compiz自带的特效插件不够多,也不够强大,为了更好的体验compiz的特效,我们可以安装特效插件,在终端输入命令:sudo apt-get install compiz-plugins就可以下载特效插件安装了. 一.安装compiz特效插件 在此过程中可能会出现一些问题,比如说依赖问题,我们需要把源更新一下.对于更新源,我们需要注意以下几点: 1.设置软件更新 注意:这里要选主服务器 2.更新源 在终端输入命令:sudo apt-get update来更新源,一般情况下,这样是可以的,但是,

unity编辑器和插件(三)

接下来 我就开始正规的编辑器和插件的制作. 我这里是按照 IOS android的 控件为例子模板.来制作 一套使用 unity书写的控件. 好首先我们来想下  IOS 和android的 控件都是以四边形基础的. SO, 接下来 我们来转像unity,在unity中 我们怎么去建立一个四边形那, 依照图形绘制的原理.三点一面的理论.我们可以使用6个点来建立一个两三角形组成的四边形. 我们先学会怎么去绘制一个view,也就是简单的一个色面. 我们知道 unity中得面也是采取这种的绘制方法,绘制

ASP.NET MVC+Bootstrap个人博客之praise.js点赞特效插件

1. 为啥要做这个点赞插件?    praise.js是一款小巧的jQuery点赞插件,使用简便,效果美观. 在做个人博客时遇到了文章点赞问题.联想到各大社交网络中的点赞特效:手势放大.红心放大等等,很酷很炫.但是并没有现成的好用的插件,于是就打算自己做一个类似的点赞插件,放上自己喜欢的点赞图标. 先来看一下效果图吧:也可以去我的博客站 www.zynblog.com亲身体验一下. 注:(博客地址:www.zynblog.com,采用ASP.NET MVC + Bootstrap搭建) 2. 插

一款基于jQuery和CSS3炫酷3D旋转画廊特效插件

这是一款效果炫酷的jQuery和CSS3 3D旋转画廊特效插件.该3D画廊插件可以通过前后导航按钮来切换图片,效果就像旋转木马一样.它还带有点击放大图片,显示图片标题和用键盘操作等功能. 在线预览   源码下载 简要教程 这是一款效果非常炫酷的jQuery和CSS3 3D旋转画廊特效插件.第一个DEMO是一个简单的例子,使用CSS3来制作3d旋转效果,然后用js来控制前后导航按钮.第二个DEMO是第一个DEMO的升级版,它增加了图片标题.查看图片.键盘控制等其它功能. HTML结构 这个3D画廊

【VR】Leap Motion 官网文档 Unity资源与插件

前言: Leap Motion的官网文档已经有不少的热心网友参与了翻译,但没有覆盖官网文档的全部. 为迎合Unity VR的热潮与大家的学习需要,本博客将推出针对Unity方向的官方文档翻译系列. 本篇首先对Leap Motion所提供的Unity资源与插件进行概述. 英文原文网址:https://developer.leapmotion.com/documentation/unity/index.html 译文首发&持续更新:http://blog.csdn.net/duzixi Leap M