当前位置: 首页 > news >正文

PBR光照模型相关知识

PBR是基于物理的光照模型,与lambert光照模型以及Blinn-Phong光照模型有所不同

一、三种光照模型的区别

原理基础

  • Lambert 光照模型:基于朗伯余弦定律,该定律表明,漫反射光的强度与入射光的方向和物体表面法线的夹角的余弦值成正比。也就是说,当光线垂直照射物体表面时,漫反射光最强;随着入射角增大,漫反射光逐渐减弱。它只考虑了漫反射,认为物体表面是完全粗糙的,光线在表面均匀散射,不考虑光线的反射方向和视角的影响。
  • Blinn - Phong 光照模型:是对 Phong 光照模型的改进。Phong 光照模型将光照效果分为环境光、漫反射光和镜面反射光三部分。Blinn - Phong 模型同样考虑这三部分,但在计算镜面反射时引入了半程向量(光线方向和视线方向的中间向量),通过计算半程向量与物体表面法线的夹角来确定镜面反射的强度,简化了计算过程。
  • PBR 光照模型:基于物理原理,更准确地模拟光线与物体表面的相互作用。它考虑了光的能量守恒、微表面理论和菲涅尔效应等物理现象。PBR 模型将物体表面看作由许多微小的面元组成,每个面元都遵循物理定律进行反射和折射,从而能够更真实地模拟不同材质在不同光照条件下的外观。

表现效果

  • Lambert 光照模型:由于只考虑漫反射,物体表面看起来比较单调、缺乏光泽和立体感。它适用于模拟一些表面粗糙、没有明显高光的物体,如砖块、未经打磨的石头等。但对于需要表现光泽和反射效果的物体,Lambert 模型的效果就显得不够真实。
  • Blinn - Phong 光照模型:引入了镜面反射,能够在物体表面产生高光效果,使物体看起来更有光泽和立体感。通过调整镜面反射的参数(如高光指数),可以控制高光的大小和强度。然而,Blinn - Phong 模型仍然是一种经验模型,其高光效果在某些情况下可能不够真实,尤其是对于金属等具有特殊反射特性的材质。
  • PBR 光照模型:能够提供更加真实和准确的光照效果。它可以模拟不同材质的独特外观,如金属的强反射、塑料的半光泽等。PBR 模型还能更好地处理不同光照条件下的光照变化,使物体在不同环境中都能呈现出自然的外观。例如,在不同的时间和天气条件下,PBR 模型可以更准确地模拟物体的光照效果。

计算复杂度

  • Lambert 光照模型:计算简单,只需要计算光线方向和物体表面法线的点积,因此计算速度快,对硬件性能的要求较低。这使得它在对性能要求较高的场景中(如早期的游戏和一些实时渲染场景)得到广泛应用。
  • Blinn - Phong 光照模型:在 Lambert 模型的基础上增加了镜面反射的计算,计算复杂度有所提高,但仍然相对较低。它在计算效率和表现效果之间取得了一定的平衡,在许多游戏和实时渲染应用中仍然被广泛使用。
  • PBR 光照模型:由于考虑了更多的物理因素,计算复杂度较高。它需要进行更复杂的数学计算,如微表面分布函数、菲涅尔方程的计算等。这使得 PBR 模型在实时渲染中对硬件性能有较高的要求,但随着硬件技术的不断发展,PBR 模型在游戏、电影等领域的应用越来越广泛。

材质参数

  • Lambert 光照模型:主要使用漫反射颜色这一参数来定义物体表面的颜色,参数简单,易于理解和使用。
  • Blinn - Phong 光照模型:除了漫反射颜色外,还需要定义镜面反射颜色和高光指数等参数。高光指数控制高光的大小和强度,不同的高光指数可以模拟出不同光滑程度的物体表面。
  • PBR 光照模型:使用更多的物理参数来定义物体的材质特性,如基础颜色(Albedo)、金属度(Metallic)、粗糙度(Roughness)等。这些参数能够更准确地描述物体的材质属性,使渲染结果更加真实。例如,金属度参数可以区分金属和非金属材质,粗糙度参数可以控制物体表面的光滑程度。

二、PBR光照模型

PBR光照模型的重要公式:

LightingStandard_GI1(o, giInput, gi);   

// 用于计算全局光照中间接光照的漫反射和镜面反射颜色Specular   

// gi.indirect.diffuse ;
// gi.indirect.specular ; 

fixed4 c = LightingStandard1 (o, giInput.worldViewDir, gi);         

// PBR光照模型的核心计算公式,目的是将直接光的漫反射、镜面反射和间接光的漫反射、镜面反射混合     

函数中参数的具体内容:

  • 1.SurfaceOutputStandard o

//初始化SurfaceOutputStandard
SurfaceOutputStandard o;
UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);

fixed4 mainTex =tex2D(_MainTex,i.uv);
//fixed3 Albedo  (基础色 三维向量)
o.Albedo=mainTex*_Color;      // base (diffuse or specular) color

//采样法线贴图
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;

//自发光
o.Emission=0;

//金属度   0=non-metal, 1=metal
fixed4 metallicTex=tex2D(_MetallicTex,i.uv);
o.Metallic=metallicTex.r*_Metallic;  

// 0=rough, 1=smooth
o.Smoothness=metallicTex.g*_Glossiness;    

o.Occlusion=metallicTex.b*_AO;     

o.Alpha=1;      

  •  UnityGI gi

UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);  
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;

gi.light.color = _LightColor0.rgb;
//主平行灯的方向
gi.light.dir = _WorldSpaceLightPos0.xyz;

  • UnityGIInput giInput;

UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = worldPos;
giInput.worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
giInput.atten = atten;
giInput.lightmapUV = 0.0;


