Unity Internal-DeferredShading 分析

news2025/4/13 1:15:26

1. 延迟渲染的原理

延迟渲染主要包含了两个Pass。在第一个Pass中,我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区中。然后,在第二个Pass中,我们利用G缓冲区的各个片元信息,例如表面法线、视角方向、漫反射系数等,进行真正的光照计算。

延迟渲染的过程大致可以用下面的伪代码来描述:

// 第一个 Pass 不进行真正的光照计算
// 仅仅把光照计算需要的信息存储到 G 缓冲中
for (each primitive in this model) {
    for (each fragment covered by this primitive) {
        if (failed in depth test) {
            // 如果没有通过深度测试,说明该片元是不可见的
            discard;
        } else {
            // 如果该片元可见
            // 就把需要的信息存储到 G 缓冲中
            writeGBuffer(materialInfo, pos, normal, lightDir, viewDir);
        }
    }
}

// 利用 G 缓冲中的信息进行真正的光照计算
for (each pixel in the screen) {
    if (the pixel is valid) {
        // 如果该像素是有效的
        // 读取它对应的 G 缓冲中的信息
        readGBuffer(pixel, materialInfo, pos, normal, lightDir, viewDir);

        // 根据读取到的信息进行光照计算
        float4 color = Shading(materialInfo, pos, normal, lightDir, viewDir);

        // 更新帧缓冲
        writeFrameBuffer(pixel, color);
    }
}

Unity 里面的延迟渲染

一、代码结构

