I want to know how to achieve persistent storage of textures.

  • BlueGary
  • Topic Author
More
5 days 20 hours ago #1 by BlueGary I want to know how to achieve persistent storage of textures. was created by BlueGary
When writing shaders, I ran into a problem: I found that textures get initialized every frame. I want to know how to achieve persistent storage for textures and ensure they are not initialized at the beginning or end of the frame.
/*
 * SCAC
 * 屏幕颜色自动校准
 * Screen colour automatic calibration
 * by 灰灰蓝 [email protected]
 * version 0.01 Create at 2025/12/13
 * TODO 添加亮度极值平滑系统。
 */
#include "ReShadeUI.fxh"
uniform float3 RGB_offset < __UNIFORM_SLIDER_FLOAT3
    ui_min = -1.0; ui_max = 1.0;
    ui_label = "RGB offset";
    ui_tooltip = "对颜色进行偏移,校准黑位/Adjust offset for color to calibrate the black level.";
> = float3(0.0, 0.0, 0.0);
uniform float3 RGB_Gamma < __UNIFORM_SLIDER_FLOAT3
    ui_min = 0.0; ui_max = 2.0;
    ui_label = "RGB Gamma";
    ui_tooltip = "对颜色进行幂乘,调整整体明暗/Adjust midtones for color.";
> = float3(1.0, 1.0, 1.0);
uniform float3 RGB_Gain < __UNIFORM_SLIDER_FLOAT3
    ui_min = 0.0; ui_max = 2.0;
    ui_label = "RGB Gain";
    ui_tooltip = "对颜色进行乘数,校准白位/Multiply the color to calibrate the white point.";
> = float3(1.0, 1.0, 1.0);
uniform float3 RGB_Contrast < __UNIFORM_SLIDER_FLOAT3
    ui_min = 0.0; ui_max = 2.0;
    ui_label = "RGB Contrast";
    ui_tooltip = "对颜色进行对称双曲线,修改对比度/Apply symmetrical hyperbola to colors and adjust contrast.";
> = float3(1.0, 1.0, 1.0);
uniform bool EnableDebug <
    ui_label = "Enable Debug View";
    ui_tooltip = "启用调试视图,显示所有规约纹理/Enable debug view to display all shader textures.";
> = false;
uniform bool EnableAutoStats <
    ui_label = "Enable Auto Statistics";
    ui_tooltip = "启用自动颜色统计计算/Enable automatic color statistics calculation.";
> = true;
uniform float WhiteLimiter <
    ui_type = "slider";
    ui_min = 0.0; ui_max = 1.5;
    ui_step = 0.01f;
    ui_label = "White Limiter";
    ui_tooltip = "自动校准最高亮度的无效范围/Automatic calibration of the invalid range of maximum brightness.";
> = 0.95;
uniform float BlackLimiter <
    ui_type = "slider";
    ui_min = 0.01; ui_max = 1.0;
    ui_step = 0.01f;
    ui_label = "Black Limiter";
    ui_tooltip = "自动校准最低亮度的无效范围/Automatic calibration of the invalid range of minimum brightness.";
> = 0.05;
uniform int SamplingAera <
    ui_type = "combo";
    ui_label = "Sampling Aera";
    ui_tooltip = "选择采样区域/Select sampling aera.";
    ui_items = "Full Screen\0Custom Area\0";
> = 0;
uniform float2 CustomAreaCenter <
    ui_type = "slider";
    ui_min = 0.0; ui_max = 1.0;
    ui_label = "Custom Area Center";
    ui_tooltip = "自定义采样区域的中心位置/Center position of custom sampling area. ";
> = float2(0.5, 0.5);
uniform float2 CustomAreaSize <
    ui_type = "slider";
    ui_min = 0.0; ui_max = 2.0;
    ui_label = "Custom Area Size";
    ui_tooltip = "自定义采样区域的大小/Size of custom sampling area. 1.0 = default size (1024x1024 pixels).";
> = float2(1.0, 1.0);
uniform bool ShowSamplingBorder <
    ui_label = "Show Sampling Border";
    ui_tooltip = "显示采样区域的边界/Show sampling area border.";
