Added Compositor Effects

This commit is contained in:
Josef 2025-04-23 14:00:43 +02:00
parent 22530dff10
commit 50e4bf74b4
74 changed files with 2559 additions and 8 deletions

View File

@ -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()
{

View File

@ -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<byte> Convert( List<float> floats )
{
var list = new List<byte>();
floats.ForEach( f => list.AddRange( BitConverter.GetBytes( f ) ) );
return list;
}
public static List<byte> Convert( List<int> ints )
{
var list = new List<byte>();
ints.ForEach( i => list.AddRange( BitConverter.GetBytes( i ) ) );
return list;
}
}
}

View File

@ -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 )
{

View File

@ -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 );

View File

@ -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 );

View File

@ -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<Texture2D> Dilate( Texture2D texture, Func<Task> 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<Task> waiting;
async Task<Texture2D> _Dilate( Texture2D texture )
{
_buffer = TextureCombinerBuffer.From( texture );
await _Process();
return _buffer.CreateImageTexture();
}
public float alphaTreshold = 250f/255f;
HashSet<int> _processed = new HashSet<int>();
HashSet<int> _unprocessed = new HashSet<int>();
HashSet<int> _edges = new HashSet<int>();
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 );
}
}
}

View File

@ -0,0 +1 @@
uid://jk67aba6i3mx

View File

@ -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 );

View File

@ -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<byte>();
var packedFloats = new List<float>();
var packedInts = new List<int>();
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<RDUniform>(){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<RDUniform>(){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;
}
}
}

View File

@ -0,0 +1 @@
uid://dlgkbntnwnjyg

View File

@ -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);
}
}

View File

@ -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]

View File

@ -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();
}
}
}

View File

@ -0,0 +1 @@
uid://cwhhaasonvhy

View File

@ -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 );
}

View File

@ -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]

View File

@ -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();
}
}
}

View File

@ -0,0 +1 @@
uid://bxnpsjejq7ldo

View File

@ -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 );
}

View File

@ -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]

View File

@ -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 );
}

View File

@ -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]

View File

@ -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();
}
}
}

View File

@ -0,0 +1 @@
uid://c81fs31jiamwd

View File

@ -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();
}
}
}

View File

@ -0,0 +1 @@
uid://ljinskwo4rsc

View File

@ -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);
}

View File

@ -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]

View File

@ -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();
}
}
}

View File

@ -0,0 +1 @@
uid://c5np4sijoledw

View File

@ -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 ) );
}

View File

@ -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]

View File

@ -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();
}
}
}

View File

@ -0,0 +1,11 @@
using Godot;
namespace Rokojori
{
public class CompositorEffectGraphConnection:CompositorEffectGraphNode
{
public CompositorEffectGraphConnection( _XX_CompositorEffectGraph graph ):base( graph ){}
}
}

View File

@ -0,0 +1 @@
uid://d0kyta606sede

View File

@ -0,0 +1,10 @@
using Godot;
namespace Rokojori
{
public class CompositorEffectGraphInput:CompositorEffectGraphConnection
{
public CompositorEffectGraphInput( _XX_CompositorEffectGraph graph ):base( graph ){}
}
}

View File

@ -0,0 +1 @@
uid://d2eejfvpgahbr

View File

@ -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;
}
}
}

View File

@ -0,0 +1 @@
uid://dockxjmc1equ8

View File

@ -0,0 +1,10 @@
using Godot;
namespace Rokojori
{
public class CompositorEffectGraphOutput:CompositorEffectGraphConnection
{
public CompositorEffectGraphOutput( _XX_CompositorEffectGraph graph ):base( graph ){}
}
}

View File

@ -0,0 +1 @@
uid://c1tsn5wy1vpmx

View File

@ -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()
{
}
}
}

View File

@ -0,0 +1 @@
uid://88e7cnyhvdba

View File

@ -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<RDUniformSet> _uniformSets = new List<RDUniformSet>();
protected override void OnInitialize()
{
graph.Verbose( "Trying to load shader: ", _shaderPath );
if ( _shaderPath == null )
{
graph.Error( "_shaderPath == null" );
return;
}
var glslFile = GD.Load<RDShaderFile>( _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();
}
}
}

View File

@ -0,0 +1 @@
uid://cgjc4lhtxmyth

View File

@ -0,0 +1,13 @@
using Godot;
using System.Collections.Generic;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class _XX_CompositorEffectGraph:RokojoriCompositorEffect
{
List<CompositorEffectGraphNode> _nodes;
}
}

View File

@ -0,0 +1 @@
uid://b8c32jccxtncj

View File

@ -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() );
}
}
}

View File

@ -0,0 +1 @@
uid://cq0h2frxmmtx0

View File

@ -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 ) );
}
}
}

View File

@ -0,0 +1 @@
uid://de7bto3duqn2i

View File

@ -0,0 +1,230 @@
using Godot;
using System;
using System.Collections.Generic;
namespace Rokojori
{
public class RDPushConstants
{
protected List<float> _floats = new List<float>();
protected int _floatIndex = 0;
protected List<int> _ints = new List<int>();
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;
}
}
}
}

View File

@ -0,0 +1 @@
uid://crf86mq4o5ybx

View File

@ -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 ) );
}
}
}

View File

@ -0,0 +1 @@
uid://cwht50f7wwxgg

View File

@ -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 );
}
}
}

View File

@ -0,0 +1 @@
uid://flybmkbccn5l

View File

@ -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 );
}
}
}

View File

@ -0,0 +1 @@
uid://d3r7qnm0bl73d

View File

@ -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<RDUniform>{ uniform } );
// var rid = rd.UniformSetCreate( new Array<RDUniform>{ 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<RDUniform>{ uniform } );
// var rid = rd.UniformSetCreate( new Array<RDUniform>{ uniform }, effect.context.shader.rid, (uint) setIndex );
return new RDUniformSet( effect, setIndex, rid );
}
}
}

View File

@ -0,0 +1 @@
uid://cb5jtvktd1epc

View File

@ -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;
}
}
}

View File

@ -0,0 +1 @@
uid://xeqc03e3llpu

View File

@ -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<RDUniformSet> _uniformSets = new List<RDUniformSet>();
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;
}
}
}

View File

@ -0,0 +1 @@
uid://ccu40hi7l5hmu

View File

@ -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<RenderingObject> _cleanUps = new List<RenderingObject>();
protected List<string> _cleanUpInfo = new List<string>();
EditableRokojoriCompositorContext _context;
protected bool _hasContext = false;
public RokojoriCompositorContext context => _hasContext ? _context : null;
protected List<Message> _messages = new List<Message>();
public List<Message> 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<RenderingObject> 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 );
}
}
}
}

View File

@ -0,0 +1 @@
uid://chfoyvoiddqc3

View File

@ -0,0 +1 @@
uid://5hwmnvb3xo7j

View File

@ -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<RDShaderFile>( _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 );
}
}
}

View File

@ -0,0 +1 @@
uid://dkcn0rdtj7arp

View File

@ -304,8 +304,6 @@ namespace Rokojori
list.RemoveAll( e => removalSet.Contains( e ) );
}
public static int CountItems<T>( List<T> list, Predicate<T> test )
{
var result = 0;

View File

@ -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<bool> condition, System.Action action, System.Action onTooManyIterations = null )
{