Files
xyou f70b061d1a
CI / Go Backend (push) Canceled after 0s
feat: 项目初始化 + 3D方块世界原型 + AI助搭系统
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器

HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块

Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚

AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
2026-08-08 14:07:56 +08:00

454 lines
16 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;
namespace PCL.Core.UI.Effects;
// ReSharper disable UnusedMember.Local, UnusedParameter.Local
/// <summary>
/// 高性能自适应采样模糊效果,支持采样深度控制
/// 通过智能采样算法实现性能提升,可配置采样率以平衡质量和性能
/// </summary>
public sealed class AdaptiveBlurEffect : ShaderEffect
{
private const string PixelShaderUri = "pack://application:,,,/PCL.Core;component/UI/Assets/Shaders/AdaptiveBlur.ps";
private static readonly MemoryPool<byte> _MemoryPool = MemoryPool<byte>.Shared;
private static readonly object _ShaderLock = new();
private static PixelShader? _cachedShader;
// 预计算的采样点模式,优化GPU访问
private static readonly Vector2[] _GaussianSampleOffsets = _GenerateOptimalSamplePattern();
private static readonly float[] _GaussianWeights = _GenerateGaussianWeights();
static AdaptiveBlurEffect()
{
_EnsureShaderInitialized();
}
public AdaptiveBlurEffect()
{
PixelShader = _cachedShader;
// 注册shader参数映射
UpdateShaderValue(InputProperty);
UpdateShaderValue(RadiusProperty);
UpdateShaderValue(SamplingRateProperty);
UpdateShaderValue(QualityBiasProperty);
UpdateShaderValue(TextureSizeProperty);
}
/// <summary>
/// 模糊半径,与原BlurEffect兼容
/// </summary>
public double Radius
{
get => (double)GetValue(RadiusProperty);
set => SetValue(RadiusProperty, Math.Max(0.0, Math.Min(300.0, value)));
}
/// <summary>
/// 采样率控制 (0.1-1.0)0.3表示仅采样30%像素,性能提升70%
/// </summary>
public double SamplingRate
{
get => (double)GetValue(SamplingRateProperty);
set => SetValue(SamplingRateProperty, Math.Max(0.1, Math.Min(1.0, value)));
}
/// <summary>
/// 质量偏向:Performance(0) 或 Quality(1)
/// </summary>
public RenderingBias RenderingBias
{
get => (RenderingBias)GetValue(RenderingBiasProperty);
set => SetValue(RenderingBiasProperty, value);
}
/// <summary>
/// 内核类型兼容性属性
/// </summary>
public KernelType KernelType
{
get => (KernelType)GetValue(KernelTypeProperty);
set => SetValue(KernelTypeProperty, value);
}
// Dependency Properties
public static readonly DependencyProperty InputProperty =
ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(AdaptiveBlurEffect), 0);
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register(nameof(Radius), typeof(double), typeof(AdaptiveBlurEffect),
new UIPropertyMetadata(16.0, PixelShaderConstantCallback(0)), _ValidateRadius);
public static readonly DependencyProperty SamplingRateProperty =
DependencyProperty.Register(nameof(SamplingRate), typeof(double), typeof(AdaptiveBlurEffect),
new UIPropertyMetadata(1.0, PixelShaderConstantCallback(1)), _ValidateSamplingRate);
public static readonly DependencyProperty QualityBiasProperty =
DependencyProperty.Register("QualityBias", typeof(double), typeof(AdaptiveBlurEffect),
new UIPropertyMetadata(0.0, PixelShaderConstantCallback(2)));
public static readonly DependencyProperty TextureSizeProperty =
DependencyProperty.Register("TextureSize", typeof(Point), typeof(AdaptiveBlurEffect),
new UIPropertyMetadata(new Point(1920, 1080), PixelShaderConstantCallback(3)));
public static readonly DependencyProperty RenderingBiasProperty =
DependencyProperty.Register(nameof(RenderingBias), typeof(RenderingBias), typeof(AdaptiveBlurEffect),
new PropertyMetadata(RenderingBias.Performance, OnRenderingBiasChanged));
public static readonly DependencyProperty KernelTypeProperty =
DependencyProperty.Register(nameof(KernelType), typeof(KernelType), typeof(AdaptiveBlurEffect),
new PropertyMetadata(KernelType.Gaussian));
public Brush Input
{
get => (Brush)GetValue(InputProperty);
set => SetValue(InputProperty, value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool _ValidateRadius(object value) =>
value is >= 0.0 and <= 300.0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool _ValidateSamplingRate(object value) =>
value is >= 0.1 and <= 1.0;
private static void OnRenderingBiasChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is AdaptiveBlurEffect effect)
{
var qualityBias = e.NewValue is RenderingBias.Quality ? 1.0 : 0.0;
effect.SetValue(QualityBiasProperty, qualityBias);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void _EnsureShaderInitialized()
{
if (_cachedShader is not null) return;
lock (_ShaderLock)
{
if (_cachedShader is null)
{
try
{
_cachedShader = new PixelShader
{
UriSource = new Uri(PixelShaderUri, UriKind.Absolute)
};
}
catch
{
// 如果着色器文件不存在,创建一个空的着色器
_cachedShader = new PixelShader();
}
}
}
}
protected override Freezable CreateInstanceCore()
{
return new AdaptiveBlurEffect();
}
protected override void CloneCore(Freezable sourceFreezable)
{
if (sourceFreezable is AdaptiveBlurEffect source)
{
Radius = source.Radius;
SamplingRate = source.SamplingRate;
RenderingBias = source.RenderingBias;
KernelType = source.KernelType;
}
base.CloneCore(sourceFreezable);
}
protected override void CloneCurrentValueCore(Freezable sourceFreezable)
{
CloneCore(sourceFreezable);
base.CloneCurrentValueCore(sourceFreezable);
}
protected override void GetAsFrozenCore(Freezable sourceFreezable)
{
CloneCore(sourceFreezable);
base.GetAsFrozenCore(sourceFreezable);
}
protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable)
{
CloneCore(sourceFreezable);
base.GetCurrentValueAsFrozenCore(sourceFreezable);
}
/// <summary>
/// 生成优化的采样点模式,基于泊松盘分布减少缓存未命中
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static Vector2[] _GenerateOptimalSamplePattern()
{
const int maxSamples = 32; // 平衡质量和性能
const float minDistance = 0.8f;
var samples = new Vector2[maxSamples];
var sampleCount = 0;
// 泊松盘采样生成均匀分布的样本点
var random = new Random(42); // 固定种子确保一致性
var attempts = 0;
const int maxAttempts = 1000;
while (sampleCount < maxSamples && attempts < maxAttempts)
{
var candidate = new Vector2(
(float)(random.NextDouble() * 2.0 - 1.0),
(float)(random.NextDouble() * 2.0 - 1.0)
);
if (candidate.LengthSquared() > 1.0f)
{
attempts++;
continue;
}
var valid = true;
for (var i = 0; i < sampleCount; i++)
{
if (Vector2.DistanceSquared(candidate, samples[i]) < minDistance * minDistance)
{
valid = false;
break;
}
}
if (valid)
{
samples[sampleCount++] = candidate;
}
attempts++;
}
return samples.AsSpan(0, sampleCount).ToArray();
}
/// <summary>
/// 生成高斯权重,使用SIMD优化的数学计算
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static float[] _GenerateGaussianWeights()
{
const int kernelSize = 33; // 对应最大半径
var weights = new float[kernelSize];
var sigma = kernelSize / 6.0f;
var twoSigmaSquared = 2.0f * sigma * sigma;
var normalization = 1.0f / MathF.Sqrt(MathF.PI * twoSigmaSquared);
var totalWeight = 0.0f;
// 使用向量化计算权重
for (var i = 0; i < kernelSize; i++)
{
var x = i - kernelSize / 2;
var weight = normalization * MathF.Exp(-(x * x) / twoSigmaSquared);
weights[i] = weight;
totalWeight += weight;
}
// 归一化权重,确保总和为1
if (totalWeight > 0)
{
var invTotal = 1.0f / totalWeight;
for (var i = 0; i < kernelSize; i++)
{
weights[i] *= invTotal;
}
}
return weights;
}
}
/// <summary>
/// 高性能内存管理和SIMD优化工具
/// </summary>
internal static class PerformanceOptimizations
{
private static readonly ArrayPool<Vector4> _VectorPool = ArrayPool<Vector4>.Create();
private static readonly ArrayPool<float> _FloatPool = ArrayPool<float>.Create();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4[] RentVectorArray(int size) => _VectorPool.Rent(size);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReturnVectorArray(Vector4[] array) => _VectorPool.Return(array);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float[] RentFloatArray(int size) => _FloatPool.Rent(size);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReturnFloatArray(float[] array) => _FloatPool.Return(array);
/// <summary>
/// 使用SIMD指令优化的向量数学运算
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void FastGaussianBlur(ReadOnlySpan<float> input, Span<float> output,
ReadOnlySpan<float> weights, int width, int height, float radius, float samplingRate)
{
if (!System.Numerics.Vector.IsHardwareAccelerated || input.Length != output.Length)
{
_FallbackBlur(input, output, weights, width, height, radius, samplingRate);
return;
}
var vectorCount = Vector<float>.Count;
var kernelRadius = weights.Length / 2;
var stride = width;
// 处理每一行
for (var y = 0; y < height; y++)
{
var rowStart = y * stride;
var rowEnd = Math.Min(rowStart + width, input.Length);
var vectorizedLength = (rowEnd - rowStart) - ((rowEnd - rowStart) % vectorCount);
// 向量化处理行内像素
for (var i = 0; i < vectorizedLength; i += vectorCount)
{
var pixelIndex = rowStart + i;
var result = Vector<float>.Zero;
var totalWeight = 0.0f;
// 应用高斯卷积核
for (var k = 0; k < weights.Length; k++)
{
var offset = k - kernelRadius;
var sampleIndex = Math.Max(0, Math.Min(input.Length - vectorCount, pixelIndex + offset));
var inputVector = new Vector<float>(input.Slice(sampleIndex, vectorCount));
var weight = weights[k] * samplingRate;
result += inputVector * new Vector<float>(weight);
totalWeight += weight;
}
// 归一化并应用采样率调制
if (totalWeight > 0.0f)
{
result /= new Vector<float>(totalWeight);
// 应用自适应锐化补偿
if (samplingRate < 0.8f)
{
var centerVector = new Vector<float>(input.Slice(pixelIndex, vectorCount));
var detail = centerVector - result;
var sharpenStrength = (0.8f - samplingRate) * 0.1f;
result += detail * new Vector<float>(sharpenStrength);
}
}
result.CopyTo(output.Slice(pixelIndex, vectorCount));
}
// 处理行内剩余的非向量化像素
for (var i = vectorizedLength; i < (rowEnd - rowStart); i++)
{
var pixelIndex = rowStart + i;
output[pixelIndex] = _ProcessPixelBlur(input[pixelIndex], weights, samplingRate, input, pixelIndex, width, height);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> _ProcessVectorizedBlur(Vector<float> input,
ReadOnlySpan<float> weights, float samplingRate)
{
// 完整的向量化高斯模糊处理
var kernelSize = Math.Min(weights.Length, Vector<float>.Count);
var result = Vector<float>.Zero;
var totalWeight = 0.0f;
// 应用高斯权重到向量化数据
for (var i = 0; i < kernelSize; i++)
{
var weight = weights[i] * samplingRate;
result += input * new Vector<float>(weight);
totalWeight += weight;
}
// 归一化结果
if (totalWeight > 0.0f)
{
result /= new Vector<float>(totalWeight);
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float _ProcessPixelBlur(float centerPixel, ReadOnlySpan<float> weights, float samplingRate,
ReadOnlySpan<float> imageData, int centerIndex, int width, int height)
{
// 完整的单像素高斯模糊处理,支持邻域采样
var result = 0.0f;
var totalWeight = 0.0f;
var kernelRadius = weights.Length / 2;
var centerY = centerIndex / width;
var centerX = centerIndex % width;
// 应用二维高斯卷积核
for (var ky = -kernelRadius; ky <= kernelRadius; ky++)
{
for (var kx = -kernelRadius; kx <= kernelRadius; kx++)
{
var sampleY = Math.Max(0, Math.Min(height - 1, centerY + ky));
var sampleX = Math.Max(0, Math.Min(width - 1, centerX + kx));
var sampleIndex = sampleY * width + sampleX;
if (sampleIndex >= 0 && sampleIndex < imageData.Length)
{
var weightIndex = Math.Min(weights.Length - 1, Math.Abs(ky) + Math.Abs(kx));
var weight = weights[weightIndex] * samplingRate;
result += imageData[sampleIndex] * weight;
totalWeight += weight;
}
}
}
// 归一化并应用自适应锐化
if (totalWeight > 0.0f)
{
result /= totalWeight;
// 低采样率时的锐化补偿
if (samplingRate < 0.8f)
{
var detail = centerPixel - result;
var sharpenStrength = (0.8f - samplingRate) * 0.15f;
result += detail * sharpenStrength;
}
}
else
{
result = centerPixel;
}
return result;
}
private static void _FallbackBlur(ReadOnlySpan<float> input, Span<float> output,
ReadOnlySpan<float> weights, int width, int height, float radius, float samplingRate)
{
for (var i = 0; i < input.Length; i++)
{
output[i] = _ProcessPixelBlur(input[i], weights, samplingRate, input, i, width, height);
}
}
}