ODOShader

ODOS丨ShaderToy 2 ShaderLab

by ERIN.Z, 2022-03-01


Snipaste_2022-03-01_17-42-35.png

ShaderLanguage

Shader Language目前主要有3种语言:基于OpenGL的OpenGL Shading Language,简称GLSL;基于DirectX的High Level Shading Language,简称HLSL;还有NVIDIA公司的C for Graphic,简称Cg语言。 Unity使用的Shader程序嵌入的小片段是用Cg/HLSL编写的,从“CGPROGRAM”开始,到“CGEND”结束。 ShaderToy使用的WebGL程序由JavaScript编写的句柄和OpenGL Shading Language(GLSL)编写的着色器代码组成,该语言类似于C或C++,并在电脑的图形处理器(GPU)上执行。 所以想在Unity中查看ShaderToy的shader首先要将GLSL语言转化为HLSL/CG语言——

关键词替换

在开始之前,把shadertoy中的代码粘贴到pass下的CGPROGRAM语句段内:

可直接CtrlF替换

Syntax vec → float mat → floatx fract( → frac( mix( → lerp( texture( → tex2D(/tex3D(/texCUBE KeyWords iTime → _Time.y

需要前文定义

#define atan(x,y) atan2(y,x) #define mod(x,y) x-y*floor(x/y)

手动修改

语义修正

Matrix Multiplication * → mul() 注意顺序:A*=B → A=mul(B,A) A*B → mul(B,A) Type Casting vec3(0) → float3 a = 1或 float3(0,0,0)

需要前文定义/外挂脚本

  • iMouse 需要在properties 定义fixed4变量,然后在CG程序块里再次声明同名变量。接下来要外挂C#脚本,可以参考乐乐老师的版本:【ShaderToy】开篇
  • Channel 需要在properties 定义对应种类的变量(2D/3D/CUBE),然后在CG程序块里再次声明同名变量。

代码结构

main (诚邀美女们下载这个VSCode的粉嫩主题-Dracula Official🍓

以jb猫为例

虽然raymarching modeling is not 4 UNITY,但是它可爱。所以就它了! 除去之前提到的注意事项,还有一点点关于AA的修正:因为没有iResolution,所以smoothstep给了定值;另外在主函数中上下左右取样AA的offset用了ddx(uv.x)来做单位,其实不太确定对不对... 但总之It works! inUnity 其实这个写法还是不太规范,uv的运算借用了maintex的运算矩阵来控制offset和scale,但其实没有用到maintex。 注意预览动态材质时要开启alway refreshing: toggle 完整的代码在下面:

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

            samplerCUBE _iChannel0;
            sampler2D _MainTex;
            float4 _MainTex_ST;

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

    #define TMIN 0.01
    #define TMAX 200.
    #define RAYMARCH_TIME 128
    #define PRECISION .001
    #define AA 3
    #define PI 3.1415926

    #define S(v,r) smoothstep( r, r+0.005, v )
    float logo(float2 uv);

    //========SDFunctions========
float sdSphere(float3 p, float3 o, float r){
    return length(p-o)-r;
}
float sdCapsule(float3 p,float3 a, float3 b,float r){
    float3 ab = b - a;
    float3 ap = p - a;
    float t = dot(ab, ap)/dot(ab,ab);
    t = clamp(t,0.,1.);
    float3 c = a +t*ab;
    return length(p-c)-r;
}
//https:www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdRoundCone( float3 p, float r1, float r2, float h )
{
  // sampling independent computations (only depend on shape)
  float b = (r1-r2)/h;
  float a = sqrt(1.0-b*b);

  // sampling dependant computations
  float2 q = float2( length(p.xz), p.y );
  float k = dot(q,float2(-b,a));
  if( k<0.0 ) return length(q) - r1;
  if( k>a*h ) return length(q-float2(0.0,h)) - r2;
  return dot(q, float2(a,b) ) - r1;
}
//===============TRANSFORM=================
float2x2 rotate(float a){
return float2x2(cos(a),sin(a),-sin(a),cos(a));
}
float smUni( float d1, float d2, float k ) {
    float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
    return lerp( d2, d1, h ) - k*h*(1.0-h); 
}
//===============RENDER===================
//Scene
float f(float3 p){
    p.x=abs(p.x);
    float d;
    {//face
    float3 p0 = float3(p.x*.8,p.y+.4,p.z);
    d = sdSphere(p0,float3(0,0,0),1.5); 
    p0 = float3(p.x*.6,p.y+.6,p.z+.7);
    float d0 = sdSphere(p0,float3(0,0,0),1.);
    d = smUni(d,d0,.3);
    }
    float angle = sin(_Time.y*5.)*.1;
    {//ear
    float3 p0 = float3(p.x-.85,p.y-.3,p.z*1.2+.3);
    p0.xy = mul(rotate(-.3),p0.xy);
    p0.yz = mul(rotate(-.3),p0.yz);
    float d0 = sdRoundCone(p0,.8,.2,1.2)/1.2; 
    d = smUni(d,d0,.3);
    }
    {//nose
    float d0 = sdCapsule(p,float3(0,0,-1.5),float3(0,-.6,-1.7),.3); 
    d = smUni(d,d0,.05);
    }
    {//nose
    float d0 = sdSphere(p,float3(.3,-.6,-1.65),.45); 
    d = smUni(d,d0,.05);
    }
    {//eye
    float3 p0 = float3(p.x-.6,p.y+.1,p.z+1.45);
    p0.xy = mul(rotate(-1.2),p0.xy);
    p0.yz = mul(rotate(-0.3),p0.yz);
    float d0 = sdRoundCone(p0,.06,.08,.2); 
    d = smUni(d,d0,.05);
    }
    {//
    float3 p0 = float3(p.x-.9,p.y+.5,p.z+1.3);
    p0.xy = mul(rotate(.2+angle*.5),p.xy);
    float d0 = sdCapsule(p0,float3(0,0,0),float3(.8,0,0),.1);
    p0.xy = mul(rotate(-.4+angle*.5),p.xy);
    d0 = smUni(d0,sdCapsule(p0,float3(0,0,0),float3(.8,0,0),.1),.05);
    d = smUni(d,d0,.05);
    }
    return d;
}
float rayMarch(in float3 ro, in float3 rd) {
    float t = TMIN;
    for(int i = 0; i < RAYMARCH_TIME ; i++) {
        float3 p = ro + t * rd;
        float d = f(p);
        t += d;
        if(d < PRECISION || t > TMAX)
            break;
    }
    return t;
}
// https://www.iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
float3 calcNormal(in float3 p) {
    const float h = 0.0001;
    const float2 k = float2(1, -1);
    return normalize(k.xyy * f(p + k.xyy * h) +
        k.yyx * f(p + k.yyx * h) +
        k.yxy * f(p + k.yxy * h) +
        k.xxx * f(p + k.xxx * h));
}

float3x3 setCamera(in float3 camtar, in float3 campos, in float camro){
    float3 z = normalize(camtar-campos);
    float3 cp = float3(sin(camro),cos(camro),0.);
    float3 x = normalize(cross(cp,z));
    float3 y = cross(z,x);
    return float3x3(x,y,z);
}
float3 render(float2 uv){
    float3 lightPos = float3(-5., 5.,-5);//light

    //SET Camera
    float3 cam_tar = float3(0,-.5,0);//cam target
    float angle = pow(sin(_Time.y+.3),3.)*.5;
    float3 cam_pos = float3(sin(angle),0,-cos(angle))*10.;//cam position

    float3 rd = float3(uv,4.); //decide view width
    rd = normalize(mul(rd,setCamera(cam_tar,cam_pos,0.)));//viewing frustum

    float t = rayMarch(cam_pos,rd);//raymarching

    float3 color = lerp(float3(0,0,1),float3(0,0,.6),uv.y*.5+.5);//background

    if(t > TMAX) return color; 

    float3 p = cam_pos + t*rd;
    float3 n = calcNormal(p);
    float3 l = normalize(lightPos-p);//lightDir
    float3 h = normalize(l-rd);//

    float3 diffusecol = 1;//diffuse color
    float3 specol = 1;//specular color
    float3 cmrfl = .5*float3(1,1,1)*texCUBE(_iChannel0,reflect(rd,n)).rgb;//cubemap reflection

    float dif = clamp(dot(l,n),0.,1.);//diffuse    
    float spe = pow(clamp(dot(h,n),0.,1.),50.);//specular
    float fresnel = pow(clamp(1. - dot(n,-rd),0.,1.),5.);

    color = cmrfl + .1*dif*diffusecol + smoothstep(.6,1.,spe)*specol;//metal
    color = smoothstep(0.,1.,color);//add contrast

    color += fresnel*.4;

    return color;
}

            fixed4 frag (v2f i) : SV_Target
            {
            float2 uv = i.uv - 0.5;//i.uv是0~1,
            float3 color = 0;

                #if AA>1
                for(int m = 0; m < AA; m++) {
                    for(int n = 0; n < AA; n++) {
                    float2 offset = 2. * (float2(float(m), float(n)) / float(AA) - .5) * ddx(i.uv.x);
                    uv = i.uv+offset;
                #else
                    uv = i.uv;
                #endif
                    color += render(uv);
                #if AA>1
                }
            }
            color /= float(AA*AA);
            #endif

            color = lerp(color,float3(1,1,1),logo(uv));
            return float4(color,1.0);
            }
            float logo(float2 uv){
            float n = 0.;
            n += S(.05,abs(length(uv-float2(-1.23,0))-.12));
            n *= 1.-S(-1.25,uv.x);
            n += S(.17,abs(uv.y))*S(.05,abs(uv.x+1.29));
            n += S(.05,abs(length(uv-float2(-1.5,0))-.12));
            n += S(.05,abs(length(uv-float2(-0.9,0))-.12));
            n += (1.+S(-.6,uv.x)-S(.05,uv.y))*S(.05,abs(length(uv-float2(-0.6,.03))-.09));
            n += (1.-S(-.6,uv.x)+S(-.05,uv.y))*S(.05,abs(length(uv-float2(-0.6,-.04))-.09));
            return n;
            }
            ENDCG
        }
    }
}

by ERIN.Z

2024 © typecho & elise