Help porting shader (ShaderToy to HLSL)

Hello :slight_smile:

Atm I’m trying to learn HLSL and got some simple shaders to work. Now I’m trying to port the following shader from ShaderToy to HLSL (https://www.shadertoy.com/view/lslXRS)

This is my attempt:

#if OPENGL
    #define SV_POSITION POSITION
    #define VS_SHADERMODEL vs_3_0
    #define PS_SHADERMODEL ps_3_0
#else
    #define VS_SHADERMODEL vs_4_0_level_9_1
    #define PS_SHADERMODEL ps_4_0_level_9_1
#endif

float time;
Texture2D<float4> noiseTexture;

sampler TexSampler : register(s0);

sampler noiseSampler = sampler_state
{
    Texture = <noiseTexture>;
    MinFilter = None;
    MagFilter = None;
    MipFilter = None;
};

struct VertexShaderOutput
{
    float4 Position : SV_POSITION;
    float4 Color : COLOR0;
    float2 texCoord : TEXCOORD0;
};

/*float noise(in float2 uv)
{
    float2 noise = (frac(sin(dot(uv, float2(12.9898, 78.233)*2.0)) * 43758.5453));
    return abs(noise.x + noise.y) * 0.5;
}*/

float noise(float2 x)
{
    float4 tex = tex2D(noiseSampler, x*.01);
    return tex.x;
}

float2x2 makem2(in float theta) 
{ 
    float c = cos(theta);
    float s = sin(theta); 
    return float2x2(c, -s, s, c); 
}

float2 gradn(float2 p)
{
    float ep = 0.09;
    float gradx = noise(float2(p.x + ep, p.y)) - noise(float2(p.x - ep, p.y));
    float grady = noise(float2(p.x, p.y + ep)) - noise(float2(p.x, p.y - ep));
    return float2(gradx, grady);
}

float flow(in float2 p)
{
    float z = 2;
    float rz = 0;
    float2 bp = p;
    float utime = time * 0.1;

    for (float i = 1.; i < 7.; i++)
    {
        //primary flow speed
        p += utime * .6;

        //secondary flow speed
        bp += utime * 1.9;

        //displacement field
        float2 gr = gradn(i*p*.34 + utime*1.);

        //rotation of the displacement field
        gr = mul(gr,makem2(utime*6. - (0.05*p.x + 0.03*p.y)*40.));

        //displace the system
        p += gr*.5;

        //add noise octave
        rz += (sin(noise(p)*7.)*0.5 + 0.5) / z;

        //blend factor
        p = lerp(bp, p, .77);

        //intensity scaling
        z *= 1.4;

        //octave scaling
        p *= 2;
        bp *= 1.9;
    }

    return rz;
}

float4 PSMain(VertexShaderOutput input) : COLOR
{
    float2 p = input.texCoord.xy / float2(1280,768).xy;
    p *= 3;
    float rz = flow(p);

    float3 col = float3(.2, 0.07, 0.01) / rz;
    col = pow(col, 1.4);
    return float4(col, 1.0);
    //return tex * input.Color;
}

technique Lava
{
    pass P0
    {
        //VertexShader = compile VS_SHADERMODEL MainVS();
        PixelShader = compile PS_SHADERMODEL PSMain();
    }
`};

And in C#:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace ShaderTest
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D _background;
        Matrix world;
        Effect _effect;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            _background = Content.Load<Texture2D>("bg_city");
            _effect = Content.Load<Effect>("Lava");

            _effect.Parameters["noiseTexture"].SetValue(Content.Load<Texture2D>("noiseTexture"));
            
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            _effect.Parameters["time"].SetValue((float)gameTime.TotalGameTime.TotalSeconds);

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(effect:_effect);
            spriteBatch.Draw(_background, Vector2.Zero, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

But it just renders a single color for the whole texture.
Then again with the commented noise-function it’s completely random red-colored noise(as expected).

Can someone help me to correct this shader?

This is the noise-texture I’m using:

Hi!

Have you tried something like:

SamplerState mySamplerState = new SamplerState()
{
   AddressU = TextureAddressMode.Wrap,
   AddressV = TextureAddressMode.Wrap,
   Filter = TextureFilter.LinearMipPoint
}

(Set texture sampler state in custom effect)

Hi,

sadly, this doesn’t change anything.
I actually think the noise-texture is not really the problem. Because when I do something like this:

texture2D<float4> noiseTexture;

sampler TexSampler : register(s0);

sampler noiseSampler = sampler_state
{
    Texture = <noiseTexture>;
};

struct VertexShaderOutput
{
    float4 Position : SV_POSITION;
    float4 Color : COLOR0;
    float2 texCoord : TEXCOORD0;
};

float4 MainPS(VertexShaderOutput input) : COLOR
{
    float2 pos = input.texCoord;
    return tex2D(noiseSampler,pos);
}

technique BasicColorDrawing
{
    pass P0
    {
        PixelShader = compile PS_SHADERMODEL MainPS();
    }
};

The noise-texture gets rendered just fine. So getting the pixel-color from the texture works.

I did not get it to work exactly like the one I ported it from. But I managed to make somethign “interesting” work.
I just fiddled with the values and the textures.

I tried different values in the noise-function and also decreased the speed with:
float utime = time * 0.001;

Now I use a bigger texture (the previous texture now also works, but does look even weirder)
This it what it looks like right now:
http://gph.is/2gyAgZK

Does anyone know what I’m doing wrong?

float2 p = input.texCoord.xy / float2(1280,768).xy;

The texture coordinates you receive are already normalized (in the [0,1] range), so you shouldn’t divide it by the resolution again. That will make the sampler sample the same point for every pixel. Changing that gave me some result, but not quite like on ShaderToy. I’ll see if there’s anything else I can figure out :slight_smile:

1 Like

Aw man! That was exactly the missing piece.
With the following texture it works perfectly :slight_smile:
Thank you!

And a screenshot:

And the final code, free to use for everyone:
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

float time;
Texture2D<float4> noiseTexture;

sampler TexSampler : register(s0);

sampler noiseSampler = sampler_state
{
    Texture = <noiseTexture>;
};

struct VertexShaderOutput
{
    float4 Position : SV_POSITION;
    float4 Color : COLOR0;
    float2 texCoord : TEXCOORD0;
};

float noise(float2 x)
{
    float4 tex = tex2D(noiseSampler, x * 0.01);
    return tex.x;
}

float2x2 makem2(in float theta)
{
    float c = cos(theta);
    float s = sin(theta);
    return float2x2(c, -s, s, c);
}

float2 gradn(float2 p)
{
    float ep = 0.09;
    float gradx = noise(float2(p.x + ep, p.y)) - noise(float2(p.x - ep, p.y));
    float grady = noise(float2(p.x, p.y + ep)) - noise(float2(p.x, p.y - ep));
    return float2(gradx, grady);
}

float flow(in float2 p)
{
    float z = 2;
    float rz = 0;
    float2 bp = p;
    float utime = time * 0.1;

    for (float i = 1.; i < 7.; i++)
    {
		//primary flow speed
        p += utime * .6;

		//secondary flow speed
        bp += utime * 1.9;

		//displacement field
        float2 gr = gradn(i * p * .34 + utime * 0.01);

		//rotation of the displacement field
        gr = mul(gr, makem2(utime * 6. - (0.05 * p.x + 0.03 * p.y) * 40.));

		//displace the system
        p += gr * .5;

		//add noise octave
        rz += (sin(noise(p) * 7.) * 0.5 + 0.5) / z;

		//blend factor
        p = lerp(bp, p, .77);

		//intensity scaling
        z *= 1.4;

		//octave scaling
        p *= 2;
        bp *= 1.9;
    }

    return rz;
}

float4 PSMain(VertexShaderOutput input) : COLOR
{
    float2 p = input.texCoord.xy;// / float2(100, 100).xy;
    p *= 3;
    float rz = flow(p);

    float3 col = float3(.2, 0.07, 0.01) / rz;
    col = pow(col, 1.4);
    return float4(col, 1.0);
    //return tex2D(TexSampler, input.texCoord) * float4(col, 1.0);
}

technique Lava
{
    pass P0
    {
		//VertexShader = compile VS_SHADERMODEL MainVS();
        PixelShader = compile PS_SHADERMODEL PSMain();
    }
};
1 Like