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

news2024/11/24 20:33:06

文章目录

  • 前言
    • 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"
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ | 继承和多态

目录 继承 继承的概念及用法 继承的作用域 向上转型和向下转型 继承过程中的默认生成函数 菱形继承及其解决方案 - 虚继承 虚继承的原理 - 虚基类表 继承和组合 多态 虚函数 多态的定义及使用 纯虚函数与抽象类 多态的原理 小点补充 虚表的位置 父类指针new一个…

聊聊测试左移到需求阶段

这是鼎叔的第七十九篇原创文章。行业大牛和刚毕业的小白,都可以进来聊聊。 欢迎关注本公众号《敏捷测试转型》,星标收藏,大量原创思考文章陆续推出。本人新书《无测试组织-测试团队的敏捷转型》​​​​​​​已出版(机械工业出版…

单链表的基本操作代码

#include<stdio.h> #include<stdlib.h> typedef int Status;//函数类型&#xff08;当return值为函数结果状态时用&#xff09;需要自定义&#xff01; typedef int ElemType;//相当于给 int起个别名 typedef struct LinkList{ ElemType data; struct L…

JMeter实现持续压测websocket

1、安装插件&#xff1a;JMeter WebSocket Samplers pjtr / JMeter WebSocket Samplers / Downloads — Bitbuckethttps://bitbucket.org/pjtr/jmeter-websocket-samplers/downloads/ 将下载的Jar包放在安装jmeter的/lib/ext路径下&#xff0c;重启生效 查看测试计划--》配置…

python爬虫怎么翻页

爬虫程序的代码实现如下&#xff1a; #include <iostream> #include <string> #include <curl/curl.h>int main() {CURL *curl;CURLcode res;std::string readBuffer;curl_global_init(CURL_GLOBAL_DEFAULT);curl curl_easy_init();if(curl) {curl_easy_se…

ChatGPT、GPT-4 Turbo接口调用(stream模式)

接口地址 https://chat.xutongbao.top/api/light/chat/createChatCompletion 请求方式 post 请求参数 model可选值&#xff1a; “gpt-3.5-turbo-1106”、 “gpt-3.5-turbo-16k” 、 “gpt-4”、“gpt-4-1106-preview”。 默认值为&#xff1a; “gpt-3.5-turbo-1106” to…

LeetCode 17. 电话号码的字母组合 中等

题目 - 点击直达 1. 17. 电话号码的字母组合 中等1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 解题思路1. 思路分析2. 时间复杂度3. 代码实现 3. 知识与收获 1. 17. 电话号码的字母组合 中等 1. 题目详情 1. 原题链接 LeetCode 17. 电话号码的字母组合 中等 2. 题目要…

后端架构选择:构建安全强大的知识付费小程序平台

构建知识付费小程序平台需要考虑后端架构&#xff0c;确保系统安全性、性能和可扩展性。以下是一些常见的后端技术和最佳实践&#xff0c;能帮助您构建强大且安全的知识付费小程序平台。 1. 服务器端语言和框架选择 选择流行、成熟的后端语言和框架&#xff0c;如Node.js、P…

基于php js+mysql+laravel技术架构的手术麻醉管理系统源码 手麻系统源码

PHP手术麻醉管理系统源码 手麻系统源码 手术麻醉管理系统定义&#xff1a; 手术麻醉系统主要是由麻醉信息管理和监护设备数据采集系统两个部分组成&#xff0c;主要是将麻醉信息和从监护仪器上采集到的数据以及手术信息进行统计。 手术麻醉系统是指专用于住院患者手术与麻醉…

AR工业眼镜:智能化生产新时代的引领者!!

科技飞速发展&#xff0c;人工智能与增强现实&#xff08;AR&#xff09;技术结合正在改变生活工作方式。AR工业眼镜在生产领域应用广泛&#xff0c;具有实时信息展示、智能导航定位、远程协作培训、智能安全监测等功能&#xff0c;提高生产效率、降低操作风险&#xff0c;为企…

网络通信TCP、UDP详解

目录 IP 和端口 网络传输中的 2 个对象&#xff1a;server 和 client 两种传输方式&#xff1a;TCP/UDP TCP 和 UDP 原理上的区别 为何存在 UDP 协议 TCP/UDP 网络通信大概交互图 IP 和端口 所有的数据传输&#xff0c;都有三个要素 &#xff1a;源、目的、长度。 怎么表…

开机自启动笔记本的小键盘

虽然电脑开机次数不多&#xff0c;但每次开机都要摁下小键盘的开关&#xff0c;好烦 终于忍不住了&#xff1a; 将下面文件命名为 XXX.bat echo off rem 禁用批处理文件中的命令回显&#xff0c;以使输出更整洁rem 查询注册表中 "InitialKeyboardIndicators" 的值 r…

devops完整搭建教程(gitlab、jenkins、harbor、docker)

devops完整搭建教程&#xff08;gitlab、jenkins、harbor、docker&#xff09; 文章目录 devops完整搭建教程&#xff08;gitlab、jenkins、harbor、docker&#xff09;1.简介&#xff1a;2.工作流程&#xff1a;3.优缺点4.环境说明5.部署前准备工作5.1.所有主机永久关闭防火墙…

ChatGPT-4:OpenAI的革命性升级

在人工智能领域&#xff0c;OpenAI这家公司凭借其创新性的技术&#xff0c;成为了备受瞩目的领导者。他们最近发布的ChatGPT-4&#xff0c;以其卓越的语言处理能力和先进的模型架构&#xff0c;引领了语言模型领域的革命性升级。 ChatGPT-4的模型容量相较于前一版本有了显著的提…

各种业务场景调用API代理的API接口教程(附带电商平台api接口商品详情数据接入示例)

API代理的API接口在各种业务场景中具有广泛的应用&#xff0c;本文将介绍哪些业务场景可以使用API代理的API接口&#xff0c;并提供详细的调用教程和代码演示&#xff0c;同时&#xff0c;我们还将讨论在不同场景下使用API代理的API接口所带来的好处。 哪些业务场景可以使用API…

Android 图层列表 、 LayerDrawable 、 layer-list \ 改变 seekbar thumb 滑块 的颜色

android 官网 &#xff1a; 图层列表 LayerDrawable / layer-list LayerDrawable 是管理其他可绘制对象数组的可绘制对象。列表中的每个可绘制对象均按照列表顺序绘制。列表中的最后一个可绘制对象绘于顶部。 每个可绘制对象均由单个 <layer-list> 元素内的 <item>…

万能在线预约小程序系统源码 适合任何行业在线预约小程序+预约到店模式 带完整的搭建教程

大家好啊&#xff0c;源码小编又来给大家分享啦&#xff01;随着互联网的发展和普及&#xff0c;越来越多的服务行业开始使用在线预约系统以方便客户和服务管理。例如&#xff0c;美发店、健身房、餐厅等都可以通过在线预约系统提高服务效率&#xff0c;减少等待时间&#xff0…

云计算、大数据技术的智慧工地,实现对建筑工地实时监测、管理和控制的一种新型建筑管理方式

智慧工地是利用物联网、云计算、大数据等技术&#xff0c;实现对建筑工地实时监测、管理和控制的一种新型建筑管理方式。 智慧工地架构&#xff1a; 1、终端层&#xff1a; 充分利用物联网技术、移动应用、智能硬件设备提高现场管控能力。通过RFID、传感器、摄像头、手机等终…

Liunx终极环境搭建

华子目录 网络服务准备工作安装RHEL9系统部署RHEL9操作系统虚拟网络编辑器配置RHEL9系统系统中的设置更换yum源修改主机名关闭selinux&#xff0c;firewalld设置静态ip &#xff08;网络配置&#xff09; 网络服务 准备工作 以下为RHEL9镜像资源&#xff0c;有需要的博友们可…

【蓝桥杯选拔赛真题17】C++时间换算 第十二届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析

目录 C/C++时间换算 一、题目要求 1、编程实现 2、输入输出 二、算法分析 <