Shader "Hidden/Internal-DeferredShading" {
    Properties {
        // 光照贴图(用于点光源/聚光灯衰减)
        _LightTexture0 ("Light Texture", any) = "" {}
        // 光照方向贴图(用于聚光灯方向衰减)
        _LightTextureB0 ("Light Direction Texture", 2D) = "" {}
        // 阴影贴图(来自深度缓冲)
        _ShadowMapTexture ("Shadow Map", any) = "" {}
        // 混合模式参数(源/目标混合因子)
        _SrcBlend ("Source Blend", Float) = 1
        _DstBlend ("Destination Blend", Float) = 1
    }

    SubShader {
        
        Pass {
        	// Pass 1: 延迟光照计算(叠加或减法混合)
        }
		Pass {
        	// Pass 2: LDR模式最终解码(将对数值转为线性)
        }

    Fallback Off // 无备用着色器
}

二、第一个Pass

Pass {
          ZWrite Off               // 关闭深度写入
          Blend [_SrcBlend] [_DstBlend] // 动态混合模式(HDR时为加法,LDR时为减法)

          CGPROGRAM
          #pragma target 3.0          // 要求SM3.0以上
          #pragma vertex vert_deferred // 使用Unity内置延迟渲染顶点着色器
          #pragma fragment frag        // 片段着色器
          #pragma multi_compile_lightpass // 多编译光照传递模式
          #pragma multi_compile ___ UNITY_HDR_ON // 根据是否启用HDR编译不同路径

          #pragma exclude_renderers nomrt // 排除不支持多渲染目标的平台

          #include "UnityCG.cginc"        // Unity基础CG库
          #include "UnityDeferredLibrary.cginc" // 延迟渲染专用库
          #include "UnityPBSLighting.cginc" // 物理渲染光照计算
          #include "UnityStandardUtils.cginc" // 标准着色器工具
          #include "UnityGBuffer.cginc"    // GBuffer解包
          #include "UnityStandardBRDF.cginc" // BRDF计算

          // GBuffer纹理采样器(包含材质信息)
          sampler2D _CameraGBufferTexture0; // Albedo + 金属度
          sampler2D _CameraGBufferTexture1; // 法线 + 粗糙度
          sampler2D _CameraGBufferTexture2; // 前照光 + 漫反射

          // 计算单个光源的光照贡献
          half4 CalculateLight (unity_v2f_deferred i) {
              float3 wpos;          // 世界空间坐标
              float2 uv;            // GBuffer纹理坐标
              float atten, fadeDist;// 光照衰减和雾化距离
              UnityLight light;     // 光照结构体
              UNITY_INITIALIZE_OUTPUT(UnityLight, light); // 初始化光照结构
              UnityDeferredCalculateLightParams (
                  i, wpos, uv, light.dir, atten, fadeDist
              ); // 计算光照参数(方向、衰减等)

              // 设置光照颜色(光源颜色 * 衰减)
              light.color = _LightColor.rgb * atten;

              // 从GBuffer解包材质属性 
              //“Unity Standard Shader 解析(六)之Deferred”里面,可以看到Gbuffer的数据来源
              half4 gbuffer0 = tex2D(_CameraGBufferTexture0, uv);
              half4 gbuffer1 = tex2D(_CameraGBufferTexture1, uv);
              half4 gbuffer2 = tex2D(_CameraGBufferTexture2, uv);
              UnityStandardData data = UnityStandardDataFromGbuffer(
                  gbuffer0, gbuffer1, gbuffer2
              ); // 转换为标准材质数据结构

              // 计算视角方向(世界空间)
              float3 eyeVec = normalize(wpos - _WorldSpaceCameraPos);

              // 计算非高光部分(1 - 反射率)
              half oneMinusReflectivity = 1 - SpecularStrength(data.specularColor.rgb);

              // 环境光(此处设为0,因为延迟渲染通常单独处理)
              UnityIndirect ind;
              UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind);
              ind.diffuse = 0;
              ind.specular = 0;

              // 使用标准BRDF计算光照结果
              return UNITY_BRDF_PBS(
                  data.diffuseColor,      // 漫反射颜色
                  data.specularColor,     // 高光颜色
                  oneMinusReflectivity,   // 非高光部分
                  data.smoothness,        // 粗糙度
                  data.normalWorld,       // 法线方向
                  -eyeVec,                // 视角方向(取反)
                  light,                  // 光照参数
                  ind                    // 环境光(未使用)
              );
          }

          // 主片段着色器入口
          #ifdef UNITY_HDR_ON
          half4 frag (unity_v2f_deferred i) : SV_Target {
          #else
          fixed4 frag (unity_v2f_deferred i) : SV_Target {
          #endif
              half4 c = CalculateLight(i); // 计算光照
              #ifdef UNITY_HDR_ON
                  return c; // HDR模式直接返回线性值
              #else
                  return exp2(-c); // LDR模式对数编码
              #endif
          }
          ENDCG
      }

1.顶点着色器

vert_deferred定义在UnityDeferredLibrary.cginc里面

// 顶点着色器部分
// 延迟渲染顶点着色器输出结构体
struct unity_v2f_deferred {
    float4 pos : SV_POSITION; // 裁剪空间顶点坐标
    float4 uv : TEXCOORD0;    // 屏幕空间UV坐标(用于采样GBuffer)
    float3 ray : TEXCOORD1;   // 视线方向向量(用于光照计算)
};

// 控制是否使用全屏四边形模式的Shader变量
float _LightAsQuad;

// 延迟渲染顶点着色器入口函数
unity_v2f_deferred vert_deferred (float4 vertex : POSITION, float3 normal : NORMAL) 
{
    unity_v2f_deferred o;

    // 1. 将顶点从物体空间转换为裁剪空间
    o.pos = UnityObjectToClipPos(vertex);

    // 2. 计算屏幕空间UV坐标(范围[0,1],保留深度信息)
    o.uv = ComputeScreenPos(o.pos);

    // 3. 计算视线方向向量(视图空间下的相机到顶点方向)
    // UnityObjectToViewPos将顶点转换为视图空间坐标
    // 乘以float3(-1,-1,1)调整坐标方向(可能与坐标系转换有关)
    o.ray = UnityObjectToViewPos(vertex) * float3(-1, -1, 1);

    // 4. 根据_LightAsQuad选择ray的来源:
    //    - 当_LightAsQuad=1时:使用传入的normal参数(实际是相机到近平面角落的向量)
    //    - 当_LightAsQuad=0时:使用顶点计算的ray
    o.ray = lerp(o.ray, normal, _LightAsQuad);

    return o;
}

2.UnityDeferredCalculateLightParams

// --------------------------------------------------------
// 核心光照参数计算函数

void UnityDeferredCalculateLightParams (
    unity_v2f_deferred i,
    out float3 outWorldPos, // 输出世界空间坐标
    out float2 outUV,       // 输出屏幕UV坐标
    out half3 outLightDir,  // 输出光照方向
    out float outAtten,     // 输出光照衰减
    out float outFadeDist)  // 输出阴影衰减距离
{
    // 1. 计算视线方向(归一化到近裁剪面)
    i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
    float2 uv = i.uv.xy / i.uv.w;

    // 2. 从深度缓冲区重建世界坐标
    float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
    depth = Linear01Depth(depth); // 将深度转换为线性0-1范围
    float4 vpos = float4(i.ray * depth, 1); // 视图空间坐标
    float3 wpos = mul(unity_CameraToWorld, vpos).xyz; // 世界空间坐标

    // 3. 计算阴影衰减距离
    float fadeDist = UnityComputeShadowFadeDistance(wpos, vpos.z);

    // 4. 根据光照类型计算光照参数
    #if defined (SPOT) // 聚光灯
        float3 tolight = _LightPos.xyz - wpos; // 光源到顶点向量
        half3 lightDir = normalize(tolight);    // 光照方向
        float4 uvCookie = mul(unity_WorldToLight, float4(wpos,1)); // 光源空间坐标

        // 聚光灯衰减(带贴图)
        float atten = tex2Dbias(_LightTexture0, float4(uvCookie.xy / uvCookie.w, 0, -8)).w;
        atten *= uvCookie.w < 0; // 防止背面采样
        float att = dot(tolight, tolight) * _LightPos.w; // 距离衰减
        atten *= tex2D(_LightTextureB0, att.rr).r; // 衰减贴图采样

        // 计算阴影
        atten *= UnityDeferredComputeShadow(wpos, fadeDist, uv);

    #elif defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE) // 方向光
        half3 lightDir = -_LightDir.xyz; // 光方向(反向)
        float atten = 1.0;

        // 计算阴影
        atten *= UnityDeferredComputeShadow(wpos, fadeDist, uv);

        #if defined (DIRECTIONAL_COOKIE) // 带贴图的方向光
            // 采样方向光贴图(如天空盒投影)
            atten *= tex2Dbias(_LightTexture0, float4(mul(unity_WorldToLight, half4(wpos,1)).xy, 0, -8)).w;
        #endif

    #elif defined (POINT) || defined (POINT_COOKIE) // 点光源
        float3 tolight = wpos - _LightPos.xyz; // 顶点到光源向量
        half3 lightDir = -normalize(tolight); // 光照方向(反向)
        float att = dot(tolight, tolight) * _LightPos.w; // 距离衰减
        float atten = tex2D(_LightTextureB0, att.rr).r; // 衰减贴图

        // 计算阴影
        atten *= UnityDeferredComputeShadow(tolight, fadeDist, uv);

        #if defined (POINT_COOKIE) // 带贴图的点光源
            // 采样立方体阴影贴图
            atten *= texCUBEbias(_LightTexture0, float4(mul(unity_WorldToLight, half4(wpos,1)).xyz, -8)).w;
        #endif

    #else // 无效光照类型
        half3 lightDir = 0;
        float atten = 0;
    #endif

    // 输出结果
    outWorldPos = wpos;
    outUV = uv;
    outLightDir = lightDir;
    outAtten = atten;
    outFadeDist = fadeDist;
}

3,UnityComputeShadowFadeDistance

// 计算阴影衰减距离(用于混合实时阴影和烘焙阴影)
//float3 wpos:顶点的世界空间坐标(通过深度缓冲区重建)。
//float z:顶点的归一化设备坐标(NDC)的Z值(范围 [0,1]),表示顶点到相机的距离。
float UnityComputeShadowFadeDistance(float3 wpos, float z)
{
    // 1. 计算顶点到阴影衰减中心点的线性距离
    // unity_ShadowFadeCenterAndType.xyz 是阴影衰减球体的中心点坐标(世界空间)
    float sphereDist = distance(wpos, unity_ShadowFadeCenterAndType.xyz);

    // 2. 根据混合因子 lerp 在 z(深度值)和 sphereDist(球体距离)之间插值
    // unity_ShadowFadeCenterAndType.w 是混合权重(0~1):
    // - 当为0时,完全使用 z(深度值)作为衰减距离
    // - 当为1时,完全使用 sphereDist(球体距离)作为衰减距离
    // - 中间值则线性插值
    return lerp(z, sphereDist, unity_ShadowFadeCenterAndType.w);
}

4.UnityDeferredComputeShadow

// 计算混合阴影(实时+烘焙)
half UnityDeferredComputeShadow(float3 vec, float fadeDist, float2 uv)
{
    half fade = UnityComputeShadowFade(fadeDist); // 计算阴影衰减因子
    half shadowMaskAttenuation = UnityDeferredSampleShadowMask(uv); // 烘焙阴影
    half realtimeShadowAttenuation = UnityDeferredSampleRealtimeShadow(fade, vec, uv); // 实时阴影

    // 混合烘焙和实时阴影
    return UnityMixRealtimeAndBakedShadows(realtimeShadowAttenuation, shadowMaskAttenuation, fade);
}

5.UnityComputeShadowFade

half UnityComputeShadowFade(float fadeDist)
{
    // 计算衰减因子:将 fadeDist 乘以比例因子(scale),加上偏移因子(offset)
    // 然后通过 saturate() 将结果限制在 [0, 1] 范围内
    return saturate(fadeDist * _LightShadowData.z + _LightShadowData.w);
}

6.UnityDeferredSampleShadowMask


// 采样阴影掩码(烘焙阴影)
half UnityDeferredSampleShadowMask(float2 uv)
{
    half shadowMaskAttenuation = 1.0f;

    #if defined (SHADOWS_SHADOWMASK)
        // 从GBuffer的第四通道(_CameraGBufferTexture4)读取阴影掩码
        half4 shadowMask = tex2D(_CameraGBufferTexture4, uv);
        // 使用unity_OcclusionMaskSelector计算最终的阴影衰减
        shadowMaskAttenuation = saturate(dot(shadowMask, unity_OcclusionMaskSelector));
    #endif
    return shadowMaskAttenuation;
}

7.UnityDeferredSampleRealtimeShadow

// 采样实时阴影(动态阴影)
half UnityDeferredSampleRealtimeShadow(half fade, float3 vec, float2 uv)
{
    half shadowAttenuation = 1.0f;

    // 方向光/带贴图的方向光的阴影计算(屏幕空间阴影)
    #if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
        #if defined(SHADOWS_SCREEN)
            // 从_ShadowMapTexture采样阴影值
            shadowAttenuation = tex2D(_ShadowMapTexture, uv).r;
        #endif
    #endif

    // 快速分支优化(Unity 5.6+)
    #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING)
        // 当衰减小于阈值时,跳过计算(提升性能)
        UNITY_BRANCH
        if (fade < (1.0f - 1e-2f))
        {
    #endif

        // 聚光灯阴影(深度阴影)
        #if defined(SPOT)
            #if defined(SHADOWS_DEPTH)
                // 转换到阴影坐标系并采样
                float4 shadowCoord = mul(unity_WorldToShadow[0], float4(vec, 1));
                shadowAttenuation = UnitySampleShadowmap(shadowCoord);
            #endif
        #endif

        // 点光源/带贴图的点光源阴影(立方体贴图阴影)
        #if defined (POINT) || defined (POINT_COOKIE)
            #if defined(SHADOWS_CUBE)
                // 直接采样立方体阴影贴图
                shadowAttenuation = UnitySampleShadowmap(vec);
            #endif
        #endif

    #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING)
        }
    #endif

    return shadowAttenuation;
}

8.UnitySampleShadowmap

// ------------------------------------------------------------------
// Spot 光源阴影采样逻辑
// ------------------------------------------------------------------
// 仅在启用深度阴影(SHADOWS_DEPTH)且光源类型为 Spot(SPOT)时编译此部分
#if defined(SHADOWS_DEPTH) && defined(SPOT)
    // 阴影采样函数(核心逻辑)
    inline fixed UnitySampleShadowmap (float4 shadowCoord)
    {
        #if defined(SHADOWS_SOFT)
            half shadow = 1; // 默认全亮(无阴影)

            // 情况1:不支持硬件比较采样器(如部分移动设备或 Xbox360)
            #if !defined(SHADOWS_NATIVE)
                float3 coord = shadowCoord.xyz / shadowCoord.w; // 将齐次坐标转换为归一化坐标 [0,1]
                
                // 使用四个偏移量进行软阴影采样(PCF)
                float4 shadowVals;
                shadowVals.x = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[0].xy);
                shadowVals.y = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[1].xy);
                shadowVals.z = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[2].xy);
                shadowVals.w = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[3].xy);

                // 比较采样深度与当前坐标深度,计算阴影权重(0为全黑,1为全亮)
                half4 shadows = (shadowVals < coord.zzzz) ? _LightShadowData.rrrr : 1.0f;
                shadow = dot(shadows, 0.25f); // 四个采样的平均值

            #else // 情况2:支持硬件比较采样器(如移动设备)

                // 使用硬件比较采样器进行高效采样
                float3 coord = shadowCoord.xyz / shadowCoord.w;
                half4 shadows;
                shadows.x = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[0]);
                shadows.y = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[1]);
                shadows.z = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[2]);
                shadows.w = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[3]);
                shadow = dot(shadows, 0.25f); // 四个采样的平均值

            #else // 情况3:其他平台(如PC)

                // 使用更复杂的3x3采样(PCF3x3)提高阴影质量
                float3 coord = shadowCoord.xyz / shadowCoord.w;
                float3 receiverPlaneDepthBias = UnityGetReceiverPlaneDepthBias(coord, 1.0f);
                shadow = UnitySampleShadowmap_PCF3x3(float4(coord, 1), receiverPlaneDepthBias);

            #endif

            // 根据光照阴影强度混合阴影效果
            shadow = lerp(_LightShadowData.r, 1.0f, shadow);

        #else // 情况4:硬阴影(非软阴影)

            // 硬阴影直接采样(1-tap)
            #if defined(SHADOWS_NATIVE)
                // 使用硬件比较采样器
                half shadow = UNITY_SAMPLE_SHADOW_PROJ(_ShadowMapTexture, shadowCoord);
                shadow = lerp(_LightShadowData.r, 1.0f, shadow);
            #else
                // 手动比较深度
                half shadow = SAMPLE_DEPTH_TEXTURE_PROJ(_ShadowMapTexture, UNITY_PROJ_COORD(shadowCoord)) 
                    < (shadowCoord.z / shadowCoord.w) ? _LightShadowData.r : 1.0;
            #endif

        #endif

        return shadow;
    }

