尝试如何把shadertoy 的代码转变成 unity 的shader

最近浏览国外视频网站,发现原来有一个叫shadertoy的网站https://www.shadertoy.com,这个网站展示了许多酷炫的视觉效果,而且让我难以置信的是,这些效果居然很多只是通过代码去实现的,what the F。这个视频也讲解了shadertoy与unity shader 的区别和如何通过修改代码,从而在unity中得到一样的效果。

首先是两者代码上的一些相对应地方的对照表:

当然,我觉得并不是所有的shadertoy代码都可以通过这种方式导入unity。

视频的作者导入了这个shader:

https://www.shadertoy.com/view/4sXBRn

跟着他的步骤我也成功在unity中实现了这个炫酷的效果。

整个shader如下:

Shader "Unlit/ocean"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			// Luminescence by Martijn Steinrucken aka BigWings - 2017
			// Email:countfrolic@gmail.com Twitter:@The_ArtOfCode
			// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

			// My entry for the monthly challenge (May 2017) on r/proceduralgeneration 
			// Use the mouse to look around. Uncomment the SINGLE define to see one specimen by itself.
			// Code is a bit of a mess, too lazy to clean up. Hope you like it!

			// Music by Klaus Lunde
			// https://soundcloud.com/klauslunde/zebra-tribute

			// YouTube: The Art of Code -> https://www.youtube.com/channel/UCcAlTqd9zID6aNX3TzwxJXg
			// Twitter: @The_ArtOfCode

#define INVERTMOUSE -1.

#define MAX_STEPS 100.
#define VOLUME_STEPS 8.
			//#define SINGLE
#define MIN_DISTANCE 0.1
#define MAX_DISTANCE 100.
#define HIT_DISTANCE .01

