XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFEEDToolBox.Core.Rendering;

/// <summary>Rejects flat empty cubes and sharp scene geometry in original environment-map candidates.</summary>
public static class SkyboxPixels
{
    public readonly record struct Metrics(double Mean,int LongestEdge,int LargestEdgeComponent);
    public static Metrics Inspect(byte[] bgra,int width,int height)
    {
        if(width<8||height<8||bgra.Length!=(long)width*height*4)throw new ArgumentException("Invalid skybox inspection pixels.");
        var luminance=new float[width*height];var edges=new bool[luminance.Length];double sum=0;
        for(var i=0;i<luminance.Length;i++){var p=i*4;luminance[i]=(bgra[p]*.114f+bgra[p+1]*.587f+bgra[p+2]*.299f)/255;sum+=luminance[i];}
        var longest=0;
        for(var y=1;y<height;y++)
        {
            var run=0;
            for(var x=1;x<width;x++)
            {
                var i=y*width+x;var vertical=Math.Abs(luminance[i]-luminance[i-width])>.035f;
                edges[i]=vertical||Math.Abs(luminance[i]-luminance[i-1])>.035f;
                run=vertical?run+1:0;longest=Math.Max(longest,run);
            }
        }
        for(var x=1;x<width;x++)
        {
            var run=0;for(var y=1;y<height;y++){var i=y*width+x;run=Math.Abs(luminance[i]-luminance[i-1])>.035f?run+1:0;longest=Math.Max(longest,run);}
        }
        var queue=new int[luminance.Length];var largest=0;
        for(var i=0;i<edges.Length;i++)
        {
            if(!edges[i])continue;edges[i]=false;var read=0;var count=1;queue[0]=i;
            while(read<count)
            {
                var pixel=queue[read++];
                void Visit(int next){if(edges[next]){edges[next]=false;queue[count++]=next;}}
                if(pixel%width>0)Visit(pixel-1);if(pixel%width<width-1)Visit(pixel+1);
                if(pixel>=width)Visit(pixel-width);if(pixel+width<edges.Length)Visit(pixel+width);
            }
            largest=Math.Max(largest,count);
        }
        return new(sum/luminance.Length,longest,largest);
    }
}