> = false;
uniform bool EnableUIFilter <
    ui_label = "Enable UI Filter";
    ui_tooltip = "启用UI滤除功能,排除UI元素对亮度统计的影响/Enable UI filtering to exclude UI elements from luminance statistics.";
> = true;
uniform float UiFilterBlack <
    ui_type = "slider";
    ui_min = 0.0; ui_max = 0.02;
    ui_step = 0.000001f;
    ui_label = "UI Filter Black Level";
    ui_tooltip = "滤除UI过暗像素的阈值/Threshold for filtering overly dark UI pixels.";
> = 0.0;
uniform bool ShowFilterEffect <
    ui_label = "Show Filter Effect";
    ui_tooltip = "显示滤除效果:确保黑色只在ui中出现,在画面中面积最小/Show filtering effect: ensure black only appears in the UI, with minimal area on the screen.";
> = false;
uniform float ScreenMin <
    ui_label = "Screen Minimum (Black Level)";
    ui_tooltip = "屏幕黑位校准值/Screen Black Level Calibration Value.";
    ui_type = "drag";
    ui_min = 0.0;
    ui_max = 1.0;
    ui_step = 0.000001f;
> = 0.0;
uniform float ScreenMax <
    ui_label = "Screen Maximum (White Level)";
    ui_tooltip = "屏幕白位校准颜色值/Screen White Level Calibration Value.";
    ui_type = "drag";
    ui_min = 0.0;
    ui_max = 50.0;
    ui_step = 0.001f;
> = 1.0;
uniform int CalibrationMode <
    ui_type = "combo";
    ui_label = "Calibration View";
    ui_tooltip = "选择校准模式,使画面刚好纯黑纯白/Select the calibration mode so that the screen is perfectly black and white.";
    ui_items = "Off\0Black Level Calibration\0White Level Calibration\0";
> = 0;
uniform bool EnableHistorySmoothing <
    ui_label = "Enable History Smoothing";
    ui_tooltip = "启用历史值平滑系统,使用16帧历史缓冲区/Enable history value smoothing system using 16-frame history buffer.";
