Interesting, they did go with your approach. Thanks for bringing that up.
I’m in too deep though, I’m making my version much more complicated so I need some strange tools to do it. It’s more like a compute shader.
With my very rough understanding of shaders, I believe I can create a writable buffer using DirectX ps_5_0 and
RWTexture2D<float> TransferTexture: register(u1);
sampler2D TransferTextureSampler = sampler_state
{
Texture = <TransferTexture>;
};
And setting a value using TransferTexture[xy] = float4(0, 0, 0, 0,). I can then read the buffer using a second pass.
I am caught on one problem though, I can’t initialize the buffer? I assume I need to define the width and height of the texture somewhere, but doing
effect.Parameters["TransferTexture"].SetValue(new RenderTarget2D(Parent.GraphicsDevice, Width, Height));
Throws a null reference exception because it cannot find the parameter. The solution may be interfacing with it through SharpDX.Utilities.AllocateMemory() as suggested below. Maybe I will have to do it all through DirectX/SharpX.
I wonder if this is an issue with Monogame? Seems like effect.Parameters should be able to access it.
Just for clarity, I’ll post my .fx code so far, with much commented out to focus on the issue. Maybe someone can point out a dumb mistake I’m making. That’s enough research for me tonight though.
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_5_0
#define PS_SHADERMODEL ps_5_0
#endif
static const float FTB = 0.00390625; // psuedo incremental byte value of float (1/256)
float Width;
float Height;
float MutationRate = 0.1;
float mutationratehalf = 0.05; // set with above
float Range = 8;
float rangehalf = 4; // set with above
float Decay = 0.004;
// RNG seed
float2 rng_seed = float2(0, 0);
float2 rng_inc = float2(0.001, 0.001);
const float2 t = float2(3, 3);
Texture2D SpriteTexture;
sampler2D SpriteTextureSampler = sampler_state
{
Texture = <SpriteTexture>;
};
RWTexture2D<float> TransferTexture: register(u1);
sampler2D TransferTextureSampler = sampler_state
{
Texture = <TransferTexture>;
};
float nrand(float2 uv)
{
return frac(sin(dot(uv + rng_seed, float2(12.9898, 78.233))) * 43758.5453);
rng_seed += rng_inc;
}
// https://forum.unity.com/threads/encode-float4-rgba-to-uint.695176/
uint PackFloat4(float4 f)
{
uint packedR = uint(f.r * 255);
uint packedG = uint(f.g * 255) << 8; // shift bits over 8 places
uint packedB = uint(f.b * 255) << 16; // shift bits over 16 places
uint packedA = uint(f.a * 255) << 24; // shift bits over 24 places
return packedR + packedG + packedB + packedA; // Note: Alpha is the largest value
}
float4 UnPackUint(uint i)
{
return float4(
i % 256 / 256,
i / 256 % 256 / 256,
i / 65536 % 256 / 256,
i / 16777216 % 256 / 256);
}
float4 GetNeighbor(float2 texture_coordinates, int x, int y)
{
return tex2D(SpriteTextureSampler, texture_coordinates + float2(x / Width, y / Height));
};
static float2 LoopCoordinates(float2 texture_coordinates)
{
float2 target = texture_coordinates % float2(1, 1);
return float2(1, 1) - (float2(1, 1) - target) % float2(1, 1);
}
float4 GetNeighborLoop(float2 texture_coordinates, int x, int y)
{
float2 target = texture_coordinates + float2(x / Width, y / Height);
target = target % float2(1, 1);
target = float2(1, 1) - (float2(1, 1) - target) % float2(1, 1);
return tex2D(SpriteTextureSampler, target);
};
//void SetRelativeBufferValue(float2 texture_coordinate, int x, int y, float4 value)
//{
// TransferTexture.Store(
// texture_coordinate.x * Width + texture_coordinate.y * Width * Height,
// PackFloat4(value));
//}
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
float2 TextureCoordinates : TEXCOORD0;
};
float4 StoreValuePS(VertexShaderOutput input) : COLOR
{
//// move to new pixel
//SetRelativeBufferValue(
// LoopCoordinates(input.TextureCoordinates),
// input.Color.r * 32 - 16,
// input.Color.g * 32 - 16,
// input.Color);
float2 index = LoopCoordinates(input.TextureCoordinates);
TransferTexture[
input.TextureCoordinates +
float2((input.Color.r * 32 - 16) / Width, (input.Color.r * 32 - 16) / Height)]
= float(3);
return input.Color;
}
float4 ProcessValuePS(VertexShaderOutput input) : COLOR
{
// mutate
//float4 result = input.Color + (float4
//(
//nrand(input.TextureCoordinates),
//nrand(input.TextureCoordinates),
//0,
//0
//) % float4(MutationRate, MutationRate, 1, 1)) - float4(mutationratehalf, mutationratehalf, 0, 0);
// decay
//result = result - float4(Decay, Decay, 0, 0);
return input.Color; //GetBufferValue(input.TextureCoordinates);
}
technique SpriteDrawing
{
pass P0
{
PixelShader = compile PS_SHADERMODEL StoreValuePS();
}
//pass P1
//{
// PixelShader = compile PS_SHADERMODEL ProcessValuePS();
//}
}