smkplus / ShaderMan

Convert ShaderToy to Unity HLSL/CG
https://smkplus.github.io/ShaderMan.io
MIT License
1.42k stars 197 forks source link

Issues with function fmod, numeric type constructor, matrix multiplication #5

Open przemyslawzaworski opened 6 years ago

przemyslawzaworski commented 6 years ago

Recently I created simple shader to test ShaderMan converter. ShaderToy code: mat3 rotationX( float x) { return mat3 ( 1.0,0.0,0.0, 0.0,cos(x),sin(x), 0.0,-sin(x),cos(x) ); } float map (vec3 p) { vec2 t=vec2(0.20,0.1); vec2 q = vec2(sqrt( p.x*p.x + p.z*p.z )-t.x,p.y); q = q*q; q = q*q;q = q*q; float s = pow( q.x + q.y, 0.125 )-t.y; vec3 h = vec3(atan(p.x,p.z)/6.2831,p.y,0.02+0.5*length(p)); vec3 g = mod(h,vec3(0.05,1.0,0.05))-0.5*vec3(0.05,1.0,0.05); vec2 d = (vec2(length(g.xz),g.y)) - vec2(0.02,0.6); float u = -(min(max(d.x,d.y),0.0) + abs(max(d.x,0.0))); return max( s,u); } vec3 set_normal (vec3 p) { vec3 x = vec3 (0.001,0,0); vec3 y = vec3 (0,0.001,0); vec3 z = vec3 (0,0,0.001); return normalize(vec3 (map(p+x)-map(p-x),map(p+y)-map(p-y),map(p+z)-map(p-z))); } vec4 lighting (vec3 ro,vec3 rd) { vec4 AmbientLight = vec4 (0.2); vec3 LightDirection = normalize(vec3(0,0,-20)); vec3 NormalDirection = set_normal(ro); vec4 LightColor = vec4(0.7) ; return max(dot(LightDirection,NormalDirection),0.0)*LightColor+AmbientLight; } vec4 raymarch (vec3 ro, vec3 rd) { for (int i=0;i<128;i++) { float t = map (ro); if (t<0.001) return lighting(ro,rd);
ro+=t*rd; } return vec4(0.0,0.0,0.0,1.0); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = (2.0 * fragCoord.xy - iResolution.xy) / iResolution.y; vec3 ro = vec3 (0,0.35,-0.75); vec3 rd = normalize(vec3(uv,2.0)*rotationX(-0.5)); fragColor = raymarch(ro,rd); }

Converter doesn't translate matrix multiplication properly (should be "mul" function, not * operator), also not generate correct number of arguments for HLSL variables (for example AmbientLight). Also there are differences between GLSL "mod" and HLSL "fmod". In the most of cases direct "mod" to "fmod" conversion is enough, but in above shader it doesn't work properly. Here is my solution with source code:

https://github.com/przemyslawzaworski/Unity3D-CG-programming/blob/master/gear_wheel.shader

Explanation : HLSL fmod: float3 fmod(float3 x, float3 y) {
return x - y * trunc(x/y); } GLSL mod: vec3 mod(vec3 x, vec3 y) { return x - y * floor(x/y); }

smkplus commented 6 years ago

thanks for your solution i couldn't fix matrix multiplication because diagnosis is difficult already i wrote Regex but somewhere I had a problem

a *=b;
a = mul(a,b);