LightingStandard_GI1(o, giInput, gi)函数源码:

    //计算间接光照的漫反射inline UnityGI UnityGI_Base1(UnityGIInput data, half occlusion, half3 normalWorld){UnityGI o_gi;ResetUnityGI(o_gi);// Base pass with Lightmap support is responsible for handling ShadowMask / blending here for performance reason#if defined(HANDLE_SHADOWS_BLENDING_IN_GI)half bakedAtten = UnitySampleBakedOcclusion(data.lightmapUV.xy, data.worldPos);float zDist = dot(_WorldSpaceCameraPos - data.worldPos, UNITY_MATRIX_V[2].xyz);float fadeDist = UnityComputeShadowFadeDistance(data.worldPos, zDist);data.atten = UnityMixRealtimeAndBakedShadows(data.atten, bakedAtten, UnityComputeShadowFade(fadeDist));#endifo_gi.light = data.light;o_gi.light.color *= data.atten;#if UNITY_SHOULD_SAMPLE_SHo_gi.indirect.diffuse = ShadeSHPerPixel(normalWorld, data.ambient, data.worldPos);#endif#if defined(LIGHTMAP_ON)// Baked lightmapshalf4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);half3 bakedColor = DecodeLightmap(bakedColorTex);#ifdef DIRLIGHTMAP_COMBINEDfixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);o_gi.indirect.diffuse += DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)ResetUnityLight(o_gi.light);o_gi.indirect.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap (o_gi.indirect.diffuse, data.atten, bakedColorTex, normalWorld);#endif#else // not directional lightmapo_gi.indirect.diffuse += bakedColor;#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)ResetUnityLight(o_gi.light);o_gi.indirect.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap(o_gi.indirect.diffuse, data.atten, bakedColorTex, normalWorld);#endif#endif#endif#ifdef DYNAMICLIGHTMAP_ON// Dynamic lightmapsfixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, data.lightmapUV.zw);half3 realtimeColor = DecodeRealtimeLightmap (realtimeColorTex);#ifdef DIRLIGHTMAP_COMBINEDhalf4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);o_gi.indirect.diffuse += DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normalWorld);#elseo_gi.indirect.diffuse += realtimeColor;#endif#endifo_gi.indirect.diffuse *= occlusion;return o_gi;}//计算间接光照的镜面反射  Unity_GlossyEnvironmentData为之前的准备数据inline half3 UnityGI_IndirectSpecular1(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn){//声明返回的变量specular,用来存储镜面反射的颜色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//当将材质中的reflections的选项去掉时执行下面的语句#ifdef _GLOSSYREFLECTIONS_OFFspecular = unity_IndirectSpecColor.rgb;#else//若开启了reflections的分支half3 env0 = Unity_GlossyEnvironment(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, Unity_GlossyEnvironmentData glossIn){//声明UnityGI类型的变量 o_gi,将最后求得的o_gi赋值给gi//UnityGI_Base函数中计算了全局光照中间接光照的漫反射UnityGI o_gi = UnityGI_Base1(data, occlusion, normalWorld);//计算间接光照的镜面反射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){//声明返回的结构体gUnity_GlossyEnvironmentData g;//粗糙度的计算g.roughness /* perceptualRoughness */ = SmoothnessToPerceptualRoughness1(Smoothness);//反射球的UV采样坐标(R)g.reflUVW = reflect(-worldViewDir, Normal);return g;}//PBR光照模型的全局光照GI中间接光照的漫反射和镜面反射计算inline void LightingStandard_GI1(SurfaceOutputStandard s,UnityGIInput data,inout UnityGI gi){//#if defined(UNITY_PASS_DEFERRED)如果是延迟渲染的Pass则执行下面语句   //&& UNITY_ENABLE_REFLECTION_BUFFERS - render reflection probes in deferred way, when using deferred shading(如果使用延迟渲染的Pass时,使用延迟渲染的方式渲染反射探针)#if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERSgi = UnityGlobalIllumination1(data, s.Occlusion, s.Normal);#else//Unity_GlossyEnvironmentData是镜面反射的准备数据Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic));//进行GI计算并输出gigi = UnityGlobalIllumination1(data, s.Occlusion, s.Normal, g);#endif}