> = true;
#include "ReShade.fxh"
// ============================================================================
// 辅助函数
// ============================================================================
// 计算像素亮度:max(max(r,g),b) - 单通道简化,max确保黑位准确。
float CalculateLuminance(float3 color)
{
    return max(max(color.r, color.g), color.b);
}
// 颜色校准函数 - 支持scRGB/HDR
float3 ColorCalibration(float3 color,
                        float3 offset,
                        float3 gamma,
                        float3 gain,
                        float3 contrast,
                        float3 minColor,
                        float3 maxColor)
{
    //限制maxColor和minColor
    maxColor = max(maxColor,ScreenMax * WhiteLimiter);
    minColor = min(minColor,ScreenMin + BlackLimiter);
   
    //maxColor = ScreenMax;
    // 校准黑位和白位(合并为一步)
    color = ScreenMin + (color - minColor) * (ScreenMax - ScreenMin) / (maxColor - minColor);
    // 将颜色调整至归一化范围,确保计算精度。
    color /= (ScreenMax + 0.1);
    // Gamma
    color = pow(color, 1.0 / gamma);
    // 对比度
    // 显示滤除效果(如果启用)
    [branch]
    if (ShowFilterEffect && EnableUIFilter)
    {
        contrast = (0.001,0.001,0.001);
    }
    color = 1.0 / (1.0 + pow(((1.0 - color) / color), contrast));
    color = min(color,1);//防止颜色越界
    // 恢复颜色范围
    color *= (ScreenMax + 0.1);
    //color = (color - 0.01)*1.0204081632;
    // 校准黑位
    //color += ScreenMin - minColor;
    // 校准白位
    //color *= ScreenMax/maxColor;
    //偏移
    color += offset;
    color = max(color, 0);
    //增益
    color *= gain;
    return color;
}
// 绘制校准图案函数
float3 DrawCalibrationPattern(float2 texcoord, int mode)
{
    // 计算4x4网格的单元格大小
    float cellWidth = 1.0 / 4.0;  // 每个单元格占屏幕宽度的1/4
    float cellHeight = 1.0 / 4.0; // 每个单元格占屏幕高度的1/4
   
    // 矩形占单元格面积的75%,所以矩形大小为单元格大小的sqrt(0.75) ≈ 0.866
    float rectSize = 0.866; // sqrt(0.75)
   
    // 矩形在单元格内的偏移量,使其居中
    float rectOffset = (1.0 - rectSize) * 0.5;
   
    // 确定当前像素属于哪个网格单元格
    int cellX = floor(texcoord.x / cellWidth);
    int cellY = floor(texcoord.y / cellHeight);
   
    // 计算在单元格内的归一化坐标
    float cellLocalX = (texcoord.x - cellX * cellWidth) / cellWidth;
    float cellLocalY = (texcoord.y - cellY * cellHeight) / cellHeight;
   
    // 检查当前像素是否在矩形区域内
    bool inRect = (cellLocalX >= rectOffset && cellLocalX <= rectOffset + rectSize &&
                   cellLocalY >= rectOffset && cellLocalY <= rectOffset + rectSize);
   
    // 根据校准模式返回颜色
    if (mode == 1) // 黑位校准
    {
        // 背景:纯黑,矩形:ScreenMin
        return inRect ? ScreenMin : float3(0.0, 0.0, 0.0);
    }
    else if (mode == 2) // 白位校准
    {
        // 背景:1e6(高亮度白色),矩形:ScreenMax
        float3 whiteBackground = float3(1e6, 1e6, 1e6);
        return inRect ? ScreenMax : whiteBackground;
    }
   
    // 如果不是校准模式,返回黑色(不应该到达这里)
    return float3(0.0, 0.0, 0.0);
}
// 通用4x4归约函数
float4 ReductionPass(float4 position : SV_Position, float2 texcoord : TexCoord, sampler2D inputSampler, float2 pixelSize) : SV_Target
{
    // texcoord是归一化坐标[0,1]
    // 每个输出像素对应输入纹理中的4x4块
    // 计算4x4块的起始坐标(从中心偏移-1.5个像素)将初始采样点从4x4的中心移到左上角第一个像素中心。
    float2 startCoord = texcoord - float2(1.5 * pixelSize.x, 1.5 * pixelSize.y);
   
    // 采样4x4区域的16个像素
    float minVal = 1e6;     // 初始化为很大的值,支持scRGB/HDR(可能超过1000尼特)
    float maxVal = 0.0;     // 初始化为很小的值
   
    for (int y = 0; y < 4; y++)     // 这个循环用来遍历4x4块采样。
    {
        for (int x = 0; x < 4; x++)
        {
            float2 sampleCoord = startCoord + float2(x * pixelSize.x, y * pixelSize.y);
            // 确保采样坐标在有效范围内
            // sampleCoord = clamp(sampleCoord, pixelSize * 0.5, 1.0 - pixelSize * 0.5);注释掉因为这个clamp似乎并不必要
            float4 sampleVal = tex2D(inputSampler, sampleCoord);
           
            minVal = min(minVal, sampleVal.r);
            maxVal = max(maxVal, sampleVal.g);
        }
    }
   
    // 存储结果:R通道存最小值,G通道存最大值
    return float4(minVal, maxVal, 0.0, 1.0);
}
// ============================================================================
// 纹理定义
// 固定5次归约:1024 -> 256 -> 64 -> 16 -> 4 -> 1
// ============================================================================
// 纹理0:1024x1024 - 存储下采样后的亮度值
texture2D TextureMip0 <
    pooled = true;
