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}}}
相关文章:

Unity中Shader的BRDF解析(一)
文章目录 前言现在我们主要来看Standard的 漫反射 和 镜面反射一、PBS的核心计算BRDF二、Standard的镜面高光颜色三、具体的BRDF计算对于BRDF的具体计算,在下篇文章中,继续解析 四、最终代码.cginc文件Shader文件 前言 在上篇文章中,我们解析…...
《软件工程原理与实践》复习总结与习题——软件工程概述
软件 什么是软件? 程序数据配套文档 软件危机 概念 计算机软件的开发和维护过程中所遇到的一系列严重问题 表现 20世纪60年代中后期,大容量、高速度计算机的出现,使计算机应用范围增大,软件开发需求急剧增长 软件工程 背景 德国…...
acwing算法基础之动态规划--线性DP和区间DP
目录 1 基础知识2 模板3 工程化 1 基础知识 线性DP:状态转移表达式存在明显的线性关系。 区间DP:与顺序有关,状态与区间有关。 2 模板 3 工程化 题目1:数字三角形。 解题思路:直接DP即可,f[i][j]可以来…...

力扣 622.设计循环队列
目录 1.解题思路2.代码实现 1.解题思路 首先,该题是设计循环队列,因此我们有两种实现方法,即数组和链表,但具体考虑后,发现数组实现要更容易一些,因此使用数组实现,因此我们要给出头和尾变量&a…...

初识Linux(2).妈妈再也不用担心我Linux找不到门了。
文章目录 前言 1.man指令(重要):例如: 2.cp指令(重要):例如:把123.txt复制到a目录中类似window如下操作: 3.mv例如:类似window如下操作: 4.nano例…...

房屋租赁出售经纪人入驻小程序平台
一款专为房屋中介开发的小程序平台,支持独立部署,源码交付,数据安全无忧。 核心功能:房屋出租、经纪人独立后台、分佣后台、楼盘展示、房型展示、在线咨询、地址位置配套设施展示。 程序已被很多房屋交易中介体验使用过&#x…...

【计算方法与科学建模】矩阵特征值与特征向量的计算(五):乘幂法的加速(带有原点移位的乘幂法)
文章目录 一、Jacobi 旋转法二、Jacobi 过关法三、Householder 方法四、乘幂法四、乘幂法的加速 矩阵的特征值(eigenvalue)和特征向量(eigenvector)在很多应用中都具有重要的数学和物理意义。 本文将详细介绍乘幂法的基本原理和步…...

2023年【起重机械指挥】考试题库及起重机械指挥考试资料
题库来源:安全生产模拟考试一点通公众号小程序 2023年【起重机械指挥】考试题库及起重机械指挥考试资料,包含起重机械指挥考试题库答案和解析及起重机械指挥考试资料练习。安全生产模拟考试一点通结合国家起重机械指挥考试最新大纲及起重机械指挥考试真…...
GoLang语言范围(Range)
目录 一、在数组、切片上使用‘range’ 二、在映射上使用range 三、在通道上使用range Go语言中的range关键字用于迭代数组(数组、切片、字符串)、映射(map)、通道(channel)或者在 for 循环中迭代每一个…...

汽车电子 -- 车载ADAS之FCW(前方碰撞预警)
相关法规文件: FCW: GB∕T 33577-2017 智能运输系统 车辆前向碰撞预警系统 性能要求和测试规程 一、前方碰撞预警 FCW( Forward Collision Warning) 参看:法规标准-GB/T 33577标准解读(2017版) 1、状态机 系统关闭 当车辆前向碰撞预警系…...

爬虫系统Docker和Kubernetes部署运维最佳实践
在构建和管理爬虫系统时,使用Docker和Kubernetes可以带来诸多好处,如方便的部署、弹性伸缩和高可靠性。然而,正确的部署和运维实践对于确保系统稳定运行至关重要。在本文中,我将分享爬虫系统在Docker和Kubernetes上的最佳部署和运…...
音视频5、libavformat-1
libavformat库,是FFmpeg中用于处理各种媒体容器格式(media container format)的库。它的两个最主要的功能是 : demuxing:解封装,将一个媒体文件分割为多个多媒体流 muxing:封装,将多个多媒体数据流写入到指定媒体容器格式的文件中 这两个过程所做的…...

【数据结构复习之路】树和二叉树(严蔚敏版)万字详解主打基础
专栏:数据结构复习之路 复习完上面四章【线性表】【栈和队列】【串】【数组和广义表】,我们接着复习 树和二叉树,这篇文章我写的非常详细且通俗易懂,看完保证会带给你不一样的收获。如果对你有帮助,看在我这么辛苦整理…...
nginx使用详解:转发规则、负载均衡、server_name
文章目录 一、nginx常用的转发规则location 指令说明location转发使用 二、upstream负载均衡使用三、server_name使用四、其他常用配置限制请求类型处理静态资源目录遍历问题限制客户端使用的ip或者域名 五、需要注意的地方location /api1 探讨location ~ /api1 探讨࿰…...

HarmonyOS 数据持久化 Preferences 如何在页面中对数据进行读写
背景介绍 最近在了解并跟着官方文档尝试做一个鸿蒙app 小demo的过程中对在app中保存数据遇到些问题 特此记录下来 这里的数据持久化以 Preferences为例子展开 废话不多说 这里直接上节目(官方提供的文档示例:) 以Stage模型为例 1.明确preferences的类型 import data_prefer…...

ESP32-Web-Server编程- JS 基础 4
ESP32-Web-Server编程- JS 基础 4 概述 HTML 内联事件处理器,你永远不应该使用 HTML 事件处理器属性——因为那些已经过时了,使用它们是不好的做法。 在前端编程中,除了将期望发生的事件写为 JS 文件外,还可以使用一些组件自带…...
JAVA的反射机制
什么是反射机制 Java反射机制是指在运行时动态地获取类的信息并操作类的成员(属性、方法、构造方法等)的能力。通过反射,我们可以解析出类的完整信息,包括构造函数、成员变量、继承关系等。以下是一个使用反射机制创建对象、调用…...

Couchdb 权限绕过漏洞复现(CVE-2017-12635)
Couchdb 权限绕过漏洞复现(CVE-2017-12635) 开启环境给了三个端口号,不知道哪个是正常的,最后试出来52226端口正常。 登录URL:http://192.168.91.129:52226/_utils/# 来到了登录页面 用postman发送PUT…...
GZ031 应用软件系统开发赛题第2套
2023年全国职业院校技能大赛 应用软件系统开发赛项(高职组) 赛题第2套 工位号: 2023年4月 竞赛说明 一、项目背景 党的二十大报告指出,要加快建设制造强国、数字中国,推动制造业高端化、智能化、…...

lack——主页前后端开发优化(精华:java多线程实现数据插入)
lack——主页前后端开发优化 前端开发主页 最容易的方式:list列表<template><van-cardv-for"user in props.userList":desc"user.profile":title"${user.username} (${user.planetCode})":thumb"user.avatarUrl"…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...