fixed4 c = LightingStandard1 (o, giInput.worldViewDir, gi)函数源码:

    //cosA代表N和V点乘后的结果,视线垂直于物体表面时N·V的结果(cosA的值)最大且接近于1inline half3 FresnelLerp1(half3 F0, half3 F90, half cosA){half t = Pow5(1 - cosA); // ala Schlick interpoliationreturn lerp(F0, F90, t);}//V项计算inline float SmithJointGGXVisibilityTerm1(float NdotL, float NdotV, float roughness){#if 0// Original formulation://  lambda_v    = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;//  lambda_l    = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;//  G           = 1 / (1 + lambda_v + lambda_l);// Reorder code to be more optimalhalf a          = roughness;half a2         = a * a;half lambdaV    = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);half lambdaL    = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);// Simplify visibility term: (2.0f * NdotL * NdotV) /  ((4.0f * NdotL * NdotV) * (lambda_v + lambda_l + 1e-5f));return 0.5f / (lambdaV + lambdaL + 1e-5f);  // This function is not intended to be running on Mobile,// therefore epsilon is smaller than can be represented by half#else// Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)float a = roughness;float lambdaV = NdotL * (NdotV * (1 - a) + a);float lambdaL = NdotV * (NdotL * (1 - a) + a);#if defined(SHADER_API_SWITCH)return 0.5f / (lambdaV + lambdaL + UNITY_HALF_MIN);#elsereturn 0.5f / (lambdaV + lambdaL + 1e-5f);#endif#endif}//D项计算inline float GGXTerm1(float NdotH, float roughness){float a2 = roughness * roughness;float d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad//加上1*e的-7次方可以使得分母不为0return UNITY_INV_PI * a2 / (d * d + 1e-7f); // This function is not intended to be running on Mobile,// therefore epsilon is smaller than what can be represented by half}//求解roughnessfloat PerceptualRoughnessToRoughness1(float perceptualRoughness){return perceptualRoughness * perceptualRoughness;}//使得归一化向量安全求解inline float3 Unity_SafeNormalize1(float3 inVec){// normalize(v) = rsqrt(dot(v,v))*v;float dp3 = max(0.001f, dot(inVec, inVec));    //使得根号下dot(v,v)的值>0  (使得归一化的值更安全)return inVec * rsqrt(dp3);}//F0是在限定条件下折射和反射的比例,也称为反射率inline half3 FresnelTerm1(half3 F0, half cosA){half t = Pow5(1 - cosA); // ala Schlick interpoliationreturn F0 + (1 - F0) * t;}//计算直接光的漫反射分布系数half DisneyDiffuse1(half NdotV, half NdotL, half LdotH, half perceptualRoughness){half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;     //fd90指的是视线向量与法线向量呈90度夹角// Two schlick fresnel termhalf lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));return lightScatter * viewScatter;}half4 BRDF1_Unity_PBS1(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,float3 normal, float3 viewDir,UnityLight light, UnityIndirect gi){float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);   //return (1 - smoothness);float3 halfDir = Unity_SafeNormalize1(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 term 迪士尼漫反射half diffuseTerm = DisneyDiffuse1(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 = PerceptualRoughnessToRoughness1(perceptualRoughness);//GGX具有比较好的效果#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 = SmithJointGGXVisibilityTerm1(nl, nv, roughness);float D = GGXTerm1(nh, roughness);#else// Legacy//half V = SmithBeckmannVisibilityTerm(nl, nv, roughness);// half D = NDFBlinnPhongNormalizedTerm(nh, PerceptualRoughnessToSpecPower(perceptualRoughness));#endif//由于直接光的漫反射强度计算中未除以Pi,所以在镜面反射的计算时需乘以pi以平衡float specularTerm = V * D * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later//若处于Gamma空间时,进行下面计算#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);   //乘以法线与入射光的点乘结果//若关闭镜面高光时,使specularTerm = 0.0#if defined(_SPECULARHIGHLIGHTS_OFF)specularTerm = 0.0;#endif// surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(roughness^2+1)half surfaceReduction;//若在Gamma空间#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 diffuse = diffColor * (gi.diffuse + light.color * diffuseTerm); // diffColor=s.Albedo(贴图颜色)// 镜面反射 = DV * 灯光颜色 * Fhalf3 specular = specularTerm * light.color * FresnelTerm1(specColor, lh);// IBL  用于计算间接光照下的镜面反射效果  // surfaceReduction通常与物体表面的粗糙度相关,粗糙度越高,表面的微表面结构越复杂,反射光越分散,surfaceReduction 的值可能越小;粗糙度越低,表面越光滑,反射光越集中,surfaceReduction 的值可能越大half3 ibl= surfaceReduction * gi.specular * FresnelLerp1(specColor, grazingTerm, nv);half3 color = diffuse + specular + ibl;return half4(color, 1);   //最终的颜色效果}#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_PBS BRDF3_Unity_PBS   // 效果最差的BRDF#elif defined(UNITY_PBS_USE_BRDF3)#define UNITY_BRDF_PBS BRDF3_Unity_PBS   #elif defined(UNITY_PBS_USE_BRDF2)#define UNITY_BRDF_PBS BRDF2_Unity_PBS#elif defined(UNITY_PBS_USE_BRDF1)#define UNITY_BRDF_PBS1 BRDF1_Unity_PBS1#else#error something broke in auto-choosing BRDF  //#error作用:进行报错并使得编译失败#endif#endifinline half OneMinusReflectivityFromMetallic1(half metallic){// We'll need oneMinusReflectivity, so//   1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic) // lerp(dielectricSpec, 1, metallic)为物体高光反射率的计算公式,dielectricSpec为非金属的反射率,1为金属的反射率// lerp(A,B,v)=A+v(B-A);// 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){// specColor:镜面高光颜色// lerp(A, B, alpha) 若alpha = 0 则返回A; 若alpha = 1 则返回B; alpha在0-1之间时,返回A与B之间的混合值// 当metallic=0(非金属/绝缘体),返回unity_ColorSpaceDielectricSpec.rgb; half4(0.04,0.04,0.04,1.0-0.04) (非金属的反射率≈0.04)// unity_ColorSpaceDielectricSpec.rgb表示非金属、绝缘体的通用反射颜色,用0.04来表示反射颜色、反射率// 当metallic=1(金属),返回albedo;也就是物体本身的颜色信息specColor = lerp(unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);//计算1-反射率oneMinusReflectivity = OneMinusReflectivityFromMetallic1(metallic);//返回物体的基础颜色贴图乘以(1-反射率=漫反射率)return albedo * oneMinusReflectivity;}// PBR的核心计算inline half4 LightingStandard1(SurfaceOutputStandard s, float3 viewDir, UnityGI gi)// s = 模型表面的数据信息 // viewDir = 视线方向 // gi = 全局光照{s.Normal = normalize(s.Normal);half oneMinusReflectivity;half3 specColor;// 该函数的作用是计算s.Albedo; 然后分别计算并输出specColor和oneMinusReflectivitys.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的值 :/*out*/outputAlphahalf outputAlpha;s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/outputAlpha);// s.Albedo = 物体表面的基础颜色// specColor = 镜面反射颜色// oneMinusReflectivity = 漫反射率// s.Smoothness = 物体表面的光滑度// s.Normal = 物体表面的法线// viewDir = 视线的方向// gi.light = 直接光信息// gi.indirect = 间接光信息half4 c = UNITY_BRDF_PBS1(s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);c.a = outputAlpha;return c;}

  三、解析PBR光照模型 

1.总漫反射

 half3 diffuse = diffColor * (gi.diffuse + light.color * diffuseTerm);

 // 总漫反射 = 贴图颜色 * (间接光漫反射+灯光颜色*直接光漫反射系数/强度)

 //diffColor = s.Albedo(贴图颜色)      

2.直接光镜面反射

// 直接光镜面反射 = DV * 灯光颜色 * F
half3 specular = specularTerm * light.color * FresnelTerm1(specColor, lh); 

接下来看一下Blinn-Phong光照模型的直接光镜面反射与PBR光照模型有何区别:

其中,Blinn-Phong 光照模型将光照效果分为环境光、漫反射光和镜面反射光三部分

Cdiff:漫反射颜色

Cspec:高光颜色/镜面反射颜色

m:用来控制高光的范围,m越大,高光的范围越小,光斑越集中

同时可将上面的公式换为以下公式:

之后对上述公式的参数进行一定的调整