>
{
    Width = 1024;
    Height = 1024;
    Format = RGBA16F;
};
sampler2D SamplerMip0 {
    Texture = TextureMip0;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// 纹理1:256x256 - 第一次4x4归约
texture2D TextureMip1 <
    pooled = true;
>
{
    Width = 256;
    Height = 256;
    Format = RGBA16F;
};
sampler2D SamplerMip1 {
    Texture = TextureMip1;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// 纹理2:64x64 - 第二次4x4归约
texture2D TextureMip2 <
    pooled = true;
>
{
    Width = 64;
    Height = 64;
    Format = RGBA16F;
};
sampler2D SamplerMip2 {
    Texture = TextureMip2;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// 纹理3:16x16 - 第三次4x4归约
texture2D TextureMip3 <
    pooled = true;
>
{
    Width = 16;
    Height = 16;
    Format = RGBA16F;
};
sampler2D SamplerMip3 {
    Texture = TextureMip3;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// 纹理4:4x4 - 第四次4x4归约
texture2D TextureMip4 <
    pooled = true;
>
{
    Width = 4;
    Height = 4;
    Format = RGBA16F;
};
sampler2D SamplerMip4 {
    Texture = TextureMip4;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// 纹理5:1x1 - 第五次4x4归约(最终结果)
texture2D TextureMip5 <
    pooled = true;
>
{
    Width = 1;
    Height = 1;
    Format = RGBA16F;
};
sampler2D SamplerMip5 {
    Texture = TextureMip5;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// 纹理4_History:4x4 - 历史缓冲区(存储16帧历史的最大值和最小值)
texture2D TextureMip4_History<
    //storage = true;
>
{
    //storage2D = true;
    Width = 4;
    Height = 4;
    Format = RGBA16F;
};
sampler2D SamplerMip4_History {
    Texture = TextureMip4_History;
    MinFilter = Point;    // 缩小过滤:点过滤
    MagFilter = Point;    // 放大过滤:点过滤
    MipFilter = Point;    // Mipmap过滤:点过滤
    AddressU = Border;     // U方向寻址:边缘
    AddressV = Border;     // V方向寻址:边缘
};
// ============================================================================
// Pass着色器
// ============================================================================
// Pass 1:将后缓冲区采样到1024x1024并计算亮度
float4 Pass1_DownsampleTo1024(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    // 测试模式:输出测试图案以验证坐标映射
    // R通道:水平渐变(0到1)
    // G通道:垂直渐变(0到1)
    // B通道:固定0
    // 这样我们可以清楚地看到纹理是否覆盖整个区域
   
    // float2 testPattern = texcoord; // 直接使用texcoord作为渐变
   
    // 存储到TextureMip0(R通道存水平渐变,G通道存垂直渐变)
    // return float4(testPattern.x, testPattern.y, 0.0, 1.0);
   
    // 计算像素大小(用于边界检查)
    float2 pixelSize = 1.0 / float2(BUFFER_WIDTH, BUFFER_HEIGHT);
   
    // 根据采样模式计算采样坐标
    float2 sampleCoord;
    [branch]
    if (SamplingAera == 0) // 全屏模式
    {
        // 直接使用texcoord作为采样坐标
        sampleCoord = texcoord;
    }
    else // 自定义模式 (SamplingAera == 1)
    {
        // 采样区域
        float2 sampleSize = float2(1024*CustomAreaSize.x*pixelSize.x, 1024*CustomAreaSize.y*pixelSize.y);
       
        float2 sampleCenter = CustomAreaCenter;
       
        // 将1024x1024纹理坐标映射到自定义区域
        // 公式:中心 + (texcoord - 0.5) * 大小
        sampleCoord = sampleCenter + (texcoord - 0.5) * sampleSize;
    }
   
    // 注意:这里不需要clamp,因为AddressU = Border; AddressV = Border;
    // 允许采样坐标超过[0,1]范围,边缘模式会返回边界颜色
   
    // 从后缓冲区采样RGB值(使用Point过滤直接采样)
    float3 color = tex2D(ReShade::BackBuffer, sampleCoord).rgb;
   
    // UI滤除(如果启用)
    [branch]
    if (EnableUIFilter)
    {
        // 创建float3类型的滤除阈值
        float3 filterBlack = float3(UiFilterBlack, UiFilterBlack, UiFilterBlack);
       
        // 应用滤除:限制颜色在[filterBlack, +inf]范围内
        color = max(filterBlack, color);
       
        // 确保R、G、B通道使用相同的值(取亮度)
        float luminance = CalculateLuminance(color);
        color = float3(luminance, luminance, luminance);
    }
   
    // 计算亮度(单通道)
    float luminance = CalculateLuminance(color);
   
    // 存储到TextureMip0(R通道存亮度,G通道存相同值用于后续处理)
    return float4(luminance, luminance, 0.0, 1.0);
}
// Pass 2:第一次4x4归约(1024x1024 -> 256x256)
float4 Pass2_Reduction1(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    return ReductionPass(position, texcoord, SamplerMip0, 1.0 / 1024.0);
}
// Pass 3:第二次4x4归约(256x256 -> 64x64)
float4 Pass3_Reduction2(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    return ReductionPass(position, texcoord, SamplerMip1, 1.0 / 256.0);
}
// Pass 4:第三次4x4归约(64x64 -> 16x16)
float4 Pass4_Reduction3(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    return ReductionPass(position, texcoord, SamplerMip2, 1.0 / 64.0);
}
// Pass 5:第四次4x4归约(16x16 -> 4x4)
float4 Pass5_Reduction4(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    return ReductionPass(position, texcoord, SamplerMip3, 1.0 / 16.0);
}
// Pass 6:第五次4x4归约(4x4 -> 1x1)和历史平均值计算
float4 Pass6_Reduction5(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    // 执行正常的4x4归约
    float4 result = ReductionPass(position, texcoord, SamplerMip4, 1.0 / 4.0);
   
    // 如果启用历史平滑,计算历史平均值
    [branch]
    if (EnableHistorySmoothing)
    {
        // 从TextureMip4采样所有16个像素并计算历史值的平均值
        // TextureMip4的B通道存储历史最小值,A通道存储历史最大值
        float2 pixelSize = 1.0 / 4.0; // 4x4纹理的像素大小
        float2 startCoord = float2(0.5 * pixelSize.x, 0.5 * pixelSize.y); // 从第一个像素中心开始
       
        float historySumMin = 0.0;
        float historySumMax = 0.0;
       
        for (int y = 0; y < 4; y++)
        {
            for (int x = 0; x < 4; x++)
            {
                float2 sampleCoord = startCoord + float2(x * pixelSize.x, y * pixelSize.y);
                float4 mip4Value = tex2D(SamplerMip4, sampleCoord);
               
                // B通道存储历史最小值,A通道存储历史最大值
                historySumMin += mip4Value.b;
                historySumMax += mip4Value.a;
            }
        }
       
        // 添加当前帧值到总和中(result.r存储当前帧最小值,result.g存储当前帧最大值)
        // 现在总共有17个数据:16个历史值 + 1个当前帧值
        float totalSumMin = historySumMin + result.r;
        float totalSumMax = historySumMax + result.g;
       
        // 计算17个数据的平均值
        float totalAvgMin = totalSumMin / 17.0;
        float totalAvgMax = totalSumMax / 17.0;
       
        // 将17个数据的平均值存储在结果的B和A通道中
        result.b = totalAvgMin;
        result.a = totalAvgMax;
    }
   
    return result;
}
// Pass 7:将当前帧的1x1纹理值存储到历史纹理(0,0)
float4 Pass7_StoreCurrentToHistory(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    // 这个Pass只写入历史纹理的(0,0)位置
    if (texcoord.x == 0.125 && texcoord.y == 0.125)
    {
        // 从1x1纹理读取当前帧的最小值和最大值
        float4 currentFrame = tex2D(SamplerMip5, float2(0.5, 0.5));
       
        // 存储到历史纹理的(0,0)位置
        // R通道:当前帧最小值
        // G通道:当前帧最大值
        // B和A通道:保留为0(后续用于平均值)
        return float4(currentFrame.r, currentFrame.g, 0.0, 0.0);
    }
   
    // 其他位置返回0
    return float4(0.0, 0.0, 0.0, 0.0);
}
// Pass 8:将历史纹理RG通道复制到TextureMip4的BA通道
float4 Pass8_CopyHistoryToMip4(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    // 首先执行正常的4x4归约(从TextureMip4读取)
    float4 mip4Value = tex2D(SamplerMip4, texcoord);
   
    // 如果启用历史平滑,从历史纹理读取对应的历史值
    [branch]
    if (EnableHistorySmoothing)
    {
        // 从历史纹理读取对应位置的值
        float4 historyValue = tex2D(SamplerMip4_History, texcoord);
       
        // 将历史纹理的R和G通道(最小值和最大值)复制到B和A通道
        mip4Value.b = historyValue.r; // 历史最小值
        mip4Value.a = historyValue.g; // 历史最大值
    }
   
    return mip4Value;
}
// Pass 9:历史值移位
float4 Pass9_HistoryShift(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    // 这个Pass将历史纹理中的值向前移动一位
    // 使用4x4纹理作为16帧的循环缓冲区
    // 将二维坐标转换为一维[0,15]
   
    // 计算当前像素的行列索引(4x4纹理)
    uint col = uint(texcoord.x * 4.0);
    uint row = uint(texcoord.y * 4.0);
    uint pixelIndex = row * 4 + col;
   
    // 计算前一个索引(循环缓冲区)
    uint prevIndex;
    if (pixelIndex == 0)
    {
        prevIndex = 15; // 循环到最后一个位置
    }
    else
    {
        prevIndex = pixelIndex - 1;
    }
   
    // 将一维索引转换回二维纹理坐标
    uint prevCol = prevIndex % 4;
    uint prevRow = prevIndex / 4;
   
    // 计算前一个位置的纹理坐标(像素中心)
    float2 prevTexcoord = float2(
        prevCol * 0.25 + 0.125,
        prevRow * 0.25 + 0.125
    );
   
    // 读取前一个位置的值
    float4 prevValue = tex2D(SamplerMip4_History, prevTexcoord);
   
    return prevValue;
}
// Pass 10:最终颜色校准
float3 Pass10_FinalCalibration(float4 position : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
    // 检查校准模式
    [branch]
    if (CalibrationMode == 1 || CalibrationMode == 2)
    {
        // 显示校准图案
        return DrawCalibrationPattern(texcoord, CalibrationMode);
    }
   
    // 从后缓冲区采样
    float3 color = tex2D(ReShade::BackBuffer, texcoord).rgb;
   
    // 将texcoord转换为像素坐标(用于调试视图)
    uint x = (uint)(texcoord.x * BUFFER_WIDTH);
    uint y = (uint)(texcoord.y * BUFFER_HEIGHT);
   
    // 获取统计结果
    float minLuminance = 0.0;
    float maxLuminance = 1000.0;
   
    if (EnableAutoStats)
    {
        // 从最终1x1纹理读取结果
        float4 finalStats = tex2D(SamplerMip5, float2(0.5, 0.5));
        minLuminance = finalStats.r;
        maxLuminance = finalStats.g;
       
        // 防止除零
        maxLuminance = max(maxLuminance, minLuminance + 0.001);
       
        // 调试视图 - 显示历史纹理和规约纹理
        [branch]
        if (EnableDebug)
        {
            // 左侧显示区域:显示3个历史相关纹理,每个占屏幕高度的1/3
            float leftDisplaySize = BUFFER_HEIGHT / 3.0;
            float leftDisplayWidth = leftDisplaySize;
            float leftDisplayHeight = leftDisplaySize;
           
            // 右侧显示区域:显示6个规约纹理,每个占屏幕高度的1/6
            float rightDisplaySize = BUFFER_HEIGHT / 6.0;
            float rightDisplayWidth = rightDisplaySize;
            float rightDisplayHeight = rightDisplaySize;
           
            // 检查当前像素是否在左侧显示区域内
            if (x < leftDisplayWidth)
            {
                // 计算在左侧显示区域内的相对位置
                uint displayX = x;
                uint displayY = y;
               
                // 计算当前像素属于哪个历史纹理(0-2)
                uint historyTextureIndex = displayY / (uint)leftDisplayHeight;
               
                // 确保纹理索引在0-2范围内
                if (historyTextureIndex < 3)
                {
                    // 计算在当前纹理显示区域内的相对位置(归一化到[0,1])
                    float localY = (displayY % (uint)leftDisplayHeight) / leftDisplayHeight;
                    float localX = displayX / leftDisplayWidth;
                   
                    // 根据纹理索引采样对应的历史纹理
                    float4 historyValue;
                    if (historyTextureIndex == 0)
                    {
                        // TextureMip4_History: 4x4 - 完整图像(RGBA)
                        float2 mipCoord = float2(localX, localY);
                        historyValue = tex2D(SamplerMip4_History, mipCoord);
                        // 显示完整RGBA:R通道为红色,G通道为绿色,B通道为蓝色
                        return float3(historyValue.r, historyValue.g, historyValue.b);
                    }
                    else if (historyTextureIndex == 1)
                    {
                        // TextureMip4_History: R通道(历史最小值)
                        float2 mipCoord = float2(localX, localY);
                        historyValue = tex2D(SamplerMip4_History, mipCoord);
                        // 只显示R通道(红色)
                        return float3(historyValue.r, 0.0, 0.0);
                    }
                    else // historyTextureIndex == 2
                    {
                        // TextureMip4_History: G通道(历史最大值)
                        float2 mipCoord = float2(localX, localY);
                        historyValue = tex2D(SamplerMip4_History, mipCoord);
                        // 只显示G通道(绿色)
                        return float3(0.0, historyValue.g, 0.0);
                    }
                }
            }
           
            // 检查当前像素是否在屏幕右侧的显示区域内
            if (x > BUFFER_WIDTH - rightDisplayWidth)
            {
                // 计算在显示区域内的相对位置
                uint displayX = x - (BUFFER_WIDTH - (uint)rightDisplayWidth);
                uint displayY = y;
               
                // 计算当前像素属于哪个纹理(0-5)
                uint textureIndex = displayY / (uint)rightDisplayHeight;
               
                // 确保纹理索引在0-5范围内
                if (textureIndex < 6)
                {
                    // 计算在当前纹理显示区域内的相对位置(归一化到[0,1])
                    float localY = (displayY % (uint)rightDisplayHeight) / rightDisplayHeight;
                    float localX = displayX / rightDisplayWidth;
                   
                    // 根据纹理索引采样对应的纹理
                    float4 mipValue;
                    if (textureIndex == 0)
                    {
                        // TextureMip0: 1024x1024
                        float2 mipCoord = float2(localX, localY);
                        mipValue = tex2D(SamplerMip0, mipCoord);
                    }
                    else if (textureIndex == 1)
                    {
                        // TextureMip1: 256x256
                        float2 mipCoord = float2(localX, localY);
                        mipValue = tex2D(SamplerMip1, mipCoord);
                    }
                    else if (textureIndex == 2)
                    {
                        // TextureMip2: 64x64
                        float2 mipCoord = float2(localX, localY);
                        mipValue = tex2D(SamplerMip2, mipCoord);
                    }
                    else if (textureIndex == 3)
                    {
                        // TextureMip3: 16x16
                        float2 mipCoord = float2(localX, localY);
                        mipValue = tex2D(SamplerMip3, mipCoord);
                    }
                    else if (textureIndex == 4)
                    {
                        // TextureMip4: 4x4
                        float2 mipCoord = float2(localX, localY);
                        mipValue = tex2D(SamplerMip4, mipCoord);
                    }
                    else // textureIndex == 5
                    {
                        // TextureMip5: 1x1 - 总是采样中心点
                        mipValue = tex2D(SamplerMip5, float2(0.5, 0.5));
                    }
                   
                    // R通道显示为红色,G通道显示为绿色(保持一致的显示风格)
                    return float3(mipValue.r, mipValue.g, 0.0);
                }
            }
        }
    }
   
    // 显示采样边界(如果启用)
    [branch]
    if (ShowSamplingBorder)
    {
        // 紫色边界颜色
        const float3 BORDER_COLOR = float3(1.0, 0.0, 1.0); // 紫色
       
        // 边界宽度(3像素)
        const float BORDER_WIDTH = 3.0;
       
        // 计算归一化的边界宽度
        float borderWidthX = BORDER_WIDTH / BUFFER_WIDTH;
        float borderWidthY = BORDER_WIDTH / BUFFER_HEIGHT;
       
        // 计算当前像素的归一化坐标
        float2 normalizedCoord = float2(x / float(BUFFER_WIDTH), y / float(BUFFER_HEIGHT));
       
        // 根据采样模式确定边界区域
        float2 borderMin, borderMax;
       
        if (SamplingAera == 0) // 全屏模式
        {
            // 整个屏幕的边界
            borderMin = float2(0.0, 0.0);
            borderMax = float2(1.0, 1.0);
        }
        else // 自定义模式
        {
            // 计算像素大小(与Pass1_DownsampleTo1024一致)
            float2 pixelSize = 1.0 / float2(BUFFER_WIDTH, BUFFER_HEIGHT);
           
            // 采样区域大小(与Pass1_DownsampleTo1024一致)
            float2 sampleSize = float2(1024*CustomAreaSize.x*pixelSize.x, 1024*CustomAreaSize.y*pixelSize.y);
            float2 sampleCenter = CustomAreaCenter;
           
            // 计算采样区域的边界
            float2 halfSize = sampleSize * 0.5;
            borderMin = sampleCenter - halfSize;
            borderMax = sampleCenter + halfSize;
           
            // 注意:这里不需要clamp,因为边界可以超过[0,1]范围
            // 边缘模式允许采样坐标超过[0,1]范围
        }
       
        // 检查当前像素是否在边界区域内(3像素宽)
        bool isInBorder = false;
       
        // 检查左边界
        if (normalizedCoord.x >= borderMin.x && normalizedCoord.x <= borderMin.x + borderWidthX &&
            normalizedCoord.y >= borderMin.y && normalizedCoord.y <= borderMax.y)
        {
            isInBorder = true;
        }
        // 检查右边界
        else if (normalizedCoord.x >= borderMax.x - borderWidthX && normalizedCoord.x <= borderMax.x &&
                normalizedCoord.y >= borderMin.y && normalizedCoord.y <= borderMax.y)
        {
            isInBorder = true;
        }
        // 检查上边界
        else if (normalizedCoord.y >= borderMin.y && normalizedCoord.y <= borderMin.y + borderWidthY &&
                normalizedCoord.x >= borderMin.x && normalizedCoord.x <= borderMax.x)
        {
            isInBorder = true;
        }
        // 检查下边界
        else if (normalizedCoord.y >= borderMax.y - borderWidthY && normalizedCoord.y <= borderMax.y &&
                normalizedCoord.x >= borderMin.x && normalizedCoord.x <= borderMax.x)
        {
            isInBorder = true;
        }
       
        // 如果在边界内,返回紫色
        if (isInBorder)
        {
            return BORDER_COLOR;
        }
    }
   
    // 应用颜色校准
    float3 minColor = float3(minLuminance, minLuminance, minLuminance);
    float3 maxColor = float3(maxLuminance, maxLuminance, maxLuminance);
    return ColorCalibration(color, RGB_offset, RGB_Gamma, RGB_Gain, RGB_Contrast, minColor, maxColor);
}
// ============================================================================
// 技术定义
// ============================================================================
technique ColorCalibration
{
    pass Pass1_Downsample
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass1_DownsampleTo1024;
        RenderTarget = TextureMip0;
    }
   
    pass Pass2_Reduction1
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass2_Reduction1;
        RenderTarget = TextureMip1;
    }
   
    pass Pass3_Reduction2
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass3_Reduction2;
        RenderTarget = TextureMip2;
    }
   
    pass Pass4_Reduction3
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass4_Reduction3;
        RenderTarget = TextureMip3;
    }
   
    pass Pass5_Reduction4
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass5_Reduction4;
        RenderTarget = TextureMip4;
    }
   
    pass Pass6_Reduction5
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass6_Reduction5;
        RenderTarget = TextureMip5;
    }
   
    pass Pass7_StoreCurrentToHistory
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass7_StoreCurrentToHistory;
        RenderTarget = TextureMip4_History;
    }
   
    pass Pass8_CopyHistoryToMip4
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass8_CopyHistoryToMip4;
        RenderTarget = TextureMip4;
    }
   
    pass Pass9_HistoryShift
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass9_HistoryShift;
        RenderTarget = TextureMip4_History;
    }
   
    pass Pass10_Final
    {
        VertexShader = PostProcessVS;
        PixelShader = Pass10_FinalCalibration;
    }
}

Please Log in or Create an account to join the conversation.

  • BlueGary
  • Topic Author
More
5 days 20 hours ago #2 by BlueGary Replied by BlueGary on topic I want to know how to achieve persistent storage of textures.
I'm a fool! I didn't handle the return mechanism of pass7 properly......
 

Please Log in or Create an account to join the conversation.