#endif // #if defined(SHADOWS_DEPTH) && defined(SPOT)

三、第二个Pass

Pass {
          ZTest Always      // 总是通过深度测试
          Cull Off         // 不剔除面
          ZWrite Off       // 关闭深度写入
          Stencil {
              // 只渲染非背景区域(通过Stencil缓冲区)
              ref [_StencilNonBackground] // 参考值来自Unity的Stencil设置
              readmask [_StencilNonBackground] // 读取掩码
              compback equal // 后面面的比较函数
              compfront equal // 前面面的比较函数(修复bug,见注释)
          }

          CGPROGRAM
          #pragma target 3.0
          #pragma vertex vert
          #pragma fragment frag
          #pragma exclude_renderers nomrt

          #include "UnityCG.cginc"

          sampler2D _LightBuffer; // 光照缓冲区纹理
          struct v2f {
              float4 vertex : SV_POSITION;
              float2 texcoord : TEXCOORD0;
          };

          // 顶点着色器(传递屏幕坐标)
          v2f vert (float4 vertex : POSITION, float2 texcoord : TEXCOORD0) {
              v2f o;
              o.vertex = UnityObjectToClipPos(vertex);
              o.texcoord = texcoord.xy;
              #ifdef UNITY_SINGLE_PASS_STEREO
                  o.texcoord = TransformStereoScreenSpaceTex(o.texcoord, 1.0f);
              #endif
              return o;
          }

          // 片段着色器(解码对数值)
          fixed4 frag (v2f i) : SV_Target {
              return -log2(tex2D(_LightBuffer, i.texcoord)); // 对数解码
          }
          ENDCG
      }