在修改后的公式中镜面反射增加了m+8/8π,可以解决当m增大时,光斑越集中而其颜色没有相应的变亮的问题;乘以N·L可以使当物体表面处于背光面时使得高光变暗

上面公式中括号内的即为基于Blinn-Phong的BRDF公式

以上公式是一个简化的基于经验的 BRDF(双向反射分布函数)公式,常用于传统光照模型(如 Blinn - Phong),它与 PBR(基于物理的渲染)中的 BRDF 公式相比,存在以下缺点:

物理准确性:

  • 简化的光学模型(没有考虑到微平面理论):该公式中的漫反射部分只是简单地将漫反射颜色除以,基于朗伯漫反射模型,它假设物体表面是完全均匀且各向同性的漫反射体,没有考虑微表面结构等真实物理因素对漫反射的影响。而 PBR 的 BRDF 公式(如基于微表面理论的 Cook - Torrance BRDF)考虑了表面的微观几何结构,能更准确地描述光线在实际粗糙表面的散射情况。
  • 菲涅尔效应处理不足:在提供的公式的镜面反射部分,没有显式地考虑菲涅尔效应,即光线在不同入射角下反射和折射比例的变化。PBR 的 BRDF 公式会精确地结合菲涅尔方程,能够准确地模拟不同材质在不同角度下反射光的强度变化,比如金属在掠射角下反射光增强的现象。

材质表现能力:

  • 参数单一性:该公式仅通过漫反射颜色和镜面反射颜色以及高光指数来描述材质反射特性,对于复杂材质的表现能力有限。PBR 的 BRDF 公式通常使用更多基于物理的参数,如金属度、粗糙度等,能够更细致地表现各种材质,如区分金属与非金属材质,以及不同粗糙度表面的反射差异。
  • 缺乏各向异性支持:此公式默认材质是各向同性的,即反射特性在各个方向上相同。而 PBR 的 BRDF 可以支持各向异性材质的模拟,比如拉丝金属、头发等具有方向依赖反射特性的材质。

能量守恒:

  • 潜在的能量不守恒:在某些情况下,该经验公式可能无法严格保证能量守恒。例如,当高光指数和反射颜色设置不当时,可能会导致反射光的能量超过入射光的能量。而 PBR 的 BRDF 公式基于物理原理推导,在理论上能够保证能量守恒,确保渲染结果的合理性。

光照一致性:

  • 难以处理复杂光照环境:该公式在处理间接光照、多次反射等复杂光照场景时表现不佳。PBR 的 BRDF 公式可以更好地与全局光照算法集成,准确地模拟光线在场景中的多次反弹和间接光照效果,从而在各种光照条件下提供更一致和真实的渲染结果。

而对于PBR光照模型中的BRDF公式则考虑到了微平面理论(法线分布函数D、可见性函数V)、菲尼尔效果F以及能量守恒等各种问题,从而使得模型具有更复杂且更真实的材质效果

  • 法线分布函数(D)

由于物体表面非绝对光滑,而是由大量微小的面元组成。这些微观面元的法线方向各不相同,法线分布函数用于描述这些微表面法线的分布情况。比如金属表面看似光滑,但在微观尺度下有许多不规则起伏。通过法线分布函数,可以精确刻画不同材质表面微结构的差异,进而准确模拟光线与这些微表面的相互作用,使渲染出的物体更接近真实外观。

法线分布函数在计算镜面反射的过程中起着关键作用,它决定了有多少微表面的法线方向与半程向量h(入射光方向和视线方向的中间向量)接近,从而对镜面反射有贡献。微表面法线与半角向量方向越接近,该微表面对镜面反射的贡献越大;因为只要半角向量和微表面法线越接近,反射光线就有可能进入观察者的视线,并且越接近,反射光线进入视线的概率和强度就越大。

  • 可见性函数(V)

由于自身的遮挡,有很多点根本无法接受到入射光线,也有很多点反射的光线无法射出表面。因此,我们此处再定义一个函数叫“可见性函数”,用V表示。它的作用就是根据给定的入射光线和出射光线的方向,计算出不被自身遮挡的光线的比例

在源码中D和V的计算:

half3 specular = specularTerm * light.color * FresnelTerm1(specColor, lh);

//由于直接光的漫反射强度计算中未除以Pi,所以在镜面反射的计算时需乘以pi以平衡
float specularTerm = V * D * UNITY_PI;

  • 菲尼尔系数(F)

光垂直射向表面时,折射光线最多,反射光线最少;相反当入射光线与法线的夹角越大,反射的光线越多,折射的光线越少

例如,我们能够看见水底下或者玻璃后的东西,那肯定是光线发生了折射所导致的。而对于水面上的倒影或者是玻璃变得像镜子一样这些都是因为光线发生了反射所导致的。

F0 是当入射光线垂直照射到物体表面时,物体的反射率

根据F0求得菲尼尔方程F:

图中代表的是折射率为1.5的绝缘体(例如某种玻璃)的反射情况。可以发现当夹角为0时,即入射光垂直于表面,反射光的比例只有4%左右,而当夹角为90度时,即入射光平行于表面,反射比例将近100%,符合我们前面所说的菲涅尔效应。

上图代表一导体的反射率,光线垂直于导体表面,有90%的光被反射(反射率较高)。这也证实了为什么我们可以用铜来做镜子,却没法使用玻璃来做镜子


​​​​​​​菲涅尔方程(Fresnel Equation) - 知乎 (zhihu.com)

PBR物理光照计算公式推导详解_引擎中的pbr公式-CSDN博客


3.间接光镜面反射 

half3 ibl= surfaceReduction * gi.specular * FresnelLerp1(specColor, grazingTerm, nv);     

// IBL :用于计算间接光照下的镜面反射效果  

surfaceReduction 通常与物体表面的粗糙度相关,粗糙度越高,表面的微表面结构越复杂,反射光越分散,surfaceReduction 的值可能越小;粗糙度越低,表面越光滑,反射光越集中,surfaceReduction 的值可能越大

//若在Gamma空间
#ifdef UNITY_COLORSPACE_GAMMA
        surfaceReduction = 1.0-0.28*roughness*perceptualRoughness;     
//若在线性空间
#else
        surfaceReduction = 1.0 / (roughness * roughness + 1.0);
