Unity中Shader的BRDF解析(一)

文章目录

  • 前言
  • 现在我们主要来看Standard的 漫反射 和 镜面反射
  • 一、PBS的核心计算BRDF
  • 二、Standard的镜面高光颜色
  • 三、具体的BRDF计算
    • 对于BRDF的具体计算,在下篇文章中,继续解析
  • 四、最终代码
    • .cginc文件
    • Shader文件


前言

在上篇文章中,我们解析了Standard的GI实现,这篇文章我们来解析一下Standard的PBS计算。

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

在这里插入图片描述
上篇文章中,主要解析了这个公式 GI漫反射 和 GI镜面反射


现在我们主要来看Standard的 漫反射 和 镜面反射


一、PBS的核心计算BRDF

LightingStandard1(o, worldViewDir, gi);
在这里插入图片描述

  • 在该函数中,主要进行了如下计算:

在这里插入图片描述


二、Standard的镜面高光颜色

s.Albedo = DiffuseAndSpecularFromMetallic1 (s.Albedo, s.Metallic, /out/ specColor, /out/ oneMinusReflectivity);

在这里插入图片描述

这里漫反射的反射率(oneMinusReflectivity)推导公式如下:

在这里插入图片描述

在这里插入图片描述

lerp(A,B,v) = A + v(B - A)


三、具体的BRDF计算

在这里插入图片描述

在这里插入图片描述

  • #error 错误信息 : 会在控制台输出错误信息,并且报错后Shader不会渲染

我们在片元着色器返回物体颜色前测试一下:

在这里插入图片描述
可以看见我们控制台输出了错误信息:

在这里插入图片描述

对于BRDF的具体计算,在下篇文章中,继续解析

  • UNITY_PBS_USE_BRDF3
  • UNITY_PBS_USE_BRDF2
  • UNITY_PBS_USE_BRDF1

四、最终代码

.cginc文件