总结Unity中关于内部延迟渲染(Deferred Shading)的实现,主要包括了原理介绍、代码结构和关键函数的作用。

延迟渲染的原理

延迟渲染通过两个Pass完成:第一个Pass只计算哪些片元是可见的,并将这些片元的相关信息存储到G缓冲区中;第二个Pass利用G缓冲区的信息进行光照计算。这种方法允许在不增加额外复杂度的情况下处理大量光源。

Unity里面的延迟渲染

一、代码结构
  • Shader “Hidden/Internal-DeferredShading”:定义了一个隐藏的着色器,用于内部延迟渲染。
  • Properties块:定义了各种纹理属性,如光纹理、阴影贴图等。
  • SubShader块:包含了具体的渲染过程,分为多个Pass来执行不同的渲染任务。
二、第一个Pass
  • ZWrite Off 和 Blend:关闭深度写入并设置混合模式。
  • CGPROGRAM块:包含了顶点和片段着色器的实现,使用多编译指令以适应不同平台和配置。
  • CalculateLight函数:根据从GBuffer读取的信息计算单个光源对像素颜色的贡献。
  • frag函数:主片段着色器入口,根据是否启用高动态范围(HDR)选择不同的返回值处理方式。
关键函数
  • vert_deferred:延迟渲染使用的顶点着色器,负责转换坐标系并将必要信息传递给片段着色器。
  • UnityDeferredCalculateLightParams:核心光照参数计算函数,根据当前片元的位置和其他信息计算出光照方向、衰减等因素。
  • UnityComputeShadowFadeDistance:计算阴影衰减距离,用于混合实时阴影和烘焙阴影。
  • UnityDeferredComputeShadow:计算混合阴影效果,结合实时阴影和烘焙阴影。
  • UnityComputeShadowFade:计算阴影衰减因子。
  • UnityDeferredSampleShadowMask:采样阴影掩码,即烘焙阴影。
  • UnityDeferredSampleRealtimeShadow:采样实时阴影,即动态生成的阴影。
  • UnitySampleShadowmap:阴影贴图采样逻辑,支持多种情况下的阴影采样,包括软阴影和硬阴影。
