Unity中Shader的Standard材质解析(二)

文章目录

  • 前言
  • 一、我们对 Standard 的 PBR 的 GI 进行解析
    • 1、我们先创建一个PBR的.cginc文件,用于整理用到的函数
    • 2、然后在Standard的Shader中引用该cginc文件
  • 二、依次整理函数到该cginc文件中
    • 我们来看一下PBR中GI的镜面反射做了些什么
  • 二、最终代码
    • .cginc代码:
    • Shader代码:


前言

Unity中Shader的Standard材质解析(二),对 Standard 的 PBR 的 GI 进行解析

  • Unity中Shader的Standard材质解析(一)

一、我们对 Standard 的 PBR 的 GI 进行解析

在这里插入图片描述

1、我们先创建一个PBR的.cginc文件,用于整理用到的函数

在这里插入图片描述

2、然后在Standard的Shader中引用该cginc文件

#include “CGInclude/MyPhysicallyBasedRendering.cginc”


二、依次整理函数到该cginc文件中

  • 整理 LightingStandard_GI1(o, giInput, gi); 中的数据

在这里插入图片描述

  • Unity_GlossyEnvironmentData表示GI中的反射准备数据

在这里插入图片描述

  • 准备好反射数据后,计算得出GI中的 漫反射 和 镜面反射

在这里插入图片描述

  • 输出漫反射看看效果

在这里插入图片描述
在这里插入图片描述

  • 输出镜面反射看看效果

在这里插入图片描述

在这里插入图片描述

  • 我们可以自定义一下Cubemap,看看不同的反射效果

(这就是PBR的优点,可以根据不同的环境,直接呈现效果,不用再根据环境调节参数)

请添加图片描述

我们来看一下PBR中GI的镜面反射做了些什么

  • 这个程序块只会在,反射探针中开启Box Projection时,才会运行

在这里插入图片描述
在这里插入图片描述
这选项的作用是:使用反射探针的物体在移动时,效果不会变,只有在摄像机方向变时,效果才会变化。那么,要让物体动时,反射效果同时改变的话,就需要开启该选项。

  • 在取消了材质的Reflection后,会运行该程序块
  • 反之,运行之后的部分

在这里插入图片描述

在这里插入图片描述

  • 在开启反射效果后,对于感性粗糙度的计算。
  • 在Unity中的粗糙度,使用分级贴图来模拟粗糙度(节省性能)

在这里插入图片描述

  • 由于粗糙度与反射探针的mip变化不呈现线性正比,所以需要一个公式来改变

//r = r * (1.7 - 0.7r)
perceptualRoughness = perceptualRoughness
(1.7 - 0.7*perceptualRoughness);

在这里插入图片描述

在Blender中,粗糙度是按数值改变的:
请添加图片描述

在Unity中,反射探针是按贴图分级来模拟的粗糙度:

请添加图片描述

在这里插入图片描述


二、最终代码

.cginc代码:

#ifndef MYPHYSICALLYBASERENDERING_INCLUDE#define MYPHYSICALLYBASERENDERING_INCLUDEhalf3 Unity_GlossyEnvironment1 (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn){half perceptualRoughness = glossIn.roughness /* perceptualRoughness */ ;// TODO: CAUTION: remap from Morten may work only with offline convolution, see impact with runtime convolution!// For now disabled#if 0float m = PerceptualRoughnessToRoughness(perceptualRoughness); // m is the real roughness parameterconst float fEps = 1.192092896e-07F;        // smallest such that 1.0+FLT_EPSILON != 1.0  (+1e-4h is NOT good here. is visibly very wrong)float n =  (2.0/max(fEps, m*m))-2.0;        // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdfn /= 4;                                     // remap from n_dot_h formulatino to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.htmlperceptualRoughness = pow( 2/(n+2), 0.25);      // remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)#else// MM: came up with a surprisingly close approximation to what the #if 0'ed out code above does.//r = r * (1.7 - 0.7*r)//由于粗糙度与反射探针的mip变化不呈现线性正比,所以需要一个公式来改变perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);#endif//UNITY_SPECCUBE_LOD_STEPS = 6,表示反射探针的mip级别有 6 档。粗糙度X6得到最终得mip级别half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);half3 R = glossIn.reflUVW;half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);return DecodeHDR(rgbm, hdr);}//GI中的镜面反射inline half3 UnityGI_IndirectSpecular1(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn){half3 specular;//如果开启了反射探针的Box Projection#ifdef UNITY_SPECCUBE_BOX_PROJECTION// we will tweak reflUVW in glossIn directly (as we pass it to Unity_GlossyEnvironment twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirectionhalf3 originalReflUVW = glossIn.reflUVW;glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);#endif#ifdef _GLOSSYREFLECTIONS_OFFspecular = unity_IndirectSpecColor.rgb;#elsehalf3 env0 = Unity_GlossyEnvironment1 (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn);//如果开启了反射探针混合#ifdef UNITY_SPECCUBE_BLENDINGconst float kBlendFactor = 0.99999;float blendLerp = data.boxMin[0].w;UNITY_BRANCHif (blendLerp < kBlendFactor){#ifdef UNITY_SPECCUBE_BOX_PROJECTIONglossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);#endifhalf3 env1 = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), data.probeHDR[1], glossIn);specular = lerp(env1, env0, blendLerp);}else{specular = env0;}#elsespecular = env0;#endif#endifreturn specular * occlusion;}inline UnityGI UnityGlobalIllumination1 (UnityGIInput data, half occlusion, half3 normalWorld){return UnityGI_Base(data, occlusion, normalWorld);}//GI计算inline UnityGI UnityGlobalIllumination1 (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn){//计算得出GI中的漫反射UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);//计算得出GI中的镜面反射o_gi.indirect.specular = UnityGI_IndirectSpecular1(data, occlusion, glossIn);return o_gi;}float SmoothnessToPerceptualRoughness1(float smoothness){return (1 - smoothness);}Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup1(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0){Unity_GlossyEnvironmentData g;//粗糙度g.roughness /* perceptualRoughness */   = SmoothnessToPerceptualRoughness1(Smoothness);//反射球的采样坐标g.reflUVW   = reflect(-worldViewDir, Normal);return g;}//PBR光照模型的GI计算inline void LightingStandard_GI1(SurfaceOutputStandard s,UnityGIInput data,inout UnityGI gi){//如果是延迟渲染PASS并且开启了延迟渲染反射探针的话#if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERSgi = UnityGlobalIllumination1(data, s.Occlusion, s.Normal);#else//Unity_GlossyEnvironmentData表示GI中的反射准备数据Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup1(s.Smoothness, data.worldViewDir, s.Normal,lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo,s.Metallic));//进行GI计算并返回输出gigi = UnityGlobalIllumination1(data, s.Occlusion, s.Normal, g);#endif}#endif

Shader代码:

//Standard材质
Shader "MyShader/P2_2_5"
{Properties{_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}[NoScaleOffset]_MetallicTex("Metallic(R) Smoothness(G) AO(B)",2D) = "white" {}[NoScaleOffset][Normal]_NormalTex("NormalTex",2D) = "bump" {}_Glossiness ("Smoothness", Range(0,1)) = 0.0_Metallic ("Metallic", Range(0,1)) = 0.0_AO("AO",Range(0,1)) = 1.0}SubShader{Tags{"RenderType"="Opaque"}LOD 200// ---- forward rendering base pass:Pass{Name "FORWARD"Tags{"LightMode" = "ForwardBase"}CGPROGRAM// compile directives#pragma vertex vert#pragma fragment frag#pragma target 3.0#pragma multi_compile_instancing#pragma multi_compile_fog#pragma multi_compile_fwdbase#include "UnityCG.cginc"#include "Lighting.cginc"#include "UnityPBSLighting.cginc"#include "AutoLight.cginc"#include "CGInclude/MyPhysicallyBasedRendering.cginc"sampler2D _MainTex;float4 _MainTex_ST;half _Glossiness;half _Metallic;fixed4 _Color;sampler2D _MetallicTex;half _AO;sampler2D _NormalTex;struct appdata{float4 vertex : POSITION;float4 tangent : TANGENT;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;float4 texcoord1 : TEXCOORD1;float4 texcoord2 : TEXCOORD2;float4 texcoord3 : TEXCOORD3;fixed4 color : COLOR;UNITY_VERTEX_INPUT_INSTANCE_ID};// vertex-to-fragment interpolation data// no lightmaps:struct v2f{float4 pos : SV_POSITION;float2 uv : TEXCOORD0; // _MainTexfloat3 worldNormal : TEXCOORD1;float3 worldPos : TEXCOORD2;#if UNITY_SHOULD_SAMPLE_SHhalf3 sh : TEXCOORD3; // SH#endif//切线空间需要使用的矩阵float3 tSpace0 : TEXCOORD4;float3 tSpace1 : TEXCOORD5;float3 tSpace2 : TEXCOORD6;UNITY_FOG_COORDS(7)UNITY_SHADOW_COORDS(8)};// vertex shaderv2f vert(appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;float3 worldNormal = UnityObjectToWorldNormal(v.normal);//世界空间下的切线half3 worldTangent = UnityObjectToWorldDir(v.tangent);//切线方向half tangentSign = v.tangent.w * unity_WorldTransformParams.w;//世界空间下的副切线half3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;//切线矩阵o.tSpace0 = float3(worldTangent.x, worldBinormal.x, worldNormal.x);o.tSpace1 = float3(worldTangent.y, worldBinormal.y, worldNormal.y);o.tSpace2 = float3(worldTangent.z, worldBinormal.z, worldNormal.z);o.worldPos.xyz = worldPos;o.worldNormal = worldNormal;// SH/ambient and vertex lights#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXELo.sh = 0;// Approximated illumination from non-important point lights#ifdef VERTEXLIGHT_ONo.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, worldPos, worldNormal);#endifo.sh = ShadeSHPerVertex (worldNormal, o.sh);#endifUNITY_TRANSFER_LIGHTING(o, v.texcoord1.xy);UNITY_TRANSFER_FOG(o, o.pos); // pass fog coordinates to pixel shaderreturn o;}// fragment shaderfixed4 frag(v2f i) : SV_Target{UNITY_EXTRACT_FOG(i);float3 worldPos = i.worldPos.xyz;float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));SurfaceOutputStandard o;UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard, o);fixed4 mainTex = tex2D(_MainTex, i.uv);o.Albedo = mainTex.rgb * _Color;o.Emission = 0.0;fixed4 metallicTex = tex2D(_MetallicTex, i.uv);o.Metallic = metallicTex.r * _Metallic;o.Smoothness = metallicTex.g * _Glossiness;o.Occlusion = metallicTex.b * _AO;o.Alpha = 1;half3 normalTex = UnpackNormal(tex2D(_NormalTex,i.uv));half3 worldNormal = half3(dot(i.tSpace0,normalTex),dot(i.tSpace1,normalTex),dot(i.tSpace2,normalTex));o.Normal = worldNormal;// compute lighting & shadowing factorUNITY_LIGHT_ATTENUATION(atten, i, worldPos)// Setup lighting environmentUnityGI gi;UNITY_INITIALIZE_OUTPUT(UnityGI, gi);gi.indirect.diffuse = 0;gi.indirect.specular = 0;gi.light.color = _LightColor0.rgb;gi.light.dir = _WorldSpaceLightPos0.xyz;// Call GI (lightmaps/SH/reflections) lighting functionUnityGIInput giInput;UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);giInput.light = gi.light;giInput.worldPos = worldPos;giInput.worldViewDir = worldViewDir;giInput.atten = atten;#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)giInput.lightmapUV = IN.lmap;#elsegiInput.lightmapUV = 0.0;#endif#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXELgiInput.ambient = i.sh;#elsegiInput.ambient.rgb = 0.0;#endifgiInput.probeHDR[0] = unity_SpecCube0_HDR;giInput.probeHDR[1] = unity_SpecCube1_HDR;#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending#endif#ifdef UNITY_SPECCUBE_BOX_PROJECTIONgiInput.boxMax[0] = unity_SpecCube0_BoxMax;giInput.probePosition[0] = unity_SpecCube0_ProbePosition;giInput.boxMax[1] = unity_SpecCube1_BoxMax;giInput.boxMin[1] = unity_SpecCube1_BoxMin;giInput.probePosition[1] = unity_SpecCube1_ProbePosition;#endifLightingStandard_GI1(o, giInput, gi);//return fixed4(gi.indirect.specular,1);// PBS的核心计算fixed4 c = LightingStandard(o, worldViewDir, gi);UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fogUNITY_OPAQUE_ALPHA(c.a); //把c的Alpha置1return c;}ENDCG}}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中兴亮相中国国际现代化铁路技术装备展览会 筑智铁路5G同行

近日&#xff0c;第十六届中国国际现代化铁路技术装备展览会在北京中国国际展览中心举办&#xff0c;中兴以“数智铁路&#xff0c;5G同行”主题亮相本次展览会&#xff0c;并全面展示了“数字铁路网络基础设施”、“云边结合的铁路行业云”、“数字铁路赋能赋智”等方面的最新…

github国内访问小解(windows)

git 下载安装 使用 github 前必须确保电脑上已经安装了 Git&#xff0c;可以从 Git 官方网站去下载。 官方的网站在国内访问会比较慢&#xff0c;这里可以选择国内镜像&#xff1a;https://registry.npmmirror.com/binary.html?pathgit-for-windows/ github 之旅 确认电脑已…

HCIA-H12-811题目解析(1)

1、【多选题】关于动态 MAC 地址表说法正确的是&#xff1f; A、通过报文中的源MAC地址学习获得的动态MAC表项会老化 B、通过查看指定动态MAC地址表项的个数&#xff0c;可以获取接口下通信的用户数 C、在设备重启后&#xff0c;之前的动态表项会丢失 D、在设备重启后&…

运维 在Windows上搭建小型Git服务

文章目录 1、Git选型1.1、主要特性1.2、代码管理1.3、工单管理1.4、Pull/Merge requests1.5、第三方集成1.6、选型结论 2、环境搭建2.1、Gitea下载2.2、Gitea安装2.3、配置服务信息2.4、运行服务2.5、注册Gitea为服务2.6、正常使用 1、Git选型 1.1、主要特性 1.2、代码管理 1.…

VUE2+THREE.JS项目搭建

THREE项目搭建 简介学习文档推荐搭建1.下载three.js2.新建3DWorkShop.vue文件3.创建utils/three/tool.js4.创建components/three/draw.vue[重点]4.1 引入文件4.2 初始化场景4.3 初始化渲染器4.4 初始化光源4.5 初始化相机(人眼模式)4.6 初始化控制器4.7 初始化动画4.8 添加全局…

GB28181学习(十七)——基于jrtplib实现tcp被动和主动发流

前言 GB/T28181-2022实时流的传输方式介绍&#xff1a;https://blog.csdn.net/www_dong/article/details/134255185 基于jrtplib实现tcp被动和主动收流介绍&#xff1a;https://blog.csdn.net/www_dong/article/details/134451387 本文主要介绍下级平台或设备发流功能&#…

【心得】XXE漏洞利用个人笔记

XML中关于DTD类型(内部(SYSTEM)的和外部(PUBLIC)的区别) xxe的利用 XML Entity 实体注入 当程序处理xml文件时&#xff0c;没有禁止对外部实体的处理&#xff0c;容易造成xxe漏洞 危害 主流是任意文件读取 XML 文件 一般表示带有结构的数据 祖父 3个叔父 8个堂弟堂妹 …

【C++】string模拟

string讲解&#xff1a;【C】String类-CSDN博客 基本框架 #pragma once #include <iostream> using namespace std; ​ namespace wzf {class string{public:// 默认构造函数string(): _str(new char[1]), _size(0), _capacity(0){_str[0] \0; // 在没有内容时仍要有终…

ChatGPT 使用入门

背景 ChatGPT是一个强大的聊天机器人助手&#xff0c;内置了大量的互联网知识文档&#xff0c;且具有上下文记忆&#xff0c;可以帮我们快速地查找一些资料&#xff0c;了解一个知识&#xff0c;帮我们回答问题&#xff0c;编写代码等。此外&#xff0c;在使用ChatGPT时具有一…

拼图游戏制作

2.创建用户界面 package domain; /** * ClassName: User * Author: Kox * Data: 2023/2/2 * Sketch: */ public class User { private String username; private String password; public User() { } public User(String username, String p…

简单好用!日常写给 ChatGPT 的几个提示词技巧

ChatGPT 很强&#xff0c;但是有时候又显得很蠢&#xff0c;下面是使用 GPT4 的一个实例&#xff1a; 技巧一&#xff1a;三重冒号 """ 引用内容使用三重冒号 """&#xff0c;让 ChatGPT 清晰引用的内容&#xff1a; 技巧二&#xff1a;角色设定…

【数据清洗 | 数据规约】数据类别型数据 编码最佳实践,确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

mysql8下载与安装教程

文章目录 1. MySQL下载2. 方式一&#xff1a;msi文件安装2.1 安装2.2 添加环境变量2.3 登录mysql 3. 方式二&#xff1a;zip文件安装3.1 安装3.2 配置文件3.3 加入环境变量3.4 初始化mysql3.5 登录mysql 1. MySQL下载 以下两个网址二选一 官网&#xff1a;https://downloads.…

LeetCode(46)汇总区间【区间】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 汇总区间 1.题目 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某…

知识蒸馏代码实现(以MNIST手写数字体为例,自定义MLP网络做为教师和学生网络)

dataloader_tools.py import torchvision from torchvision import transforms from torch.utils.data import DataLoaderdef load_data():# 载入MNIST训练集train_dataset torchvision.datasets.MNIST(root "../datasets/",trainTrue,transformtransforms.ToTens…

鸿蒙系统扫盲(三):鸿蒙开发用什么语言?

1.两种开发方向 我们常说鸿蒙开发&#xff0c;但是其实鸿蒙开发分为两个方向&#xff1a; 一个是系统级别的开发&#xff0c;比如驱动&#xff0c;内核和框架层的开发&#xff0c;这种开发以C/C为主 还有一个是应用级别的开发&#xff0c;在API7以及以下&#xff0c;还是支持…

咨询+低代码,强强联合为制造业客户赋能

内容来自演讲&#xff1a;沈毅 | 遨睿智库 | 董事长 & 王劭禹 | 橙木智能 | 联合创始人 摘要 文章主要讲述了智库董事长沈毅创办广告公司的经历&#xff0c;以及他在管理公司过程中遇到的问题和挑战&#xff0c;最后通过与明道云以及橙木智能联合创始人王邵禹老师的合作&…

分布式篇---第五篇

系列文章目录 文章目录 系列文章目录前言一、你知道哪些限流算法?二、说说什么是计数器(固定窗口)算法三、说说什么是滑动窗口算法前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去…

【软件测试】盘一盘工作中遇到的 Redis 异常测试

在测试工作中&#xff0c;涉及到与 redis 交互的场景变的越来越多了。关于redis本身就不作赘述了&#xff0c;网上随便搜&#xff0c;本人也做过一些整理。 今天只来复盘一下&#xff0c;在测试过程中与 redis 的二三事儿。其中提到的案例是经过抽象化的&#xff0c;用作辅助说…

阿里云跨账号建立局域网

最近有活动&#xff0c;和好友一并薅了下阿里云的羊毛。琢磨着两台机器组一个局域网&#xff0c;于是有了这个需求&#xff0c;把步骤记录一下&#xff1a; 假设两台机器叫A和B&#xff0c;我们开始进行建立和组网 1. 建立ECS 把A机器公共环境装好&#xff0c;然后使用《实例与…