diff --git a/RokojoriPlugin.cs b/RokojoriPlugin.cs index e2ffb80..1effc78 100644 --- a/RokojoriPlugin.cs +++ b/RokojoriPlugin.cs @@ -10,8 +10,14 @@ namespace Rokojori { GizmoDrawerPlugin gizmoDrawerPlugin = new GizmoDrawerPlugin(); + public static readonly string path = "res://addons/rokojori_action_library"; + public static string Path( string path ) + { + return RokojoriPlugin.path + "/" + path; + } + static readonly string RokojoriRootAutoLoad = "RokojoriRootAutoLoad"; - static readonly string RokojoriRootAutoLoadPath = "res://addons/rokojori_action_library/Runtime/Godot/Root.cs"; + static readonly string RokojoriRootAutoLoadPath = Path( "Runtime/Godot/Root.cs" ); public override void _EnablePlugin() { diff --git a/Runtime/Bits/Bytes.cs b/Runtime/Bits/Bytes.cs index 4d61e34..3da5202 100644 --- a/Runtime/Bits/Bytes.cs +++ b/Runtime/Bits/Bytes.cs @@ -1,7 +1,8 @@ using Godot; using System; -using System.Text; +using System.Collections.Generic; + namespace Rokojori { @@ -26,5 +27,19 @@ namespace Rokojori var mask = 1 << position; return ( mask & value ) == mask ; } + + public static List Convert( List floats ) + { + var list = new List(); + floats.ForEach( f => list.AddRange( BitConverter.GetBytes( f ) ) ); + return list; + } + + public static List Convert( List ints ) + { + var list = new List(); + ints.ForEach( i => list.AddRange( BitConverter.GetBytes( i ) ) ); + return list; + } } } \ No newline at end of file diff --git a/Runtime/Colors/ColorX.cs b/Runtime/Colors/ColorX.cs index be36016..27a80e6 100644 --- a/Runtime/Colors/ColorX.cs +++ b/Runtime/Colors/ColorX.cs @@ -4,7 +4,15 @@ namespace Rokojori { public static class ColorX { - + public static Color UnblendBlack( this Color c, float treshold = 0 ) + { + if ( c.A <= treshold ) + { + return c; + } + + return new Color( c.R / c.A, c.G / c.A, c.B / c.A, c.A ); + } public static float AlphaMultipliedR( this Color c ) { diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs index f47d976..c07adb3 100644 --- a/Runtime/Godot/Nodes.cs +++ b/Runtime/Godot/Nodes.cs @@ -284,6 +284,16 @@ namespace Rokojori RJLog.Log( resource, messages ); } + public static void LogInfoIf( this Resource resource, bool condition, params object[] messages ) + { + if ( ! condition ) + { + return; + } + + RJLog.Log( resource, messages ); + } + public static void LogError( this Resource resource, params object[] messages ) { RJLog.Error( resource, messages ); diff --git a/Runtime/Procedural/Baking/MultiBaker/MultiBaker.cs b/Runtime/Procedural/Baking/MultiBaker/MultiBaker.cs index 1c7e7d7..716958d 100644 --- a/Runtime/Procedural/Baking/MultiBaker/MultiBaker.cs +++ b/Runtime/Procedural/Baking/MultiBaker/MultiBaker.cs @@ -307,10 +307,11 @@ namespace Rokojori this.LogInfo( "Texture created:", bakingMaterialModes[ i ] ); - texture = Textures.Copy( texture ); - await this.RequestNextFrame(); await this.RequestNextFrame(); + texture = await CPUTextureDilater.Dilate( texture, this.RequestNextFrame ); + + this.LogInfo( "Assigning Texture", bakingMaterialModes[ i ] ); bakeMode.AssignMaterial( bakingMaterialModes[ i ], texture ); diff --git a/Runtime/Procedural/Textures/CPUTextureDilater/CPUTextureDilater.cs b/Runtime/Procedural/Textures/CPUTextureDilater/CPUTextureDilater.cs new file mode 100644 index 0000000..aac1755 --- /dev/null +++ b/Runtime/Procedural/Textures/CPUTextureDilater/CPUTextureDilater.cs @@ -0,0 +1,254 @@ +using System.Collections; +using System.Collections.Generic; +using Godot; +using System; +using System.Threading.Tasks; + +using System.Linq; +using TriangleNet.Geometry; + +namespace Rokojori +{ + public class CPUTextureDilater + { + public static async Task Dilate( Texture2D texture, Func waiting, float alphaTreshold = 250f/255f ) + { + var dilater = new CPUTextureDilater(); + dilater.alphaTreshold = alphaTreshold; + dilater.waiting = waiting; + + var t = await dilater._Dilate( texture ); + + return t; + } + + TextureCombinerBuffer _buffer; + Func waiting; + + async Task _Dilate( Texture2D texture ) + { + _buffer = TextureCombinerBuffer.From( texture ); + + await _Process(); + + return _buffer.CreateImageTexture(); + } + + public float alphaTreshold = 250f/255f; + + HashSet _processed = new HashSet(); + HashSet _unprocessed = new HashSet(); + HashSet _edges = new HashSet(); + + + + async Task _Process() + { + _buffer.UnblendBlack(); + + GrabInitialPixels(); + + + if ( _unprocessed.Count == _buffer.numPixels ) + { + return; + } + + int maxMessages = 100; + int messageCounter = 0; + int messageLimit = 200000; + + int max = 1000 * 1000; + int it = 0; + + var random = LCG.WithSeed( 1984 ); + + while ( _edges.Count > 0 && it < max ) + { + it++; + + if ( messageCounter >= messageLimit ) + { + await waiting(); + messageCounter = 0; + RJLog.Log( + RegexUtility._FF( 100f *_processed.Count / _buffer.numPixels ) + "%", + "Valid: ", ( _processed.Count + _edges.Count + _unprocessed.Count ) == _buffer.numPixels, + "P", _processed.Count, "E",_edges.Count, "U", _unprocessed.Count + ); + } + else + { + messageCounter ++; + } + + var edge = _edges.ElementAt( random.IntegerExclusive( _edges.Count ) ); + _edges.Remove( edge ); + + if ( ! _processed.Contains( edge ) ) + { + var edgeColor = ComputeColor( edge ); + _processed.Add( edge ); + _buffer.SetIndexed( edge, edgeColor ); + } + + AddEdgeNeighbors( edge ); + + } + + if ( _edges.Count > 0 && it == max ) + { + RJLog.Log( "Aborted, too many entries" ); + } + + } + + void GrabInitialPixels() + { + for ( int i = 0; i < _buffer.numPixels; i++ ) + { + if ( ! HasColor( i ) ) + { + _unprocessed.Add( i ); + } + else + { + if ( IsEdge( i ) ) + { + _edges.Add( i ); + } + + _processed.Add( i ); + } + } + } + + void AddEdgeNeighbors( int i ) + { + var position = _buffer.ComputePositionFromIndex( i ); + + for ( int x = -1; x <= 1; x++ ) + { + for ( int y = -1; y <= 1; y++ ) + { + if ( x == 0 && y == 0 ) + { + continue; + } + + var index = _buffer.ComputeIndexFromPosition( position.X + x, position.Y + y ); + + if ( index < 0 || index >= _buffer.numPixels ) + { + continue; + } + + if ( ! _unprocessed.Contains( index ) ) + { + continue; + } + + _unprocessed.Remove( index ); + _edges.Add( index ); + } + } + + } + + bool HasColor( int x, int y ) + { + return HasColor( _buffer.ComputeIndexFromPosition( x, y ) ); + } + + bool HasColor( int i ) + { + if ( i < 0 || i >= _buffer.numPixels ) + { + return false; + } + + var pixel = _buffer.GetIndexed( i ); + + if ( pixel.A > alphaTreshold ) + { + return true; + } + + return _processed.Contains( i ); + } + + + + bool IsEdge( int i ) + { + if ( ! HasColor( i ) ) + { + return false; + } + + var position = _buffer.ComputePositionFromIndex( i ); + + for ( int x = -1; x <= 1; x++ ) + { + for ( int y = -1; y <= 1; y++ ) + { + if ( x == 0 && y == 0 ) + { + continue; + } + + if ( ! HasColor( position.X + x, position.Y + y ) ) + { + return true; + } + } + } + + return false; + + } + + Color ComputeColor( int i ) + { + var position = _buffer.ComputePositionFromIndex( i ); + + var pixel = _buffer.GetIndexed( i ); + var distance = 10f; + var closestPixel = -1; + + for ( int x = -1; x <= 1; x++ ) + { + for ( int y = -1; y <= 1; y++ ) + { + if ( ( x == 0 && y == 0 ) || ! HasColor( position.X + x, position.Y + y ) ) + { + continue; + } + + var d = new Vector2( x, y ).Length(); + + if ( d >= distance ) + { + continue; + } + + distance = d; + closestPixel = _buffer.ComputeIndexFromPosition( position.X + x, position.Y + y ); + + // var pixelColor = _buffer.GetAt( position.X + x, position.Y + y ); + // rawColor += new Vector3( pixelColor.R, pixelColor.G, pixelColor.B); + // numColors ++; + } + } + + // rawColor /= numColors; + + var rawColor = _buffer.GetIndexed( closestPixel ); + + + + return new Color( rawColor.R, rawColor.G, rawColor.B, pixel.A ); + } + } + +} \ No newline at end of file diff --git a/Runtime/Procedural/Textures/CPUTextureDilater/CPUTextureDilater.cs.uid b/Runtime/Procedural/Textures/CPUTextureDilater/CPUTextureDilater.cs.uid new file mode 100644 index 0000000..4f01462 --- /dev/null +++ b/Runtime/Procedural/Textures/CPUTextureDilater/CPUTextureDilater.cs.uid @@ -0,0 +1 @@ +uid://jk67aba6i3mx diff --git a/Runtime/Procedural/Textures/TextureCombiner/TextureCombinerBuffer.cs b/Runtime/Procedural/Textures/TextureCombiner/TextureCombinerBuffer.cs index 426c45a..b1f1b02 100644 --- a/Runtime/Procedural/Textures/TextureCombiner/TextureCombinerBuffer.cs +++ b/Runtime/Procedural/Textures/TextureCombiner/TextureCombinerBuffer.cs @@ -17,6 +17,8 @@ namespace Rokojori Color[] _pixels; + public int numPixels => _pixels.Length; + public static TextureCombinerBuffer Create( int w, int h ) { var tb = new TextureCombinerBuffer(); @@ -27,6 +29,14 @@ namespace Rokojori return tb; } + public void UnblendBlack( float treshold = 10f/255f ) + { + for ( int i = 0; i < _pixels.Length; i++ ) + { + _pixels[ i ] = _pixels[ i ].UnblendBlack( treshold ); + } + } + public static TextureCombinerBuffer From( Texture2D texture ) { var buffer = Create( texture.GetWidth(), texture.GetHeight() ); @@ -35,6 +45,15 @@ namespace Rokojori return buffer; } + public ImageTexture CreateImageTexture() + { + var image = Image.CreateEmpty( width, height, true, Image.Format.Rgba8 ); + CopyTo( 0, 0, 0, 0, width, height, image ); + image.GenerateMipmaps(); + + return ImageTexture.CreateFromImage( image ); + } + public TextureCombinerBuffer Resize( int w, int h ) { var buffer = Create( w, h ); @@ -102,6 +121,14 @@ namespace Rokojori return x + y * _width; } + public Vector2I ComputePositionFromIndex( int index ) + { + var x = index % width; + var y = index / width; + + return new Vector2I( x, y ); + } + public void SetAt( int x, int y, Color value ) { SetIndexed( ComputeIndexFromPosition( x, y ), value ); diff --git a/Runtime/Rendering/CompositorEffects/Blur/BlurCompositorEffect.cs b/Runtime/Rendering/CompositorEffects/Blur/BlurCompositorEffect.cs new file mode 100644 index 0000000..870f5bf --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Blur/BlurCompositorEffect.cs @@ -0,0 +1,300 @@ + +using Godot; +using Godot.Collections; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class BlurCompositorEffect:CompositorEffect + { + public enum BlurType + { + Box, + Gaussian + } + + [ExportGroup( "Blur Properties" )] + [Export] + public BlurType blurType = BlurType.Box; + + [Export( PropertyHint.Range, "1,80" )] + public int blurSamples = 15; + [Export( PropertyHint.Range, "1,80" )] + public int blurWidth = 80; + [Export( PropertyHint.Range, "0,0.5" )] + public float dither = 0; + [Export( PropertyHint.Range, "1,4" )] + public int mipLevel = 1; + [Export] + public bool logDebugInfo = false; + + //for sensing when the backbuffers need rebuilding + public Vector2I sizeCache = new Vector2I(); + public int mipCache; + + public RenderingDevice rd; + public Rid shader; + public Rid pipeline; + public Array backbuffers = new Array(); + public RDTextureFormat backbufferFormat; + public RDTextureView texview; + public RDSamplerState samplerState; + public Rid linearSampler; + + + public BlurCompositorEffect() + { + RJLog.Log( "_Init" ); + RenderingServer.CallOnRenderThread( Callable.From( InitializeComputeShader ) ); + } + + public void InitializeComputeShader() + { + RJLog.Log( "InitializeComputeShader" ); + + rd = RenderingServer.GetRenderingDevice(); + + if ( rd == null ) + { + RJLog.Log( "Initializing failed" ); + return; + } + + RJLog.Log( "Initializing succeed, loading shader" ); + //Make sure this is correctly pointing to the GLSL file + RDShaderFile glslFile = ( RDShaderFile ) GD.Load( "res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl" ); + + shader = rd.ShaderCreateFromSpirV( glslFile.GetSpirV() ); + pipeline = rd.ComputePipelineCreate( shader ); + + samplerState = new RDSamplerState(); + samplerState.MinFilter = RenderingDevice.SamplerFilter.Linear; + samplerState.MagFilter = RenderingDevice.SamplerFilter.Linear; + + linearSampler = rd.SamplerCreate( samplerState ); + + + RJLog.Log( "Initializing done", shader, pipeline, samplerState, linearSampler ); + + } + + public override void _Notification( int what ) + { + if ( what != NotificationPredelete || ! shader.IsValid || rd == null ) + { + return; + } + + rd.FreeRid( shader ); + rd.FreeRid( linearSampler ); + + foreach( var b in backbuffers ) + { + rd.FreeRid( ( Rid ) b ); + } + + } + + + public override void _RenderCallback( int effectCallbackType, RenderData renderData ) + { + DoPass( renderData, 1 ); // horizontal blur + DoPass( renderData, 2 ); // vertical blur + DoPass( renderData, 3 ); // draw buffers to screen + + } + + public void DoPass( RenderData renderData, int passNum ) + { + if ( rd == null ) + { + this.LogInfoIf( logDebugInfo, "No RD" ); + return; + } + + //get fresh scene buffers && data for this pass + RenderSceneBuffersRD sceneBuffers = ( RenderSceneBuffersRD ) renderData.GetRenderSceneBuffers(); + RenderSceneDataRD sceneData = ( RenderSceneDataRD ) renderData.GetRenderSceneData(); + + if ( sceneBuffers == null && sceneData == null ) + { + this.LogInfoIf( logDebugInfo, "sceneBuffers == null && sceneData == null" ); + return; + } + + var size = sceneBuffers.GetInternalSize(); + + if ( size.X == 0 || size.Y == 0 ) + { + this.LogInfoIf( logDebugInfo, "size.X == 0 || size.Y == 0" ); + return; + } + + int xGroups; + int yGroups; + + if ( passNum == 1 || passNum == 2 ) + { + xGroups = ( size.X/mipLevel ) / 16 + 1; + yGroups = ( size.Y/mipLevel ) / 16 + 1; + } + else + { + xGroups = size.X / 16 + 1; + yGroups = size.Y / 16 + 1; + + } + + int viewCount = ( int ) sceneBuffers.GetViewCount(); + + if ( backbuffers.Count < viewCount * 2 || sizeCache != size || mipCache != mipLevel ) + { + InitBackbuffer( viewCount * 2, size ); + } + + var packedBytes = new List(); + var packedFloats = new List(); + var packedInts = new List(); + + if ( passNum == 1 || passNum == 2 ) + { + packedFloats.Add( size.X/mipLevel ) ; + packedFloats.Add( size.Y/mipLevel ) ; + } + else + { + packedFloats.Add( size.X ) ; + packedFloats.Add( size.Y ) ; + } + + packedFloats.Add( dither ) ; + + packedInts.Add( blurType == BlurType.Gaussian ? 1 : 0 ); + packedInts.Add( Mathf.Min( blurSamples, blurWidth )) ; + packedInts.Add( blurWidth ); + packedInts.Add( passNum ); + + packedBytes.AddRange( Bytes.Convert( packedFloats ) ); + packedBytes.AddRange( Bytes.Convert( packedInts ) ); + + while ( packedBytes.Count < 32 ) + { + packedBytes.Add( 0 ); + } + + for ( int i = 0; i < viewCount; i++ ) + { + var view = i; + + Rid screenTex = sceneBuffers.GetColorLayer( (uint)view ); + + Rid screenImageUniformSet = new Rid(); + Rid backbufferUniformSet1 = new Rid(); + Rid backbufferUniformSet2 = new Rid(); + + if ( passNum == 1 ) + { + backbufferUniformSet1 = CreateImageUniformSet( (Rid) backbuffers[view] ); + screenImageUniformSet = CreateSamplerUniformSet( screenTex ); + } + else if ( passNum == 2 ) + { + backbufferUniformSet2 = CreateImageUniformSet( (Rid) backbuffers[ viewCount + view ] ); + backbufferUniformSet1 = CreateSamplerUniformSet( (Rid) backbuffers[view] ); + } + else if ( passNum == 3 ) + { + backbufferUniformSet2 = CreateImageUniformSet( screenTex ); + screenImageUniformSet = CreateSamplerUniformSet( (Rid) backbuffers[viewCount + view] ); + } + + int computeList = (int) rd.ComputeListBegin(); + rd.ComputeListBindComputePipeline( computeList, pipeline ); + + if ( passNum == 1 ) + { + rd.ComputeListBindUniformSet( computeList, backbufferUniformSet1, 0 ); + rd.ComputeListBindUniformSet( computeList, screenImageUniformSet, 1 ); + } + else if ( passNum == 2 ) + { + rd.ComputeListBindUniformSet( computeList, backbufferUniformSet2, 0 ); + rd.ComputeListBindUniformSet( computeList, backbufferUniformSet1, 1 ); + } + else if ( passNum == 3 ) + { + rd.ComputeListBindUniformSet( computeList, screenImageUniformSet, 1 ); + rd.ComputeListBindUniformSet( computeList, backbufferUniformSet2, 0 ); + + } + + rd.ComputeListSetPushConstant( computeList, packedBytes.ToArray(), (uint) packedBytes.Count ); + rd.ComputeListDispatch( computeList, (uint) xGroups, (uint)yGroups, 1 ); + rd.ComputeListEnd(); + + } + } + + Rid CreateImageUniformSet( Rid image ) + { + var uniform = new RDUniform(); + uniform.UniformType = RenderingDevice.UniformType.Image; + uniform.Binding = 0; + uniform.AddId( image ); + return UniformSetCacheRD.GetCache( shader, 0, new Array(){uniform} ); + } + + Rid CreateSamplerUniformSet( Rid texture ) + { + var uniform = new RDUniform(); + uniform.UniformType = RenderingDevice.UniformType.SamplerWithTexture; + uniform.Binding = 0; + uniform.AddId( linearSampler ); + uniform.AddId( texture ) ; + return UniformSetCacheRD.GetCache( shader, 1, new Array(){uniform} ); + } + + + public void InitBackbuffer( int count, Vector2I size ) + { + //remember to properly free the buffers else the memory leak will blow up your pc + foreach( var b in backbuffers ) + { + rd.FreeRid( ( Rid ) b ); + } + + backbuffers.Clear(); + + if ( backbufferFormat == null ) + { + backbufferFormat = new RDTextureFormat(); + //there's loads of formats to choose from. This one is RGBA 16bit float with values 0.0 - 1.0 + } + + backbufferFormat.Format = RenderingDevice.DataFormat.R16G16B16A16Unorm; + backbufferFormat.Width = ( uint ) ( size.X / mipLevel ); + backbufferFormat.Height = ( uint ) ( size.Y / mipLevel ); + backbufferFormat.UsageBits = + RenderingDevice.TextureUsageBits.StorageBit | + RenderingDevice.TextureUsageBits.SamplingBit; + + if ( texview == null ) + { + texview = new RDTextureView(); + } + + for ( int i = 0; i < count; i++ ) + { + backbuffers.Add( rd.TextureCreate( backbufferFormat, texview ) ); + } + + mipCache = mipLevel; + sizeCache.X = size.X; + sizeCache.Y = size.Y; + } + + } + +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/Blur/BlurCompositorEffect.cs.uid b/Runtime/Rendering/CompositorEffects/Blur/BlurCompositorEffect.cs.uid new file mode 100644 index 0000000..fbbc069 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Blur/BlurCompositorEffect.cs.uid @@ -0,0 +1 @@ +uid://dlgkbntnwnjyg diff --git a/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl b/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl new file mode 100644 index 0000000..57baa26 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl @@ -0,0 +1,98 @@ +#[compute] +#version 450 + +//process 16 by 16 chunk per invocation. Chosen arbitrarily. Im not sure what the optimal value here is +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +//documentation reccomends using 'restrict' whenever possible. Not able to use it with the sampler +layout(rgba16f, binding=0, set=0) restrict uniform image2D image1; //write +layout(binding=0, set=1) uniform sampler2D sampler1; //read + +layout(push_constant, std430) uniform Params { + vec2 screen_size; //dimensions of buffer we're writing to + float dither; //[0.0 - 0.5] amount of dithering + int is_gaussian; //[0 - 1] 0 is box blur, 1 is gaussian weighting + int kern_samples; //number of samples per pass + int kern_width; //width of the blur + int pass; //[1,2,3] 1 horizontal blur, 2 vertical blur, 3 copy to screen +} p; + +// Random number generator for dithering +float rng(vec2 seed) { + return fract(sin(dot(seed.xy, vec2(12.9898, 78.233))) * 43758.5453123); +} + +// Apply dithering to the kernel offset +float get_dither(float ks) { + if (p.dither <= 0.0) return 0.0; //avoid some math if we don't need dithering + return (rng(gl_GlobalInvocationID.xy / p.screen_size) * 2.0 - 1.0) * ks * p.dither; +} + +// Compute Gaussian weight for a given distance and sigma +float gaussian(float x, float sigma) { + return exp(-(x * x) / (2.0 * sigma * sigma)) / (sqrt(2.0 * 3.14159) * sigma); +} + +// Precompute Gaussian weights for the kernel +void compute_gaussian_weights(int samples, float sigma, out float weights[161]) { + float total_weight = 0.0; + for (int i = 0; i <= samples; i++) { + float x = float(i) - float(samples) / 2.0; + weights[i] = gaussian(x, sigma); + total_weight += weights[i]; + } + // Normalize weights + for (int i = 0; i <= samples; i++) { + weights[i] /= total_weight; + } +} + +void main() { + //coordinates + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + vec2 uv = vec2(pixel) / p.screen_size; + + // Early exit if the pixel is outside the screen bounds + if (pixel.x >= p.screen_size.x || pixel.y >= p.screen_size.y) return; + + // Kernel parameters + float kern_spacing = float(p.kern_width) / float(p.kern_samples); + float kern_half = float(p.kern_width) * 0.5; + + // Gaussian weights + float weights[161]; //Not allowed to have variable length arrays in GLSL, so hard code theoretical max kernel size. + float sigma = float(p.kern_width) / (6.0 * float(p.kern_width)/float(p.kern_samples)); // Adjust sigma based on kernel width + if(p.is_gaussian == 1) { + compute_gaussian_weights(p.kern_samples, sigma, weights); + } + + vec4 col = vec4(0.0); + vec2 coord; + + if (p.pass == 1) { + // Horizontal pass + for (int i = 0; i <= p.kern_samples; i++) { + coord.x = pixel.x + (i * kern_spacing) - kern_half + get_dither(kern_spacing); + coord.y = pixel.y; + //if gaussian blur, add a weighted sample, if box we can average all at once at the end of loop + if(p.is_gaussian == 1) col += texture(sampler1, clamp(coord / p.screen_size, 0.0, 1.0)) * weights[i]; + else col += texture(sampler1, clamp(coord / p.screen_size, 0.0, 1.0)); + } + if(p.is_gaussian == 0) col.rgb /= float(p.kern_samples + 1); + imageStore(image1, pixel, col); + } else if (p.pass == 2) { + // Vertical pass + for (int j = 0; j <= p.kern_samples; j++) { + coord.x = pixel.x; + coord.y = pixel.y + (j * kern_spacing) - kern_half + get_dither(kern_spacing); + if(p.is_gaussian == 1) col += texture(sampler1, clamp(coord / p.screen_size, 0.0, 1.0)) * weights[j]; + else col += texture(sampler1, clamp(coord / p.screen_size, 0.0, 1.0)); + } + if(p.is_gaussian == 0) col.rgb /= float(p.kern_samples + 1); + imageStore(image1, pixel, col); + } else if (p.pass == 3) { + //copy buffer to screen + col = texture(sampler1, uv); + imageStore(image1, pixel, col); + } +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl.import b/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl.import new file mode 100644 index 0000000..1ed8d62 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://b7s44e3k68axi" +path="res://.godot/imported/BlurEffect.glsl-adc1ff46efeaf20c40c851da38f62fae.res" + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/Blur/BlurEffect.glsl" +dest_files=["res://.godot/imported/BlurEffect.glsl-adc1ff46efeaf20c40c851da38f62fae.res"] + +[params] + diff --git a/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingEffect.cs b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingEffect.cs new file mode 100644 index 0000000..0633f3d --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingEffect.cs @@ -0,0 +1,84 @@ + +using Godot; +using Godot.Collections; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class DepthAntiAliasingEffect:SingleShaderCompositorEffect + { + public static readonly string shaderPath = + RokojoriPlugin.Path( "Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl" ); + + + RDPushConstants constants = new RDPushConstants(); + RDSampler sampler; + + [Export( PropertyHint.Range, "0,1") ] + public float greyAmount; + + [Export( PropertyHint.Range, "0,1") ] + public float depthAmount; + + [Export( PropertyHint.Range, "0,1") ] + public float effectStrength = 1; + + [Export( PropertyHint.Range, "0,20") ] + public float depthEdgeTreshold = 2f; + + [Export( PropertyHint.Range, "0,1") ] + public float depthEdgeIntensity = 1f; + + [Export( PropertyHint.Range, "0,100") ] + public float colorContrastTreshold = 2f; + + [Export( PropertyHint.Range, "0,1") ] + public float colorContrastIntensity = 1f; + + [Export( PropertyHint.Range, "0,1") ] + public float debugView = 0f; + + protected override void OnConfigure() + { + EffectCallbackType = EffectCallbackTypeEnum.PostTransparent; + _shaderPath = shaderPath; + _groupSize = 8; + } + + protected override void OnInitialize() + { + base.OnInitialize(); + + sampler = Sampler( RenderingDevice.SamplerFilter.Nearest, RenderingDevice.SamplerRepeatMode.ClampToEdge ); + } + + + + protected override void ForAllViews() + { + constants.Set( + (Vector2)context.internalSize, + new Vector2( greyAmount, depthAmount ), + effectStrength, + depthEdgeTreshold / 100f, + depthEdgeIntensity * 20f, + colorContrastTreshold / 100f, + colorContrastIntensity * 20f, + debugView + ); + } + + protected override void RenderView() + { + context.Assign_ScreenColorTexture(); + context.Assign_ScreenDepthTexture( sampler ); + + context.pushConstants = constants; + + context.Render(); + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingEffect.cs.uid b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingEffect.cs.uid new file mode 100644 index 0000000..4e92ab4 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingEffect.cs.uid @@ -0,0 +1 @@ +uid://cwhhaasonvhy diff --git a/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl new file mode 100644 index 0000000..ff088ea --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl @@ -0,0 +1,94 @@ +#[compute] +#version 450 + +layout( local_size_x = 8, local_size_y = 8, local_size_z = 1 ) in; + +layout( rgba16f, set = 0, binding = 0 ) +uniform image2D color_image; + +layout( set = 1, binding = 0 ) +uniform sampler2D depth_sampler; + + +layout( push_constant, std430 ) +uniform Params +{ + vec2 rasterSize; + vec2 amounts; + float effectStrength; + float edgeThreshold; + float edgeIntensity; + float contrastThreshold; + float contrastIntensity; + float debugView; + +} params; + +float sampleDepth( ivec2 coord ) +{ + coord = clamp( coord, ivec2( 0 ), ivec2( params.rasterSize ) - ivec2( 1 ) ); + + vec2 uv = ( vec2( coord ) + 0.5 ) / params.rasterSize; + return texture( depth_sampler, uv ).r; +} + +void main( ) +{ + ivec2 uv = ivec2( gl_GlobalInvocationID.xy ); + ivec2 size = ivec2( params.rasterSize ); + + if ( uv.x >= size.x || uv.y >= size.y ) + { + return; + } + + float centerDepth = sampleDepth( uv ); + + float top_left = sampleDepth( uv + ivec2( -1, -1 ) ); + float top = sampleDepth( uv + ivec2( 0, -1 ) ); + float top_right = sampleDepth( uv + ivec2( 1, -1 ) ); + float left = sampleDepth( uv + ivec2( -1, 0 ) ); + float right = sampleDepth( uv + ivec2( 1, 0 ) ); + float bottom_left = sampleDepth( uv + ivec2( -1, 1 ) ); + float bottom = sampleDepth( uv + ivec2( 0, 1 ) ); + float bottom_right = sampleDepth( uv + ivec2( 1, 1 ) ); + + + float gx = -top_left - 2.0 * left - bottom_left + top_right + 2.0 * right + bottom_right; + float gy = -top_left - 2.0 * top - top_right + bottom_left + 2.0 * bottom + bottom_right; + + float edgeStrength = length( vec2( gx, gy ) ); + + // float edgeStrength = abs( left - right ); + + edgeStrength = clamp( ( edgeStrength - params.edgeThreshold ) * params.edgeIntensity, 0.0, 1.0 ); + float edge = edgeStrength; + + + vec4 color = imageLoad( color_image, uv ); + + vec4 color_left = imageLoad( color_image, uv + ivec2( -1, 0 ) ); + vec4 color_left2 = imageLoad( color_image, uv + ivec2( -2, 0 ) ); + vec4 color_right = imageLoad( color_image, uv + ivec2( 1, 0 ) ); + vec4 color_right2 = imageLoad( color_image, uv + ivec2( 2, 0 ) ); + + float c = ( length( color_left - color_right ) - params.contrastThreshold ) * params.contrastIntensity; + + float d = min( 1.0, c ); + + edge = max( d, edge ); + + vec4 smoothedColor = color_left + color_left2 + + 2.0 * color + + color_right + color_right2; + + smoothedColor /= 6.0; + + float gray = color.r * 0.2125 + color.g * 0.7154 + color.b * 0.0721; + vec3 debugViewColor = vec3( params.amounts.x * gray, params.amounts.y * centerDepth, edge ); + + color.rgb = mix( color.rgb, smoothedColor.rgb, edge * params.effectStrength ); + color.rgb = mix( color.rgb, debugViewColor, params.debugView ); + + imageStore( color_image, uv, color ); +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl.import b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl.import new file mode 100644 index 0000000..17d37f1 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://us4n0un8oo2v" +path="res://.godot/imported/DepthAntiAliasingShader.glsl-ea5a9a21bccd9baeec39a54eb65d5afd.res" + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/DepthAntiAliasing/DepthAntiAliasingShader.glsl" +dest_files=["res://.godot/imported/DepthAntiAliasingShader.glsl-ea5a9a21bccd9baeec39a54eb65d5afd.res"] + +[params] + diff --git a/Runtime/Rendering/CompositorEffects/DepthView/DepthViewEffect.cs b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewEffect.cs new file mode 100644 index 0000000..f911571 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewEffect.cs @@ -0,0 +1,64 @@ + +using Godot; +using Godot.Collections; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class DepthViewEffect:SingleShaderCompositorEffect + { + public static readonly string shaderPath = + RokojoriPlugin.Path( "Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl" ); + + + RDPushConstants constants = new RDPushConstants(); + RDSampler sampler; + + [Export( PropertyHint.Range, "0,1") ] + public float greyAmount; + + [Export( PropertyHint.Range, "0,1") ] + public float depthAmount; + + [Export( PropertyHint.Range, "0.001,3") ] + public float depthPower; + + protected override void OnConfigure() + { + EffectCallbackType = EffectCallbackTypeEnum.PostTransparent; + _shaderPath = shaderPath; + _groupSize = 8; + } + + protected override void OnInitialize() + { + base.OnInitialize(); + + sampler = Sampler( RenderingDevice.SamplerFilter.Nearest, RenderingDevice.SamplerRepeatMode.ClampToEdge ); + } + + + + protected override void ForAllViews() + { + constants.Set( + (Vector2)context.internalSize, + new Vector2( greyAmount, depthAmount ), + depthPower + ); + } + + protected override void RenderView() + { + context.Assign_ScreenColorTexture(); + context.Assign_ScreenDepthTexture( sampler ); + + context.pushConstants = constants; + + context.Render(); + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/DepthView/DepthViewEffect.cs.uid b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewEffect.cs.uid new file mode 100644 index 0000000..0a1a546 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewEffect.cs.uid @@ -0,0 +1 @@ +uid://bxnpsjejq7ldo diff --git a/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl new file mode 100644 index 0000000..2189f93 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl @@ -0,0 +1,48 @@ +#[compute] +#version 450 + +layout( local_size_x = 8, local_size_y = 8, local_size_z = 1 ) in; + +layout( rgba16f, set = 0, binding = 0) +uniform image2D color_image; + +layout( set = 1, binding = 0) +uniform sampler2D depth_sampler; + + +layout(push_constant, std430) +uniform Params +{ + vec2 raster_size; + vec2 amounts; + float power; + +} params; + +float sample_depth( ivec2 coord ) +{ + coord = clamp( coord, ivec2( 0 ), ivec2( params.raster_size ) - ivec2( 1 ) ); + + vec2 uv = ( vec2( coord ) + 0.5 ) / params.raster_size; + return texture( depth_sampler, uv ).r; +} + +void main() +{ + ivec2 uv = ivec2( gl_GlobalInvocationID.xy ); + ivec2 size = ivec2( params.raster_size ); + + if ( uv.x >= size.x || uv.y >= size.y ) + { + return; + } + + vec4 color = imageLoad( color_image, uv ); + float depth = sample_depth( uv ); + + float gray = color.r * 0.2125 + color.g * 0.7154 + color.b * 0.0721; + + color.rgb = vec3( params.amounts.x * gray, pow( params.amounts.y * depth, params.power ), 0.0 ); + + imageStore( color_image, uv, color ); +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl.import b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl.import new file mode 100644 index 0000000..df1af13 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://ccufacegh2n8s" +path="res://.godot/imported/DepthViewShader.glsl-c19eff884d9bff6ff641a138482426b5.res" + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/DepthView/DepthViewShader.glsl" +dest_files=["res://.godot/imported/DepthViewShader.glsl-c19eff884d9bff6ff641a138482426b5.res"] + +[params] + diff --git a/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl b/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl new file mode 100644 index 0000000..08b8c38 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl @@ -0,0 +1,35 @@ +#[compute] +#version 450 + +layout( local_size_x = 16, local_size_y = 16, local_size_z = 1 ) in; + +layout( rgba16f, set = 0, binding = 0) +uniform image2D color_image; + +layout(push_constant, std430) +uniform Params +{ + vec2 raster_size; + vec2 reserved; + +} params; + + +void main() +{ + ivec2 uv = ivec2( gl_GlobalInvocationID.xy ); + ivec2 size = ivec2( params.raster_size ); + + if ( uv.x >= size.x || uv.y >= size.y ) + { + return; + } + + vec4 color = imageLoad( color_image, uv ); + + float gray = color.r * 0.2125 + color.g * 0.7154 + color.b * 0.0721; + + color.rgb = vec3( gray ); + + imageStore( color_image, uv, color ); +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl.import b/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl.import new file mode 100644 index 0000000..1baa77d --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://biw2n3t4ci7t" +path="res://.godot/imported/GrayScaleShader.glsl-89be3b50af0d77c6515222d93b33ffb3.res" + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl" +dest_files=["res://.godot/imported/GrayScaleShader.glsl-89be3b50af0d77c6515222d93b33ffb3.res"] + +[params] + diff --git a/Runtime/Rendering/CompositorEffects/GreyScale/GreyScaleEffect.cs b/Runtime/Rendering/CompositorEffects/GreyScale/GreyScaleEffect.cs new file mode 100644 index 0000000..3e78989 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/GreyScale/GreyScaleEffect.cs @@ -0,0 +1,43 @@ + +using Godot; +using Godot.Collections; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class GreyScaleEffect:SingleShaderCompositorEffect + { + public static readonly string shaderPath = + RokojoriPlugin.Path( "Runtime/Rendering/CompositorEffects/GreyScale/GrayScaleShader.glsl" ); + + + protected override void OnConfigure() + { + EffectCallbackType = EffectCallbackTypeEnum.PostTransparent; + _shaderPath = shaderPath; + _groupSize = 8; + } + + RDPushConstants constants = new RDPushConstants(); + + protected override void ForAllViews() + { + constants.Set( + (Vector2)context.internalSize, + Vector2.Zero + ); + } + + protected override void RenderView() + { + context.Assign_ScreenColorTexture(); + + context.pushConstants = constants; + + context.Render(); + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/GreyScale/GreyScaleEffect.cs.uid b/Runtime/Rendering/CompositorEffects/GreyScale/GreyScaleEffect.cs.uid new file mode 100644 index 0000000..4e8013e --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/GreyScale/GreyScaleEffect.cs.uid @@ -0,0 +1 @@ +uid://c81fs31jiamwd diff --git a/Runtime/Rendering/CompositorEffects/Pixelation/PixelationEffect.cs b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationEffect.cs new file mode 100644 index 0000000..56a4fc8 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationEffect.cs @@ -0,0 +1,48 @@ + +using Godot; +using Godot.Collections; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class PixelationEffect:SingleShaderCompositorEffect + { + public static readonly string shaderPath = + RokojoriPlugin.Path( "Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl" ); + + [Export] + public float pixelSize = 1f; + + [Export] + public float pixelSizePower = 1f; + + protected override void OnConfigure() + { + EffectCallbackType = EffectCallbackTypeEnum.PostTransparent; + _shaderPath = shaderPath; + _groupSize = 8; + } + + RDPushConstants constants = new RDPushConstants(); + + protected override void ForAllViews() + { + constants.Set( + (Vector2)context.internalSize, + Mathf.Pow( pixelSize, pixelSizePower ) + ); + } + + protected override void RenderView() + { + context.Assign_ScreenColorTexture(); + + context.pushConstants = constants; + + context.Render(); + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/Pixelation/PixelationEffect.cs.uid b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationEffect.cs.uid new file mode 100644 index 0000000..7c3078a --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationEffect.cs.uid @@ -0,0 +1 @@ +uid://ljinskwo4rsc diff --git a/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl new file mode 100644 index 0000000..c062528 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl @@ -0,0 +1,34 @@ +#[compute] +#version 450 +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(rgba16f, set = 0, binding = 0) uniform image2D color_image; + +layout(push_constant, std430) uniform Params { + vec2 raster_size; + float pixel_size; + float reserved; +} params; + +void main() +{ + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + ivec2 size = ivec2(params.raster_size); + + if (uv.x >= size.x || uv.y >= size.y ) + { + return; + } + + float x = float(int(gl_GlobalInvocationID.x) % int(params.pixel_size)); + float y = float(int(gl_GlobalInvocationID.y) % int(params.pixel_size)); + + x = gl_GlobalInvocationID.x + floor(params.pixel_size / 2.0) - x; + y = gl_GlobalInvocationID.y + floor(params.pixel_size / 2.0) - y; + + x = min( x, params.raster_size.x - max( 1.0, params.pixel_size / 2.0 ) ); + y = min( y, params.raster_size.y - max( 1.0, params.pixel_size / 2.0 ) ); + + vec4 color = imageLoad(color_image, ivec2( x, y ) ); + imageStore(color_image, uv, color); +} diff --git a/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl.import b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl.import new file mode 100644 index 0000000..8b33dbb --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://ghbawysn1d3c" +path="res://.godot/imported/PixelationShader.glsl-7bf34134c1434ce83105711f1252021f.res" + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/Pixelation/PixelationShader.glsl" +dest_files=["res://.godot/imported/PixelationShader.glsl-7bf34134c1434ce83105711f1252021f.res"] + +[params] + diff --git a/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurEffect.cs b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurEffect.cs new file mode 100644 index 0000000..45ecabf --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurEffect.cs @@ -0,0 +1,57 @@ + +using Godot; +using Godot.Collections; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class RadialBlurEffect:SingleShaderCompositorEffect + { + public static readonly string shaderPath = + RokojoriPlugin.Path( "Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl" ); + + [Export] + public Vector2 center = new Vector2( 0.5f, 0.5f ); + + [Export] + public float radius = 0.5f; + + [Export] + public float intensity = 0.5f; + + [Export] + public float samples = 16f; + + protected override void OnConfigure() + { + EffectCallbackType = EffectCallbackTypeEnum.PostTransparent; + _shaderPath = shaderPath; + _groupSize = 32; + } + + RDPushConstants constants = new RDPushConstants(); + + protected override void ForAllViews() + { + constants.Set( + center, + radius, + intensity, + samples, + Vector2.Zero + ); + } + + protected override void RenderView() + { + context.Assign_ScreenColorTexture(); + + context.pushConstants = constants; + + context.Render(); + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurEffect.cs.uid b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurEffect.cs.uid new file mode 100644 index 0000000..a88852c --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurEffect.cs.uid @@ -0,0 +1 @@ +uid://c5np4sijoledw diff --git a/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl new file mode 100644 index 0000000..33c460f --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl @@ -0,0 +1,48 @@ +#[compute] +#version 450 + +layout( local_size_x = 32, local_size_y = 32, local_size_z = 1 ) in; + +layout( rgba16f, set = 0, binding = 0 ) +uniform image2D color_image; + +layout( push_constant, std430 ) +uniform Params +{ + vec2 center; // 8 bytes + float radius; // 4 bytes + float intensity; // 4 bytes + float samples; // 4 bytes ( will be cast to int ) + vec2 _padding; // 8 bytes ( matches 32-byte total ) + +} params; + +void main( ) +{ + ivec2 img_size = imageSize( color_image ); + ivec2 texel_coord = ivec2( gl_GlobalInvocationID.xy ); + + if ( any( greaterThanEqual( texel_coord, img_size ) ) ) + { + return; + } + + vec2 uv = ( vec2( texel_coord ) + 0.5 ) / vec2( img_size ); + vec2 dir = normalize( uv - params.center ); + int num_samples = int( clamp( params.samples, 1.0, 64.0 ) ); + + vec4 color = vec4( 0.0 ); + + for ( int i = 0; i < num_samples; i++ ) + { + float t = float( i ) / float( num_samples ); + vec2 sample_uv = clamp( uv + dir * t * params.radius, vec2( 0.0 ), vec2( 1.0 ) ); + ivec2 sample_coord = ivec2( sample_uv * vec2( img_size ) ); + sample_coord = clamp( sample_coord, ivec2( 0 ), img_size - ivec2( 1 ) ); + color += imageLoad( color_image, sample_coord ); + } + + color /= float( num_samples ); + vec4 original_color = imageLoad( color_image, texel_coord ); + imageStore( color_image, texel_coord, mix( original_color, color, params.intensity ) ); +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl.import b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl.import new file mode 100644 index 0000000..af2dae9 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://yioccj34hlex" +path="res://.godot/imported/RadialBlurShader.glsl-495ace3264af9b141d13d88646f4d37b.res" + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/CompositorEffects/RadialBlur/RadialBlurShader.glsl" +dest_files=["res://.godot/imported/RadialBlurShader.glsl-495ace3264af9b141d13d88646f4d37b.res"] + +[params] + diff --git a/Runtime/Rendering/CompositorEffects/TextureDilation/TextureDilationCompositerEffect.cs b/Runtime/Rendering/CompositorEffects/TextureDilation/TextureDilationCompositerEffect.cs new file mode 100644 index 0000000..a294f5c --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/TextureDilation/TextureDilationCompositerEffect.cs @@ -0,0 +1,58 @@ + +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using System; +using Godot; + + + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class TextureDilationCompositerEffect:CompositorEffect + { + RenderingDevice renderingDevice; + Rid frameBuffer; + + public void _Init() + { + EffectCallbackType = EffectCallbackTypeEnum.PostOpaque; + renderingDevice = RenderingServer.GetRenderingDevice(); + + } + + public override void _Notification(int what) + { + + } + + public override void _RenderCallback( int effectCallbackType, RenderData renderData ) + { + if ( renderingDevice == null || effectCallbackType != (int) EffectCallbackTypeEnum.PostOpaque ) + { + return; + } + + var renderBuffers = (RenderSceneBuffersRD) renderData.GetRenderSceneBuffers(); + + if ( renderBuffers == null ) + { + return; + } + + var size = renderBuffers.GetInternalSize(); + + if ( size.X == 0 || size.Y == 0 ) + { + return; + } + + var groups = new Vector3((size.X - 1.0f) / 8.0f + 1.0f, (size.Y - 1.0f) / 8.0f + 1.0f, 1.0f).Floor(); + + + } + } + +} \ No newline at end of file diff --git a/Runtime/Rendering/CompositorEffects/TextureDilation/TextureDilationCompositerEffect.cs.uid b/Runtime/Rendering/CompositorEffects/TextureDilation/TextureDilationCompositerEffect.cs.uid new file mode 100644 index 0000000..6b49679 --- /dev/null +++ b/Runtime/Rendering/CompositorEffects/TextureDilation/TextureDilationCompositerEffect.cs.uid @@ -0,0 +1 @@ +uid://3x8f0sys0kxb diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphConnection.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphConnection.cs new file mode 100644 index 0000000..328c61d --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphConnection.cs @@ -0,0 +1,11 @@ + +using Godot; + +namespace Rokojori +{ + public class CompositorEffectGraphConnection:CompositorEffectGraphNode + { + public CompositorEffectGraphConnection( _XX_CompositorEffectGraph graph ):base( graph ){} + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphConnection.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphConnection.cs.uid new file mode 100644 index 0000000..73d4ddc --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphConnection.cs.uid @@ -0,0 +1 @@ +uid://d0kyta606sede diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphInput.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphInput.cs new file mode 100644 index 0000000..5d3d737 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphInput.cs @@ -0,0 +1,10 @@ + +using Godot; + +namespace Rokojori +{ + public class CompositorEffectGraphInput:CompositorEffectGraphConnection + { + public CompositorEffectGraphInput( _XX_CompositorEffectGraph graph ):base( graph ){} + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphInput.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphInput.cs.uid new file mode 100644 index 0000000..d7179cd --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphInput.cs.uid @@ -0,0 +1 @@ +uid://d2eejfvpgahbr diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphNode.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphNode.cs new file mode 100644 index 0000000..d8761e4 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphNode.cs @@ -0,0 +1,16 @@ + +using Godot; + +namespace Rokojori +{ + public class CompositorEffectGraphNode + { + _XX_CompositorEffectGraph _graph; + public _XX_CompositorEffectGraph graph => _graph; + + public CompositorEffectGraphNode( _XX_CompositorEffectGraph graph ) + { + _graph = graph; + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphNode.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphNode.cs.uid new file mode 100644 index 0000000..8412876 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphNode.cs.uid @@ -0,0 +1 @@ +uid://dockxjmc1equ8 diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphOutput.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphOutput.cs new file mode 100644 index 0000000..8dcff6f --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphOutput.cs @@ -0,0 +1,10 @@ + +using Godot; + +namespace Rokojori +{ + public class CompositorEffectGraphOutput:CompositorEffectGraphConnection + { + public CompositorEffectGraphOutput( _XX_CompositorEffectGraph graph ):base( graph ){} + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphOutput.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphOutput.cs.uid new file mode 100644 index 0000000..6448f46 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphOutput.cs.uid @@ -0,0 +1 @@ +uid://c1tsn5wy1vpmx diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphProcessor.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphProcessor.cs new file mode 100644 index 0000000..4e882d6 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphProcessor.cs @@ -0,0 +1,32 @@ + +using Godot; + +namespace Rokojori +{ + public class CompositorEffectGraphProcessor:CompositorEffectGraphNode + { + public CompositorEffectGraphProcessor( _XX_CompositorEffectGraph graph ):base( graph ){} + + bool _initialized = false; + + public void Initialize() + { + if ( _initialized ) + { + return; + } + + OnInitialize(); + } + + protected virtual void OnInitialize() + { + + } + + public virtual void Process() + { + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphProcessor.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphProcessor.cs.uid new file mode 100644 index 0000000..1943cf5 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectGraphProcessor.cs.uid @@ -0,0 +1 @@ +uid://88e7cnyhvdba diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectShaderProcessor.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectShaderProcessor.cs new file mode 100644 index 0000000..877fba7 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectShaderProcessor.cs @@ -0,0 +1,73 @@ + +using Godot; +using System.Collections.Generic; + +namespace Rokojori +{ + public class CompositorEffectShaderProcessor:CompositorEffectGraphProcessor + { + protected string _shaderPath; + + public CompositorEffectShaderProcessor( _XX_CompositorEffectGraph graph, string shaderPath ):base( graph ) + { + this._shaderPath = shaderPath; + } + + protected RDShader _shader; + protected RDPipeline _pipeline; + protected RDPushConstants _constants; + protected List _uniformSets = new List(); + + + protected override void OnInitialize() + { + graph.Verbose( "Trying to load shader: ", _shaderPath ); + + if ( _shaderPath == null ) + { + graph.Error( "_shaderPath == null" ); + return; + } + + var glslFile = GD.Load( _shaderPath ); + + if ( glslFile == null ) + { + graph.Error( "Couldn't load shader at path:", _shaderPath ); + return; + } + + _shader = RDShader.CreateFromSpirV( graph, glslFile.GetSpirV() ); + + if ( _shader == null ) + { + graph.Error( "Couldn't create shader from code, path:", _shaderPath ); + return; + } + + _pipeline = RDPipeline.Create( graph, _shader ); + + if ( _shader == null ) + { + graph.Error( "Couldn't create pipeline from compiled shader, path:", _shaderPath ); + return; + } + + graph.Verbose( "Created shader at path: ", _shaderPath ); + } + + public override void Process() + { + var context = graph.context; + + context.Clear(); + context.SetShaderAndPipeline( _shader, _pipeline ); + + _uniformSets.ForEach( context.AddUniformSet ); + + context.pushConstants = _constants; + + context.Render(); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectShaderProcessor.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectShaderProcessor.cs.uid new file mode 100644 index 0000000..a089aaf --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/CompositorEffectShaderProcessor.cs.uid @@ -0,0 +1 @@ +uid://cgjc4lhtxmyth diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/_XX_CompositorEffectGraph.cs b/Runtime/Rendering/Objects/CompositorEffectGraph/_XX_CompositorEffectGraph.cs new file mode 100644 index 0000000..6359267 --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/_XX_CompositorEffectGraph.cs @@ -0,0 +1,13 @@ + +using Godot; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class _XX_CompositorEffectGraph:RokojoriCompositorEffect + { + List _nodes; + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/CompositorEffectGraph/_XX_CompositorEffectGraph.cs.uid b/Runtime/Rendering/Objects/CompositorEffectGraph/_XX_CompositorEffectGraph.cs.uid new file mode 100644 index 0000000..6ee66fa --- /dev/null +++ b/Runtime/Rendering/Objects/CompositorEffectGraph/_XX_CompositorEffectGraph.cs.uid @@ -0,0 +1 @@ +uid://b8c32jccxtncj diff --git a/Runtime/Rendering/Objects/RDComputeList.cs b/Runtime/Rendering/Objects/RDComputeList.cs new file mode 100644 index 0000000..e6fba63 --- /dev/null +++ b/Runtime/Rendering/Objects/RDComputeList.cs @@ -0,0 +1,53 @@ + +using Godot; + +namespace Rokojori +{ + public class RDComputeList + { + RenderingDevice _rd; + public RenderingDevice rd => _rd; + + long _computeListID; + public long id => _computeListID; + + public RDComputeList( RenderingDevice rd, long id ) + { + _rd = rd; + _computeListID = id; + } + + public void End() + { + rd.ComputeListEnd(); + _computeListID = 0; + _rd = null; + } + + public void BindPipeline( RDPipeline pipeline ) + { + rd.ComputeListBindComputePipeline( _computeListID, pipeline.rid ); + } + + public void BindUniformSet( RDUniformSet uniformSet, int index ) + { + rd.ComputeListBindUniformSet( _computeListID, uniformSet.rid, (uint) index ); + } + + public void SetPushConstants( RDPushConstants constants ) + { + var bytes = constants.bytes; + rd.ComputeListSetPushConstant( _computeListID, bytes, (uint) bytes.Length ); + } + + public void Dispatch( Vector3I groups ) + { + rd.ComputeListDispatch( _computeListID, (uint)groups.X, (uint)groups.Y, (uint)groups.Z ); + } + + public static RDComputeList Begin( RenderingDevice rd ) + { + return new RDComputeList( rd, rd.ComputeListBegin() ); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDComputeList.cs.uid b/Runtime/Rendering/Objects/RDComputeList.cs.uid new file mode 100644 index 0000000..da56b62 --- /dev/null +++ b/Runtime/Rendering/Objects/RDComputeList.cs.uid @@ -0,0 +1 @@ +uid://cq0h2frxmmtx0 diff --git a/Runtime/Rendering/Objects/RDPipeline.cs b/Runtime/Rendering/Objects/RDPipeline.cs new file mode 100644 index 0000000..1713563 --- /dev/null +++ b/Runtime/Rendering/Objects/RDPipeline.cs @@ -0,0 +1,16 @@ + +using Godot; + +namespace Rokojori +{ + public class RDPipeline: RenderingObject + { + public RDPipeline( RokojoriCompositorEffect effect, Rid rid ):base( effect, rid ) + {} + + public static RDPipeline Create( RokojoriCompositorEffect effect, RDShader shader ) + { + return new RDPipeline( effect, effect.rd.ComputePipelineCreate( shader.rid ) ); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDPipeline.cs.uid b/Runtime/Rendering/Objects/RDPipeline.cs.uid new file mode 100644 index 0000000..f0eaa6f --- /dev/null +++ b/Runtime/Rendering/Objects/RDPipeline.cs.uid @@ -0,0 +1 @@ +uid://de7bto3duqn2i diff --git a/Runtime/Rendering/Objects/RDPushConstants.cs b/Runtime/Rendering/Objects/RDPushConstants.cs new file mode 100644 index 0000000..369db90 --- /dev/null +++ b/Runtime/Rendering/Objects/RDPushConstants.cs @@ -0,0 +1,230 @@ + +using Godot; +using System; +using System.Collections.Generic; + +namespace Rokojori +{ + public class RDPushConstants + { + protected List _floats = new List(); + protected int _floatIndex = 0; + + protected List _ints = new List(); + protected int _intIndex = 0; + + protected byte[] _bytes; + + public void Reset() + { + _floatIndex = 0; + _intIndex = 0; + } + + public void Set( params object[] objects ) + { + Reset(); + + for ( int i = 0; i < objects.Length; i++ ) + { + if ( objects[ i ] is int ) + { + _AddInt( (int) objects[ i ] ); + } + + else if ( objects[ i ] is float ) + { + _AddFloat( (float) objects[ i ] ); + } + + else if ( objects[ i ] is Vector2 ) + { + _AddVector2( (Vector2) objects[ i ] ); + } + + else if ( objects[ i ] is Vector2I ) + { + _AddVector2( (Vector2I) objects[ i ] ); + } + + else if ( objects[ i ] is Vector3 ) + { + _AddVector3( (Vector3) objects[ i ] ); + } + + else if ( objects[ i ] is Vector3I ) + { + _AddVector3( (Vector3I) objects[ i ] ); + } + + else if ( objects[ i ] is Vector4 ) + { + _AddVector4( (Vector4) objects[ i ] ); + } + } + } + + protected void _AddFloat( float value ) + { + if ( _floatIndex >= _floats.Count ) + { + _floats.Add( value ); + _floatIndex = _floats.Count; + } + else + { + _floats[ _floatIndex ] = value; + _floatIndex ++; + } + } + + protected void _AddInt( int value ) + { + if ( _intIndex >= _ints.Count ) + { + _ints.Add( value ); + _intIndex = _floats.Count; + } + else + { + _ints[ _intIndex ] = value; + _intIndex ++; + } + } + + public void Add( params float[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddFloat( values[ i ] ); + } + } + + protected void _AddVector2( Vector2 value ) + { + _AddFloat( value.X ); + _AddFloat( value.Y ); + } + + protected void _AddVector2I( Vector2I value ) + { + _AddInt( value.X ); + _AddInt( value.Y ); + } + + public void Add( params Vector2[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddVector2( values[ i ] ); + } + } + + public void Add( params Vector2I[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddVector2I( values[ i ] ); + } + } + + protected void _AddVector3( Vector3 value ) + { + _AddFloat( value.X ); + _AddFloat( value.Y ); + _AddFloat( value.Z ); + } + + protected void _AddVector3I( Vector3I value ) + { + _AddInt( value.X ); + _AddInt( value.Y ); + _AddInt( value.Z ); + } + + public void Add( params Vector3[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddVector3( values[ i ] ); + } + } + + public void Add( params Vector3I[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddVector3I( values[ i ] ); + } + } + + protected void _AddVector4( Vector4 value ) + { + _AddFloat( value.X ); + _AddFloat( value.Y ); + _AddFloat( value.Z ); + _AddFloat( value.W ); + } + + public void Add( params Vector4[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddVector4( values[ i ] ); + } + } + + + + + public void Add( params int[] values ) + { + for ( int i = 0; i < values.Length; i++ ) + { + _AddInt( values[ i ] ); + } + } + + public byte[] bytes + { + get + { + var numBytes = ( _intIndex + _floatIndex ) * 4; + + while ( numBytes % 16 != 0 ) + { + numBytes ++; + } + + if ( _bytes == null || _bytes.Length != numBytes ) + { + _bytes = new byte[ numBytes ]; + } + + for ( int i = 0; i < _floats.Count; i++ ) + { + var floatBytes = BitConverter.GetBytes( _floats[ i ] ); + Array.Copy( floatBytes, 0, _bytes, i * 4, 4 ); + } + + var floatsOffset = _floats.Count * 4; + + for ( int i = 0; i < _ints.Count; i++ ) + { + var intBytes = BitConverter.GetBytes( _ints[ i ] ); + Array.Copy( intBytes, 0, _bytes, i * 4 + floatsOffset, 4 ); + } + + var intsOffset = _ints.Count * 4; + + for ( int i = intsOffset + floatsOffset; i < _bytes.Length; i++ ) + { + _bytes[ i ] = 0; + } + + return _bytes; + } + } + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDPushConstants.cs.uid b/Runtime/Rendering/Objects/RDPushConstants.cs.uid new file mode 100644 index 0000000..3d17a5e --- /dev/null +++ b/Runtime/Rendering/Objects/RDPushConstants.cs.uid @@ -0,0 +1 @@ +uid://crf86mq4o5ybx diff --git a/Runtime/Rendering/Objects/RDSampler.cs b/Runtime/Rendering/Objects/RDSampler.cs new file mode 100644 index 0000000..2761908 --- /dev/null +++ b/Runtime/Rendering/Objects/RDSampler.cs @@ -0,0 +1,16 @@ + +using Godot; + +namespace Rokojori +{ + public class RDSampler: RenderingObject + { + public RDSampler( RokojoriCompositorEffect effect, Rid rid ):base( effect, rid ) + {} + + public static RDSampler Create( RokojoriCompositorEffect effect, RDSamplerState samplerState ) + { + return new RDSampler( effect, effect.rd.SamplerCreate( samplerState ) ); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDSampler.cs.uid b/Runtime/Rendering/Objects/RDSampler.cs.uid new file mode 100644 index 0000000..56a9f3e --- /dev/null +++ b/Runtime/Rendering/Objects/RDSampler.cs.uid @@ -0,0 +1 @@ +uid://cwht50f7wwxgg diff --git a/Runtime/Rendering/Objects/RDShader.cs b/Runtime/Rendering/Objects/RDShader.cs new file mode 100644 index 0000000..4bbcca6 --- /dev/null +++ b/Runtime/Rendering/Objects/RDShader.cs @@ -0,0 +1,17 @@ + +using Godot; + +namespace Rokojori +{ + public class RDShader: RenderingObject + { + public RDShader( RokojoriCompositorEffect effect, Rid rid ):base( effect, rid ) + {} + + public static RDShader CreateFromSpirV( RokojoriCompositorEffect effect, RDShaderSpirV rDShaderSpirV ) + { + var shaderID = effect.rd.ShaderCreateFromSpirV( rDShaderSpirV ); + return new RDShader( effect, shaderID ); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDShader.cs.uid b/Runtime/Rendering/Objects/RDShader.cs.uid new file mode 100644 index 0000000..c7be0c5 --- /dev/null +++ b/Runtime/Rendering/Objects/RDShader.cs.uid @@ -0,0 +1 @@ +uid://flybmkbccn5l diff --git a/Runtime/Rendering/Objects/RDTexture.cs b/Runtime/Rendering/Objects/RDTexture.cs new file mode 100644 index 0000000..9d7c5cf --- /dev/null +++ b/Runtime/Rendering/Objects/RDTexture.cs @@ -0,0 +1,29 @@ + +using Godot; + +namespace Rokojori +{ + public class RDTexture: RenderingObject + { + public RDTexture( RokojoriCompositorEffect effect, Rid rid ):base( effect, rid ){} + + public static RDTexture Create( RokojoriCompositorEffect effect, RDTextureFormat format, RDTextureView view ) + { + return new RDTexture( effect, effect.rd.TextureCreate( format, view ) ); + } + + public static RDTexture Color( RokojoriCompositorContext context ) + { + var rid = context.sceneBuffers.GetColorLayer( (uint) context.view ); + + return new RDTexture( context.effect, rid ); + } + + public static RDTexture Depth( RokojoriCompositorContext context ) + { + var rid = context.sceneBuffers.GetDepthLayer( (uint) context.view ); + + return new RDTexture( context.effect, rid ); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDTexture.cs.uid b/Runtime/Rendering/Objects/RDTexture.cs.uid new file mode 100644 index 0000000..793c2bc --- /dev/null +++ b/Runtime/Rendering/Objects/RDTexture.cs.uid @@ -0,0 +1 @@ +uid://d3r7qnm0bl73d diff --git a/Runtime/Rendering/Objects/RDUniformSet.cs b/Runtime/Rendering/Objects/RDUniformSet.cs new file mode 100644 index 0000000..63dc42c --- /dev/null +++ b/Runtime/Rendering/Objects/RDUniformSet.cs @@ -0,0 +1,47 @@ + +using Godot; +using Godot.Collections; + +namespace Rokojori +{ + public class RDUniformSet:RenderingObject + { + protected int _setIndex = -1; + public int setIndex => _setIndex; + + public RDUniformSet( RokojoriCompositorEffect effect, int setIndex, Rid rid ):base( effect, rid ) + { + _setIndex =setIndex; + } + + public static RDUniformSet Image( RokojoriCompositorEffect effect, RDTexture texture, int setIndex ) + { + var uniform = new RDUniform(); + uniform.UniformType = RenderingDevice.UniformType.Image; + uniform.Binding = 0; + uniform.AddId( texture.rid ); + + var rd = effect.rd; + var rid = UniformSetCacheRD.GetCache( effect.context.shader.rid, (uint) setIndex, new Array{ uniform } ); + // var rid = rd.UniformSetCreate( new Array{ uniform }, effect.context.shader.rid, (uint) setIndex ); + + return new RDUniformSet( effect, setIndex, rid ); + } + + public static RDUniformSet Sampler( RokojoriCompositorEffect effect, RDSampler sampler, RDTexture texture, int setIndex ) + { + var uniform = new RDUniform(); + uniform.UniformType = RenderingDevice.UniformType.SamplerWithTexture; + uniform.Binding = 0; + uniform.AddId( sampler.rid ); + uniform.AddId( texture.rid ) ; + + var rd = effect.rd; + + var rid = UniformSetCacheRD.GetCache( effect.context.shader.rid, (uint) setIndex, new Array{ uniform } ); + // var rid = rd.UniformSetCreate( new Array{ uniform }, effect.context.shader.rid, (uint) setIndex ); + + return new RDUniformSet( effect, setIndex, rid ); + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RDUniformSet.cs.uid b/Runtime/Rendering/Objects/RDUniformSet.cs.uid new file mode 100644 index 0000000..3106c62 --- /dev/null +++ b/Runtime/Rendering/Objects/RDUniformSet.cs.uid @@ -0,0 +1 @@ +uid://cb5jtvktd1epc diff --git a/Runtime/Rendering/Objects/RenderingObject.cs b/Runtime/Rendering/Objects/RenderingObject.cs new file mode 100644 index 0000000..fb7950a --- /dev/null +++ b/Runtime/Rendering/Objects/RenderingObject.cs @@ -0,0 +1,23 @@ + +using Godot; + +namespace Rokojori +{ + public class RenderingObject + { + protected RokojoriCompositorEffect _effect; + public RokojoriCompositorEffect effect => _effect; + + protected Rid _rid; + public Rid rid => _rid; + + public bool valid => _rid.IsValid; + + public RenderingObject( RokojoriCompositorEffect effect, Rid rid ) + { + this._effect = effect; + this._rid = rid; + } + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RenderingObject.cs.uid b/Runtime/Rendering/Objects/RenderingObject.cs.uid new file mode 100644 index 0000000..cdd337b --- /dev/null +++ b/Runtime/Rendering/Objects/RenderingObject.cs.uid @@ -0,0 +1 @@ +uid://xeqc03e3llpu diff --git a/Runtime/Rendering/Objects/RokojoriCompositorContext.cs b/Runtime/Rendering/Objects/RokojoriCompositorContext.cs new file mode 100644 index 0000000..8bafbd4 --- /dev/null +++ b/Runtime/Rendering/Objects/RokojoriCompositorContext.cs @@ -0,0 +1,167 @@ + +using Godot; +using System.Collections.Generic; + +namespace Rokojori +{ + public class RokojoriCompositorContext + { + protected RokojoriCompositorEffect _effect; + public RokojoriCompositorEffect effect => _effect; + + protected RDShader _shader; + public RDShader shader => _shader; + + protected RDPipeline _pipeline; + public RDPipeline pipeline => _pipeline; + + public void SetShaderAndPipeline( RDShader shader, RDPipeline pipeline ) + { + effect.Verbose( "Set Shader Pipeline", shader, pipeline ); + _shader = shader; + _pipeline = pipeline; + + } + + protected int _view = -1; + public int view => _view; + + protected int _effectCallbackType; + public int effectCallbackType => _effectCallbackType; + + protected RenderData _renderData; + public RenderData renderData => _renderData; + + + protected RenderSceneBuffersRD _sceneBuffers; + public RenderSceneBuffersRD sceneBuffers => _sceneBuffers; + + protected RenderSceneDataRD _sceneData; + public RenderSceneDataRD sceneData => _sceneData; + + protected Vector3I _groups; + public Vector3I groups => _groups; + + public Vector2I internalSize => _sceneBuffers.GetInternalSize(); + + public RDTexture GetScreenColorTexture() + { + return RDTexture.Color( this ); + } + + public RDTexture GetScreenDepthTexture() + { + return RDTexture.Depth( this ); + } + + public void Assign_ScreenColorTexture( RDSampler sampler = null, int setIndex = -1 ) + { + AssignUniformSet_Texture( GetScreenColorTexture(), sampler, setIndex ); + } + + public void Assign_ScreenDepthTexture( RDSampler sampler = null, int setIndex = -1 ) + { + AssignUniformSet_Texture( GetScreenDepthTexture(), sampler, setIndex ); + } + + public void AssignUniformSet_Texture( RDTexture texture, RDSampler sampler = null, int setIndex = -1 ) + { + // effect.Verbose( "Incoming Uniform Index", setIndex ); + + if ( setIndex == -1 ) + { + setIndex = _uniformSets.Count; + } + + // effect.Verbose( "Set Uniform Index", setIndex ); + + if ( sampler == null ) + { + // effect.Verbose( "Adding Image" ); + AddUniformSet( RDUniformSet.Image( _effect, texture, setIndex ) ); + } + else + { + // effect.Verbose( "Adding Sampler" ); + AddUniformSet( RDUniformSet.Sampler( _effect, sampler,texture, setIndex ) ); + } + } + + List _uniformSets = new List(); + public RDPushConstants pushConstants; + + public void AddUniformSet( RDUniformSet uniformSet ) + { + _uniformSets.Add( uniformSet ); + } + + public void Clear() + { + _uniformSets.Clear(); + pushConstants = null; + } + + public void Render() + { + try + { + + var computeList = RDComputeList.Begin( _effect.rd ); + computeList.BindPipeline( pipeline ); + + + _uniformSets.ForEach( + ( u )=> + { + computeList.BindUniformSet( u, u.setIndex ); + } + ); + + + if ( pushConstants != null ) + { + computeList.SetPushConstants( pushConstants ); + } + + + + computeList.Dispatch( groups ); + + + computeList.End(); + } + catch( System.Exception e ) + { + effect.Error( e ); + } + + Clear(); + } + + } + + public class EditableRokojoriCompositorContext:RokojoriCompositorContext + { + public void SetEffect( RokojoriCompositorEffect effect ) + { + this._effect = effect; + } + + public void SetRenderData( RenderData renderData, RenderSceneBuffersRD buffers, RenderSceneDataRD sceneData ) + { + this._renderData = renderData; + this._sceneBuffers = buffers; + this._sceneData = sceneData; + } + + public void SetView( int view ) + { + this._view = view; + } + + public void SetGroups( Vector3I groups ) + { + this._groups = groups; + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RokojoriCompositorContext.cs.uid b/Runtime/Rendering/Objects/RokojoriCompositorContext.cs.uid new file mode 100644 index 0000000..9d70986 --- /dev/null +++ b/Runtime/Rendering/Objects/RokojoriCompositorContext.cs.uid @@ -0,0 +1 @@ +uid://ccu40hi7l5hmu diff --git a/Runtime/Rendering/Objects/RokojoriCompositorEffect.cs b/Runtime/Rendering/Objects/RokojoriCompositorEffect.cs new file mode 100644 index 0000000..decea36 --- /dev/null +++ b/Runtime/Rendering/Objects/RokojoriCompositorEffect.cs @@ -0,0 +1,291 @@ + +using Godot; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class RokojoriCompositorEffect:CompositorEffect + { + protected RenderingDevice _rd; + public RenderingDevice rd => _rd; + + protected int _groupSize = 16; + protected List _cleanUps = new List(); + protected List _cleanUpInfo = new List(); + + EditableRokojoriCompositorContext _context; + protected bool _hasContext = false; + public RokojoriCompositorContext context => _hasContext ? _context : null; + + protected List _messages = new List(); + public List messages => _messages; + public bool logMessages = true; + public int messageLogLevel = Messages.GetLevel( MessageType.Verbose ); + + protected virtual void OnConfigure(){} + protected virtual void OnInitialize(){} + protected virtual void ForAllViews(){} + protected virtual void RenderView(){} + + public RokojoriCompositorEffect():base() + { + RenderingServer.CallOnRenderThread( Callable.From( _InitializeCompositorEffect ) ); + } + + protected void _InitializeCompositorEffect() + { + OnConfigure(); + + _rd = RenderingServer.Singleton.GetRenderingDevice(); + + if ( _rd == null ) + { + Error( "Found no rendering device" ); + return; + } + + _context = new EditableRokojoriCompositorContext(); + _context.SetEffect( this ); + + _hasContext = true; + OnInitialize(); + _hasContext = false; + + } + + public override void _RenderCallback( int effectCallbackType, RenderData renderData ) + { + + _hasContext = false; + + if ( rd == null ) + { + Error( "No render device" ); + return; + } + + var sceneBuffers = ( RenderSceneBuffersRD ) renderData.GetRenderSceneBuffers(); + var sceneData = ( RenderSceneDataRD ) renderData.GetRenderSceneData(); + + if ( sceneBuffers == null && sceneData == null ) + { + Error( "sceneBuffers == null && sceneData == null" ); + return; + } + + + + var size = sceneBuffers.GetInternalSize(); + + if ( size.X == 0 || size.Y == 0 ) + { + Warning( "InternalSize.X == 0 || InternalSize.Y == 0" ); + return; + } + + _context.SetRenderData( renderData, sceneBuffers, sceneData ); + _context.SetView( -1 ); + _context.SetGroups( new Vector3I( 1, 1, 1 ) ); + + + + _hasContext = true; + var groups = ComputeGroups(); + _context.SetGroups( groups ); + + ForAllViews(); + + + + int viewCount = ( int ) sceneBuffers.GetViewCount(); + + for ( int i = 0; i < viewCount; i++ ) + { + _context.SetView( i ); + RenderView(); + } + + _hasContext = false; + } + + protected virtual Vector3I ComputeGroups() + { + var size = context.sceneBuffers.GetInternalSize(); + + var xGroups = Mathf.CeilToInt( size.X / (float) _groupSize ); + var yGroups = Mathf.CeilToInt( size.Y / (float) _groupSize ); + + return new Vector3I( xGroups, yGroups, 1 ); + } + + + public override void _Notification( int what ) + { + var _shader = context.shader; + + Verbose( "Got notification: ", what ); + + if ( what != NotificationPredelete || ( _shader == null || !_shader.valid ) || rd == null ) + { + Verbose( + "what != NotificationPredelete", what != NotificationPredelete, + "( _shader == null || !_shader.valid )", ( _shader == null || !_shader.valid ), + "rd == null", rd == null + ); + return; + } + + CleanUp( _shader, "Shader" ); + + var index = 0; + + _cleanUps.ForEach( + c => + { + CleanUp( c, "_cleanUps[" + index + "]"); + index ++; + } + ); + + _cleanUps.Clear(); + + } + + public void AddToCleanUp( RenderingObject ro, string info = null ) + { + var _shader = context.shader; + + if ( _cleanUps.Contains( ro ) || _shader == ro ) + { + return; + } + + _cleanUps.Add( ro ); + _cleanUpInfo.Add( info ); + } + + public void AddToCleanUp( List ro, string info = null ) + { + var index = 0; + info = info == null ? "" : info; + + ro.ForEach( + r => + { + AddToCleanUp( r, info + "["+ index + "]" ); + index ++; + } + ); + } + + void CleanUp( RenderingObject ro, string info ) + { + if ( ro == null ) + { + Warning( "ro == null, couldn't clean up: ", info ); + return; + } + + Verbose( "Cleaning up: ", info, ro.rid ); + rd.FreeRid( ro.rid ); + } + + + + // --------------------------------------------- + // --------------------------------------------- + // CONVINIENCE + // --------------------------------------------- + // --------------------------------------------- + + public RDSampler Sampler( RDSamplerState state = null) + { + if ( state == null ) + { + state = new RDSamplerState(); + state.MinFilter = RenderingDevice.SamplerFilter.Linear; + state.MagFilter = RenderingDevice.SamplerFilter.Linear; + state.RepeatU = RenderingDevice.SamplerRepeatMode.Repeat; + state.RepeatV = RenderingDevice.SamplerRepeatMode.Repeat; + } + + var sampler = RDSampler.Create( this, state ); + return sampler; + } + + public RDSampler Sampler( RenderingDevice.SamplerFilter filter, RenderingDevice.SamplerRepeatMode repeatMode) + { + var state = new RDSamplerState(); + + state.MinFilter = filter; + state.MagFilter = filter; + + state.RepeatU = repeatMode; + state.RepeatV = repeatMode; + + return Sampler( state ); + } + + + + // --------------------------------------------- + // --------------------------------------------- + // MESSAGES + // --------------------------------------------- + // --------------------------------------------- + + + public void Error( params object[] messages ) + { + var message = RJLog.GetLogString( messages ); + + Messages.Error( _messages, message ); + + if ( logMessages ) + { + this.LogError( message ); + } + } + + public void Warning( params object[] messages ) + { + var message = RJLog.GetLogString( messages ); + + Messages.Warning( _messages, message ); + + if ( logMessages && Messages.GetLevel( MessageType.Warning ) >= messageLogLevel ) + { + this.LogInfo( message ); + } + } + + public void Info( params object[] messages ) + { + var message = RJLog.GetLogString( messages ); + + Messages.Info( _messages, message ); + + if ( logMessages && Messages.GetLevel( MessageType.Info ) >= messageLogLevel ) + { + this.LogInfo( message ); + } + } + + public void Verbose( params object[] messages ) + { + var message = RJLog.GetLogString( messages ); + + Messages.Verbose( _messages, message ); + + if ( logMessages && Messages.GetLevel( MessageType.Verbose ) >= messageLogLevel ) + { + this.LogInfo( message ); + } + } + + + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/RokojoriCompositorEffect.cs.uid b/Runtime/Rendering/Objects/RokojoriCompositorEffect.cs.uid new file mode 100644 index 0000000..e7ed1b3 --- /dev/null +++ b/Runtime/Rendering/Objects/RokojoriCompositorEffect.cs.uid @@ -0,0 +1 @@ +uid://chfoyvoiddqc3 diff --git a/Runtime/Rendering/Objects/ShaderProgram.cs.uid b/Runtime/Rendering/Objects/ShaderProgram.cs.uid new file mode 100644 index 0000000..83b8d78 --- /dev/null +++ b/Runtime/Rendering/Objects/ShaderProgram.cs.uid @@ -0,0 +1 @@ +uid://5hwmnvb3xo7j diff --git a/Runtime/Rendering/Objects/SingleShaderCompositorEffect.cs b/Runtime/Rendering/Objects/SingleShaderCompositorEffect.cs new file mode 100644 index 0000000..0c2359c --- /dev/null +++ b/Runtime/Rendering/Objects/SingleShaderCompositorEffect.cs @@ -0,0 +1,56 @@ + +using Godot; +using System.Collections.Generic; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class SingleShaderCompositorEffect:RokojoriCompositorEffect + { + protected string _shaderPath; + + protected RDShader _shader; + protected RDPipeline _pipeline; + + protected override void OnInitialize() + { + Verbose( "Trying to load shader: ", _shaderPath ); + + if ( _shaderPath == null ) + { + Error( "_shaderPath == null" ); + return; + } + + var glslFile = GD.Load( _shaderPath ); + + if ( glslFile == null ) + { + Error( "Couldn't load shader at path:", _shaderPath ); + return; + } + + _shader = RDShader.CreateFromSpirV( this, glslFile.GetSpirV() ); + + if ( _shader == null ) + { + Error( "Couldn't create shader from code, path:", _shaderPath ); + return; + } + + _pipeline = RDPipeline.Create( this, _shader ); + + if ( _shader == null ) + { + Error( "Couldn't create pipeline from compiled shader, path:", _shaderPath ); + return; + } + + Verbose( "Created shader at path: ", _shaderPath ); + + context.SetShaderAndPipeline( _shader, _pipeline ); + } + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Objects/SingleShaderCompositorEffect.cs.uid b/Runtime/Rendering/Objects/SingleShaderCompositorEffect.cs.uid new file mode 100644 index 0000000..da2caf2 --- /dev/null +++ b/Runtime/Rendering/Objects/SingleShaderCompositorEffect.cs.uid @@ -0,0 +1 @@ +uid://dkcn0rdtj7arp diff --git a/Runtime/Shading/Shaders/PostProcessing/ChromaticDIstortion.material b/Runtime/Shading/Shaders/PostProcessing/ChromaticDIstortion.material index ebb528c..fcd1a68 100644 Binary files a/Runtime/Shading/Shaders/PostProcessing/ChromaticDIstortion.material and b/Runtime/Shading/Shaders/PostProcessing/ChromaticDIstortion.material differ diff --git a/Runtime/Tools/Lists.cs b/Runtime/Tools/Lists.cs index ad120dd..8019fb4 100644 --- a/Runtime/Tools/Lists.cs +++ b/Runtime/Tools/Lists.cs @@ -304,8 +304,6 @@ namespace Rokojori list.RemoveAll( e => removalSet.Contains( e ) ); } - - public static int CountItems( List list, Predicate test ) { var result = 0; diff --git a/Runtime/Tools/Safe.cs b/Runtime/Tools/Safe.cs index dbb85b6..83785b1 100644 --- a/Runtime/Tools/Safe.cs +++ b/Runtime/Tools/Safe.cs @@ -8,7 +8,7 @@ namespace Rokojori { public class Safe { - static readonly int maxWhileIterations = 1000 * 1000; + static readonly int maxWhileIterations = 2000 * 1000; public static void While( Func condition, System.Action action, System.Action onTooManyIterations = null ) {