Unity中Shader的间接光的产生Meta Pass

文章目录

  • 前言
    • Unity中Shader的间接光的产生Meta Pass,这也是属于全局光照 GI 的内容。主要实现像现实生活中,光线照到有颜色的物体后,该物体有反射出该颜色的光的效果。
  • 一、我们先使用Unity自带的Shader看看间接光效果
    • 1、先按照如下设置搭建一个场景
    • 2、然后,按下图设置,做一个材质球给小球
    • 3、最后,按下图设置GI,烘焙看一下效果
    • 烘焙前效果:
    • 烘焙后效果:(墙上已经有了间接光的效果)
    • 在这里插入图片描述
  • 二、在我们的Shader中实现间接光的效果
    • 1、在属性面板定义一个颜色属性
    • 2、在Unity自带的Shader中,把名叫 META 的Pass复制到我们的Shader中,该Pass实现了自发光功能
    • 3、因为该Pass一般是在烘焙时完成,所以不影响我们的实时渲染,我们可以不用修改它,我们看一下实现的功能
    • 4、上面在Shader最后加的那句话,我们还有其他方法可以实现同样的修改


前言

Unity中Shader的间接光的产生Meta Pass,这也是属于全局光照 GI 的内容。主要实现像现实生活中,光线照到有颜色的物体后,该物体有反射出该颜色的光的效果。

一、我们先使用Unity自带的Shader看看间接光效果

1、先按照如下设置搭建一个场景

在这里插入图片描述

2、然后,按下图设置,做一个材质球给小球

在这里插入图片描述

3、最后,按下图设置GI,烘焙看一下效果

在这里插入图片描述

烘焙前效果:

在这里插入图片描述

烘焙后效果:(墙上已经有了间接光的效果)

在这里插入图片描述

二、在我们的Shader中实现间接光的效果

继续完成上一篇文章 GI 中的间接光效果

  • Unity中Shader光照探针的支持

这是没有实现间接光前的烘焙效果

在这里插入图片描述

1、在属性面板定义一个颜色属性

Properties
{
_Color(“Color”,Color) = (1,1,1,1)
}

2、在Unity自带的Shader中,把名叫 META 的Pass复制到我们的Shader中,该Pass实现了自发光功能

在这里插入图片描述

//在正常的渲染时,是不会被使用的。一般用于烘焙时,计算间接光反弹
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "META"
            Tags
            {
                "LightMode" = "Meta"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #include "UnityCG.cginc"
            #include "UnityMetaPass.cginc"

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvMain : TEXCOORD0;
                float2 uvIllum : TEXCOORD1;
                #ifdef EDITOR_VISUALIZATION
            float2 vizUV : TEXCOORD2;
            float4 lightCoord : TEXCOORD3;
                #endif
                UNITY_VERTEX_OUTPUT_STEREO
            };

            float4 _MainTex_ST;
            float4 _Illum_ST;

            v2f vert(appdata_full v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST,
         unity_DynamicLightmapST);
                o.uvMain = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.uvIllum = TRANSFORM_TEX(v.texcoord, _Illum);
                #ifdef EDITOR_VISUALIZATION
            o.vizUV = 0;
            o.lightCoord = 0;
            if (unity_VisualizationMode == EDITORVIZ_TEXTURE)
                o.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.texcoord.xy, v.texcoord1.xy, v.texcoord2.xy, unity_EditorViz_Texture_ST);
            else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK)
            {
                o.vizUV = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                o.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1)));
            }
                #endif
                return o;
            }

            sampler2D _MainTex;
            sampler2D _Illum;
            fixed4 _Color;
            fixed _Emission;

            half4 frag(v2f i) : SV_Target
            {
                UnityMetaInput metaIN;
                    UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);

                fixed4 tex = tex2D(_MainTex, i.uvMain);
                fixed4 c = tex * _Color;
                metaIN.Albedo = c.rgb;
                metaIN.Emission = c.rgb * tex2D(_Illum, i.uvIllum).a;
                #if defined(EDITOR_VISUALIZATION)
            metaIN.VizUV = i.vizUV;
            metaIN.LightCoord = i.lightCoord;
                #endif

                return UnityMetaFragment(metaIN);
            }
            ENDCG
        }

