【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】
Unity Build-In管线的SurfaceShader剖析
- 在Unity Build-In 管线(Universal Render Pipeline)
- 新建一个Standard Surface Shader
- 文件里的代码如下:
- 选中"MyPBR.Shader",在Inspector面板,打开"Show generated code"
- 跳转到VScode,这里有1677行代码
- 将其复制到shader文件里。
- PASS
- 删除不用的pass后的大致结构
- FallBack "Diffuse"的作用
- 包含文件
- 判断语句
- 如果/是否定义了(语义)
- 是否使用lightmaps?
- ifdef和ifndef的条件语句的经典应用
- high-precision高精度,half-precision半精度
- 结构体 Struct v2f_surf
- UNITY_POSITION(pos); = float4 pos :SV_POSITION;
- pack0 就是_MainTex的uv
- 在v2f_surf 里声明三个变量用于组成成切线空间下的旋转矩阵
- 最后v2f_surf 结构的完整代码:
- vertex顶点着色器
- 其中appdata_full
- 整理后的vertex——vert_surf顶点着色器如下:
- frag_surf 片段着色器
- 从return c;往前解析
- UNITY_OPAQUE_ALPHA(c.a);
- fixed4 c = LightingStandard (o, worldViewDir, gi);
- LightingStandard (o, worldViewDir, gi)解析
- LightingStandard 的第一个参数"o":
- 不同平台的编译指令区分
- 宏:UNITY_INITIALIZE_OUTPUT(type,name) 解析
- 金属工作流下的SurfaceOutputStandard结构
- 给SurfaceOutputStandard 结构内的参数逐一赋值
- 最后SurfaceOutputStandard 代码和注释
- SurfaceOutputStandard 代码的注释补充:
- o.Normal = worldNormal;
- UnityGI gi;
- UnityGI结构体
- UnityLightingCommon.cginc文件
- UnityLight light; 直接光照包含信息
- UnityIndirect indirect; 间接光照包含信息
- 完整的Shader,保留原始计算和注释的代码如下:
- 新建一个cginc 文件
- 完整的cginc代码,代码如下:
- 最后精简后的Shader
- 最后精简后的cginc代码
在Unity Build-In 管线(Universal Render Pipeline)
新建一个Standard Surface Shader

- 命名为MyPBR
- 双击打开文件

文件里的代码如下:
Shader "Custom/MyPBR"
{Properties{_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}_Glossiness ("Smoothness", Range(0,1)) = 0.5_Metallic ("Metallic", Range(0,1)) = 0.0}SubShader{Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM// Physically based Standard lighting model, and enable shadows on all light types#pragma surface surf Standard fullforwardshadows// Use shader model 3.0 target, to get nicer looking lighting#pragma target 3.0sampler2D _MainTex;struct Input{float2 uv_MainTex;};half _Glossiness;half _Metallic;fixed4 _Color;// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.// #pragma instancing_options assumeuniformscalingUNITY_INSTANCING_BUFFER_START(Props)// put more per-instance properties hereUNITY_INSTANCING_BUFFER_END(Props)void surf (Input IN, inout SurfaceOutputStandard o){// Albedo comes from a texture tinted by colorfixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;o.Albedo = c.rgb;// Metallic and smoothness come from slider variableso.Metallic = _Metallic;o.Smoothness = _Glossiness;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"
}
选中"MyPBR.Shader",在Inspector面板,打开"Show generated code"

跳转到VScode,这里有1677行代码
将文件 Ctrl K 再 Ctrl 0,折叠代码。
里面有Unity的部分详细注释。

将其复制到shader文件里。
- pass 部分的LightMode 注释
- ForwardBase pass 主要是支持最亮主平行灯的逐像素光照。
- ForwardAdd pass 是支持其他等的逐像素光照,这个看项目需求是否需要。
- Deferred pass 是支持延迟渲染,手机上一般很少用这种渲染pass
- Meta 光照烘焙
- 保留ForwardBase pass ,其他的都去除。
// ---- forward rendering base pass:Pass {Name "FORWARD"Tags { "LightMode" = "ForwardBase" }...}// ---- forward rendering additive lights pass:Pass {Name "FORWARD"Tags { "LightMode" = "ForwardAdd" }...}// ---- deferred shading pass:Pass {Name "DEFERRED"Tags { "LightMode" = "Deferred" }...}// ---- meta information extraction pass:Pass {Name "Meta"Tags { "LightMode" = "Meta" }...}
PASS
删除不用的pass后的大致结构

FallBack "Diffuse"的作用
- 是保证不同平台的兜底着色,还有就是支持阴影,如果去掉阴影可能会不显示,
}//这个的作用是保证不同平台的兜底着色,还有就是支持阴影,如果去掉阴影可能会不显示,FallBack "Diffuse"
}
包含文件
- 这些包含文件,内部会相互包含串联应用。

// #include "HLSLSupport.cginc"// #define UNITY_INSTANCED_LOD_FADE// #define UNITY_INSTANCED_SH// #define UNITY_INSTANCED_LIGHTMAPSTS// #include "UnityShaderVariables.cginc"// #include "UnityShaderUtilities.cginc"
判断语句
如果/是否定义了(语义)
- #if !defined(INSTANCIN1G_ON) 表示如果没有定义GPU实例化,那么执行 #if 到 #endif 里面的计算
- #if defined(INSTANCING_ON) 表示如果定义了GPU实例化,那么执行 #if 到 #endif 里面的计算
- -------- variant for: when no other keywords are defined
- #if !defined(INSTANCING_ON)

是否使用lightmaps?
- #ifndef LIGHTMAP_ON 表示如果没有定义LIGHTMAP_ON
- #ifdef LIGHTMAP_ON 表示如果定义了LIGHTMAP_ON

