shadertoy 原型,https://www.shadertoy.com/view/XslGRrwindows
先說幾個概念app
轉unity代碼以下:函數
Shader "Shadertoy/Cloud" { Properties{ iMouse ("Mouse Pos", Vector) = (100, 100, 0, 0) // iChannel0("iChannel0", 2D) = "white" {} // iChannelResolution0 ("iChannelResolution0", Vector) = (10, 10, 0, 0) } CGINCLUDE #include "UnityCG.cginc" #pragma target 3.0 #define vec2 float2 #define vec3 float3 #define vec4 float4 #define mat2 float2x2 #define mat3 float3x3 #define mat4 float4x4 #define iTime _Time.y // fmod用於求餘數,好比fmod(1.5, 1.0) 返回0.5; #define mod fmod // 插值運算,lerp(a,b,w) return a + w*(a-b); #define mix lerp // fract(x): 取小數部分 #define fract frac #define texture2D tex2D // 屏幕的尺寸 #define iResolution _ScreenParams // 屏幕中的座標,以pixel爲單位.(_iParam.scrPos.xy/_iParam.scrPos.w)在屏幕中歸一化後的屏幕位置,即返回份量範圍在(0, 1)的屏幕橫縱座標值。屏幕的左下角值爲(0, 0),右上角值爲(1, 1)。 #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy) #define PI2 6.28318530718 #define pi 3.14159265358979 #define halfpi (pi * 0.5) #define oneoverpi (1.0 / pi) fixed4 iMouse; // sampler2D iChannel0; // fixed4 iChannelResolution0; struct v2f { float4 pos : SV_POSITION; float4 scrPos : TEXCOORD0; }; //ComputeScreenPos是在UnityCG.cginc中定義的函數,它就做用如名字同樣,計算該頂點轉換到屏幕上的位置 v2f vert(appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.scrPos = ComputeScreenPos(o.pos); return o; } vec4 main(vec2 fragCoord); fixed4 frag(v2f _iParam) : COLOR0 { vec2 fragCoord = gl_FragCoord; // vec2 pos =fragCoord.xy / iResolution.xy * 2. - 1.; return main(fragCoord); } //////////////////////////////////////////////////////////////////// // https://www.shadertoy.com/view/4sfGzS mat3 setCamera( in vec3 ro, in vec3 ta, float cr ) { vec3 cw = normalize(ta-ro); vec3 cp = vec3(sin(cr), cos(cr),0.0); vec3 cu = normalize( cross(cw,cp) ); vec3 cv = normalize( cross(cu,cw) ); return mat3( cu, cv, cw ); } vec3 sundir = normalize( vec3(-1.0,0.0,-1.0) ); #define MARCH(STEPS,MAPLOD) for(int i=0; i<STEPS; i++) { vec3 pos = ro + t*rd; if( pos.y<-3.0 || pos.y>2.0 || sum.a > 0.99 ) break; float den = MAPLOD( pos ); if( den>0.01 ) { float dif = clamp((den - MAPLOD(pos+0.3*sundir))/0.6, 0.0, 1.0 ); sum = integrate( sum, dif, den, bgcol, t ); } t += max(0.05,0.02*t); } float iqhash( float n ) { return fract(sin(n)*43758.5453); } float noise( vec3 x ) { // The noise function returns a value in the range -1.0f -> 1.0f vec3 p = floor(x); vec3 f = fract(x); f = f*f*(3.0-2.0*f); float n = p.x + p.y*57.0 + 113.0*p.z; return mix(mix(mix( iqhash(n+0.0 ), iqhash(n+1.0 ),f.x), mix( iqhash(n+57.0 ), iqhash(n+58.0 ),f.x),f.y), mix(mix( iqhash(n+113.0), iqhash(n+114.0),f.x), mix( iqhash(n+170.0), iqhash(n+171.0),f.x),f.y),f.z); } float map5( in vec3 p ) { vec3 q = p - vec3(0.0,0.1,1.0)*iTime; float f; f = 0.50000*noise( q ); q = q*2.02; f += 0.25000*noise( q ); q = q*2.03; f += 0.12500*noise( q ); q = q*2.01; f += 0.06250*noise( q ); q = q*2.02; f += 0.03125*noise( q ); return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 ); } float map4( in vec3 p ) { vec3 q = p - vec3(0.0,0.1,1.0)*iTime; float f; f = 0.50000*noise( q ); q = q*2.02; f += 0.25000*noise( q ); q = q*2.03; f += 0.12500*noise( q ); q = q*2.01; f += 0.06250*noise( q ); return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 ); } float map3( in vec3 p ) { vec3 q = p - vec3(0.0,0.1,1.0)*iTime; float f; f = 0.50000*noise( q ); q = q*2.02; f += 0.25000*noise( q ); q = q*2.03; f += 0.12500*noise( q ); return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 ); } float map2( in vec3 p ) { vec3 q = p - vec3(0.0,0.1,1.0)*iTime; float f; f = 0.50000*noise( q ); q = q*2.02; f += 0.25000*noise( q );; return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 ); } vec4 integrate( in vec4 sum, in float dif, in float den, in vec3 bgcol, in float t ) { // lighting vec3 lin = vec3(0.65,0.7,0.75)*1.4 + vec3(1.0, 0.6, 0.3)*dif; vec4 col = vec4( mix( vec3(1.0,0.95,0.8), vec3(0.25,0.3,0.35), den ), den ); col.xyz *= lin; col.xyz = mix( col.xyz, bgcol, 1.0-exp(-0.003*t*t) ); // front to back blending col.a *= 0.4; col.rgb *= col.a; return sum + col*(1.0-sum.a); } vec4 raymarch( in vec3 ro, in vec3 rd, in vec3 bgcol, in int2 px ) { vec4 sum = vec4(0.0,0.0,0.0,0.0); float t = 0.0;//0.05*texelFetch( iChannel0, px&255, 0 ).x; MARCH(30,map5); MARCH(30,map4); MARCH(30,map3); MARCH(30,map2); //clamp(x,min,max),min(max(x, min), max), //if min < x < max , return x; //if x < min , return min; //if x > max , return max; return clamp( sum, 0.0, 1.0 ); } //獲得像素點的顏色值 vec4 render( in vec3 ro, in vec3 rd, in int2 px ) { // background sky // dot 點積,各份量分別相乘 後 相加 float sun = clamp( dot(sundir,rd), 0.0, 1.0 ); vec3 col = vec3(0.6,0.71,0.75) - rd.y*0.2*vec3(1.0,0.5,1.0) + 0.15*0.5; col += 0.2*vec3(1.0,.6,0.1)*pow( sun, 8.0 ); // clouds vec4 res = raymarch( ro, rd, col, px ); col = col*(1.0-res.w) + res.xyz; // sun glare // pow(x, y): x的y次方; col += 0.2*vec3(1.0,0.4,0.2)*pow( sun, 3.0 ); return vec4( col, 1.0 ); } vec4 main(vec2 fragCoord) { //iResolution:screen size //fragCoord:在屏幕上的位置,單位pixel vec2 p = (-iResolution.xy + 2.0*fragCoord.xy)/ iResolution.y; vec2 m = iMouse.xy/iResolution.xy; //camera vec3 ro = 4.0*normalize(vec3(sin(3.0*m.x), 0.4*m.y, cos(3.0*m.x))); vec3 ta = vec3(0.0, -1.0, 0.0); mat3 ca = setCamera( ro, ta, 0.0 ); //ray vec3 rd = mul(ca , normalize( vec3(p.xy,1.5))); //fragCoord屏幕像素位置. vec2 pos = fragCoord.xy / iResolution.xy; return render( ro, rd, int2(fragCoord-0.5) ); } //////////////////////////////////////////////////////////////////// ENDCG SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest ENDCG } } FallBack Off }
參考了樂樂(candycat)的博客,想深刻學習shader的能夠多看看她的博客和書,不少乾貨,而後就是https://msdn.microsoft.com/en-us/library/windows/apps/dn166865.aspx,GLSL轉HLSL參考文檔。學習
還有一我的必定要說,shaderToy網站上的iq,創造了好多shader,效果很是很是贊。網站
最後有兩個東西沒解決,textureLod,和texelFetch這兩個函數怎麼映射到unity?spa