1
\$\begingroup\$

I've been working on a shockwave shader based on some examples I've looked at. My primary issue is that the screen/resolution dictates the shape of the shockwave. I need it to be spherical, but with default screen shapes it's an oval.

I can resolve the issue by reverse the resolution ratio calc but that winds up stretching the actual texture.

https://www.shadertoy.com/view/XlfBWj

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    float offset = (iTime- floor(iTime))/iTime;
    float CurrentTime = (iTime)*(offset);    

    vec3 WaveParams = vec3(10.0, 0.8, 0.1 ); 

    vec2 center = vec2(0.5, 0.5);

    vec2 uv = fragCoord.xy / iResolution.xy;

    //float ratio = iResolution.y/iResolution.x;
    //WaveCentre.y *= ratio;
    //texCoord.y *= ratio;

    float dist = distance(uv, center);

    vec4 Color = texture(iChannel0, uv);

    if (dist <= CurrentTime + WaveParams.z &&
        dist >= CurrentTime - WaveParams.z) {
        //The pixel offset distance based on the input parameters
        float Diff = (dist - CurrentTime);
        float ScaleDiff = (1.0 - pow(abs(Diff * WaveParams.x), WaveParams.y));
        float DiffTime = (Diff  * ScaleDiff);

        //The direction of the distortion
        vec2 dir = normalize(uv - center);


        //Perform the distortion and reduce the effect over time
        uv += ((dir * DiffTime) / (CurrentTime * dist * 40.0));
        Color = texture(iChannel0, uv);

    }

    fragColor = Color; 
} 
\$\endgroup\$
  • \$\begingroup\$ you need remapping your uv vec2 uv = fragCoord.xy / iResolution.y; uv = uv*2.0-1.0; \$\endgroup\$ – Seyed Morteza Kamali Dec 14 '17 at 5:15
  • \$\begingroup\$ @SeyedMortezaKamaly that looks like it would be worth proposing as an answer. Since the user has marked this question with the Unity tag, you might want to show a version using _ScreenParams. \$\endgroup\$ – DMGregory Dec 14 '17 at 6:06
  • \$\begingroup\$ @DMGregory I don't think it needs because he need fix his shader on shadertoy.anyway i created tool for converting shadertoy to unity github.com/smkplus/ShaderMan \$\endgroup\$ – Seyed Morteza Kamali Dec 14 '17 at 6:18
  • \$\begingroup\$ @SeyedMortezaKamaly I tried your solution too but that scales the source image 4.5 times. It does fix the shape of the shockwave, but I need to find ways to reverse/avoid distortions to my image. \$\endgroup\$ – BotskoNet Dec 19 '17 at 18:56
  • \$\begingroup\$ @BotskoNet oh right it have problem , sorry.... if you want reverse your distortion you can do if (time > 0. && dist <= waveParams.z-time) { and waveParams.z = 0.5 and for avoid distortion you can have condition if (time > 0. && dist <= waveParams.z-time && _Enable>0.0) { \$\endgroup\$ – Seyed Morteza Kamali Dec 20 '17 at 3:42
1
\$\begingroup\$

The uv coordinates always go from 0 to 1 on both axes regardless of the aspect ratio if you use this method. To solves this you need to make it act based on the resolution. What I usually do is the following:

If you want to make the y axis 1 unit long:

vec2 uv = fragCoord.xy / iResolution.yy;

If you want to make the x axis 1 unit long:

vec2 uv = fragCoord.xy / iResolution.xx;

If the canvas stays wide, then use the former method, and if the canvas stays high, then use the latter one.

If however A) you aren't sure, that the canvas keeps its aspect ratio or B) you don't know which side of the canvas is longer, then you need to use a more sophisticated method:

float maxSize = max(iResolution.x, iResolution.y);
vec2 uv = fragCoord / maxSize;
\$\endgroup\$
  • \$\begingroup\$ This method solves the shape issue, although the shockwave doesn't originate at the center anymore, it's centered horizontally, but is near the top of the image vertically. I tried all three methods just in case, with the x-axis method moving the center to the left. \$\endgroup\$ – BotskoNet Dec 14 '17 at 15:26
  • \$\begingroup\$ So my center = vec2(0.5, 0.5) is the cause, I assume I need to scale those values to properly be half of the axis? I've tried iResolution.y / 2. or 0.5 * iResolution.y but those aren't working. \$\endgroup\$ – BotskoNet Dec 14 '17 at 15:31
  • \$\begingroup\$ @BotskoNet Your center is vec2(iResolution.x / iResolution.y / 2, 0.5) in the first case, vec2(0.5, iResolution.y / iResolution.x / 2) the second and iResolution / maxSize / 2 in the third \$\endgroup\$ – Bálint Dec 14 '17 at 15:33
  • \$\begingroup\$ Do you know of any differences this might have when ported to unity? This code works well on shadertoy but when I adapt it to Unity the image is stretched (but the shockwave is centered). \$\endgroup\$ – BotskoNet Dec 14 '17 at 16:02
  • \$\begingroup\$ I'm not sure about unity. Maybe the resolution isn't right \$\endgroup\$ – Bálint Dec 14 '17 at 20:19
0
\$\begingroup\$

in your comments you mentioned need a way to use shader in unity so i convert it to unity.

//Converted by ShaderMan
//https://github.com/smkplus/ShaderMan
Shader"ShaderMan/Shockwave"{
Properties{
_MainTex("_MainTex", 2D) = "white"{}
[Toggle]_Enable("Enable",Float) = 1
_Scale("Sclae",Vector) = (1,1,1,1)
}
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float _Enable;
float4 _Scale;
float _Movement;

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};

v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}