第二个Pass
  • ZTest Always, Cull Off, ZWrite Off:总是通过深度测试,不剔除面,关闭深度写入。
  • Stencil块:仅渲染非背景区域,通过模板缓冲区实现。
  • CGPROGRAM块:解码对数值,主要是通过对数运算将HDR颜色值转换为线性空间颜色值。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Axure RP9教程 【数据传输】(页面值传递)| 作用域 :全局变量、局部变量

文章目录 引言作用域:全局变量作用域>局部变量作用域I 基于全局变量实现一个简单的登陆操作设置变量值的交互动作打开链接的交互动作接收并显示变量值注意点see also共享原型引言 全局变量在交互效果作用是页面值传递 作用域:全局变量作用域>局部变量作用域 全局变量…

IBM Rational Software Architect安装感受及使用初体验

1 安装感受 最近准备用UML 2.0绘制模型图。在读UML创始人之一Grady Booch写的书《Object-Oriented Analysis and Design with Applications》&#xff08;第3版&#xff09;1时&#xff0c;发现书中用的UML工具之一为IBM Rational Software Architect&#xff08;RSA&#xff…

VRRP学习

虚拟路由器冗余技术【三层技术】&#xff1a;网关冗余VRRP设计了VRRP组的概念&#xff0c;在一个 VRRP 组中&#xff0c;多台路由器共同构成一个虚拟路由器。这个虚拟路由器拥有一个虚拟 IP 地址【VRRP-ID默认是8位二进制&#xff0c;范围是0~255&#xff0c;用以标识和区别不同…