#ifndef MYPHYSICALLYBASERENDERING_INCLUDE#define MYPHYSICALLYBASERENDERING_INCLUDE//Standard的漫反射和镜面反射计算↓// Main Physically Based BRDF// Derived from Disney work and based on Torrance-Sparrow micro-facet model////   BRDF = kD / pi + kS * (D * V * F) / 4//   I = BRDF * NdotL//// * NDF (depending on UNITY_BRDF_GGX)://  a) Normalized BlinnPhong//  b) GGX// * Smith for Visiblity term// * Schlick approximation for Fresnelhalf4 BRDF1_Unity_PBS1 (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,float3 normal, float3 viewDir,UnityLight light, UnityIndirect gi){float perceptualRoughness = SmoothnessToPerceptualRoughness (smoothness);float3 halfDir = Unity_SafeNormalize (float3(light.dir) + viewDir);// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping// In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts.// but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too).// Following define allow to control this. Set it to 0 if ALU is critical on your platform.// This correction is interesting for GGX with SmithJoint visibility function because artifacts are more visible in this case due to highlight edge of rough surface// Edit: Disable this code by default for now as it is not compatible with two sided lighting used in SpeedTree.#define UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV 0#if UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV// The amount we shift the normal toward the view vector is defined by the dot product.half shiftAmount = dot(normal, viewDir);normal = shiftAmount < 0.0f ? normal + viewDir * (-shiftAmount + 1e-5f) : normal;// A re-normalization should be applied here but as the shift is small we don't do it to save ALU.//normal = normalize(normal);float nv = saturate(dot(normal, viewDir)); // TODO: this saturate should no be necessary here#elsehalf nv = abs(dot(normal, viewDir));    // This abs allow to limit artifact#endiffloat nl = saturate(dot(normal, light.dir));float nh = saturate(dot(normal, halfDir));half lv = saturate(dot(light.dir, viewDir));half lh = saturate(dot(light.dir, halfDir));// Diffuse termhalf diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;// Specular term// HACK: theoretically we should divide diffuseTerm by Pi and not multiply specularTerm!// BUT 1) that will make shader look significantly darker than Legacy ones// and 2) on engine side "Non-important" lights have to be divided by Pi too in cases when they are injected into ambient SHfloat roughness = PerceptualRoughnessToRoughness(perceptualRoughness);#if UNITY_BRDF_GGX// GGX with roughtness to 0 would mean no specular at all, using max(roughness, 0.002) here to match HDrenderloop roughtness remapping.roughness = max(roughness, 0.002);float V = SmithJointGGXVisibilityTerm (nl, nv, roughness);float D = GGXTerm (nh, roughness);#else// Legacyhalf V = SmithBeckmannVisibilityTerm (nl, nv, roughness);half D = NDFBlinnPhongNormalizedTerm (nh, PerceptualRoughnessToSpecPower(perceptualRoughness));#endiffloat specularTerm = V*D * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later#   ifdef UNITY_COLORSPACE_GAMMAspecularTerm = sqrt(max(1e-4h, specularTerm));#   endif// specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane valuespecularTerm = max(0, specularTerm * nl);#if defined(_SPECULARHIGHLIGHTS_OFF)specularTerm = 0.0;#endif// surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(roughness^2+1)half surfaceReduction;#   ifdef UNITY_COLORSPACE_GAMMAsurfaceReduction = 1.0-0.28*roughness*perceptualRoughness;      // 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]#   elsesurfaceReduction = 1.0 / (roughness*roughness + 1.0);           // fade \in [0.5;1]#   endif// To provide true Lambert lighting, we need to be able to kill specular completely.specularTerm *= any(specColor) ? 1.0 : 0.0;half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));half3 color =   diffColor * (gi.diffuse + light.color * diffuseTerm)+ specularTerm * light.color * FresnelTerm (specColor, lh)+ surfaceReduction * gi.specular * FresnelLerp (specColor, grazingTerm, nv);return half4(color, 1);}// Based on Minimalist CookTorrance BRDF// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255//// * NDF (depending on UNITY_BRDF_GGX)://  a) BlinnPhong//  b) [Modified] GGX// * Modified Kelemen and Szirmay-​Kalos for Visibility term// * Fresnel approximated with 1/LdotHhalf4 BRDF2_Unity_PBS1 (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,float3 normal, float3 viewDir,UnityLight light, UnityIndirect gi){float3 halfDir = Unity_SafeNormalize (float3(light.dir) + viewDir);half nl = saturate(dot(normal, light.dir));float nh = saturate(dot(normal, halfDir));half nv = saturate(dot(normal, viewDir));float lh = saturate(dot(light.dir, halfDir));// Specular termhalf perceptualRoughness = SmoothnessToPerceptualRoughness (smoothness);half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);#if UNITY_BRDF_GGX// GGX Distribution multiplied by combined approximation of Visibility and Fresnel// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course// https://community.arm.com/events/1155float a = roughness;float a2 = a*a;float d = nh * nh * (a2 - 1.f) + 1.00001f;#ifdef UNITY_COLORSPACE_GAMMA// Tighter approximation for Gamma only rendering mode!// DVF = sqrt(DVF);// DVF = (a * sqrt(.25)) / (max(sqrt(0.1), lh)*sqrt(roughness + .5) * d);float specularTerm = a / (max(0.32f, lh) * (1.5f + roughness) * d);#elsefloat specularTerm = a2 / (max(0.1f, lh*lh) * (roughness + 0.5f) * (d * d) * 4);#endif// on mobiles (where half actually means something) denominator have risk of overflow// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))#if defined (SHADER_API_MOBILE)specularTerm = specularTerm - 1e-4f;#endif#else// Legacyhalf specularPower = PerceptualRoughnessToSpecPower(perceptualRoughness);// Modified with approximate Visibility function that takes roughness into account// Original ((n+1)*N.H^n) / (8*Pi * L.H^3) didn't take into account roughness// and produced extremely bright specular at grazing angleshalf invV = lh * lh * smoothness + perceptualRoughness * perceptualRoughness; // approx ModifiedKelemenVisibilityTerm(lh, perceptualRoughness);half invF = lh;half specularTerm = ((specularPower + 1) * pow (nh, specularPower)) / (8 * invV * invF + 1e-4h);#ifdef UNITY_COLORSPACE_GAMMAspecularTerm = sqrt(max(1e-4f, specularTerm));#endif#endif#if defined (SHADER_API_MOBILE)specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles#endif#if defined(_SPECULARHIGHLIGHTS_OFF)specularTerm = 0.0;#endif// surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(realRoughness^2+1)// 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]// 1-x^3*(0.6-0.08*x)   approximation for 1/(x^4+1)#ifdef UNITY_COLORSPACE_GAMMAhalf surfaceReduction = 0.28;#elsehalf surfaceReduction = (0.6-0.08*perceptualRoughness);#endifsurfaceReduction = 1.0 - roughness*perceptualRoughness*surfaceReduction;half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));half3 color =   (diffColor + specularTerm * specColor) * light.color * nl+ gi.diffuse * diffColor+ surfaceReduction * gi.specular * FresnelLerpFast (specColor, grazingTerm, nv);return half4(color, 1);}sampler2D_float unity_NHxRoughness1;half3 BRDF3_Direct1(half3 diffColor, half3 specColor, half rlPow4, half smoothness){half LUT_RANGE = 16.0; // must match range in NHxRoughness() function in GeneratedTextures.cpp// Lookup texture to save instructionshalf specular = tex2D(unity_NHxRoughness1, half2(rlPow4, SmoothnessToPerceptualRoughness(smoothness))).r * LUT_RANGE;#if defined(_SPECULARHIGHLIGHTS_OFF)specular = 0.0;#endifreturn diffColor + specular * specColor;}half3 BRDF3_Indirect1(half3 diffColor, half3 specColor, UnityIndirect indirect, half grazingTerm, half fresnelTerm){half3 c = indirect.diffuse * diffColor;c += indirect.specular * lerp (specColor, grazingTerm, fresnelTerm);return c;}// Old school, not microfacet based Modified Normalized Blinn-Phong BRDF// Implementation uses Lookup texture for performance//// * Normalized BlinnPhong in RDF form// * Implicit Visibility term// * No Fresnel term//// TODO: specular is too weak in Linear rendering modehalf4 BRDF3_Unity_PBS1 (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,float3 normal, float3 viewDir,UnityLight light, UnityIndirect gi){float3 reflDir = reflect (viewDir, normal);half nl = saturate(dot(normal, light.dir));half nv = saturate(dot(normal, viewDir));// Vectorize Pow4 to save instructionshalf2 rlPow4AndFresnelTerm = Pow4 (float2(dot(reflDir, light.dir), 1-nv));  // use R.L instead of N.H to save couple of instructionshalf rlPow4 = rlPow4AndFresnelTerm.x; // power exponent must match kHorizontalWarpExp in NHxRoughness() function in GeneratedTextures.cpphalf fresnelTerm = rlPow4AndFresnelTerm.y;half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));half3 color = BRDF3_Direct1(diffColor, specColor, rlPow4, smoothness);color *= light.color * nl;color += BRDF3_Indirect1(diffColor, specColor, gi, grazingTerm, fresnelTerm);return half4(color, 1);}// Default BRDF to use://在 ProjectSetting->Graphics->TierSetting中设置//StandardShaderQuality = low(UNITY_PBS_USE_BRDF3)//StandardShaderQuality = Medium(UNITY_PBS_USE_BRDF2)//StandardShaderQuality = High(UNITY_PBS_USE_BRDF1)#if !defined (UNITY_BRDF_PBS1) // allow to explicitly override BRDF in custom shader// still add safe net for low shader models, otherwise we might end up with shaders failing to compile#if SHADER_TARGET < 30 || defined(SHADER_TARGET_SURFACE_ANALYSIS) // only need "something" for surface shader analysis pass; pick the cheap one#define UNITY_BRDF_PBS1 BRDF3_Unity_PBS1  //效果最差的BRDF#elif defined(UNITY_PBS_USE_BRDF3)#define UNITY_BRDF_PBS1 BRDF3_Unity_PBS1#elif defined(UNITY_PBS_USE_BRDF2)#define UNITY_BRDF_PBS1 BRDF2_Unity_PBS1#elif defined(UNITY_PBS_USE_BRDF1)#define UNITY_BRDF_PBS1 BRDF1_Unity_PBS1#else#error something broke in auto-choosing BRDF#endif#endifinline half OneMinusReflectivityFromMetallic1(half metallic){// We'll need oneMinusReflectivity, so//   1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)// store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then//   1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =//                  = alpha - metallic * alphahalf oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;}inline half3 DiffuseAndSpecularFromMetallic1 (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity){//计算镜面高光颜色//当metallic为0(即非金属时),返回unity_ColorSpaceDielectricSpec.rgb(0.04)//unity_ColorSpaceDielectricSpec.rgb表示的是绝缘体的通用反射颜色//迪士尼经大量测量用 0.04 来表示//当 metallic = 1 时(金属),返回Albedo,也就是物体本身的颜色specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);oneMinusReflectivity = OneMinusReflectivityFromMetallic1(metallic);return albedo * oneMinusReflectivity;}//s : 物体表面数据信息//viewDir : 视线方向//gi : 全局光照(GI漫反射 和 GI镜面反射)inline half4 LightingStandard1 (SurfaceOutputStandard s, float3 viewDir, UnityGI gi){s.Normal = normalize(s.Normal);half oneMinusReflectivity;//镜面高光颜色half3 specColor;s.Albedo = DiffuseAndSpecularFromMetallic1 (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);// shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)// this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha//当开启半透明模式时,对 Alpha 进行相关计算half outputAlpha;s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);//具体的BRDF计算//s.Albedo : 物体表面的基础颜色//specColor : 镜面反射颜色//oneMinusReflectivity : 漫反射率 = 1 - 镜面反射率//s.Smoothness : 物体表面的光滑度//s.Normal : 物体表面的法线//viewDir : 视线方向//gi.light : 直接光信息//gi.indirect : GI间接光信息half4 c = UNITY_BRDF_PBS1 (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);c.a = outputAlpha;return c;}//Standard的GI计算↓half3 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_6"
{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 = LightingStandard1(o, worldViewDir, gi);UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fogUNITY_OPAQUE_ALPHA(c.a); //把c的Alpha置1#error 错了没(⊙o⊙)?return c;}ENDCG}}}

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

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

相关文章

当消费增值模式遇上Dapp:擦出创新商业的火花

随着区块链技术和智能合约的不断发展&#xff0c;去中心化应用&#xff08;Dapp&#xff09;逐渐成为一种创新的商业模式。当消费增值模式与Dapp相遇&#xff0c;它们之间擦出了怎样的火花呢&#xff1f; 一、Dapp与消费增值模式的结合 Dapp是一种基于区块链技术和智能合约的去…

在Rust中处理命令行参数和环境变量

1.摘要 Rust的命令行和环境变量处理在标准库中提供了一整套实现方法, 在本文中除了探索标准库的使用方法之外, 也在不断适应Rust独有的语法特点。在本文中, 我们通过标准库函数的返回值熟悉了迭代器的使用方法, 操作迭代器精确控制保存的内容, 包括字符串和键值对的使用方法。…

Mysql快速查找用逗号分割的列中含有某个字符的行:FIND_IN_SET

看标题比较绕口&#xff0c;但是我举一个例子你就清楚了 这是一个查询&#xff1a;我现在想要的是attr_val中含有黑色属性的行&#xff1a; 你用模糊匹配可以&#xff0c;用REGEXP也行&#xff0c;下面介绍一种mysql自带的函数&#xff1a;FIND_IN_SET。它的用法是&#xff1a…

每日汇评:原油价格正在等待欧佩克对2024年供应削减配额的决定

OPEC会议推迟至周四&#xff0c;个别配额和供应削减仍然是会议的核心议题&#xff1b; 原油价格在欧佩克会议前持平&#xff0c;但是否有意外的看涨取决于欧佩克的减产&#xff1b; 布伦特原油价格在关键的82美元和200均线的交叉点被明显拒绝后走低&#xff1b; 上周三&#xf…

JOSEF 漏电继电器JHOK-ZBL1 DH-50L 系统1140V 电源AC220V

系列型号&#xff1a; JHOK-ZBL多档切换式漏电&#xff08;剩余&#xff09;继电器 JHOK-ZBL1多档切换式漏电&#xff08;剩余&#xff09;继电器 JHOK-ZBL2多档切换式漏电&#xff08;剩余&#xff09;继电器 JHOK-ZBM多档切换式漏电&#xff08;剩余&#xff09;继电器 …

【傻瓜级JS-DLL-WINCC-PLC交互】3.JS-DLL进行交互

思路 JS-DLL-WINCC-PLC之间进行交互&#xff0c;思路&#xff0c;先用Visual Studio创建一个C#的DLL控件&#xff0c;然后这个控件里面嵌入浏览器组件&#xff0c;实现JS与DLL通信&#xff0c;然后DLL放入到WINCC里面的图形编辑器中&#xff0c;实现DLL与WINCC的通信。然后PLC与…

玻色量子事件活动

2023年 2023.7 玻色量子携最新相干光量子计算机惊艳亮相2023数字经济大会 2023.6 打造“新型计算数据中心”&#xff01;玻色量子与科华数据&#xff08;002335.SZ&#xff09;携手共创 2023.6 玻色量子“天工量子大脑”亮相中关村论坛&#xff0c;大放异彩 2023.5 100量…

机器学习实战第3天:手写数字识别

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 一、任务描述 二、数据集描述 三、主要代码 &#xff08;1&#xff09;主要代码库的说明与导入方法 &#xff08;2&#xff09;数据预…

实现了父类 纯虚函数为什么还有 无法解析外部符号错误

使用背景&#xff1a; 将C 的函数或接口使用 pybind11 封装成可以供python 使用调用的接口或函数&#xff0c;使用了CMake 编译&#xff08;若之前可以编译通过&#xff0c;现在编译不通过&#xff0c;重新选择 source code 路径&#xff09;成 VS 2019 可使用的目标解决方案&a…

四丶openlayer之瓦片地图

瓦片地图源于一种大地图解决方案&#xff0c;针对一整块非常大的地图进行切片&#xff0c;分成很多相同大小的小块地图&#xff0c;在用户访问的时候&#xff0c;再一块一块小地图加载&#xff0c;拼接在一起&#xff0c;从而还原成一整块大的地图。这样做的优点在于&#xff0…

zblog插件-zblog采集插件下载

在当今数字化的时代&#xff0c;博客已经成为人们分享思想、经验和知识的重要平台。而对于使用zblog博客系统的用户来说&#xff0c;充实博客内容是提高用户体验和吸引读者的不二法门。然而&#xff0c;手动收集内容对于博主来说既费时又繁琐。在这个背景下&#xff0c;zblog插…

QQ导出聊天记录,学会这3个方法,轻松解决!

QQ是我们与他人沟通、交流的重要方式之一。特别是对于那些将QQ作为主要通讯工具的人来说&#xff0c;聊天记录中可能包含了大量重要的信息。那么&#xff0c;如果想要导出QQ聊天记录该怎么办呢&#xff1f;qq导出聊天记录的方法有哪些&#xff1f;本文将为您介绍三种方法&#…