#define S(x,y,z) smoothstep(x,y,z)
#define B(x,y,z,w) S(x-z, x+z, w)*S(y+z, y-z, w)
#define sat(x) clamp(x,0.,1.)
#define SIN(x) sin(x)*.5+.5
#define mod(x,y) (x-y*floor(x/y))

			static const float3 lf = float3(1., 0., 0.);
			static const float3 up = float3(0., 1., 0.);
			static const float3 fw = float3(0., 0., 1.);

			static const float halfpi = 1.570796326794896619;
			static const float pi = 3.141592653589793238;
			static const float twopi = 6.283185307179586;


			static float3 accentColor1 = float3(1., .1, .5);
			static float3 secondColor1 = float3(.1, .5, 1.);

			static float3 accentColor2 = float3(1., .5, .1);
			static float3 secondColor2 = float3(.1, .5, .6);

			float3 bg;	 	// global background color
			float3 accent;	// color of the phosphorecence

			float N1(float x) { return frac(sin(x)*5346.1764); }
			float N2(float x, float y) { return N1(x + y*23414.324); }

			float N3(float3 p) {
				p = frac(p*0.3183099 + .1);
				p *= 17.0;
				return frac(p.x*p.y*p.z*(p.x + p.y + p.z));
			}

			struct ray {
				float3 o;
				float3 d;
			};

			struct camera {
				float3 p;			// the position of the camera
				float3 forward;	// the camera forward vector
				float3 left;		// the camera left vector
				float3 up;		// the camera up vector

				float3 center;	// the center of the screen, in world coords
				float3 i;			// where the current ray intersects the screen, in world coords
				ray ray;		// the current ray: from cam pos, through current uv projected on screen
				float3 lookAt;	// the lookat point
				float zoom;		// the zoom factor
			};

			struct de {
				// data type used to pass the various bits of information used to shade a de object
				float d;	// final distance to field
				float m; 	// material
				float3 uv;
				float pump;

				float3 id;
				float3 pos;		// the world-space coordinate of the fragment
			};

			struct rc {
				// data type used to handle a repeated coordinate
				float3 id;	// holds the floor'ed coordinate of each cell. Used to identify the cell.
				float3 h;		// half of the size of the cell
				float3 p;		// the repeated coordinate
							//float3 c;		// the center of the cell, world coordinates
			};

			rc Repeat(float3 pos, float3 size) {
				rc o;
				o.h = size*.5;
				o.id = floor(pos / size);			// used to give a unique id to each cell
				o.p = mod(pos, size) - o.h;
				//o.c = o.id*size+o.h;

				return o;
			}

			camera cam;


			void CameraSetup(float2 uv, float3 position, float3 lookAt, float zoom) {

				cam.p = position;
				cam.lookAt = lookAt;
				cam.forward = normalize(cam.lookAt - cam.p);
				cam.left = cross(up, cam.forward);
				cam.up = cross(cam.forward, cam.left);
				cam.zoom = zoom;

				cam.center = cam.p + cam.forward*cam.zoom;
				cam.i = cam.center + cam.left*uv.x + cam.up*uv.y;

				cam.ray.o = cam.p;						// ray origin = camera position
				cam.ray.d = normalize(cam.i - cam.p);	// ray direction is the vector from the cam pos through the point on the imaginary screen
			}


			// ============== Functions I borrowed ;)

			//  3 out, 1 in... DAVE HOSKINS
			float3 N31(float p) {
				float3 p3 = frac((p) * float3(.1031, .11369, .13787));
				p3 += dot(p3, p3.yzx + 19.19);
				return frac(float3((p3.x + p3.y)*p3.z, (p3.x + p3.z)*p3.y, (p3.y + p3.z)*p3.x));
			}

			// DE functions from IQ
			float smin(float a, float b, float k)
			{
				float h = clamp(0.5 + 0.5*(b - a) / k, 0.0, 1.0);
				return lerp(b, a, h) - k*h*(1.0 - h);
			}

			float smax(float a, float b, float k)
			{
				float h = clamp(0.5 + 0.5*(b - a) / k, 0.0, 1.0);
				return lerp(a, b, h) + k*h*(1.0 - h);
			}

			float sdSphere(float3 p, float3 pos, float s) { return (length(p - pos) - s); }

			// From http://mercury.sexy/hg_sdf
			float2 pModPolar(inout float2 p, float repetitions, float fix) {
				float angle = twopi / repetitions;
				float a = atan2(p.y, p.x) + angle / 2.;
				float r = length(p);
				float c = floor(a / angle);
				a = mod(a, angle) - (angle / 2.)*fix;
				p = float2(cos(a), sin(a))*r;

				return p;
			}

			// -------------------------


			float Dist(float2 P, float2 P0, float2 P1) {
				//2d point-line distance

				float2 v = P1 - P0;
				float2 w = P - P0;

				float c1 = dot(w, v);
				float c2 = dot(v, v);

				if (c1 <= 0.)  // before P0
					return length(P - P0);

				float b = c1 / c2;
				float2 Pb = P0 + b*v;
				return length(P - Pb);
			}

			float3 ClosestPoint(float3 ro, float3 rd, float3 p) {
				// returns the closest point on ray r to point p
				return ro + max(0., dot(p - ro, rd))*rd;
			}

			float2 RayRayTs(float3 ro1, float3 rd1, float3 ro2, float3 rd2) {
				// returns the two t's for the closest point between two rays
				// ro+rd*t1 = ro2+rd2*t2

				float3 dO = ro2 - ro1;
				float3 cD = cross(rd1, rd2);
				float v = dot(cD, cD);

				float t1 = dot(cross(dO, rd2), cD) / v;
				float t2 = dot(cross(dO, rd1), cD) / v;
				return float2(t1, t2);
			}

			float DistRaySegment(float3 ro, float3 rd, float3 p1, float3 p2) {
				// returns the distance from ray r to line segment p1-p2
				float3 rd2 = p2 - p1;
				float2 t = RayRayTs(ro, rd, p1, rd2);

				t.x = max(t.x, 0.);
				t.y = clamp(t.y, 0., length(rd2));

				float3 rp = ro + rd*t.x;
				float3 sp = p1 + rd2*t.y;

				return length(rp - sp);
			}

			float2 sph(float3 ro, float3 rd, float3 pos, float radius) {
				// does a ray sphere intersection
				// returns a float2 with distance to both intersections
				// if both a and b are MAX_DISTANCE then there is no intersection

				float3 oc = pos - ro;
				float l = dot(rd, oc);
				float det = l*l - dot(oc, oc) + radius*radius;
				if (det < 0.0) return (MAX_DISTANCE);

				float d = sqrt(det);
				float a = l - d;
				float b = l + d;

				return float2(a, b);
			}


			float3 background(float3 r) {

				float x = atan2(r.x, r.z);		// from -pi to pi	
				float y = pi*0.5 - acos(r.y);  		// from -1/2pi to 1/2pi		

				float3 col = bg*(1. + y);

				float t = _Time.y;				// add god rays

				float a = sin(r.x);

				float beam = sat(sin(10.*x + a*y*5. + t));
				beam *= sat(sin(7.*x + a*y*3.5 - t));

				float beam2 = sat(sin(42.*x + a*y*21. - t));
				beam2 *= sat(sin(34.*x + a*y*17. + t));

				beam += beam2;
				col *= 1. + beam*.05;

				return col;
			}




			float remap(float a, float b, float c, float d, float t) {
				return ((t - a) / (b - a))*(d - c) + c;
			}



			de map(float3 p, float3 id) {

				float t = _Time.y*2.;

				float N = N3(id);

				de o;
				o.m = 0.;

				float x = (p.y + N*twopi)*1. + t;
				float r = 1.;

				float pump = cos(x + cos(x)) + sin(2.*x)*.2 + sin(4.*x)*.02;

				x = t + N*twopi;
				p.y -= (cos(x + cos(x)) + sin(2.*x)*.2)*.6;
				p.xz *= 1. + pump*.2;

				float d1 = sdSphere(p, float3(0., 0., 0.), r);
				float d2 = sdSphere(p, float3(0., -.5, 0.), r);

				o.d = smax(d1, -d2, .1);
				o.m = 1.;

				if (p.y<.5) {
					float sway = sin(t + p.y + N*twopi)*S(.5, -3., p.y)*N*.3;
					p.x += sway*N;	// add some sway to the tentacles
					p.z += sway*(1. - N);

					float3 mp = p;
					mp.xz = pModPolar(mp.xz, 6., 0.);

					float d3 = length(mp.xz - float2(.2, .1)) - remap(.5, -3.5, .1, .01, mp.y);
					if (d3<o.d) o.m = 2.;
					d3 += (sin(mp.y*10.) + sin(mp.y*23.))*.03;

					float d32 = length(mp.xz - float2(.2, .1)) - remap(.5, -3.5, .1, .04, mp.y)*.5;
					d3 = min(d3, d32);
					o.d = smin(o.d, d3, .5);

					if (p.y<.2) {
						float3 op = p;
						op.xz = pModPolar(op.xz, 13., 1.);

						float d4 = length(op.xz - float2(.85, .0)) - remap(.5, -3., .04, .0, op.y);
						if (d4<o.d) o.m = 3.;
						o.d = smin(o.d, d4, .15);
					}
				}
				o.pump = pump;
				o.uv = p;

				o.d *= .8;
				return o;
			}

			float3 calcNormal(de o) {
				float3 eps = float3(0.01, 0.0, 0.0);
				float3 nor = float3(
					map(o.pos + eps.xyy, o.id).d - map(o.pos - eps.xyy, o.id).d,
					map(o.pos + eps.yxy, o.id).d - map(o.pos - eps.yxy, o.id).d,
					map(o.pos + eps.yyx, o.id).d - map(o.pos - eps.yyx, o.id).d);
				return normalize(nor);
			}

			de CastRay(ray r) {
				float d = 0.;
				float dS = MAX_DISTANCE;

				float3 pos = float3(0., 0., 0.);
				float3 n = (0.);
				de o, s;

				float dC = MAX_DISTANCE;
				float3 p;
				rc q;
				float t = _Time.y;
				float3 grid = float3(6., 30., 6.);

				for (float i = 0.; i<MAX_STEPS; i++) {
					p = r.o + r.d*d;

#ifdef SINGLE
					s = map(p, float3(0.));
#else
					p.y -= t;  // make the move up
					p.x += t;  // make cam fly forward

					q = Repeat(p, grid);

					float3 rC = ((2.*step(0., r.d) - 1.)*q.h - q.p) / r.d;	// ray to cell boundary
					dC = min(min(rC.x, rC.y), rC.z) + .01;		// distance to cell just past boundary

					float N = N3(q.id);
					q.p += (N31(N) - .5)*grid*float3(.5, .7, .5);

					if (Dist(q.p.xz, r.d.xz, (0.))<1.1)
						//if(DistRaySegment(q.p, r.d, float3(0., -6., 0.), float3(0., -3.3, 0)) <1.1) 
						s = map(q.p, q.id);
					else
						s.d = dC;


#endif

					if (s.d<HIT_DISTANCE || d>MAX_DISTANCE) break;
					d += min(s.d, dC);	// move to distance to next cell or surface, whichever is closest
				}

				if (s.d<HIT_DISTANCE) {
					o.m = s.m;
					o.d = d;
					o.id = q.id;
					o.uv = s.uv;
					o.pump = s.pump;

#ifdef SINGLE
					o.pos = p;
#else
					o.pos = q.p;
#endif
				}

				return o;
			}

			float VolTex(float3 uv, float3 p, float scale, float pump) {
				// uv = the surface pos
				// p = the volume shell pos

				p.y *= scale;

				float s2 = 5.*p.x / twopi;
				float id = floor(s2);
				s2 = frac(s2);
				float2 ep = float2(s2 - .5, p.y - .6);
				float ed = length(ep);
				float e = B(.35, .45, .05, ed);

				float s = SIN(s2*twopi*15.);
				s = s*s; s = s*s;
				s *= S(1.4, -.3, uv.y - cos(s2*twopi)*.2 + .3)*S(-.6, -.3, uv.y);

				float t = _Time.y*5.;
				float mask = SIN(p.x*twopi*2. + t);
				s *= mask*mask*2.;

				return s + e*pump*2.;
			}

			float4 JellyTex(float3 p) {
				float3 s = float3(atan2(p.x, p.z), length(p.xz), p.y);

				float b = .75 + sin(s.x*6.)*.25;
				b = lerp(1., b, s.y*s.y);

				p.x += sin(s.z*10.)*.1;
				float b2 = cos(s.x*26.) - s.z - .7;

				b2 = S(.1, .6, b2);
				return (b + b2);
			}

			float3 render(float2 uv, ray camRay, float depth) {
				// outputs a color

				bg = background(cam.ray.d);

				float3 col = bg;
				de o = CastRay(camRay);

				float t = _Time.y;
				float3 L = up;


				if (o.m>0.) {
					float3 n = calcNormal(o);
					float lambert = sat(dot(n, L));
					float3 R = reflect(camRay.d, n);
					float fresnel = sat(1. + dot(camRay.d, n));
					float trans = (1. - fresnel)*.5;
					float3 ref = background(R);
					float fade = 0.;

					if (o.m == 1.) {	// hood color
						float density = 0.;
						for (float i = 0.; i<VOLUME_STEPS; i++) {
							float sd = sph(o.uv, camRay.d, (0.), .8 + i*.015).x;
							if (sd != MAX_DISTANCE) {
								float2 intersect = o.uv.xz + camRay.d.xz*sd;

								float3 uv = float3(atan2(intersect.x, intersect.y), length(intersect.xy), o.uv.z);
								density += VolTex(o.uv, uv, 1.4 + i*.03, o.pump);
							}
						}
						float4 volTex = float4(accent, density / VOLUME_STEPS);


						float3 dif = JellyTex(o.uv).rgb;
						dif *= max(.2, lambert);

						col = lerp(col, volTex.rgb, volTex.a);
						col = lerp(col, float3(dif), .25);

						col += fresnel*ref*sat(dot(up, n));

						//fade
						fade = max(fade, S(.0, 1., fresnel));
					}
					else if (o.m == 2.) {						// inside tentacles
						float3 dif = accent;
						col = lerp(bg, dif, fresnel);

						col *= lerp(.6, 1., S(0., -1.5, o.uv.y));

						float prop = o.pump + .25;
						prop *= prop*prop;
						col += pow(1. - fresnel, 20.)*dif*prop;


						fade = fresnel;
					}
					else if (o.m == 3.) {						// outside tentacles
						float3 dif = accent;
						float d = S(100., 13., o.d);
						col = lerp(bg, dif, pow(1. - fresnel, 5.)*d);
					}

					fade = max(fade, S(0., 100., o.d));
					col = lerp(col, bg, fade);

					if (o.m == 4.)
						col = float3(1., 0., 0.);
				}
				else
					col = bg;

				return col;
			}
			
			fixed4 frag(v2f i) : SV_Target
			{
			
				float t = _Time.y*.04;

				float2 uv = i.uv;
				uv -= .5;
				//uv.y *= iResolution.y / iResolution.x;

				float2 m = 0;// iMouse.xy / iResolution.xy;

				if (m.x<0.05 || m.x>.95) {				// move cam automatically when mouse is not used
					m = float2(t*.25, SIN(t*pi)*.5 + .5);
				}

				accent = lerp(accentColor1, accentColor2, SIN(t*15.456));
				bg = lerp(secondColor1, secondColor2, SIN(t*7.345231));

				float turn = (.1 - m.x)*twopi;
				float s = sin(turn);
				float c = cos(turn);
				float3x3 rotX = float3x3(c, 0., s, 0., 1., 0., s, 0., -c);

#ifdef SINGLE
				float camDist = -10.;
#else
				float camDist = -.1;
#endif

				float3 lookAt = float3(0., -1., 0.);

				float3 camPos = mul(rotX,float3(0., INVERTMOUSE*camDist*cos((m.y)*pi), camDist));

				CameraSetup(uv, camPos + lookAt, lookAt, 1.);

				float3 col = render(uv, cam.ray, 0.);

				col = pow(col, (lerp(1.5, 2.6, SIN(t + pi))));		// post-processing
				float d = 1. - dot(uv, uv);		// vignette
				col *= (d*d*d) + .1;

				return float4(col, 1.);
			}

			
			ENDCG
		}
	}
}