#endif


FresnelLerp1(specColor, grazingTerm, nv) :

//cosA=v·h / l·h,视线垂直于物体表面时H·V的结果(cosA的值)最大且接近于1
 inline half3 FresnelLerp1(half3 F0, half3 F90, half cosA)
 {
     half t = Pow5(1 - cosA); // ala Schlick interpoliation
     return lerp(F0, F90, t);
 }

四、PBR光照模型代码

Shader "unity/PBR"
{Properties{_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}//金属度贴图_MetallicTex("Metallic(R) Smoothness(G) AO(B)",2D)="white"{}//法线贴图_NormalTex("Noraml",2D)="bump"{}//粗糙度调节杆_Glossiness ("Smoothness", Range(0,1)) = 0.5//金属度调节杆_Metallic ("Metallic", Range(0,1)) = 0.0//AO调节杆_AO ("AO", Range(0,1)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 200// ---- forward rendering base pass:Pass {Name "FORWARD"Tags { "LightMode" = "ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma target 3.0//GPU实例化//#pragma multi_compile_instancing#pragma multi_compile_fog#pragma multi_compile_fwdbase//渲染优化 (如果没有定义GPU实例化则执行下面代码)#include "UnityCG.cginc"#include "Lighting.cginc"#include "UnityPBSLighting.cginc"#include "AutoLight.cginc"//引用自定义的cginc文件#include"../CGIncludes/MyPBRRendering.cginc"sampler2D _MainTex;float4 _MainTex_ST;sampler2D _NormalTex;sampler2D _MetallicTex;half _Glossiness;half _Metallic;fixed4 _Color;half _AO;struct appdate{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};struct v2f {float4 pos:SV_POSITION;float2 uv : TEXCOORD0; // _MainTexfloat3 worldNormal : TEXCOORD1;float3 worldPos : TEXCOORD2;#if UNITY_SHOULD_SAMPLE_SHhalf3 sh : TEXCOORD3; // SH#endifUNITY_FOG_COORDS(4)UNITY_SHADOW_COORDS(5)float3 tSpace0:TEXCOORD6;float3 tSpace1:TEXCOORD7;float3 tSpace2:TEXCOORD8;};// vertex shaderv2f vert (appdate v) {v2f o;//初始化UNITY_INITIALIZE_OUTPUT(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);//计算切线空间fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;fixed3 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;//球谐光照计算#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); // pass shadow and, possibly, light cookie coordinates to pixel shaderUNITY_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;//初始化SurfaceOutputStandardSurfaceOutputStandard o;UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);fixed4 mainTex =tex2D(_MainTex,i.uv);//fixed3 Albedo  (基础色 三维向量)o.Albedo=mainTex*_Color;      // base (diffuse or specular) color//采样法线贴图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;//自发光o.Emission=0;//金属度   0=non-metal, 1=metalfixed4 metallicTex=tex2D(_MetallicTex,i.uv);o.Metallic=metallicTex.r*_Metallic;  // 0=rough, 1=smootho.Smoothness=metallicTex.g*_Glossiness;    o.Occlusion=metallicTex.b*_AO;     o.Alpha=1;      // 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;//UnityGIInput giInput;UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);giInput.light = gi.light;giInput.worldPos = worldPos;giInput.worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));giInput.atten = atten;giInput.lightmapUV = 0.0;//如果开启球谐#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXELgiInput.ambient = i.sh;#elsegiInput.ambient.rgb = 0.0;#endif//对CubeMap进行解码的数据giInput.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_PROJECTION// giInput.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);// realtime lighting: call lighting function//PBS的核心计算(参数o:模型的表面数据,例如表面颜色、法线、自发光等; gi参数:与全局光照有关的数据)fixed4 c= LightingStandard1 (o, giInput.worldViewDir, gi);//雾效的应用 // apply fogUNITY_APPLY_FOG(_unity_fogCoord, c); //使得c.a=1UNITY_OPAQUE_ALPHA(c.a);return c;}ENDCG}#LINE 50}
}

PBR材质详解_哔哩哔哩_bilibili      —可以参考此视频

 其中_MetallicTex贴图的红绿蓝通道分别为金属度贴图、粗糙度贴图、AO贴图

如何将Standard Surface Shader 转换为 Unlit Shader?

选中创建后的Standard Surface Shader,点击右侧的Show generated code可将Surface Shader编译为顶点片元Shader

然后将编译后的代码复制到创建好的Standard Surface Shade中,然后进行修改

相关文章:

PBR光照模型相关知识

PBR是基于物理的光照模型&#xff0c;与lambert光照模型以及Blinn-Phong光照模型有所不同 一、三种光照模型的区别 原理基础 Lambert 光照模型&#xff1a;基于朗伯余弦定律&#xff0c;该定律表明&#xff0c;漫反射光的强度与入射光的方向和物体表面法线的夹角的余弦值成正比…...

【Go | 从0实现简单分布式缓存】-2:HTTP服务端与一致性哈希

本文目录 一、回顾1.1 复习接口 二、http标准库三、实现HTTP服务端四、一致性哈希 本文为极客兔兔“动手写分布式缓存GeeCache”学习笔记。 一、回顾 昨天已经开发了一部分项目&#xff0c;我们先来看看项目结构。 分布式缓存需要实现节点间通信&#xff0c;建立基于 HTTP 的…...

STM32 低功耗模式

目录 背景 低功耗模式 睡眠模式 进入睡眠模式 退出睡眠模式 停止模式 进入停止模式 退出停止模式 待机模式 进入待机模式 退出待机模式 程序 睡眠模式 休眠模式配置 进入休眠模式 退出睡眠模式 停止模式 停止模式配置 进入停止模式 退出停止模式 待机模式…...

AI 百炼成神:逻辑回归, 垃圾邮件分类

第二个项目:逻辑回归垃圾邮件分类 项目代码下载地址:https://download.csdn.net/download/m0_56366541/90398247 项目目标 学习逻辑回归的基本概念。使用逻辑回归算法来实现垃圾邮件的分类。理解如何处理文本数据以及如何评估分类模型的性能。项目步骤 准备数据集 我们将使…...