GPT-5、o3和o4-mini即将到来

原计划有所变更: 关于我们应有何期待的一些零散想法。 深度研究(Deep Research)确实强大但成本高昂且速度较慢(当前使用o3模型)。即将推出的o4-mini在性能上可能与o3相近,但将突破这些限制,让全球用户——甚至免费用户(尽管会有速率限制)——都能用上世界顶级AI研究助…

C#MVC项目引用Swagger的详细步骤

目录 一、安装Swagger依赖包二、配置Swagger服务三、启用XML注释四、调整启动配置五、验证与访问常见问题解决 以下是基于ASP.NET Core项目集成Swagger的详细步骤&#xff08;已适配当前项目结构&#xff09;&#xff1a; 一、安装Swagger依赖包 通过NuGet安装 右键点击项目…

golang 对象池sync.Pool

Golang中的sync.Pool是什么&#xff1f; sync.Pool 是 Go 标准库中提供的一个对象池&#xff08;Object Pool&#xff09;实现&#xff0c;用于缓存和复用临时对象&#xff0c;以减少内存分配和垃圾回收&#xff08;GC&#xff09;的压力。它的主要特点是&#xff1a; 临时对…

聚焦AI与大模型创新,紫光云如何引领云计算行业快速演进?

【全球云观察 &#xff5c; 科技热点关注】 随着近年来AI与大模型的兴起&#xff0c;云计算行业正在发生着一场大变局。 “在2025年春节期间&#xff0c;DeepSeek两周火爆全球&#xff0c;如何进行私域部署成了企业关心的问题。”紫光云公司总裁王燕平强调指出&#xff0c;AI与…