接下来,趁着兴奋劲我便尝试自己去导入其他的炫酷效果,于是便浏览shadertoy 的网站选择一个效果,最后决定就这个了:

https://www.shadertoy.com/view/3l23Rh

1.首先新建一个Unlit Shader

2.复制网站上所有的代码

3.在v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

后面黏贴所复制的代码。

4.根据之前的对照表,把一些函数名字进行整体替换,例如:vec2,vec3 ,vec4 替换为float2,float3,float4。并不是表中所有的函数都会出现,所以按照实际情况来,每次修改完都可以保存一下,看下unity上报的错误,然后直接定位到具体的位置。

5.把void mainImage( out vec4 fragColor, in vec2 fragCoord ) 替换为fixed4 frag(v2f i) : SV_Target,原来新建的unlit shader 的fixed4 frag(v2f i) : SV_Target{ ... } 都删掉。


    rd.xy *= rot(-disp(time + 3.5).x*0.2 + bsMo.x);

改为

    rd.xy = mul(rd.xy,rot(-disp(time + 3.5).x*0.2 + bsMo.x));

 


    vec2 q = fragCoord.xy/iResolution.xy;
    vec2 p = (gl_FragCoord.xy - 0.5*iResolution.xy)/iResolution.y;
    bsMo = (iMouse.xy - 0.5*iResolution.xy)/iResolution.y;