注意:如果此时没有显示出烘焙的间接光,则在该Shader最后加上这句话

CustomEditor “LegacyIlluminShaderGUI”

在这里插入图片描述

3、因为该Pass一般是在烘焙时完成,所以不影响我们的实时渲染,我们可以不用修改它,我们看一下实现的功能

1、这个是实现该功能的主要函数,一般不做修改因为不影响我们实时渲染
在这里插入图片描述

2、UnityMetaInput 中主要有的数据
间接光一般考虑:物体的反射率,物体的自发光,物体的高光色

在这里插入图片描述
3、删除一些不用的功能,按需求来

v2f保留:

struct v2f
{
float4 pos : SV_POSITION;
};

顶点着色器保留:

v2f vert(appdata_full v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f,o)
o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST,
unity_DynamicLightmapST);
return o;
}

片元着色器保留:

half4 frag(v2f i) : SV_Target
{
UnityMetaInput metaIN;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
metaIN.Albedo = 1;
metaIN.Emission = _Color;
return UnityMetaFragment(metaIN);
}

4、上面在Shader最后加的那句话,我们还有其他方法可以实现同样的修改

CustomEditor “LegacyIlluminShaderGUI”

在这里插入图片描述

1、首先,把 Inspect 窗口修改为Debug模式

在这里插入图片描述

2、修改材质球的这个值,实现和上面那串代码同样的效果
在这里插入图片描述

最后,修改该值为2,就可以看见最后的效果了

在这里插入图片描述

最终代码:

//在这里里面使用 自定义的 cginc 来实现全局GI
//GI数据的准备
//烘培分支的判断
//GI的直接光实现
//GI的间接光实现
//再议ATTENUATION
//光照探针的支持
//间接光的产生Meta Pass
Shader "MyShader/P1_8_9"
{
    Properties
    {
        _Color("Color",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        Pass
        {
            Tags
            {
                "LightMode"="ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase

            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #include "Lighting.cginc"

            #include "CGIncludes/MyGlobalIllumination.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                //定义第二套 UV ,appdata 对应的固定语义为 TEXCOORD1
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                float4 texcoord1 : TEXCOORD1;
                #endif
                half3 normal : NORMAL;
                float4 texcoord2 : TEXCOORD2;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;

                float4 worldPos : TEXCOORD;
                //定义第二套UV
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                float4 lightmapUV : TEXCOORD1;
                #endif
                half3 worldNormal : NORMAL;

                half3 sh : TEXCOORD2;
                //1、使用 阴影采样 和 光照衰减的方案的 第一步
                //同时定义灯光衰减以及实时阴影采样所需的插值器
                UNITY_LIGHTING_COORDS(3, 4)
                //UNITY_SHADOW_COORDS(2)
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                //对第二套UV进行纹理采样
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                    o.lightmapUV.xy = v.texcoord1 * unity_LightmapST.xy + unity_LightmapST.zw;
                #endif

                //实现 球谐 或者 环境色 和 顶点照明 的计算
                //SH/ambient and vertex lights
                #ifndef LIGHTMAP_ON //当此对象没有开启静态烘焙时
                #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                    o.sh = 0;
                    //近似模拟非重要级别的点光在逐顶点上的光照效果
                #ifdef VERTEXLIGHT_ON
                        o.sh += Shade4PointLights(
                        unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
                        unity_LightColor[0].rgb,unity_LightColor[1].rgb,unity_LightColor[2].rgb,unity_LightColor[3].rgb,
                        unity_4LightAtten0,o.worldPos,o.worldNormal);
                #endif
                    o.sh = ShadeSHPerVertex(o.worldNormal,o.sh);
                #endif
                #endif


                //2、使用 阴影采样 和 光照衰减的方案的 第二步
                UNITY_TRANSFER_LIGHTING(o, v.texcoord2.xy)
                //TRANSFER_SHADOW(o)
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //1、准备 SurfaceOutput 的数据
                SurfaceOutput o;
                //目前先初始化为0,使用Unity自带的方法,把结构体中的内容初始化为0
                    UNITY_INITIALIZE_OUTPUT(SurfaceOutput, o)
                o.Albedo = 1;
                o.Normal = i.worldNormal;

                //1、代表灯光的衰减效果
                //2、实时阴影的采样
                UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);


                //2、准备 UnityGIInput 的数据
                UnityGIInput giInput;
                //初始化
                    UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
                //修改用到的数据
                giInput.light.color = _LightColor0;
                giInput.light.dir = _WorldSpaceLightPos0;
                giInput.worldPos = i.worldPos;
                giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
                giInput.atten = atten;
                giInput.ambient = 0;

                #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                    giInput.ambient = i.sh;
                #else
                giInput.ambient = 0.0;
                #endif


                #if defined(DYNAMICLIGHTMAP_ON) || defined(LIGHTMAP_ON)
                giInput.lightmapUV = i.lightmapUV;
                #endif

                //3、准备 UnityGI 的数据
                UnityGI gi;
                //直接光照数据(主平行光)
                gi.light.color = _LightColor0;
                gi.light.dir = _WorldSpaceLightPos0;
                //间接光照数据(目前先给0)
                gi.indirect.diffuse = 0;
                gi.indirect.specular = 0;

                //GI的间接光照的计算 
                LightingLambert_GI1(o, giInput, gi);
                //查看Unity源码可知,计算间接光照最主要的函数就是
                //inline UnityGI UnityGI_Base1(UnityGIInput data, half occlusion, half3 normalWorld)
                //所以我们直接给 gi 赋值,可以不使用 LightingLambert_GI1
                gi = UnityGI_Base1(giInput, 1, o.Normal);

                //GI的直接光照的计算
                //我们在得到GI的数据后,对其进行Lambert光照模型计算,即可得到结果
                fixed4 c = LightingLambert1(o, gi);

                return c;
                //return fixed4(gi.indirect.diffuse,1);
                //return 1;
            }
            ENDCG
        }

        //阴影的投射
        Pass
        {
            //1、设置 "LightMode" = "ShadowCaster"
            Tags
            {
                "LightMode" = "ShadowCaster"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //需要添加一个 Unity变体
            #pragma multi_compile_shadowcaster

            #include "UnityCG.cginc"

            //声明消融使用的变量
            float _Clip;
            sampler2D _DissolveTex;
            float4 _DissolveTex_ST;

            //2、appdata中声明float4 vertex:POSITION;和half3 normal:NORMAL;这是生成阴影所需要的语义.
            //注意:在appdata部分,我们几乎不要去修改名字 和 对应的类型。
            //因为,在Unity中封装好的很多方法都是使用这些标准的名字
            struct appdata
            {
                float4 vertex:POSITION;
                half3 normal:NORMAL;
                float4 uv:TEXCOORD;
            };

            //3、v2f中添加V2F_SHADOW_CASTER;用于声明需要传送到片断的数据.
            struct v2f
            {
                float4 uv : TEXCOORD;
                V2F_SHADOW_CASTER;
            };

            //4、在顶点着色器中添加TRANSFER_SHADOW_CASTER_NORMALOFFSET(o),主要是计算阴影的偏移以解决不正确的Shadow Acne和Peter Panning现象.
            v2f vert(appdata v)
            {
                v2f o;
                o.uv.zw = TRANSFORM_TEX(v.uv, _DissolveTex);
                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
                return o;
            }

            //5、在片断着色器中添加SHADOW_CASTER_FRAGMENT(i)

            fixed4 frag(v2f i) : SV_Target
            {
                //外部获取的 纹理 ,使用前都需要采样
                fixed4 dissolveTex = tex2D(_DissolveTex, i.uv.zw);

                //片段的取舍
                clip(dissolveTex.r - _Clip);

                SHADOW_CASTER_FRAGMENT(i);
            }
            ENDCG
        }
        //在常规的渲染时,是不会被使用的。一般使用时,是在烘焙贴图
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "META"
            Tags
            {
                "LightMode" = "Meta"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #include "UnityCG.cginc"
            #include "UnityMetaPass.cginc"
            fixed4 _Color;
            
            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                UNITY_INITIALIZE_OUTPUT(v2f,o)
                
                o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST,
         unity_DynamicLightmapST);
                
                return o;
            }
            
            half4 frag(v2f i) : SV_Target
            {
                UnityMetaInput metaIN;
                UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
                metaIN.Albedo = 1;
                metaIN.Emission = _Color;
                return UnityMetaFragment(metaIN);
            }
            ENDCG
        }
    }
    CustomEditor "LegacyIlluminShaderGUI"
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/132290.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字滤波器设计---FIR 滤波器设计