#渗透测试#批量漏洞挖掘#Apache Log4j反序列化命令执行漏洞

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 Apache Log4j反序列化命令执行漏洞 一、…...

Docker__持续更新......

Docker 1. 基本知识1.1 为什么有Docker?1.2 Docker架构与容器化 画图解释 画图解释2. 项目实战 1. 基本知识 1.1 为什么有Docker? 用一行命令跨平台安装项目&#xff0c;在不同平台上运行项目。把项目打包分享运行应用。 1.2 Docker架构与容器化 准备机器&#xff0c;在机…...

什么是语料清洗、预训练、指令微调、强化学习、内容安全; 什么是megatron,deepspeed,vllm推理加速框架

什么是语料清洗、预训练、指令微调、强化学习、内容安全 目录 什么是语料清洗、预训练、指令微调、强化学习、内容安全语料清洗预训练指令微调强化学习内容安全什么是megatron,deepspeed,vllm推理加速框架语料清洗 语料清洗是对原始文本数据进行处理的过程,旨在去除数据中的…...

Ubuntu虚拟机NDK编译ffmpeg

目录 一、ffmpeg源码下载1、安装git(用于下载ffmpeg源码)2、创建源码目录&#xff0c;下载ffmpeg源码 二、下载ubuntu对应的NDK&#xff0c;并解压到opt下1、下载并解压2、配置 ~/.bashrc 三、源码编译、1、创建编译脚本2、脚本文件内容3、设置可执行权限并运行4、编译的结果在…...

SQLAlchemyError: A transaction is already begun on this Session.

资料 sqlalchemy 事务 - 简书 在 SQLAlchemy 中&#xff0c;事务是通过会话来管理的。当你开始一个事务&#xff08;例如使用 async with db.begin()&#xff09;&#xff0c;它会开启一个新的事务&#xff0c;并在事务块结束时自动提交或回滚。如果在同一个会话中&#xff0c…...

STM32 HAL库USART串口DMA IDLE中断编程:避坑指南

HAL_UART_Receive接收最容易丢数据了,STM32 HAL库UART查询方式实例 可以考虑用中断来实现,但是HAL_UART_Receive_IT还不能直接用,容易数据丢失,实际工作中不会这样用,STM32 HAL库USART串口中断编程&#xff1a;演示数据丢失, 需要在此基础优化一下. STM32F103 HAL库USART串口…...

打造一个有点好看的 uniapp 网络测速软件

大家好&#xff0c;我是一名前端小白。今天想和分享一个有点好看的网络测速 uniapp 组件的实现过程。这个组件不仅外观精美&#xff0c;而且具有完整的功能性&#xff0c;是一个非常适合学习和实践的案例。 设计理念 在开始coding之前&#xff0c;先聊聊设计理念。一个好的测…...

DeepSeek AI 视频创作完整指南:从注册到制作

DeepSeek AI 视频创作完整指南&#xff1a;从注册到制作 前言 DeepSeek作为国产AI的新星&#xff0c;不仅在代码能力上表现出色&#xff0c;在创意内容生成方面同样令人惊艳。本教程将带您从注册到实操&#xff0c;完整体验DeepSeek的强大功能。 第一步&#xff1a;获取Deep…...

DeepSeek学术指南:DeepSeek在学术翻译改写能力应用操作案例!

DeepSeek&#xff1a;助力学术研究的智能工具 DeepSeek作为一种先进的智能工具&#xff0c;为学术研究提供了强大的支持。它不仅能够处理复杂的学术文本&#xff0c;还能在翻译和润色方面表现出色&#xff0c;极大地提高了学术写作的效率和质量。通过其强大的语言处理能力&…...

栈回溯基础

指令集区分 thumb指令集 长度&#xff1a;thumb指令通常是 16 位。特点&#xff1a;thumb 指令集是为了压缩指令集长度减少程序占用空间。对齐方式&#xff1a;2字节对齐&#xff0c;存放 thumb 指令的地址一般会被1&#xff0c;设置为奇数&#xff0c;用于表示地址上存放的是…...

JavaScript系列(76)--浏览器API深入

JavaScript浏览器API深入 &#x1f310; 浏览器提供了丰富的API&#xff0c;使JavaScript能够与浏览器环境进行交互。本文将深入探讨常用的浏览器API、最佳实践和性能优化技巧。 核心浏览器API &#x1f31f; &#x1f4a1; 小知识&#xff1a;浏览器API是连接JavaScript与浏…...

计算机网络(3)TCP格式/连接

1、TCP三大特点&#xff1a;面向连接、可靠、基于字节流 2、如何唯一确定一个TCP连接&#xff1f;TCP四元组&#xff1a;源地址、源端口、目的地址、目的端口 源地址和目标地址的字段(32 位)是在 IP 头部中&#xff0c;作用是通过 IP 协议发送报文给对方主机源端口和目标端口…...

下载安装运行测试开源vision-language-action(VLA)模型OpenVLA

1. 安装 项目官网OpenVLA 首先按照官网提示的以下代码&#xff0c;执行创建环境->安装最小依赖->git克隆项目等 # Create and activate conda environment conda create -n openvla python3.10 -y conda activate openvla# Install PyTorch. Below is a sample comma…...

3D与2D机器视觉机械臂引导的区别

3D与2D机器视觉在机械臂引导中的主要区别如下&#xff1a; 数据维度 2D视觉&#xff1a;仅处理平面图像&#xff0c;提供X、Y坐标信息&#xff0c;无法获取深度&#xff08;Z轴&#xff09;数据。 3D视觉&#xff1a;处理三维空间数据&#xff0c;提供X、Y、Z坐标及物体的姿态…...

网站搭建基本流程

需求分析&#xff1a; 实现网站搭建的过程&#xff1a;首先进行网站的需求性分析 网站可分为前台系统和后台系统&#xff0c;由不同的功能拆分为不同的模块 如下是一个电商网站可以拆分出的模块&#xff1a; 在编写代码前&#xff0c;我们要先对网站进行架构&#xff0c;通过…...

SpringBoot启动时报错:cannot use an unresolved DNS server address: I:53