ifdef和ifndef的条件语句的经典应用
- 经典应用链接

high-precision高精度,half-precision半精度
- 精度片段着色器寄存器

结构体 Struct v2f_surf
UNITY_POSITION(pos); = float4 pos :SV_POSITION;
- UNITY_POSITION(pos); 和 float4 pos :SV_POSITION; 是一个东西;
pack0 就是_MainTex的uv
float2 pack0 : TEXCOORD0; // _MainTex ,其中pack0 就是_MainTex的uv

在v2f_surf 里声明三个变量用于组成成切线空间下的旋转矩阵
float3 tSpace0:TEXCOORD3;float3 tSpace1:TEXCOORD4;float3 tSpace2:TEXCOORD5;
最后v2f_surf 结构的完整代码:
struct v2f_surf{// UNITY_POSITION(pos); = float4 pos :SV_POSITION;!!!!!!!!!!!!!!!!float4 pos :SV_POSITION;float2 pack0 : TEXCOORD0; // _MainTex ,其中pack0 就是_MainTex的uvfloat3 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;// #if SHADER_TARGET >= 30// float4 lmap : TEXCOORD6;// #endif// UNITY_VERTEX_INPUT_INSTANCE_ID// UNITY_VERTEX_OUTPUT_STEREO};
vertex顶点着色器
v2f_surf vert_surf (appdata_full v){UNITY_SETUP_INSTANCE_ID(v);v2f_surf o;// UNITY_INITIALIZE_OUTPUT(v2f_surf,o);// UNITY_TRANSFER_INSTANCE_ID(v,o);// UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);o.pos = UnityObjectToClipPos(v.vertex);o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;float3 worldNormal = UnityObjectToWorldNormal(v.normal);#if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;#endif#if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);#endifo.worldPos.xyz = worldPos;o.worldNormal = worldNormal;#ifdef DYNAMICLIGHTMAP_ONo.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;#endif#ifdef LIGHTMAP_ONo.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;#endif// SH/ambient and vertex lights#ifndef LIGHTMAP_ON#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_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);#endif#endif // !LIGHTMAP_ONUNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader#ifdef FOG_COMBINED_WITH_TSPACEUNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader#elif defined FOG_COMBINED_WITH_WORLD_POSUNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader#elseUNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader#endifreturn o;}
其中appdata_full
v2f_surf vert_surf (appdata_full v){...}
- 在UnityCG.cginc中有具体的结构体数据:
struct appdata_base{...};struct appdata_tan{...};struct appdata_full {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};

- UNITY_SETUP_INSTANCE_ID(v);
仅当您要访问片元着色器中的实例化属性时才需要。
关于实例化的Unity官方介绍

- UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
v2f_surf结构体的初始化。 - LIGHTMAP_ON——烘焙;DIRLIGHTMAP_COMBINED 方向光源
UNITY_SETUP_INSTANCE_ID(v);v2f_surf o;// UNITY_INITIALIZE_OUTPUT(v2f_surf,o);// UNITY_TRANSFER_INSTANCE_ID(v,o);// UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
整理后的vertex——vert_surf顶点着色器如下:
v2f_surf vert_surf (appdata_full v){// UNITY_SETUP_INSTANCE_ID(v);v2f_surf o;// UNITY_INITIALIZE_OUTPUT(v2f_surf,o);// UNITY_TRANSFER_INSTANCE_ID(v,o);// UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);o.pos = UnityObjectToClipPos(v.vertex);o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;float3 worldNormal = UnityObjectToWorldNormal(v.normal);// #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)// fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);// fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;// fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;// #endif// #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);// #endifo.worldPos.xyz = worldPos;o.worldNormal = worldNormal;// // 实时GI// #ifdef DYNAMICLIGHTMAP_ON// o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;// #endif// // o.lmap.xy光照贴图的UV采样// #ifdef LIGHTMAP_ON// o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;// #endif// SH/ambient and vertex lights// #ifndef LIGHTMAP_ON#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_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);#endif// #endif // !LIGHTMAP_ON// UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader// #ifdef FOG_COMBINED_WITH_TSPACE// UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader// #elif defined (FOG_COMBINED_WITH_WORLD_POS)// UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader// #elseUNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader// #endifreturn o;}
frag_surf 片段着色器
fixed4 frag_surf (v2f_surf IN) : SV_Target{UNITY_SETUP_INSTANCE_ID(IN);// prepare and unpack dataInput surfIN;#ifdef FOG_COMBINED_WITH_TSPACEUNITY_EXTRACT_FOG_FROM_TSPACE(IN);#elif defined (FOG_COMBINED_WITH_WORLD_POS)UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);#elseUNITY_EXTRACT_FOG(IN);#endifUNITY_INITIALIZE_OUTPUT(Input,surfIN);surfIN.uv_MainTex.x = 1.0;surfIN.uv_MainTex = IN.pack0.xy;float3 worldPos = IN.worldPos.xyz;#ifndef USING_DIRECTIONAL_LIGHTfixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));#elsefixed3 lightDir = _WorldSpaceLightPos0.xyz;#endiffloat3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));#ifdef UNITY_COMPILER_HLSLSurfaceOutputStandard o = (SurfaceOutputStandard)0;#elseSurfaceOutputStandard o;#endifo.Albedo = 0.0;o.Emission = 0.0;o.Alpha = 0.0;o.Occlusion = 1.0;fixed3 normalWorldVertex = fixed3(0,0,1);o.Normal = IN.worldNormal;normalWorldVertex = IN.worldNormal;// call surface functionsurf (surfIN, o);// compute lighting & shadowing factorUNITY_LIGHT_ATTENUATION(atten, IN, worldPos)fixed4 c = 0;// 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 = lightDir;// 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 = IN.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_GI(o, giInput, gi);// realtime lighting: call lighting functionc += LightingStandard (o, worldViewDir, gi);UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fogUNITY_OPAQUE_ALPHA(c.a);return c;}
从return c;往前解析
- return c; 返回c。
UNITY_OPAQUE_ALPHA(c.a);
- #define UNITY_OPAQUE_ALPHA(outputAlpha) outputAlpha = 1.0
- Alpha值为1.0

另外一个:
#if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)

fixed4 c = LightingStandard (o, worldViewDir, gi);
- fixed4 c = LightingStandard (o, worldViewDir, gi); 其中的LightingStandard 再UnityPBSLighting.cginc文件内
inline half4 LightingStandard (SurfaceOutputStandard s, half3 viewDir, UnityGI gi){s.Normal = normalize(s.Normal);half oneMinusReflectivity;half3 specColor;s.Albedo = DiffuseAndSpecularFromMetallic (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 alphahalf outputAlpha;s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);half4 c = UNITY_BRDF_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);c.a = outputAlpha;return c;}
LightingStandard (o, worldViewDir, gi)解析
LightingStandard 的第一个参数"o":
传入的第一个"o",o是片段着色段的开头部分: SurfaceOutputStandard o;

不同平台的编译指令区分
#ifdef UNITY_COMPILER_HLSLSurfaceOutputStandard o = (SurfaceOutputStandard)0;#elseSurfaceOutputStandard o;#endif
宏:UNITY_INITIALIZE_OUTPUT(type,name) 解析
- UNITY_INITIALIZE_OUTPUT(type,name)用于把所给结构体里的各个变量初始化为0。
- 在HLSLSupport文件里的定义:
- 用零值初始化任意结构。
- 某些后端不支持(例如,基于Cg,尤其是嵌套结构)。
- hlsl2glsl几乎会支持它,除非有数组的结构——所以也不支持。
- hlsl2glsl:全称High Level Shader Language to OpenGL Shading Language,简写HLSL to GLSL。
// Initialize arbitrary structure with zero values.
// Not supported on some backends (e.g. Cg-based particularly with nested structs).
// hlsl2glsl would almost support it, except with structs that have arrays -- so treat as not supported there either :(
#if defined(UNITY_COMPILER_HLSL) || defined(SHADER_API_PSSL) || defined(UNITY_COMPILER_HLSLCC)
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
#else
#define UNITY_INITIALIZE_OUTPUT(type,name)
#endif
金属工作流下的SurfaceOutputStandard结构

给SurfaceOutputStandard 结构内的参数逐一赋值
- 这里的void surf (Input IN, inout SurfaceOutputStandard o)主要作用是给SurfaceOutputStandard 结构内的参数逐一赋值。
void surf (Input IN, inout SurfaceOutputStandard o){// Albedo comes from a texture tinted by colorfixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;o.Albedo = c.rgb;// Metallic and smoothness come from slider variableso.Metallic = _Metallic;o.Smoothness = _Glossiness;o.Alpha = c.a;}
最后SurfaceOutputStandard 代码和注释

SurfaceOutputStandard 代码的注释补充:
o.Normal = worldNormal;
- appdata结构中定义NORMAL与TANGENT语义。
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};
- v2f_surf中新增声明
- float3 tSpace0:TEXCOORD6;
- float3 tSpace1:TEXCOORD7;
- float3 tSpace2:TEXCOORD8;
- float2 normal : TEXCOORD9; // _NormalTex
- 用于组成切线空间下的矩阵。
struct v2f_surf{// UNITY_POSITION(pos); = float4 pos :SV_POSITION;!!!!!!!!!!!!!!!!float4 pos :SV_POSITION;float2 pack0 : TEXCOORD0; // _MainTex ,其中pack0 就是_MainTex的uvfloat3 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;float2 normal : TEXCOORD9; // _NormalTex// #if SHADER_TARGET >= 30// float4 lmap : TEXCOORD6;// #endif// UNITY_VERTEX_INPUT_INSTANCE_ID// UNITY_VERTEX_OUTPUT_STEREO};
- 在顶点着色器中:
// vertex shaderv2f_surf vert_surf (appdata v){
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// UNITY_SETUP_INSTANCE_ID(v);v2f_surf o;// UNITY_INITIALIZE_OUTPUT(v2f_surf,o);// UNITY_TRANSFER_INSTANCE_ID(v,o);// UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------o.pos = UnityObjectToClipPos(v.vertex);o.pack0 = TRANSFORM_TEX(v.texcoord.xy, _MainTex);o.normal = TRANSFORM_TEX(v.texcoord.zw, _NormalTex);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;float3 worldNormal = UnityObjectToWorldNormal(v.normal);// #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;// #endif// #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);// #endifo.worldPos.xyz = worldPos;// o.worldNormal = worldNormal;
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// // 实时GI// #ifdef DYNAMICLIGHTMAP_ON// o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;// #endif// // o.lmap.xy光照贴图的UV采样// #ifdef LIGHTMAP_ON// o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;// #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// SH/ambient and vertex lights// #ifndef LIGHTMAP_ON#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_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);#endif// #endif // !LIGHTMAP_ON// UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader// #ifdef FOG_COMBINED_WITH_TSPACE// UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader// #elif defined (FOG_COMBINED_WITH_WORLD_POS)// UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader// #elseUNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader// #endifreturn o;}
- 如是在片段着色器的normal填充
half3 normalTex = UnpackNormal(tex2D(_NormalTex,IN.normal));half3 worldNormal = half3(dot(IN.tSpace0,normalTex),dot(IN.tSpace1,normalTex),dot(IN.tSpace2,normalTex));o.Normal = worldNormal;
UnityGI gi;
// compute lighting & shadowing factorUNITY_LIGHT_ATTENUATION(atten, IN, 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 = lightDir;// 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 = IN.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_GI(o, giInput, gi);
UnityGI结构体

UnityLightingCommon.cginc文件
fixed4 _LightColor0;
fixed4 _SpecColor;struct UnityLight
{half3 color;half3 dir;half ndotl; // Deprecated: Ndotl is now calculated on the fly and is no longer stored. Do not used it.
};struct UnityIndirect
{half3 diffuse;half3 specular;
};struct UnityGI
{UnityLight light;UnityIndirect indirect;
};struct UnityGIInput
{UnityLight light; // pixel light, sent from the enginefloat3 worldPos;half3 worldViewDir;half atten;half3 ambient;// interpolated lightmap UVs are passed as full float precision data to fragment shaders// so lightmapUV (which is used as a tmp inside of lightmap fragment shaders) should// also be full float precision to avoid data loss before sampling a texture.float4 lightmapUV; // .xy = static lightmap UV, .zw = dynamic lightmap UV#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)float4 boxMin[2];#endif#ifdef UNITY_SPECCUBE_BOX_PROJECTIONfloat4 boxMax[2];float4 probePosition[2];#endif// HDR cubemap properties, use to decompress HDR texturefloat4 probeHDR[2];
};
UnityLight light; 直接光照包含信息
struct UnityLight{half3 color;half3 dir;half ndotl; // Deprecated: Ndotl is now calculated on the fly and is no longer stored. Do not used it.};
UnityIndirect indirect; 间接光照包含信息
struct UnityIndirect{half3 diffuse;half3 specular;};
完整的Shader,保留原始计算和注释的代码如下:
// Upgrade NOTE: replaced 'defined FOG_COMBINED_WITH_WORLD_POS' with 'defined (FOG_COMBINED_WITH_WORLD_POS)'Shader "Custom/MyPBR"
{Properties{_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}_NormalTex ("NormalTex", 2D) = "bump" {}_Glossiness ("Smoothness", Range(0,1)) = 0.5_Metallic ("Metallic", Range(0,1)) = 0.0}SubShader{Tags { "RenderType"="Opaque" }LOD 200// ------------------------------------------------------------// Surface shader code generated out of a CGPROGRAM block:
// pass 部分的LightMode 注释
//ForwardBase pass 主要是支持最亮主平行灯的逐像素光照
//ForwardAdd pass 是支持其他等的逐像素光照,这个看项目需求是否需要。
// Deferred pass 是支持延迟渲染,手机上一般很少用这种渲染pass
// Meta 光照烘焙// ---- forward rendering base pass:Pass {Name "FORWARD"Tags { "LightMode" = "ForwardBase" }CGPROGRAM// compile directives#pragma vertex vert_surf#pragma fragment frag_surf#pragma target 3.0#pragma multi_compile_instancing#pragma multi_compile_fog#pragma multi_compile_fwdbase// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------//这些包含文件,内部会相互包含串联应用,// #include "HLSLSupport.cginc"// #define UNITY_INSTANCED_LOD_FADE// #define UNITY_INSTANCED_SH// #define UNITY_INSTANCED_LIGHTMAPSTS// #include "UnityShaderVariables.cginc"// #include "UnityShaderUtilities.cginc"// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// 是否定义了(语义)
// #if !defined(INSTANCING_ON) 表示如果没有定义,那么执行 #if 到 #endif 里面的计算
// #if defined(INSTANCING_ON) 表示如果定义了,那么执行 #if 到 #endif 里面的计算
// -------- variant for: <when no other keywords are defined>
// #if !defined(INSTANCING_ON)// Surface shader code generated based on:// writes to per-pixel normal: no// writes to emission: no// writes to occlusion: no// needs world space reflection vector: no// needs world space normal vector: no// needs screen space position: no// needs world space position: no// needs view direction: no// needs world space view direction: no// needs world space position for lighting: YES// needs world space view direction for lighting: YES// needs world space view direction for lightmaps: no// needs vertex color: no// needs VFACE: no// needs SV_IsFrontFace: no// passes tangent-to-world matrix to pixel shader: no// reads from normal: no// 1 texcoords actually used// float2 _MainTex#include "UnityCG.cginc"#include "Lighting.cginc"#include "UnityPBSLighting.cginc"#include "AutoLight.cginc"// #define INTERNAL_DATA// #define WorldReflectionVector(data,normal) data.worldRefl// #define WorldNormalVector(data,normal) normal// // Original surface shader snippet:// #line 13 ""// #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING// #endif// /* UNITY: Original start of shader */// // Physically based Standard lighting model, and enable shadows on all light types// //#pragma surface surf Standard fullforwardshadows// // Use shader model 3.0 target, to get nicer looking lighting// //#pragma target 3.0half _Glossiness;half _Metallic;fixed4 _Color;sampler2D _MainTex , _NormalTex;float4 _MainTex_ST , _NormalTex_ST;
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//struct Input 结构 传到void surf (Input IN, ...),所以这里也可以注释掉。// struct Input// {// float2 uv_MainTex;// };
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.// // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.// // //#pragma instancing_options assumeuniformscaling// UNITY_INSTANCING_BUFFER_START(Props)// // put more per-instance properties here// UNITY_INSTANCING_BUFFER_END(Props)
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//这里的void surf (Input IN, inout SurfaceOutputStandard o)主要作用是给SurfaceOutputStandard 结构内的参数逐一赋值。// void surf (Input IN, inout SurfaceOutputStandard o)// {// // Albedo comes from a texture tinted by color// fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;// o.Albedo = c.rgb;// // Metallic and smoothness come from slider variables// o.Metallic = _Metallic;// o.Smoothness = _Glossiness;// o.Alpha = c.a;// }// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// 是否使用lightmaps?
// #ifndef LIGHTMAP_ON 表示如果没有定义LIGHTMAP_ON
// #ifdef LIGHTMAP_ON 表示如果定义了LIGHTMAP_ON
//ifdef和ifndef的条件语句的区别// vertex-to-fragment interpolation data// no lightmaps:// #ifndef LIGHTMAP_ON
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// 半精度// half-precision fragment shader registers:// #ifdef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS// #define FOG_COMBINED_WITH_WORLD_POS// struct v2f_surf {// UNITY_POSITION(pos);// float2 pack0 : TEXCOORD0; // _MainTex// float3 worldNormal : TEXCOORD1;// float4 worldPos : TEXCOORD2;// #if UNITY_SHOULD_SAMPLE_SH// half3 sh : TEXCOORD3; // SH// #endif// UNITY_LIGHTING_COORDS(4,5)// #if SHADER_TARGET >= 30// float4 lmap : TEXCOORD6;// #endif// UNITY_VERTEX_INPUT_INSTANCE_ID// UNITY_VERTEX_OUTPUT_STEREO// };// #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// 高精度// high-precision fragment shader registers:// #ifndef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERSstruct v2f_surf{// UNITY_POSITION(pos); = float4 pos :SV_POSITION;!!!!!!!!!!!!!!!!float4 pos :SV_POSITION;float2 pack0 : TEXCOORD0; // _MainTex ,其中pack0 就是_MainTex的uvfloat3 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;float2 normal : TEXCOORD9; // _NormalTex// #if SHADER_TARGET >= 30// float4 lmap : TEXCOORD6;// #endif// UNITY_VERTEX_INPUT_INSTANCE_ID// UNITY_VERTEX_OUTPUT_STEREO};// #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// #endif// // with lightmaps:// #ifdef LIGHTMAP_ON// // half-precision fragment shader registers:// #ifdef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS// #define FOG_COMBINED_WITH_WORLD_POS// struct v2f_surf {// UNITY_POSITION(pos);// float2 pack0 : TEXCOORD0; // _MainTex// float3 worldNormal : TEXCOORD1;// float4 worldPos : TEXCOORD2;// float4 lmap : TEXCOORD3;// UNITY_LIGHTING_COORDS(4,5)// UNITY_VERTEX_INPUT_INSTANCE_ID// UNITY_VERTEX_OUTPUT_STEREO// };// #endif// // high-precision fragment shader registers:// #ifndef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS// struct v2f_surf {// UNITY_POSITION(pos);// float2 pack0 : TEXCOORD0; // _MainTex// float3 worldNormal : TEXCOORD1;// float3 worldPos : TEXCOORD2;// float4 lmap : TEXCOORD3;// UNITY_FOG_COORDS(4)// UNITY_SHADOW_COORDS(5)// #ifdef DIRLIGHTMAP_COMBINED// float3 tSpace0 : TEXCOORD6;// float3 tSpace1 : TEXCOORD7;// float3 tSpace2 : TEXCOORD8;// #endif// UNITY_VERTEX_INPUT_INSTANCE_ID// UNITY_VERTEX_OUTPUT_STEREO// };// #endif// #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------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 shaderv2f_surf vert_surf (appdata v){
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// UNITY_SETUP_INSTANCE_ID(v);v2f_surf o;// UNITY_INITIALIZE_OUTPUT(v2f_surf,o);// UNITY_TRANSFER_INSTANCE_ID(v,o);// UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------o.pos = UnityObjectToClipPos(v.vertex);o.pack0 = TRANSFORM_TEX(v.texcoord.xy, _MainTex);o.normal = TRANSFORM_TEX(v.texcoord.zw, _NormalTex);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;float3 worldNormal = UnityObjectToWorldNormal(v.normal);// #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;// #endif// #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);// #endifo.worldPos.xyz = worldPos;// o.worldNormal = worldNormal;
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// // 实时GI// #ifdef DYNAMICLIGHTMAP_ON// o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;// #endif// // o.lmap.xy光照贴图的UV采样// #ifdef LIGHTMAP_ON// o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;// #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// SH/ambient and vertex lights// #ifndef LIGHTMAP_ON#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_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);#endif// #endif // !LIGHTMAP_ON// UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader// #ifdef FOG_COMBINED_WITH_TSPACE// UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader// #elif defined (FOG_COMBINED_WITH_WORLD_POS)// UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader// #elseUNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader// #endifreturn o;}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// fragment shaderfixed4 frag_surf (v2f_surf IN) : SV_Target{
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// UNITY_SETUP_INSTANCE_ID(IN);// prepare and unpack data// Input surfIN;UNITY_EXTRACT_FOG(IN);// UNITY_INITIALIZE_OUTPUT(Input,surfIN);// #ifdef FOG_COMBINED_WITH_TSPACE// UNITY_EXTRACT_FOG_FROM_TSPACE(IN);// #elif defined (FOG_COMBINED_WITH_WORLD_POS)// UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);// #else// UNITY_EXTRACT_FOG(IN);// #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// surfIN.uv_MainTex.x = 1.0;// IN.uv_MainTex = IN.pack0.xy;float3 worldPos = IN.worldPos.xyz;// #ifndef USING_DIRECTIONAL_LIGHT// fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));// #else// fixed3 lightDir = _WorldSpaceLightPos0.xyz;// #endiffloat3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//将SurfaceOutputStandard的数据填充完整。SurfaceOutputStandard o;UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);// #ifdef UNITY_COMPILER_HLSL// SurfaceOutputStandard o = (SurfaceOutputStandard)0;// #else// SurfaceOutputStandard o;// #endiffixed4 mainTex = tex2D (_MainTex, IN.pack0) * _Color;o.Albedo = mainTex.rgb;// Metallic and smoothness come from slider variables// fixed4 metallic = tex2D (_MetallicTex, IN.uv_MainTex);//如果要用金属度贴图或者金属度遮罩,可以采样2D贴图,然后填充。o.Metallic = _Metallic; // 0=non-metal, 1=metal// 平滑是面向用户的名称,它应该是感知平滑,但用户不应该处理它。// 在代码的任何地方,你都会遇到平滑,这就是感知平滑。o.Smoothness = _Glossiness;o.Alpha = mainTex.a;o.Emission = 0.0;//如果有AO贴图,o.Occlusion = 1.0;// fixed3 normalWorldVertex = fixed3(0,0,1);half3 normalTex = UnpackNormal(tex2D(_NormalTex,IN.normal));half3 worldNormal = half3(dot(IN.tSpace0,normalTex),dot(IN.tSpace1,normalTex),dot(IN.tSpace2,normalTex));o.Normal = worldNormal;// normalWorldVertex = IN.worldNormal;
//检索 void surf (Input IN, inout SurfaceOutputStandard o),这里有注释// // call surface function// surf (surfIN, o);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// compute lighting & shadowing factorUNITY_LIGHT_ATTENUATION(atten, IN, 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 = IN.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_GI(o, giInput, gi);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------//PBR的核心计算,基于物理着色,BRDF的相关计算// realtime lighting: call lighting functionfixed4 c = LightingStandard (o, worldViewDir, gi);UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog// Alpha值为1.0UNITY_OPAQUE_ALPHA(c.a);return c;}// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// #endif// // -------- variant for: INSTANCING_ON // #if defined(INSTANCING_ON)// ...// #endif// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------ENDCG}}//这个的作用是保证不同平台的兜底着色,还有就是支持阴影,如果去掉阴影可能会不显示,FallBack "Diffuse"
}
新建一个cginc 文件
#ifndef MYPBRCGINC_CGINC#define MYPBRCGINC_CGINC#endif
完整的cginc代码,代码如下:
#ifndef MYPBRCGINC_CGINC#define MYPBRCGINC_CGINC
// ----------------------------------------------------------------------------
half3 Unity_GlossyEnvironment_MY (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.perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
#endif
// #endif
// #ifndef UNITY_SPECCUBE_LOD_STEPS
// UNITY_SPECCUBE_LOD_STEPS <6
//mip 是一个非线性函数,perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
// perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness); 简化 x = x*(1.7 - 0.7*x) 在0-1的范围是一个上拱非线性函数
// #define UNITY_SPECCUBE_LOD_STEPS (6)
// #endif
// perceptualRoughnessToMipmapLevel = perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);half3 R = glossIn.reflUVW;half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);//tex2Dlodreturn DecodeHDR(rgbm, hdr);
}// ----------------------------------------------------------------------------//
// // ---------------------------------------------------------------------------- //
// // GlossyEnvironment - Function to integrate the specular lighting with default sky or reflection probes //
// // ---------------------------------------------------------------------------- //
// struct Unity_GlossyEnvironmentData //
// { //
// // - Deferred case have one cubemap //
// // - Forward case can have two blended cubemap (unusual should be deprecated). //
// // Surface properties use for cubemap integration //
// half roughness; // CAUTION: This is perceptualRoughness but because of compatibility this name can't be change :( //
// half3 reflUVW; //
// }; //
//// 计算Gi的镜面反射inline half3 UnityGI_IndirectSpecular_MY(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn){half3 specular;
//如果开启了BoxProjection// #ifdef UNITY_SPECCUBE_BOX_PROJECTION// // we will tweak reflUVW in glossIn directly (as we pass it to Unity_GlossyEnvironment_MY twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirection// half3 originalReflUVW = glossIn.reflUVW;// glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);// #endif
//如果勾选了Standard材质面板中的禁用反射功能的情况#ifdef _GLOSSYREFLECTIONS_OFFspecular = unity_IndirectSpecColor.rgb;#elsehalf3 env0 = Unity_GlossyEnvironment_MY (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_MY (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;}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// UnityGlobalIllumination_MY 重载函数!!!!!!!!!!!!!!!!!!!!!!!!// inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half3 normalWorld)// {// return UnityGI_Base(data, occlusion, normalWorld);// }inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn){//UnityGI_Base只计算Gi的漫反射UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);//UnityGI_IndirectSpecular_MY计算Gi的镜面反射o_gi.indirect.specular = UnityGI_IndirectSpecular_MY(data, occlusion, glossIn);return o_gi;}// //// // Old UnityGlobalIllumination_MY signatures. Kept only for backward compatibility and will be removed soon// //// inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half smoothness, half3 normalWorld, bool reflections)// {// if(reflections)// {// Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup_MY(smoothness, data.worldViewDir, normalWorld, float3(0, 0, 0));// return UnityGlobalIllumination_MY(data, occlusion, normalWorld, g);// }// else// {// return UnityGlobalIllumination_MY(data, occlusion, normalWorld);// }// }// inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half smoothness, half3 normalWorld)// {// #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS// // No need to sample reflection probes during deferred G-buffer pass// bool sampleReflections = false;// #else// bool sampleReflections = true;// #endif// return UnityGlobalIllumination_MY (data, occlusion, smoothness, normalWorld, sampleReflections);// }// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//half SmoothnessToPerceptualRoughness(half smoothness){return (1 - smoothness);}
//Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup_MY(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0){Unity_GlossyEnvironmentData g;// g.roughness /* perceptualRoughness */ = (1 - smoothness);g.roughness /* perceptualRoughness */ = SmoothnessToPerceptualRoughness(Smoothness);//反射球的采样坐标g.reflUVW = reflect(-worldViewDir, Normal);return g;}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------//PBR 光照模型 GIinline void LightingStandard_GI_MY (SurfaceOutputStandard s,UnityGIInput data,inout UnityGI gi){//&& 表示的是两个条件都满足,才会执行下面的计算。否则执行 #else 下面的计算。//UNITY_PASS_DEFERRED 是延迟渲染// 其中UNITY_ENABLE_REFLECTION_BUFFERS - 使用延迟着色时,以延迟方式渲染反射探测#if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS//UnityGlobalIllumination_MYgi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal);#elseUnity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup_MY(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic));// 返回gigi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal, g);#endif}#endif
最后精简后的Shader
Shader "Custom/MyPBR"
{Properties{_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}_NormalTex ("NormalTex", 2D) = "bump" {}_Glossiness ("Smoothness", Range(0,1)) = 0.5_Metallic ("Metallic", Range(0,1)) = 0.0}SubShader{Tags { "RenderType"="Opaque" }LOD 200Pass {Name "FORWARD"Tags { "LightMode" = "ForwardBase" }CGPROGRAM#pragma vertex vert_surf#pragma fragment frag_surf#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 "MYPBRCGINC.cginc"half _Glossiness;half _Metallic;fixed4 _Color;sampler2D _MainTex , _NormalTex;float4 _MainTex_ST , _NormalTex_ST;struct v2f_surf{float4 pos :SV_POSITION;float2 pack0 : TEXCOORD0;float3 worldNormal : TEXCOORD1;float3 worldPos : TEXCOORD2;#if UNITY_SHOULD_SAMPLE_SHhalf3 sh : TEXCOORD3;#endifUNITY_FOG_COORDS(4)UNITY_SHADOW_COORDS(5)float3 tSpace0:TEXCOORD6;float3 tSpace1:TEXCOORD7;float3 tSpace2:TEXCOORD8;float2 normal : TEXCOORD9;};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};v2f_surf vert_surf (appdata v){v2f_surf o;o.pos = UnityObjectToClipPos(v.vertex);o.pack0 = TRANSFORM_TEX(v.texcoord.xy, _MainTex);o.normal = TRANSFORM_TEX(v.texcoord.zw, _NormalTex);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 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);o.worldPos.xyz = worldPos;#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXELo.sh = 0;#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_FOG(o,o.pos);return o;}fixed4 frag_surf (v2f_surf IN) : SV_Target{UNITY_EXTRACT_FOG(IN);float3 worldPos = IN.worldPos.xyz;float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));SurfaceOutputStandard o;UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);fixed4 mainTex = tex2D (_MainTex, IN.pack0) * _Color;o.Albedo = mainTex.rgb;o.Metallic = _Metallic;o.Smoothness = _Glossiness;o.Alpha = mainTex.a;o.Emission = 0.0;o.Occlusion = 1.0;half3 normalTex = UnpackNormal(tex2D(_NormalTex,IN.normal));half3 worldNormal = half3(dot(IN.tSpace0,normalTex),dot(IN.tSpace1,normalTex),dot(IN.tSpace2,normalTex));o.Normal = worldNormal;UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)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;UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);giInput.light = gi.light;giInput.worldPos = worldPos;giInput.worldViewDir = worldViewDir;giInput.atten = atten;giInput.lightmapUV = 0.0;#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXELgiInput.ambient = IN.sh;#elsegiInput.ambient.rgb = 0.0;#endifgiInput.probeHDR[0] = unity_SpecCube0_HDR;LightingStandard_GI_MY(o, giInput, gi);fixed4 c = LightingStandard (o, worldViewDir, gi);UNITY_APPLY_FOG(_unity_fogCoord, c);UNITY_OPAQUE_ALPHA(c.a);return c;}ENDCG}}FallBack "Diffuse"
}
最后精简后的cginc代码
#ifndef MYPBRCGINC_CGINC#define MYPBRCGINC_CGINChalf3 Unity_GlossyEnvironment_MY (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn){half perceptualRoughness = glossIn.roughness /* perceptualRoughness */ ;#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)#elseperceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);#endifhalf mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);half3 R = glossIn.reflUVW;half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);//tex2Dlodreturn DecodeHDR(rgbm, hdr);}inline half3 UnityGI_IndirectSpecular_MY(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn){half3 specular;#ifdef _GLOSSYREFLECTIONS_OFFspecular = unity_IndirectSpecColor.rgb;#elsehalf3 env0 = Unity_GlossyEnvironment_MY (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_MY (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 UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn){UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);o_gi.indirect.specular = UnityGI_IndirectSpecular_MY(data, occlusion, glossIn);return o_gi;}half SmoothnessToPerceptualRoughness(half smoothness){return (1 - smoothness);}Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup_MY(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0){Unity_GlossyEnvironmentData g;g.roughness = SmoothnessToPerceptualRoughness(Smoothness);g.reflUVW = reflect(-worldViewDir, Normal);return g;}inline void LightingStandard_GI_MY (SurfaceOutputStandard s,UnityGIInput data,inout UnityGI gi){#if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERSgi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal);#elseUnity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup_MY(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic));gi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal, g);#endif}
#endif
相关文章:
【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】
Unity Build-In管线的SurfaceShader剖析 在Unity Build-In 管线(Universal Render Pipeline)新建一个Standard Surface Shader文件里的代码如下:选中"MyPBR.Shader",在Inspector面板,打开"Show generat…...
thinkphp5实现ajax图片上传,压缩保存到服务器
<div class"warp"><input type"file" id"file" accept"image/*" onchange"upimg(this)" /></div> <img src"" /> <script>//上传图片方法function upimg(obj){var fileData obj.…...
王道考研计算机网络——传输层
一、传输层概述 复用:发送方不同的应用进程都可以使用同一个传输层的协议来传送数据 分用:接收方的传输层在去除报文段的首部之后能把数据交给正确的应用进程 熟知端口号就是知名端口号0-1023 客户端使用的端口号是动态变化的,不是唯一确定…...
08 集群参数配置(下)
Kafka Broker不需要太大的堆内存? Kafka Broker不需要太大的堆内存?应该把内存留给页缓存使用? kafka刷盘时宕机 kafka认为写入成功是指写入页缓存成功还是数据刷到磁盘成功算成功呢?还是上次刷盘宕机失败的问题,页…...
mac文件为什么不能拖进U盘?
对于Mac用户来说,可能会遭遇一些烦恼,比如在试图将文件从Mac电脑拖入U盘时,却发现文件无法成功传输。这无疑给用户带来了很大的不便。那么,mac文件为什么不能拖进U盘,看完这篇你就知道了。 一、U盘的读写权限问题 如果…...
RK3568的CAN驱动适配
目录 背景: 1.内核驱动模块配置 2.设备树配置 3.功能测试 4.bug修复 背景: 某个项目上使用RK3568的芯片,需要用到4路CAN接口进行通信,经过方案评审后决定使用RK3568自带的3路CAN外加一路spi转的CAN实现功能,在这个…...
Opengl之立方体贴图
简单来说,立方体贴图就是一个包含了6个2D纹理的纹理,每个2D纹理都组成了立方体的一个面:一个有纹理的立方体。你可能会奇怪,这样一个立方体有什么用途呢?为什么要把6张纹理合并到一张纹理中,而不是直接使用6个单独的纹理呢?立方体贴图有一个非常有用的特性,它可以通过一…...
EF Core报错:Error Number:-2146893019
appsettings.json中的连接字符串要添加上:TrustServerCertificatetrue; 所以这里的连接字符串为:Data SourceLAPTOP-61GDB2Q7\\SQLEXPRESS;Initial CatalogMvcMovie.Data;Persist Security InfoTrue;TrustServerCertificatetrue;User IDsa;Passwordroot…...
QT之可自由折叠和展开的布局
介绍和功能分析 主要是实现控件的折叠和展开,类似抽屉控件,目前Qt自带的控件QToolBox具有这个功能,但是一次只能展开一个,所以针对自己的需求可以自己写一个类似的功能,这里实现的方法比较多,其实原理也比较…...
javascript二维数组(7)数组指定元素求和
项目需求 对指定数据中的score求和 const data [ { name: Alice, age: 23, score: 85 }, { name: Bob, age: 30, score: 90 }, { name: Charlie, age: 35, score: 80 } ];1.封装函数 这个函数接受两个参数:一个对象数组和一个键名(也就是你想要…...
网络安全——黑客自学(笔记)
想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客!!! 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队…...
Docker 安装 Elasticsearch7.16.x
docker hub地址:https://hub.docker.com 拉取镜像 docker pull elasticsearch:7.16.3创建容器 docker run -di --nameelasticsearch -p 9200:9200 -p 9300:9300 -p 5601:5601 -e "discovery.typesingle-node" -e "cluster.nameelasticsearch" -…...
springmvc-controller视图层配置SpringMVC处理请求的流程
目录 1. 什么是springmvc 2.项目中加入springmvc支持 2.1 导入依赖 2.2 springMVC配置文件 2.3 web.xml配置 2.4 中文编码处理 3. 编写一个简单的controller 4. 视图层配置 4.1 视图解析器配 4.2 静态资源配置 4.2 编写页面 4.3 页面跳转方式 5. SpringMVC处理请求…...
三模块七电平级联H桥整流器电压平衡控制策略Simulink仿真
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
【window10】Dart+Android Studio+Flutter安装及运行
安装Dart SDK安装Android Studio安装Flutter在Android Studio中创建并运行Flutter项目 安装前,请配置好你的jdk环境,准备好你的梯子~ 安装Dart SDK 浅浅了解一下Dart: Dart 诞生于2011年,是由谷歌开发的一种强类型、跨平台的客户…...
【C++】运算符重载 ⑩ ( 下标 [] 运算符重载 | 函数原型 int operator[](int i) | 完整代码示例 )
文章目录 一、下标 [] 运算符重载1、数组类回顾2、下标 [] 运算符重载 二、完整代码示例1、Array.h 数组头文件2、Array.cpp 数组实现类3、Test.cpp 测试类4、执行结果 一、下标 [] 运算符重载 1、数组类回顾 在之前的博客 【C】面向对象示例 - 数组类 ( 示例需求 | 创建封装类…...
ROS机械臂开发-开发环境搭建【一】
目录 前言环境配置docker搭建Ubuntu环境安装ROS 基础ROS文件系统 bugs 前言 想系统学习ROS,做一些机器人开发。因为有些基础了,这里随便写写记录一下。 环境配置 docker搭建Ubuntu环境 Dockerfile # 基础镜像 FROM ubuntu:18.04 # 设置变量 ENV ETC…...
深度思考rpc框架面经之五:rpc限流:rpc事务:tps测试
11 注册中心监控和rpc限流(用友云产品部二面) 11.1 你这个注册中心有实现相关的监控吗 11.1.1 如何实现注册中心有实现相关的监控 是的,我可以为你提供关于RPC注册中心及其监控的相关信息。RPC注册中心是用于管理微服务之间调用关系的中心…...
[AIGC] Java序列化利器 gson
前言: 本篇文章主要介绍了Gson库,从是什么、为什么、怎么用三个方面进行了详细的介绍。在是什么部分,介绍了Gson库的作用和特点;在为什么部分,介绍了为什么要使用Gson库;在怎么用部分,介绍了如何…...
VMware 虚拟机删除+重建
由于本人暴力地关闭虚拟机,导致虚拟机出现了一些问题,并且还没有给虚拟机拍快照,虽然还能用,但本人不想将就,于是乎打算重新新建一个虚拟机 一、删除 1.打开workstation,选择虚拟机,右键选择移除。 虽然虚…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