解决前后端时区不一致问题

前后端时区不一致导致&#xff1a; 》数据不显示在前端 》页面显示时间有误 》一些对时间有要求的方法&#xff0c;无法正确执行&#xff0c;出现null值&#xff0c;加上我们对null值有判断/注解&#xff0c;程序就会报错中断&#xff0c;以为是业务逻辑问题&#xff0c;其实…

STL之序列式容器(Vector/Deque/List)

序列式容器 序列式容器包括&#xff1a;静态数组 array 、动态数组 vector 、双端队列 deque 、单链表 forward_ list 、双链表 list 。这五个容器中&#xff0c;我们需要讲解三个 vector 、 deque 、 list 的使 用&#xff0c;包括&#xff1a;初始化、遍历、尾部插入与删除、…

小试牛刀-抽奖程序

编写抽奖程序 需求&#xff1a;设计一个抽奖程序&#xff0c;点击抽奖按钮随机抽取一个名字作为中奖者 目标&#xff1a;了解项目结构&#xff0c;简单UI布局&#xff0c;属性方法、事件方法&#xff0c;程序运行及调试 界面原型 ​ 待抽奖&#xff1a; 点击抽奖按钮&#x…

从 MySQL 切换到国产 YashanDB 数据库时,需要在数据库字段和应用连接方面进行适配 ,使用总结