报错如下&#xff1a; 2025-02-17 13:59:41.374 [main] ERROR org.springframework.boot.SpringApplication:835 - Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name mySwaggerResourceProvider def…...

Ollama命令使用指南

Ollama 命令使用指南 Ollama 命令使用指南1. Ollama 命令概览2. Ollama 命令详解2.1 启动 Ollama2.2 创建模型2.3 查看模型信息2.4 运行模型2.5 停止运行的模型2.6 从注册表拉取模型2.7 推送模型到注册表2.8 列出本地模型2.9 查看正在运行的模型2.10 复制模型2.11 删除模型 3. …...

每日一题——将数字字符串转化为IP地址

将数字字符串转化为IP地址 题目描述解题思路回溯法步骤分解 代码实现全局变量有效性验证函数回溯函数主函数完整代码 复杂度分析关键点说明总结 这题难度还挺大的&#xff0c;整体上实现并不容易。建议参考视频 和https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%…...

2013年下半年软件设计师上午题考察知识点及其详细解释(附真题及答案解析)

以下是2013年下半年软件设计师上午题的所有题目&#xff08;从第1题到第75题&#xff09;的总结&#xff0c;按顺序列出每道题目的考察知识点及其详细解释&#xff0c;供考生背诵记忆&#xff1a; 1. Cache与主存的地址映像 知识点&#xff1a;存储管理解释&#xff1a;Cache与…...

实现可拖拽的 Ant Design Modal 并保持下层 HTML 可操作性

前言 在开发复杂的前端界面时&#xff0c;我们常常需要一个可拖拽的弹窗&#xff08;Modal&#xff09;&#xff0c;同时又希望用户能够在弹窗打开的情况下操作下层的内容。Ant Design 的 Modal 组件提供了强大的功能&#xff0c;但默认情况下&#xff0c;弹窗会覆盖整个页面&…...

unity学习43:子状态机 sub-state machine

目录 1sub-state machine子状态机 1.1 创建 sub-state machine 1.2 sub-state machine 内容 1.3 子状态机的应用 2 子状态机不同于blend tree的嵌套 3 应用例子&#xff1a;若角色拿不同武器的动画设计&#xff0c;可以使用2种方法 3.1 在1个图层layer里&#xff0c;使用…...

HTML之JavaScript DOM(document)编程处理事件

HTML之JavaScript DOM&#xff08;document&#xff09;编程处理事件 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...

线性模型 - Logistic 回归