fixed4 frag(v2f i) : SV_Target{

    // Sawtooth calc of time
    fixed offset = (_Time.y - floor(_Time.y)) / _Time.y;
    fixed time = _Time.y * offset;

    // Wave design params
    fixed3 waveParams = fixed3(10.0, 0.8, 0.1 );

    // Find coordinate, flexible to different resolutions
    fixed maxSize = max(1, 1);
    fixed2 uv = i.uv;
    fixed2 shockuv = i.uv;
    shockuv *=  _Scale;
    // Find center, flexible to different resolutions
    fixed2 center = 1 / maxSize / 2.;

    // Distance to the center
    fixed dist = distance(shockuv.xy, center);

    // Original color
    fixed4 c = tex2D(_MainTex, uv);

    // Limit to waves
    if (time > 0. && dist <= time + waveParams.z && dist >= time - waveParams.z && _Enable>0.0) {
        // The pixel offset distance based on the input parameters
        fixed diff = (dist - time);
        fixed diffPow = (1.0 - pow(abs(diff * waveParams.x), waveParams.y));
        fixed diffTime = (diff  * diffPow);

        // The direction of the distortion
        fixed2 dir = normalize(uv - center);

        // Perform the distortion and reduce the effect over time
        uv += ((dir * diffTime) / (time * dist * 80.0));

        // Grab color for the new coord
        c = tex2D(_MainTex, uv);

        // Optionally: Blow out the color for brighter-energy origin
        //c += (c * diffPow) / (time * dist * 40.0);
    }

    return  c;
}ENDCG
}
}
}
\$\endgroup\$
  • \$\begingroup\$ Thanks but I had already converted it, my issue remains, even when using your version, the image is fine but the shockwave is oval-shaped. \$\endgroup\$ – BotskoNet Dec 20 '17 at 4:06
  • \$\begingroup\$ @BotskoNet I added Scale parameter for setting scale of shock wave , you should set scale of screen size to it.... i think you need a way for setting resolution same Resolution(800,600) , some thing like _ScreenParams forum.unity.com/threads/screen-size-in-shader.47869 \$\endgroup\$ – Seyed Morteza Kamali Dec 20 '17 at 6:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.