数字滤波器设计---FIR 滤波器设计 FIR 滤波器与 IIR 滤波器的比较 与无限持续时间冲激响应 (IIR) 滤波器相比,具有有限持续时间冲激响应的数字滤波器(全零或 FIR 滤波器)既有优点又有缺点。 FIR 滤波器具有以下主要优点: 它们可…

关于Android Studio 同步Gradle失败的解决方案

(1)打开Android Studio的Settings找到Gradle的目录 (2)打开本地文件目录,找到对应的gradle版本,可以通过Index of /gradle/ 下载gradle压缩包。把目录中gradle-7.0.2-bin\一堆字符\ 下 的.lck 和.part文…

数据管理系统-week1-文件系统、数据库和数据库管理系统

文章目录 前言一、 文件系统文件系统的限制 二、 数据库系统三、 数据库管理系统参考文献 前言 一、 文件系统 对于更高级的数据处理应用程序来说,基于数据块的持久存储逻辑模型过于简单数据块序列被划分为称为文件的数据块的可变子序列,与文件相关的名…

香港云服务器用于跨境电商外贸

港作为国际金融中心和互联网枢纽,具有非常发达的网络基础设施和优质的网络连接。这意味着在香港租用云服务器,外贸企业可以享受到高速稳定的网络连接,确保数据传输的安全和稳定性。这对于外贸企业来说至关重要,因为他们需要频繁地…

html+css+javascript打造网页内容浮动导航菜单

1需求分析 前段时间把“圳品”信息发布到网站上了,内容包括四大块: 按分布区域统计分析按产品类别统计分析按认定时间统计分析河池市“圳品”清单 导致网页很长,有同事反映说查看起来不是很方便,于是决定加上一个网页内容浮动导…

视通科技新品发布:4K30分布式编解码一体机,高性价比之选!

随着信息技术的日新月异,各领域对于音视频传输、控制和显示等方面的需求呈现出爆发式的增长。这种需求的增长源于多种因素,包括但不限于高清视频的普及,实时音视频通信的广泛应用,以及各种显示设备的升级换代。 在这样的背景下&a…

大数据治理——为业务提供持续的、可度量的价值(一)

目录 大数据治理——为业务提供持续的、可度量的价值... 1 概述... 2 大数据治理系列... 2 第一部分:大数据治理统一流程模型概述和明确元数据管理策略... 2 第二部分:元数据集成体系结构... 15 第三部分:实施元数据管理... 25 第四部…

基于ubuntu22.04手动安装openstack——2023.2版本(最新版)的问题汇总

前言:基本上按照openstack官方网站动手可以搭建成功(如有需要私信发部署文档)。 但是任然有些小问题,所以汇总如下。 第一个问题 问题: ubuntu搭建2023.2版本neutorn报错,ERROR neutron.plugins.ml2.driv…

传奇GOM引擎微端连接不上如何解决