a *= b*c
a = mul(a,mul(b,c)

a = b*c
a = mul(b,c)

a = b*c*d
a = mul(b,mul(c,d)) !?

a = b*c*d*e
a = mul(e,mul(b,mul(c,d))) !?

i couldn't fix this shader by your issue https://www.shadertoy.com/view/Mds3Rn

Shader"ShaderMan/Test"{
Properties{

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

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

v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.screenCoord.xy = ComputeScreenPos(o.vertex);
return o;
}
const fixed PI=3.14159265358979323846;

#define speed (_Time.y*0.2975)
#define ground_x (1.0-0.325*sin(PI*speed*0.25))
fixed ground_y=1.0;
fixed ground_z=0.5;

fixed2 rotate(fixed2 k,fixed t)
    {
    return fixed2(cos(t)*k.x-sin(t)*k.y,sin(t)*k.x+cos(t)*k.y);
    }

fixed draw_scene(fixed3 p)
    {
    fixed tunnel_m=0.125*cos(PI*p.z*1.0+speed*4.0 * 13.14159265359);
    fixed tunnel1_p=2.0;
    fixed tunnel1_w=tunnel1_p*0.225;
    fixed tunnel1=length(fmod(p.xy,tunnel1_p)-tunnel1_p*0.5)-tunnel1_w; // tunnel1
    fixed tunnel2_p=2.0;
    fixed tunnel2_w=tunnel2_p*0.2125+tunnel2_p*0.0125*cos(PI*p.y*8.0)+tunnel2_p*0.0125*cos(PI*p.z*8.0);
    fixed tunnel2=length(fmod(p.xy,tunnel2_p)-tunnel2_p*0.5)-tunnel2_w; // tunnel2
    fixed hole1_p=1.0;
    fixed hole1_w=hole1_p*0.5;
    fixed hole1=length(fmod(p.xz,hole1_p).xy-hole1_p*0.5)-hole1_w;  // hole1
    fixed hole2_p=0.25;
    fixed hole2_w=hole2_p*0.375;
    fixed hole2=length(fmod(p.yz,hole2_p).xy-hole2_p*0.5)-hole2_w;  // hole2
    fixed hole3_p=0.5;
    fixed hole3_w=hole3_p*0.25+0.125*sin(PI*p.z*2.0);
    fixed hole3=length(fmod(p.xy,hole3_p).xy-hole3_p*0.5)-hole3_w;  // hole3
    fixed tube_m=0.075*sin(PI*p.z*1.0);
    fixed tube_p=0.5+tube_m;
    fixed tube_w=tube_p*0.025+0.00125*cos(PI*p.z*128.0);
    fixed tube=length(fmod(p.xy,tube_p)-tube_p*0.5)-tube_w;         // tube
    fixed bubble_p=0.05;
    fixed bubble_w=bubble_p*0.5+0.025*cos(PI*p.z*2.0);
    fixed bubble=length(fmod(p.yz,bubble_p)-bubble_p*0.5)-bubble_w; // bubble
    return max(min(min(-tunnel1,lerp(tunnel2,-bubble,0.375)),max(min(-hole1,hole2),-hole3)),-tube);
    }

fixed4 frag(v2f i) : SV_Target{

    fixed2 position=(i.uv.xy/1);
    fixed2 p=-1.0+2.0*position;
    fixed3 dir=normalize(fixed3(p*fixed2(1.77,1.0),1.0));       // screen ratio (x,y) fov (z)
    //dir.yz=rotate(dir.yz,PI*0.5*sin(PI*speed*0.125)); // rotation x
    dir.zx=rotate(dir.zx,13.14159265359*speed*0.25);                // rotation y
    dir.xy=rotate(dir.xy,-speed*0.5);                   // rotation z
    fixed3 ray=fixed3(ground_x,ground_y,ground_z-speed*2.5);
    fixed t=0.0;
    const int ray_n=96;
    [unroll(100)]
for(int i=0;i<ray_n;i++)
        {
        fixed k=draw_scene(ray+dir*t);
        t+=k*0.75;
        }
    fixed3 hit=ray+dir*t;
    fixed2 h=fixed2(-0.0025,0.002); // light
    fixed3 n=normalize(fixed3(draw_scene(hit+h.xyx),draw_scene(hit+h.yxy),draw_scene(hit+h.yyx)));
    fixed c=(n.x+n.y+n.z)*0.35;
    fixed3 color=fixed3(c,c,c)+t*0.0625;
    return fixed4(fixed3(c-t*0.0375+p.y*0.05,c-t*0.025-p.y*0.0625,c+t*0.025-p.y*0.025)+color*color,1.0);
    }
ENDCG
}
}
}

In the most of cases direct "mod" to "fmod" conversion is enough, but in above shader it doesn't work properly. Here is my solution with source code:

alexNecroJack commented 4 years ago

Hello. I am currently using Unity 2019.something. (Just stating for any case).

Regarding Multiplication, what I found that works is this: a = bcde; ---> a = mul(a, bcd*e);

Actually I turned this: a=aa into that: a = mul(a, a*a) And it worked fine!

Maaaaybe this has to do with "a" being of type "fixed"? .. I am thinking of this because the error in my code was set for this part of code:

fixed3 dir=fixed3(uv*zoom,1.);
//...
fixed2x2 rot1=fixed2x2(cos(a1),sin(a1),-sin(a1),cos(a1));
//...
dir.xz*=rot1; //was made: dir.xz = mul(rot1, dir.xz); 

Maybe there was an error set there because this operator "*=", was used to multiply the type "fixed" xz "property" of the "fixed3 dir", with the rot1 of type "fixed2x2"?

I am just making a hypothesis, I know not HLSL, nor GLSL.