YashanDB | 崖山数据库系统 - 崖山科技官网崖山数据库系统YashanDB是深圳计算科学研究院完全自主研发设计的新型数据库系统&#xff0c;融入原创理论&#xff0c;支持单机/主备、共享集群、分布式等多种部署方式&#xff0c;覆盖OLTP/HTAP/OLAP交易和分析混合负载场景&#xff…

【学习笔记】头文件中定义函数出现重复定义报错

目录 错误复现原因解决方案inlinestatic 扩展参考 错误复现 现在有一个头文件 duplicate_define.h 和两个源文件 duplicate_define_1.cpp 和 duplicate_define_2.cpp。 两个源文件都引入了头文件 duplicate_define.h&#xff0c;且在各自的函数中调用了定义在头文件中的全局函…

游戏开发中 C#、Python 和 C++ 的比较

&#x1f3ac; Verdure陌矣&#xff1a;个人主页 &#x1f389; 个人专栏: 《C/C》 | 《转载or娱乐》 &#x1f33e; 种完麦子往南走&#xff0c; 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ 摘要&#xff1a; 那么哪种编程语言最适合游戏开发…

DeepSeek 都开源了哪些技术?

DeepSeek作为中国领先的人工智能企业,通过开源策略推动了全球AI技术的普及与创新。以下是其官方公布的主要开源项目及其技术内容、应用场景和社区反馈的详细分析: 1. FlashMLA 技术描述:专为Hopper架构GPU优化的高效MLA(Multi-Layer Attention)解码内核,针对可变长度序列…

P8754 [蓝桥杯 2021 省 AB2] 完全平方数

题目描述 思路 一看就知道考数学&#xff0c;直接看题解试图理解(bushi) 完全平方数的质因子的指数一定为偶数。 所以 对 n 进行质因数分解&#xff0c;若质因子指数为偶数&#xff0c;对结果无影响。若质因子指数为奇数&#xff0c;则在 x 中乘以这个质因子&#xff0c;保证指…

ADGaussian:用于自动驾驶的多模态输入泛化GS方法

25年4月来自香港中文大学和浙大的论文“ADGaussian: Generalizable Gaussian Splatting for Autonomous Driving with Multi-modal Inputs”。 提出 ADGaussian 方法&#xff0c;用于可泛化的街道场景重建。所提出的方法能够从单视图输入实现高质量渲染。与之前主要关注几何细…

0501路由-react-仿低代码平台项目

文章目录 1 react路由1.1 核心库&#xff1a;React Router安装 1.2 基本路由配置路由入口组件定义路由 1.3 导航方式使用 <Link> 组件编程式导航 1.4 动态路由参数定义参数获取参数 1.5 嵌套路由父路由配置子路由占位符 1.6 重定向与404页面重定向404页面 1.7 路由守卫&a…

OpenAI即将上线新一代重磅选手——GPT-4.1

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【蓝桥杯】赛前练习

1. 排序 import os import sysn=int(input()) data=list(map(int,input().split(" "))) data.sort() for d in data:print(d,end=" ") print() for d in data[::-1]:print(d,end=" ")2. 走迷宫BFS import os import sys from collections import…

Windows 系统下用 VMware 安装 CentOS 7 虚拟机超详细教程(包含VMware和镜像安装包)

前言 资源 一、准备工作 &#xff08;一&#xff09;下载 VMware Workstation &#xff08;二&#xff09;下载 CentOS 7 镜像 二、安装 VMware Workstation&#xff08;比较简单&#xff0c;按下面走即可&#xff09; 三、创建 CentOS 7 虚拟机 四、安装 CentOS 7 系统…