Gom传奇引擎的微端连不上的原因可能有很多,比如网络问题、服务器配置问题、版本兼容性问题等。1.检查网络连接:首先要确保你的网络连接稳定。如果遇到网络问题,比如网络延迟过高,可能会导致你无法连接到服务器。建议使用稳定的网络…

Linux-基础知识

1.快捷键 ctrlc 强制停止 ctrld 退出或登出 history 查看历史命令(!/ctrlr输入内容去匹配历史命令) 光标移动快捷键 ctrla,跳到命令开头 ctrle,跳到命令结尾 ctrl键盘左键,向左跳一个单词 ctrl键盘右键&…

Maven打包引入本地依赖包

Maven打包引入本地依赖包 SpringBoot 工程,Maven 在构建项目时,如何引入本地 Jar 包? 适合场景: 引用的依赖不在 Maven 仓库第三方公司提供的 SDK 包Maven 内网离线开发引入被定制改动过的 Jar 包 解决方法: 在 I…

数据分析实战 | KNN算法——病例自动诊断分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 九、模型调参 十、模型改进 十一、模型预测 一、数据及分析对象 CSV文件——“bc_data.csv” 数据集链接:https://dow…

共享变量可见性问题以及解决方案

文章目录 1. 简介2. 解决方案 1. 简介 首先在了解可见性问题之前我们首先需要给出Java 内存模型的定义(JMM),java讲内存模型抽象为两个部分,主存以及工作内存,主 存也就是所有线程所共享的一段存储空间,工…

Netty--NIO(Non-blocking IO)基础--三大组件

NIO(Non-blocking IO)是一种非阻塞的IO模型,它通过引入Channel和Selector的概念,使得一个线程能够管理多个通道,从而提高了IO操作的效率。本文将介绍NIO的三大组件:Channel、Buffer、以及Selector&#xff…

GEE:遥感影像二值化

作者:CSDN @ _养乐多_ 在Google Earth Engine(GEE)中,图像二值化是将图像中的像素值转换为二进制(0或1)的过程。这通常用于将连续的遥感图像转换为只有两个值的二值图像,以突出图像中的特定特征或区域。 结果如下图所示,将NDVI图像中,大于0.3的值设置为1(黑色),小…

SQL 算数函数

AVG() 求数值列的平均值。 具体计算过程:其通过对表中行数计数并计算特定数值列的列值之和,求得该列的平均值。 语法: SELECT AVG(column_name) FROM table_name; 当参数 column_name 列中的数据均为空时,结果会返回 NULL。 …

Ubuntu(WSL2) mysql8.0.31 源码安装

要在 Ubuntu 上使用调试功能安装 MySQL 8.0 的源码,可以按照以下详细步骤进行操作: 1. 更新系统 首先,确保你的 Ubuntu 系统是最新的。运行以下命令更新系统软件包: sudo apt update sudo apt upgrade 2. 下载 MySQL 源码 访…

【ATTCK】MITRE Caldera -引导规划器

一、Caldera 概念 在详细介绍新的引导式规划器之前,我们先回顾一下与 Caldera 相关的概念的一些定义。 能力是 Caldera 可以执行的最小原子动作。对手由一组能力组成。例如,旨在发现和泄露感兴趣的文件的对手可能具有发现文件、创建暂存目录、将发现的文…

Visual Studio 2019下编译OpenCV 4.7 与OpenCV 4.7 contrib

一、环境 使用的环境是Win10,Visual Studio 2019,Cmake3.28,cdua 11.7,cudnn 8.5,如果只是在CPU环境下使用,则不用安装CUDA。要使用GPU处理,安装好CUDA之后,要测试安装的CUDA是否能用。不能正常使用的话,添加一下系统…

基于vue的cron表达式组件——vue-crontab插件

前言: vue 的 cron 组件,支持解析/反解析 cron 表达式,生成最近五次的符合条件时间,依赖 vue2 和 element-ui 效果图: 一、下载安装依赖插件 npm install vcrontab 二、引用方式 //全局引入 import vcrontab f…