I want to know how to achieve persistent storage of textures.
- BlueGary
- Topic Author
Less
More
5 days 18 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
Less
More
5 days 18 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.