Logistic 回归(Logistic Regression&#xff0c;LR)是一种常用的处理二分类问题的 线性模型。 Logistic 回归是一种用于二分类问题的统计模型&#xff0c;它通过将输入特征的线性组合映射到一个概率值来进行分类决策。 Logistic回归是机器学习中最经典的分类算法之一&#xf…...

分割 学习笔记cvpr2024

目录 LiteMedSam 模型37m LightM-Unet 500 str 依赖项: MLWnet 73 star memsam 340M 126 star LiteMedSam 模型37m https://github.com/bowang-lab/MedSAM/blob/LiteMedSAM/README.md LightM-Unet 500 str https://github.com/MrBlankness/LightM-UNet/blob model = Li…...

ShenNiusModularity项目源码学习(9:项目结构)

ShenNiusModularity源码主要有11个project&#xff08;其实还有officialweb、test两个文件夹&#xff0c;大致有4、5个project&#xff0c;但看着跟主要项目代码没太大关系&#xff0c;暂时不管&#xff09;&#xff0c;这11个project的依赖关系如下图所示&#xff0c;其中最下…...

【复现DeepSeek-R1之Open R1实战】系列6:GRPO源码逐行深度解析(上)

目录 4 GRPO源码分析4.1 数据类 GRPOScriptArguments4.2 系统提示字符串 SYSTEM_PROMPT4.3 奖励函数4.3.1 accuracy_reward函数4.3.2 verify函数4.3.3 format_reward函数 4.4 将数据集格式化为对话形式4.5 初始化GRPO Trainer 【复现DeepSeek-R1之Open R1实战】系列3&#xff1…...

【LangChain实践开发】如何对大模型I/O封装?

LangChain 的核心组件 模型 I/O 封装 LLMs&#xff1a;大语言模型Chat Models&#xff1a;一般基于 LLMs&#xff0c;但按对话结构重新封装PromptTemple&#xff1a;提示词模板OutputParser&#xff1a;解析输出 数据连接封装 Document Loaders&#xff1a;各种格式文件的加载…...

LangChain4j

LangChain4j 是一个基于 Java 的框架&#xff0c;旨在简化与大型语言模型&#xff08;LLMs&#xff09;的集成和应用开发。它类似于 Python 的 LangChain 框架&#xff0c;但专为 Java 开发者设计&#xff0c;提供了构建基于 LLM 的应用程序所需的工具和组件。 主要功能 LLM …...

如何系统成为高级Qt工程师?

要系统性地成为高级Qt工程师,需要从基础到进阶逐步构建知识体系,并结合实战经验、源码分析和架构设计能力的提升。以下是分阶段的系统性学习路径和建议: 一、夯实基础阶段 C++深度掌握 精通C++11/14/17特性(智能指针、lambda、移动语义等)理解面向对象设计、设计模式(如观…...

LLM 架构

LLM 分类 : 自编码模型 (encoder) : 代表模型 : BERT自回归模型 (decoder) : 代表模型 : GPT序列到序列模型 (encoder-decoder) : 代表模型 : T5 自编码模型 (AutoEncoder model , AE) 代表模型 : BERT (Bidirectional Encoder Representation from Transformers)特点 : Enc…...

MVTEC数据集笔记

前言 网上的博客只有从论文里摘出的介绍&#xff0c;没有数据集文件详细的样子&#xff0c;下载数据集之后&#xff0c;对数据集具体的构成做一个补充的笔记。 下载链接&#xff1a;https://ai-studio-online.bj.bcebos.com/v1/7d4a3cf558254bbaaf4778ea336cb14ed8bbb96a7f2a…...

[算法学习笔记]1. 枚举与暴力

一、枚举算法 定义 枚举是基于已有知识来猜测答案的问题求解策略。即在已知可能答案的范围内&#xff0c;通过逐一尝试寻找符合条件的解。 2. 核心思想 穷举验证&#xff1a;对可能答案集合中的每一个元素进行尝试终止条件&#xff1a;找到满足条件的解&#xff0c;或遍历完…...

javacv将mp4视频切分为m3u8视频并播放

学习链接 ffmpeg-demo 当前对应的 gitee代码 Spring boot视频播放(解决MP4大文件无法播放)&#xff0c;整合ffmpeg,用m3u8切片播放。 springboot 通过javaCV 实现mp4转m3u8 上传oss 如何保护会员或付费视频&#xff1f;优酷是怎么做的&#xff1f; - HLS 流媒体加密 ffmpe…...

docker 进阶命令(基于Ubuntu)

数据卷 Volume: 目录映射, 目录挂载 匿名绑定: 匿名绑定的 volume 在容器删除的时候, 数据卷也会被删除, 匿名绑定是不能做到持久化的, 地址一般是 /var/lib/docker/volumes/xxxxx/_data 绑定卷时修改宿主机的目录或文件, 容器内的数据也会同步修改, 反之亦然 # 查看所有 vo…...

鸿蒙(HarmonyOS)开发学习路线指南:从零到实战

随着鸿蒙生态的快速发展&#xff0c;HarmonyOS 已成为物联网时代的重要开发平台。其分布式架构和“一次开发、多端部署”的理念吸引了大量开发者。本文将从零开始梳理鸿蒙开发的学习路径&#xff0c;帮助开发者高效掌握核心技能。 一、学习路线概览 总目标&#xff1a;掌握鸿蒙…...

小白win10安装并配置yt-dlp

需要yt-dlp和ffmpeg 注意存放路径最好都是全英文 win10安装并配置yt-dlp 一、下载1.下载yt-dlp2. fffmpeg下载 二、配置环境三、cmd操作四、yt-dlp下视频操作 一、下载 1.下载yt-dlp yt-dlp地址 找到win的压缩包点下载&#xff0c;并解压 2. fffmpeg下载 ffmpeg官方下载 …...

CUBEAI详细使用教程(STM32运行神经网络)---以手写识别为例

系列文章目录 文章目录 系列文章目录前言一、CUBEMX配置步骤二、模型结构及模型存储方式三、常用API函数1.ai_(name)_create()2.ai_(name)_init3.ai_(name)_create_and_init()3.ai_(name)_run()官方提供的示例代码 四、如何获取官方开发文档五、手写识别案例 前言 实验效果&am…...

[NOIP 1998 提高组] 拼数

https://www.luogu.com.cn/problem/P1012 将每个数用字符串的形式读进来&#xff0c;对于任意两个数 x x x, y y y&#xff0c;如果 x y > y x xy>yx xy>yx&#xff0c;对最后的答案来说&#xff0c; x x x一定排在 y y y的前面。 简单证明&#xff1a;假设最后的…...

PHP Web 开发基础

PHP 学习资料 PHP 学习资料 PHP 学习资料 在 PHP Web 开发领域&#xff0c;掌握一些基础概念和技术是构建功能强大、用户体验良好的 Web 应用的基石。接下来&#xff0c;我们将深入探讨 HTTP 协议、表单处理、Cookie 和 Session 的管理、URL 处理等关键内容。 一、HTTP 协议…...

MME-CoT:专为评估大型多模态模型CoT推理能力的基准测试。涵盖了数学、科学、OCR、逻辑、时空和一般场景6个领域。

2025-02-09 &#xff0c;由CUHK MMLab、CUHK MulLab、字节跳动、、东北大学等机构联合发布MME-CoT数据集&#xff0c;该数据集目的评估大型多模态模型&#xff08;LMMs&#xff09;中的思维链&#xff08;CoT&#xff09;推理能力&#xff0c;涵盖数学、科学、OCR、逻辑、时空和…...

HDFS应用-后端存储cephfs-java-API

HDFS(Hadoop Distribute FileSystem)是一个适合运行在通用硬件之上,具备高度容错特性,支持高吞吐量数据访问的分布式文件系统,非常适合大规模数据集应用。 HDFS适用于如下场景: • 处理海量数据(TB或PB级别以上) • 需要很高的吞吐量 • 需要高可靠性 • 需要很好的可扩…...

A与B组件自动对齐与组装,无映射直接补偿。

网上针对组装的从视觉到控制动作,要不就是收费,要不就是简单介绍。这么详细的比较难找~ 手下留情,不喜勿喷! Show time~ 分步解决方案: 标定阶段(Calibration) 9点张氏标定(每个位置A1、A2、B1、B2): 使用机械手在相机视野内沿Z字形路径移动,覆盖9个点(XY方…...

SQL知识体系

SQL复习 MySQL SQL介绍 SQL SQL的全拼是什么&#xff1f; SQL全拼&#xff1a;Structured Query Language&#xff0c;也叫结构化查询语言。 SQL92和SQL99有什么区别呢&#xff1f; SQL92和SQL99分别代表了92年和99年颁布的SQL标准。 在 SQL92 中采用&#xff08;&#xff…...

编译安装php

前置准备 这里的可能不全&#xff0c;每个人安装的模块不一致&#xff0c;依赖也不不相同&#xff0c;按实际情况调整 yum install libxml2 -y yum install libxml2-devel -y yum install openssl-devel -y yum install sqlite-devel -y yum install libcurl-devel -yyum ins…...

【分果果——DP(困难)】

题目 分析 分果果题解参考&#xff0c;下面是补充https://blog.csdn.net/AC__dream/article/details/129431299 关于状态 设f[i][j][k]表示第i个人取到的最后一个糖果编号是j&#xff0c;第i-1个人取到的最后一个糖果编号小于等于k时的最大重量的最小值 关于转移方程 关于 j …...

利用ffplay播放udp组播视频流

ffplay -fs -fflags nobuffer -flags low_delay -analyzeduration 0 -probesize 32 -framedrop -sync ext -strict experimental udp://224.1.1.1:5001 -fs : 全屏显示 -fflags nobuffer &#xff1a; 禁用输入缓冲&#xff08;减少100-200ms缓冲延迟&#xff09; -an…...