改为       

    float2 q = i.uv;
    float2 p = q;
    bsMo = 0;// (iMouse.xy - 0.5*iResolution.xy) / iResolution.y;


    fragColor = vec4( col, 1.0 );

改为

    return float4(col, 1.0); 

以上我说的只是个大概,讲的有点粗糙,具体可参考以下完整shader:

Shader "Unlit/cloud"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			// Protean clouds by nimitz (twitter: @stormoid)
			// https://www.shadertoy.com/view/3l23Rh
			// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
			// Contact the author for other licensing options

			/*
			Technical details:

			The main volume noise is generated from a deformed periodic grid, which can produce
			a large range of noise-like patterns at very cheap evalutation cost. Allowing for multiple
			fetches of volume gradient computation for improved lighting.

			To further accelerate marching, since the volume is smooth, more than half the the density
			information isn't used to rendering or shading but only as an underlying volume	distance to
			determine dynamic step size, by carefully selecting an equation	(polynomial for speed) to
			step as a function of overall density (not necessarialy rendered) the visual results can be
			the	same as a naive implementation with ~40% increase in rendering performance.

			Since the dynamic marching step size is even less uniform due to steps not being rendered at all
			the fog is evaluated as the difference of the fog integral at each rendered step.

			*/

			static float2x2 rot(in float a) { float c = cos(a), s = sin(a); return float2x2(c, s, -s, c); }
			static const float3x3 m3 = float3x3(0.33338, 0.56034, -0.71817, -0.87887, 0.32651, -0.15323, 0.15162, 0.69596, 0.61339)*1.93;
			static float mag2(float2 p) { return dot(p, p); }
			static float linstep(in float mn, in float mx, in float x) { return clamp((x - mn) / (mx - mn), 0., 1.); }
			static float prm1 = 0.;
			static float2 bsMo = (0);

			float2 disp(float t) { return float2(sin(t*0.22)*1., cos(t*0.175)*1.)*2.; }

			float2 map(float3 p)
			{
				float3 p2 = p;
				p2.xy -= disp(p.z).xy;
				p.xy = mul(p.xy,rot(sin(p.z + _Time.y)*(0.1 + prm1*0.05) + _Time.y*0.09));
				float cl = mag2(p2.xy);
				float d = 0.;
				p *= .61;
				float z = 1.;
				float trk = 1.;
				float dspAmp = 0.1 + prm1*0.2;
				for (int i = 0; i < 5; i++)
				{
					p += sin(p.zxy*0.75*trk + _Time.y*trk*.8)*dspAmp;
					d -= abs(dot(cos(p), sin(p.yzx))*z);
					z *= 0.57;
					trk *= 1.4;
					p = mul(p,m3);
				}
				d = abs(d + prm1*3.) + prm1*.3 - 2.5 + bsMo.y;
				return float2(d + cl*.2 + 0.25, cl);
			}

			float4 render(in float3 ro, in float3 rd, float time)
			{
				float4 rez = (0);
				const float ldst = 8.;
				float3 lpos = float3(disp(time + ldst)*0.5, time + ldst);
				float t = 1.5;
				float fogT = 0.;
				for (int i = 0; i<130; i++)
				{
					if (rez.a > 0.99)break;

					float3 pos = ro + t*rd;
					float2 mpv = map(pos);
					float den = clamp(mpv.x - 0.3, 0., 1.)*1.12;
					float dn = clamp((mpv.x + 2.), 0., 3.);

					float4 col = (0);
					if (mpv.x > 0.6)
					{

						col = float4(sin(float3(5., 0.4, 0.2) + mpv.y*0.1 + sin(pos.z*0.4)*0.5 + 1.8)*0.5 + 0.5, 0.08);
						col *= den*den*den;
						col.rgb *= linstep(4., -2.5, mpv.x)*2.3;
						float dif = clamp((den - map(pos + .8).x) / 9., 0.001, 1.);
						dif += clamp((den - map(pos + .35).x) / 2.5, 0.001, 1.);
						col.xyz *= den*(float3(0.005, .045, .075) + 1.5*float3(0.033, 0.07, 0.03)*dif);
					}

					float fogC = exp(t*0.2 - 2.2);
					col.rgba += float4(0.06, 0.11, 0.11, 0.1)*clamp(fogC - fogT, 0., 1.);
					fogT = fogC;
					rez = rez + col*(1. - rez.a);
					t += clamp(0.5 - dn*dn*.05, 0.09, 0.3);
				}
				return clamp(rez, 0.0, 1.0);
			}

			float getsat(float3 c)
			{
				float mi = min(min(c.x, c.y), c.z);
				float ma = max(max(c.x, c.y), c.z);
				return (ma - mi) / (ma + 1e-7);
			}

			//from my "Will it blend" shader (https://www.shadertoy.com/view/lsdGzN)
			float3 iLerp(in float3 a, in float3 b, in float x)
			{
				float3 ic = lerp(a, b, x) + float3(1e-6, 0., 0.);
				float sd = abs(getsat(ic) - lerp(getsat(a), getsat(b), x));
				float3 dir = normalize(float3(2.*ic.x - ic.y - ic.z, 2.*ic.y - ic.x - ic.z, 2.*ic.z - ic.y - ic.x));
				float lgt = dot((1.0), ic);
				float ff = dot(dir, normalize(ic));
				ic += 1.5*dir*sd*ff*lgt;
				return clamp(ic, 0., 1.);
			}

			fixed4 frag(v2f i) : SV_Target
			{
				
				float2 q = i.uv;
				float2 p = q;
				bsMo = 0;// (iMouse.xy - 0.5*iResolution.xy) / iResolution.y;

				float time = _Time.y*3.;
				float3 ro = float3(0, 0, time);

				ro += float3(sin(_Time.y)*0.5, sin(_Time.y*1.)*0., 0);

				float dspAmp = .85;
				ro.xy += disp(ro.z)*dspAmp;
				float tgtDst = 3.5;

				float3 target = normalize(ro - float3(disp(time + tgtDst)*dspAmp, time + tgtDst));
				ro.x -= bsMo.x*2.;
				float3 rightdir = normalize(cross(target, float3(0, 1, 0)));
				float3 updir = normalize(cross(rightdir, target));
				rightdir = normalize(cross(updir, target));
				float3 rd = normalize((p.x*rightdir + p.y*updir)*1. - target);
				rd.xy = mul(rd.xy,rot(-disp(time + 3.5).x*0.2 + bsMo.x));
				prm1 = smoothstep(-0.4, 0.4, sin(_Time.y*0.3));
				float4 scn = render(ro, rd, time);

				float3 col = scn.rgb;
				col = iLerp(col.bgr, col.rgb, clamp(1. - prm1, 0.05, 1.));

				col = pow(col, float3(.55, 0.65, 0.6))*float3(1., .97, .9);

				col *= pow(16.0*q.x*q.y*(1.0 - q.x)*(1.0 - q.y), 0.12)*0.7 + 0.3; //Vign

				return float4(col, 1.0);
			}
			
			ENDCG
		}
	}
}


    

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值