環境
Unity2021.2.18f1
概要
FFTを用いたグレアフィルターです。
今回も参考リンクのページのコードを実装してみた感じです。
画像も同じのを使わせていただいています。
GenerateStarBurst2Window.cs
using System.IO; using UnityEditor; using UnityEngine; public class GenerateStarBurst2Window : EditorWindow { [MenuItem("Tools/Generate StarBurst2")] private static void Create() { var window = GetWindow<GenerateStarBurst2Window>( "GenerateStarBurst2" ); window.Show(); } private GenerateStarBurst2 _obj = null; private void OnEnable() { var ms = MonoScript.FromScriptableObject( this ); var path = AssetDatabase.GetAssetPath( ms ); path = path.Replace(Path.GetFileName( path ), "" ); path = path + "GenerateStarBurst2.asset"; _obj = AssetDatabase.LoadAssetAtPath<GenerateStarBurst2>( path ); if(_obj == null) { var assets = AssetDatabase.LoadAllAssetsAtPath(path); if(assets.Length > 0) _obj = assets[0] as GenerateStarBurst2; } if( _obj == null ) { _obj = ScriptableObject.CreateInstance<GenerateStarBurst2>(); AssetDatabase.CreateAsset( _obj, path ); AssetDatabase.ImportAsset( path, ImportAssetOptions.ForceUpdate | ImportAssetOptions.ImportRecursive ); } } private void OnDisable() { if( _obj == null ) return; EditorUtility.SetDirty( _obj ); AssetDatabase.ImportAsset( AssetDatabase.GetAssetPath( _obj ), ImportAssetOptions.ForceUpdate | ImportAssetOptions.ImportRecursive ); } private void OnGUI() { _obj.OnGUI(); Repaint(); } }
GenerateStarBurst2.cs
using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; using UnityEngine.Experimental.Rendering; public class GenerateStarBurst2 : ScriptableObject { [SerializeField] private ComputeShader _computeShader = null; [SerializeField] private Texture2D _targetTexture = null; [SerializeField] private Texture2D _apertureTexture = null; private const int m_texheight = 512; //computeShaderも変更する private float m_glareintensity = 20.0f; private float m_threshold = 0.96f; private RenderTexture[] m_RWfullsizeTex = null; private RenderTexture[] m_RWmaxminTex = null; private RenderTexture[] m_RWlineInnerTex = null; private RenderTexture m_RClearTex = null; private struct ComputeParameters { public float lambdaR; public float lambdaG; public float lambdaB; public float glareintensity; public float threshold; }; private GraphicsBuffer _gsConstantParam = null; private void OnDestroy() { if(_gsConstantParam != null) _gsConstantParam.Dispose(); if(m_RWfullsizeTex != null) { for(int i = 0; i < m_RWfullsizeTex.Length; i++) m_RWfullsizeTex[i]?.Release(); } m_RWfullsizeTex = null; if(m_RWmaxminTex != null) { for(int i = 0; i < m_RWmaxminTex.Length; i++) m_RWmaxminTex[i]?.Release(); } m_RWmaxminTex = null; if(m_RWlineInnerTex != null) { for(int i = 0; i < m_RWlineInnerTex.Length; i++) m_RWlineInnerTex[i]?.Release(); } m_RWlineInnerTex = null; m_RClearTex?.Release(); m_RClearTex = null; } private static string LabeledTextField(string label, string text, float labelFieldWidth = 100, float fieldWidth = 30) { using (var horizontalScope = new GUILayout.HorizontalScope()) { EditorGUILayout.LabelField(label, GUILayout.Width(labelFieldWidth)); var str = EditorGUILayout.TextField(text, GUILayout.Width(fieldWidth)); return str; } } public void OnGUI() { var str = LabeledTextField("Glare Intensity", m_glareintensity.ToString(), 100, 60); m_glareintensity = (float)Convert.ToDouble(str); str = LabeledTextField("Threshold", m_threshold.ToString(), 100, 60); m_threshold = (float)Convert.ToDouble(str); if(GUILayout.Button( "Generate Glare" ) == true) { GenerateGlare(); } if(GUILayout.Button( "Generate" ) == true) { Generate(); } var baseRect = GUILayoutUtility.GetLastRect(); var rect = baseRect; rect.position = new Vector2(rect.position.x, rect.position.y + rect.size.y); rect.size = new Vector2(128, 128); if(m_RWfullsizeTex != null) { for(int i = 0; i < m_RWfullsizeTex.Length; i++) { if(m_RWfullsizeTex[i] != null) EditorGUI.DrawPreviewTexture(rect, m_RWfullsizeTex[i]); rect.position = new Vector2(rect.position.x + rect.size.x, rect.position.y); } } rect.position = new Vector2(baseRect.position.x, rect.position.y + rect.size.y); if(m_RWmaxminTex != null) { for(int i = 0; i < m_RWmaxminTex.Length; i++) { if(m_RWmaxminTex[i] != null) EditorGUI.DrawPreviewTexture(rect, m_RWmaxminTex[i]); rect.position = new Vector2(rect.position.x + rect.size.x, rect.position.y); } } rect.position = new Vector2(baseRect.position.x, rect.position.y + rect.size.y); if(m_RWlineInnerTex != null) { for(int i = 0; i < m_RWlineInnerTex.Length; i++) { if(m_RWlineInnerTex[i] != null) EditorGUI.DrawPreviewTexture(rect, m_RWlineInnerTex[i]); rect.position = new Vector2(rect.position.x + rect.size.x, rect.position.y); } } rect.position = new Vector2(baseRect.position.x, rect.position.y + rect.size.y); if(m_RClearTex != null) { EditorGUI.DrawPreviewTexture(rect, m_RClearTex); rect.position = new Vector2(rect.position.x + rect.size.x, rect.position.y); } } private void CreateClearTex() { if(m_RClearTex != null) return; m_RClearTex = new RenderTexture(m_texheight, m_texheight, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Default); m_RClearTex.useMipMap = false; m_RClearTex.enableRandomWrite = true; ExecuteClearCommand(m_RClearTex); } private unsafe void GenerateGlare() { var cp = new ComputeParameters(); cp.lambdaR = 633e-9f; cp.lambdaG = 532e-9f; cp.lambdaB = 466e-9f; cp.glareintensity = m_glareintensity; cp.threshold = m_threshold; if(_gsConstantParam == null) _gsConstantParam = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 1, sizeof(ComputeParameters)); _gsConstantParam.SetData(new ComputeParameters[]{cp}); if(m_RWfullsizeTex == null) { m_RWfullsizeTex = new RenderTexture[9]; for (int i = 0; i < m_RWfullsizeTex.Length; i++) { m_RWfullsizeTex[i] = new RenderTexture(m_texheight, m_texheight, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Default); m_RWfullsizeTex[i].useMipMap = false; m_RWfullsizeTex[i].enableRandomWrite = true; } } if(m_RWmaxminTex == null) { m_RWmaxminTex = new RenderTexture[2]; for (int i = 0; i < m_RWmaxminTex.Length; i++) { m_RWmaxminTex[i] = new RenderTexture(m_texheight, m_texheight, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Default); m_RWmaxminTex[i].useMipMap = false; m_RWmaxminTex[i].enableRandomWrite = true; } } if(m_RWlineInnerTex == null) { m_RWlineInnerTex = new RenderTexture[2]; for (int i = 0; i < m_RWlineInnerTex.Length; i++) { m_RWlineInnerTex[i] = new RenderTexture(m_texheight, m_texheight, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Default); m_RWlineInnerTex[i].useMipMap = false; m_RWlineInnerTex[i].enableRandomWrite = true; } } CreateClearTex(); ExecuteFFTCommand(_apertureTexture, m_RClearTex, m_RWfullsizeTex[3], m_RWfullsizeTex[4]);//グレア生成 ExecuteCalcurateAmplitudeCommand(m_RWfullsizeTex[3], m_RWfullsizeTex[4], m_RWfullsizeTex[5], m_RWfullsizeTex[6]); ExecuteCalcMaxMinCommand(m_RWfullsizeTex[5], m_RWmaxminTex[0], m_RWmaxminTex[1]); ExecuteDivideMaxAmpCommand(m_RWmaxminTex[0], m_RWmaxminTex[1], m_RWfullsizeTex[5], m_RWfullsizeTex[6], m_RWfullsizeTex[3], m_RWfullsizeTex[4]); ExecuteRaiseRICommand(m_RWfullsizeTex[3], m_RWfullsizeTex[4], m_RWfullsizeTex[5], m_RWfullsizeTex[6]);//グレアの輝度を底上げ ExecuteSpectrumScalingCommand(m_RWfullsizeTex[5], m_RWfullsizeTex[6], m_RWfullsizeTex[3], m_RWfullsizeTex[4]);//波長スケーリング ExecuteCopyCommand(m_RWfullsizeTex[3], m_RWfullsizeTex[7]); ExecuteCopyCommand(m_RWfullsizeTex[4], m_RWfullsizeTex[8]); SaveRenderTexture(m_RWfullsizeTex[7], "GlareReal.png"); SaveRenderTexture(m_RWfullsizeTex[8], "GlareImage.png"); } private unsafe void Generate() { if(m_RWfullsizeTex == null) GenerateGlare(); CreateClearTex(); ExecuteBinaryThresholdCommand(_targetTexture, m_RWfullsizeTex[1]); ExecuteConvolutionCommand(m_RWfullsizeTex[1], m_RClearTex, m_RWfullsizeTex[1], m_RWfullsizeTex[2], m_RWfullsizeTex[7], m_RWfullsizeTex[8], m_RWfullsizeTex[3], m_RWfullsizeTex[4], m_RWfullsizeTex[5], m_RWfullsizeTex[6]); ExecuteCalcurateAmplitudeCommand(m_RWfullsizeTex[5], m_RWfullsizeTex[6], m_RWfullsizeTex[0], m_RWfullsizeTex[1]); ExecuteCalcMaxMinCommand(m_RWfullsizeTex[0], m_RWmaxminTex[0], m_RWmaxminTex[1]); ExecuteDivideMaxAmpCommand(m_RWmaxminTex[0], m_RWmaxminTex[1], m_RWfullsizeTex[0], m_RWfullsizeTex[1], m_RWfullsizeTex[3], m_RWfullsizeTex[4]); ExecuteAddCommand(_targetTexture, m_RWfullsizeTex[3], m_RWfullsizeTex[1]); SaveRenderTexture(m_RWfullsizeTex[1], "Final.png"); } private void SaveRenderTexture(RenderTexture renderTex, string path) { var prevRt = RenderTexture.active; Texture2D tex = new Texture2D(renderTex.width, renderTex.height, renderTex.graphicsFormat, TextureCreationFlags.None); RenderTexture.active = renderTex; tex.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0); tex.Apply(); RenderTexture.active = prevRt; var bytes = tex.EncodeToPNG(); File.WriteAllBytes(Path.Combine($"{Application.dataPath}", path), bytes); AssetDatabase.Refresh(); } private Dictionary<string, string> _nameDict = null; private int FindKernel(string name) { if(_nameDict == null) { _nameDict = new Dictionary<string, string>(); _nameDict.Add("mulCS", "mainMULTIPLY"); _nameDict.Add("fftCS_ROW", "mainFFT_ROW"); _nameDict.Add("fftCS_COL", "mainFFT_COL"); _nameDict.Add("ifftCS_ROW", "mainFFT_ROW_INV"); _nameDict.Add("ifftCS_COL", "mainFFT_COL_INV"); _nameDict.Add("ampCS", "mainAMPLITUDE"); _nameDict.Add("divByMaxAMPCS", "mainDivByMaxAMP"); _nameDict.Add("AddCS", "mainAdd"); _nameDict.Add("BTCS", "mainBinaryThreshold"); _nameDict.Add("copyCS", "mainCopy"); _nameDict.Add("clearCS", "mainClear"); _nameDict.Add("spectrumScalingCS", "mainSpectrumScaling"); _nameDict.Add("raiseRICS", "mainRaiseBottomRealImage"); _nameDict.Add("maxminfirstCS", "mainMAXMINfirst"); _nameDict.Add("maxminsecondCS", "mainMAXMINsecond"); } return _computeShader.FindKernel(_nameDict[name]); } private static string[] _csNames = new string[] { "computeConstants", //0 "sourceImageR", //1 "sourceImageI", //2 "destinationImageR", //3 "destinationImageI", //4 "destinationImageR1", //5 "destinationImageI1", //6 }; private string GetCsName(int i) { return _csNames[i]; } private void ExecuteCopyCommand(Texture In, Texture Out) { var kernelIndex = FindKernel("copyCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), In); _computeShader.SetTexture(kernelIndex, GetCsName(3), Out); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteBinaryThresholdCommand(Texture In, Texture Out) { var kernelIndex = FindKernel("BTCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), In); _computeShader.SetTexture(kernelIndex, GetCsName(3), Out); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteClearCommand(Texture Tex) { var kernelIndex = FindKernel("clearCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(3), Tex); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteFFTCommand(Texture Real, Texture Image) { ExecuteFFTCommand(Real, Image, Real, Image); } private void ExecuteFFTCommand(Texture Real, Texture Image, Texture OutReal, Texture OutImage) { //縦方向 var kernelIndex = FindKernel("fftCS_ROW"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), Real); _computeShader.SetTexture(kernelIndex, GetCsName(2), Image); _computeShader.SetTexture(kernelIndex, GetCsName(3), m_RWlineInnerTex[0]); _computeShader.SetTexture(kernelIndex, GetCsName(4), m_RWlineInnerTex[1]); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); //横方向 kernelIndex = FindKernel("fftCS_COL"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), m_RWlineInnerTex[0]); _computeShader.SetTexture(kernelIndex, GetCsName(2), m_RWlineInnerTex[1]); _computeShader.SetTexture(kernelIndex, GetCsName(3), OutReal); _computeShader.SetTexture(kernelIndex, GetCsName(4), OutImage); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteIFFTCommand(Texture Real, Texture Image) { //縦方向 var kernelIndex = FindKernel("ifftCS_ROW"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), Real); _computeShader.SetTexture(kernelIndex, GetCsName(2), Image); _computeShader.SetTexture(kernelIndex, GetCsName(3), m_RWlineInnerTex[0]); _computeShader.SetTexture(kernelIndex, GetCsName(4), m_RWlineInnerTex[1]); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); //横方向 kernelIndex = FindKernel("ifftCS_COL"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), m_RWlineInnerTex[0]); _computeShader.SetTexture(kernelIndex, GetCsName(2), m_RWlineInnerTex[1]); _computeShader.SetTexture(kernelIndex, GetCsName(3), Real); _computeShader.SetTexture(kernelIndex, GetCsName(4), Image); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteCalcurateAmplitudeCommand(Texture InReal, Texture InImage, Texture OutReal, Texture OutImage) { var kernelIndex = FindKernel("ampCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), InReal); _computeShader.SetTexture(kernelIndex, GetCsName(2), InImage); _computeShader.SetTexture(kernelIndex, GetCsName(3), OutReal); _computeShader.SetTexture(kernelIndex, GetCsName(4), OutImage); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteCalcMaxMinCommand(Texture Tex, Texture OutOnePixReal_MAX, Texture OutOnePixImage_MIN) { //最大値最小値の計算 var kernelIndex = FindKernel("maxminfirstCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), Tex); _computeShader.SetTexture(kernelIndex, GetCsName(3), m_RWlineInnerTex[0]); _computeShader.Dispatch(kernelIndex, m_texheight, 1, 1); kernelIndex = FindKernel("maxminsecondCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), m_RWlineInnerTex[0]); _computeShader.SetTexture(kernelIndex, GetCsName(3), OutOnePixReal_MAX); _computeShader.SetTexture(kernelIndex, GetCsName(4), OutOnePixImage_MIN); _computeShader.Dispatch(kernelIndex, 1, 1, 1); } private void ExecuteDivideMaxAmpCommand(Texture OutOnePixReal_MAX, Texture OutOnePixImage_MIN, Texture InReal, Texture InImage, Texture OutReal, Texture OutImage) { //最大振幅による除算 var kernelIndex = FindKernel("divByMaxAMPCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), OutOnePixReal_MAX); _computeShader.SetTexture(kernelIndex, GetCsName(2), OutOnePixImage_MIN); _computeShader.SetTexture(kernelIndex, GetCsName(3), InReal); _computeShader.SetTexture(kernelIndex, GetCsName(4), InImage); _computeShader.SetTexture(kernelIndex, GetCsName(5), OutReal); _computeShader.SetTexture(kernelIndex, GetCsName(6), OutImage); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteRaiseRICommand(Texture InReal, Texture InImage, Texture OutReal, Texture OutImage) { var kernelIndex = FindKernel("raiseRICS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), InReal); _computeShader.SetTexture(kernelIndex, GetCsName(2), InImage); _computeShader.SetTexture(kernelIndex, GetCsName(3), OutReal); _computeShader.SetTexture(kernelIndex, GetCsName(4), OutImage); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteSpectrumScalingCommand(Texture InReal, Texture InImage, Texture OutReal, Texture OutImage) { var kernelIndex = FindKernel("spectrumScalingCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), InReal); _computeShader.SetTexture(kernelIndex, GetCsName(2), InImage); _computeShader.SetTexture(kernelIndex, GetCsName(3), OutReal); _computeShader.SetTexture(kernelIndex, GetCsName(4), OutImage); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteConvolutionCommand(Texture InReal0, Texture InImage0, Texture InReal1, Texture InImage1, Texture OutReal, Texture OutImage) { ExecuteConvolutionCommand(InReal0, InImage0, InReal0, InImage0, InReal1, InImage1, InReal1, InImage1, OutReal, OutImage); } private void ExecuteConvolutionCommand(Texture InReal0, Texture InImage0, Texture TmpFftReal0, Texture TmpFftImage0, Texture InReal1, Texture InImage1, Texture TmpFftReal1, Texture TmpFftImage1, Texture OutReal, Texture OutImage) { //一方のFFT ExecuteFFTCommand(InReal0, InImage0, TmpFftReal0, TmpFftImage0); //もう一方のFFT ExecuteFFTCommand(InReal1, InImage1, TmpFftReal1, TmpFftImage1); //乗算 ExecuteMultiplyCommand(TmpFftReal0, TmpFftImage0, TmpFftReal1, TmpFftImage1, OutReal, OutImage); //逆FFT ExecuteIFFTCommand(OutReal, OutImage); } private void ExecuteMultiplyCommand(Texture InReal0, Texture InImage0, Texture InReal1, Texture InImage1, Texture OutReal, Texture OutImage) { var kernelIndex = FindKernel("mulCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), InReal0); _computeShader.SetTexture(kernelIndex, GetCsName(2), InImage0); _computeShader.SetTexture(kernelIndex, GetCsName(3), InReal1); _computeShader.SetTexture(kernelIndex, GetCsName(4), InImage1); _computeShader.SetTexture(kernelIndex, GetCsName(5), OutReal); _computeShader.SetTexture(kernelIndex, GetCsName(6), OutImage); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } private void ExecuteAddCommand(Texture Tex1, Texture Tex2, Texture Out) { var kernelIndex = FindKernel("AddCS"); _computeShader.SetBuffer(kernelIndex, GetCsName(0), _gsConstantParam); _computeShader.SetTexture(kernelIndex, GetCsName(1), Tex1); _computeShader.SetTexture(kernelIndex, GetCsName(2), Tex2); _computeShader.SetTexture(kernelIndex, GetCsName(3), Out); _computeShader.Dispatch(kernelIndex, 1, m_texheight, 1); } }
GenerateStarBurst2.compute
static const int WIDTH = 512; static const int HEIGHT = 512; static const float PI = 3.14159; static const float RAD = PI / 180.0; static const int LENGTH = HEIGHT; static const int BUTTERFLY_COUNT = 9; //-------------------------------- float2 complex_conjugate(float2 cmp) { return float2(cmp.x, -cmp.y); } float complex_sqr(float2 cmp) { return cmp.x * cmp.x + cmp.y * cmp.y; } float complex_norm(float2 cmp) { return sqrt(complex_sqr(cmp)); } float2 complex_add(float2 cmp1, float2 cmp2) { return float2(cmp1.x + cmp2.x, cmp1.y + cmp2.y); } float2 complex_sub(float2 cmp1, float2 cmp2) { return float2(cmp1.x - cmp2.x, cmp1.y - cmp2.y); } float2 complex_mul(float2 cmp1, float2 cmp2) { return float2(cmp1.x * cmp2.x - cmp1.y * cmp2.y, cmp1.y * cmp2.x + cmp1.x * cmp2.y); } float2 complex_div(float2 cmp1, float2 cmp2) { float2 cmp = complex_mul(cmp1, complex_conjugate(cmp2)); float sqr = complex_sqr(cmp2); return float2(cmp.x / sqr, cmp.y / sqr); } float2 complex_polar(float amp, float phase) { return float2(amp * cos(phase), amp * sin(phase)); } //------------------------ struct ComputeParameters { float lambdaR; float lambdaG; float lambdaB; float glareintensity; float threshold; }; StructuredBuffer<ComputeParameters> computeConstants; Texture2D<float4> sourceImageR : register(t0); Texture2D<float4> sourceImageI : register(t1); RWTexture2D<float4> destinationImageR : register(u0); RWTexture2D<float4> destinationImageI : register(u1); RWTexture2D<float4> destinationImageR1 : register(u2); RWTexture2D<float4> destinationImageI1 : register(u3); //------------------------ //copyCSに対応 #pragma kernel mainCopy [numthreads(WIDTH, 1, 1)] void mainCopy(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; destinationImageR[index] = sourceImageR[index]; } //BTCSに対応 #pragma kernel mainBinaryThreshold [numthreads(WIDTH, 1, 1)] void mainBinaryThreshold(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; float3 input = sourceImageR[index].rgb; float3 col = float3(0.0, 0.0, 0.0); float r = 0; float g = 0; float b = 0; if ((input.r + input.g + input.b) / 3.0 > computeConstants[0].threshold) { col = float3(1.0, 1.0, 1.0); } destinationImageR[index] = float4(col, 1.0f); } //clearCSに対応 #pragma kernel mainClear [numthreads(WIDTH, 1, 1)] void mainClear(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; destinationImageR[index] = float4(0.0, 0.0, 0.0, 1.0); } //fftCS_シリーズで使用される void ComputeSrcID(uint passIndex, uint x, out uint2 indices) { uint regionWidth = 2 << passIndex; indices.x = (x & ~(regionWidth - 1)) + (x & (regionWidth / 2 - 1)); indices.y = indices.x + regionWidth / 2; if (passIndex == 0) { indices = reversebits(indices) >> (32 - BUTTERFLY_COUNT) & (LENGTH - 1); } } void ComputeTwiddleFactor(uint passIndex, uint x, out float2 weights) { uint regionWidth = 2 << passIndex; sincos(2.0 * PI * float(x & (regionWidth - 1)) / float(regionWidth), weights.y, weights.x); weights.y *= -1; } static const int REAL = 0; static const int IMAGE = 1; #ifdef DOUBLE//メモリに余裕があるとき groupshared float3 ButterflyArray[2][2][LENGTH]; #define SharedArray(tmpID, x, realImage) (ButterflyArray[(tmpID)][(realImage)][(x)]) #else groupshared float3 ButterflyArray[2][LENGTH]; #define SharedArray(tmpID, x, realImage) (ButterflyArray[(realImage)][(x)]) #endif //fftCS_シリーズで使用される void ButterflyWeightPass(uint passIndex, uint x, uint tmp, out float3 resultR, out float3 resultI) { uint2 Indices; float2 Weights; ComputeSrcID(passIndex, x, Indices); float3 inputR1 = SharedArray(tmp, Indices.x, REAL); float3 inputI1 = SharedArray(tmp, Indices.x, IMAGE); float3 inputR2 = SharedArray(tmp, Indices.y, REAL); float3 inputI2 = SharedArray(tmp, Indices.y, IMAGE); ComputeTwiddleFactor(passIndex, x, Weights); #ifndef DOUBLE GroupMemoryBarrierWithGroupSync();//ダブルバッファでない場合は格納の完了を保証する必要がる #endif #if INVERSE resultR = (inputR1 + Weights.x * inputR2 + Weights.y * inputI2) * 0.5; resultI = (inputI1 - Weights.y * inputR2 + Weights.x * inputI2) * 0.5; #else resultR = inputR1 + Weights.x * inputR2 - Weights.y * inputI2; resultI = inputI1 + Weights.y * inputR2 + Weights.x * inputI2; #endif } void initializeFFT_SharedArray(uint bufferID, inout uint2 texPos) { texPos = (texPos + LENGTH / 2) % LENGTH; SharedArray(0, bufferID, REAL) = sourceImageR[texPos].xyz; #if ROW && !INVERSE SharedArray(0, bufferID, IMAGE) = (0.0).xxx; #else SharedArray(0, bufferID, IMAGE) = sourceImageI[texPos].xyz; #endif } void ButterflyPass(in uint bufferID, out float3 real, out float3 image) { for (uint butterFlyID = 0; butterFlyID < (uint)(BUTTERFLY_COUNT - 1); butterFlyID++) { GroupMemoryBarrierWithGroupSync(); ButterflyWeightPass(butterFlyID, bufferID, butterFlyID % 2, SharedArray((butterFlyID + 1) % 2, bufferID, REAL), SharedArray((butterFlyID + 1) % 2, bufferID, IMAGE)); } GroupMemoryBarrierWithGroupSync(); ButterflyWeightPass(BUTTERFLY_COUNT - 1, bufferID, (BUTTERFLY_COUNT - 1) % 2, real, image); } //fftCS_シリーズに対応 void mainFFT(uint3 dispatchID) { const uint bufferID = dispatchID.x; #if ROW uint2 texPos = dispatchID.xy; #else uint2 texPos = dispatchID.yx; #endif initializeFFT_SharedArray(bufferID, texPos); float3 r_result = 0, i_result = 0; ButterflyPass(bufferID, r_result, i_result); destinationImageR[texPos] = float4(r_result, 1); destinationImageI[texPos] = float4(i_result, 1); } #pragma kernel mainFFT_ROW ROW [numthreads(LENGTH, 1, 1)] void mainFFT_ROW(uint3 dispatchID : SV_DispatchThreadID) { mainFFT(dispatchID); } #pragma kernel mainFFT_COL [numthreads(LENGTH, 1, 1)] void mainFFT_COL(uint3 dispatchID : SV_DispatchThreadID) { mainFFT(dispatchID); } #pragma kernel mainFFT_ROW_INV ROW INVERSE [numthreads(LENGTH, 1, 1)] void mainFFT_ROW_INV(uint3 dispatchID : SV_DispatchThreadID) { mainFFT(dispatchID); } #pragma kernel mainFFT_COL_INV INVERSE [numthreads(LENGTH, 1, 1)] void mainFFT_COL_INV(uint3 dispatchID : SV_DispatchThreadID) { mainFFT(dispatchID); } //ampCSに対応 #pragma kernel mainAMPLITUDE [numthreads(WIDTH, 1, 1)] void mainAMPLITUDE(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; float3 inputR = sourceImageR[index].rgb; float3 inputI = sourceImageI[index].rgb; float r = inputR.r * inputR.r + inputI.r * inputI.r; float g = inputR.g * inputR.g + inputI.g * inputI.g; float b = inputR.b * inputR.b + inputI.b * inputI.b; float3 col = float3(sqrt(r), sqrt(g), sqrt(b)); destinationImageR[index] = float4(col, 1.0f); destinationImageI[index] = float4(col, 1.0f); } //maxminfirstCSに対応 #pragma kernel mainMAXMINfirst [numthreads(1, 1, 1)] void mainMAXMINfirst(uint3 dispatchID : SV_DispatchThreadID) { uint2 index = dispatchID.xy; float3 color_max = sourceImageR[float2(0, 0)].xyz; float3 color_min = color_max; int i, j; for (i = 0; i < HEIGHT; i++) { uint2 indexx = uint2(index.x, i); float3 color = sourceImageR[indexx].xyz; color_max = max(color_max, color); color_min = min(color_min, color); } destinationImageR[float2(index.x, 0)] = float4(color_max, 1.0f); destinationImageR[float2(index.x, 1)] = float4(color_min, 1.0f); } //maxminsecondCSに対応 #pragma kernel mainMAXMINsecond [numthreads(1, 1, 1)] void mainMAXMINsecond(uint3 dispatchID : SV_DispatchThreadID) { uint2 index = dispatchID.xy; float3 color_max = sourceImageR[float2(0, 0)].xyz; float3 color_min = color_max; int i, j; for (i = 0; i < HEIGHT; i++) { uint2 index1 = uint2(i, 0); uint2 index2 = uint2(i, 1); float3 colormax = sourceImageR[index1].xyz; float3 colormin = sourceImageR[index2].xyz; color_max = max(color_max, colormax); color_min = min(color_min, colormin); } destinationImageR[float2(0, 0)] = float4(color_max, 1.0f); destinationImageI[float2(0, 0)] = float4(color_min, 1.0f); } //divByMaxAMPCSに対応 #pragma kernel mainDivByMaxAMP [numthreads(WIDTH, 1, 1)] void mainDivByMaxAMP(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; float2 zero = float2(0.0, 0.0); //sourceImageRに最大値格納したテクスチャをセットしておく float3 color_max = sourceImageR[zero].rgb; //destinatinImageR/Iに正規化したいテクスチャをセットしておく float3 colorR = destinationImageR[index].rgb; float3 colorI = destinationImageI[index].rgb; colorR = colorR / color_max; colorI = colorI / color_max; float col_max_per = color_max.r; col_max_per = max(col_max_per, color_max.g); col_max_per = max(col_max_per, color_max.b); float3 ratio = color_max / col_max_per; colorR = colorR * ratio; colorI = colorI * ratio; destinationImageR1[index] = float4(colorR, 1.0f); destinationImageI1[index] = float4(colorI, 1.0f); } //raiseRICSに対応 #pragma kernel mainRaiseBottomRealImage [numthreads(WIDTH, 1, 1)] void mainRaiseBottomRealImage(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; float3 inputR = sourceImageR[index].rgb; float3 inputI = sourceImageI[index].rgb; float3 amplitude = float3(sqrt(inputR.r * inputR.r + inputI.r * inputI.r) , sqrt(inputR.g * inputR.g + inputI.g * inputI.g) , sqrt(inputR.b * inputR.b + inputI.b * inputI.b)); if ((amplitude.r + amplitude.g + amplitude.b) / 3.0f < 0.9) { /*inputR = inputR * 10.0f; inputI = inputI * 10.0f;*/ inputR = inputR * computeConstants[0].glareintensity; inputI = inputI * computeConstants[0].glareintensity; } if ((inputR.r + inputR.g + inputR.b) / 3.0f >= 1.0) { inputR = float3(1.0, 1.0, 1.0); } if ((inputI.r + inputI.g + inputI.b) / 3.0f >= 1.0) { inputI = float3(1.0, 1.0, 1.0); } destinationImageR[index] = float4(inputR, 1.0); destinationImageI[index] = float4(inputI, 1.0); } //spectrumScalingCSに対応 #pragma kernel mainSpectrumScaling [numthreads(WIDTH, 1, 1)] void mainSpectrumScaling(uint3 dispatchID : SV_DispatchThreadID) { float2 indexR = dispatchID.xy; float ratioRG = computeConstants[0].lambdaG / computeConstants[0].lambdaR; float ratioRB = computeConstants[0].lambdaB / computeConstants[0].lambdaR; float2 uvR = indexR - float2(0.5 * WIDTH, 0.5 * HEIGHT); float2 uvG = uvR * ratioRG; float2 uvB = uvR * ratioRB; float2 indexG = uvG + float2(0.5 * WIDTH, 0.5 * HEIGHT); float2 indexB = uvB + float2(0.5 * WIDTH, 0.5 * HEIGHT); float r = sourceImageR[indexR].r; float g = sourceImageR[indexG].g; float b = sourceImageR[indexB].b; destinationImageR[indexR] = float4(r, g, b, 1.0); r = sourceImageI[indexR].r; g = sourceImageI[indexG].g; b = sourceImageI[indexB].b; destinationImageI[indexR] = float4(r, g, b, 1.0); } //mulCSに対応 #pragma kernel mainMULTIPLY [numthreads(WIDTH, 1, 1)] void mainMULTIPLY(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; float3 color_real1 = sourceImageR[index].rgb;//元1 実部 float3 color_image1 = sourceImageI[index].rgb;//元1 虚部 float3 color_real2 = destinationImageR[index].rgb;//元2 実部 float3 color_image2 = destinationImageI[index].rgb;//元2 虚部 //各色からの複素数生成 float2 compR1 = float2(color_real1.r, color_image1.r); float2 compG1 = float2(color_real1.g, color_image1.g); float2 compB1 = float2(color_real1.b, color_image1.b); float2 compR2 = float2(color_real2.r, color_image2.r); float2 compG2 = float2(color_real2.g, color_image2.g); float2 compB2 = float2(color_real2.b, color_image2.b); //各色毎に乗算 float2 mulcompR = complex_mul(compR1, compR2); float2 mulcompG = complex_mul(compG1, compG2); float2 mulcompB = complex_mul(compB1, compB2); //代入用の複素数作成 float3 colorREAL = float3(mulcompR.x, mulcompG.x, mulcompB.x); float3 colorIMAGE = float3(mulcompR.y, mulcompG.y, mulcompB.y); destinationImageR1[index] = float4(colorREAL, 1.0f); destinationImageI1[index] = float4(colorIMAGE, 1.0f); } //AddCSに対応 #pragma kernel mainAdd [numthreads(WIDTH, 1, 1)] void mainAdd(uint3 dispatchID : SV_DispatchThreadID) { float2 index = dispatchID.xy; float3 input1 = sourceImageR[index].rgb; float3 input2 = sourceImageI[index].rgb; float3 col = input1 + input2; destinationImageR[index] = float4(col, 1.0f); }
感想
真ん中だけ妙にグレアってるのは何ででしょうか。
こっちの差分コード実装し忘れました
ポストエフェクトクエスト - 波長方向の積分マジ大事という話 - - Qiita