[Shader and ShaderToy] draw a circle

Write in front

        Today, I’m going to try to make a circle on Unity and ShaderToy’s website respectively to see the specific difference between the two.

        Some preparatory work before running Unity and shadertoy will be skipped, and the code and display effect will be directly uploaded.

Unity part

        Using Unity + VS to write shader is my favorite, intuitive and fast, and you can directly change the parameter setting effect on the panel, which is much higher than the webpage! Paste the code of the shader below

Shader "Custom/circle" {
	Properties {
		//xy表示圆心在屏幕中的uv值,z为半径,w为圆边缘的平滑值
		_parameters("circleParameter",Vector)=(0.5,0.5,10,0)
		_Color("circleColor",COLOR)=(1,1,1,1)
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		Pass{
		CGPROGRAM
		#include "UnityCG.cginc"
		#pragma fragmentoption ARB_precision_hint_fastest   
		#pragma target 3.0
		#pragma vertex vert
		#pragma fragment frag

		#define vec2 float2
		#define vec3 float3
		#define vec4 float4
		#define mat2 float2
		#define mat3 float3
		#define mat4 float4
		#define iGlobalTime _Time.y
		#define mod fmod
		#define mix lerp
		#define fract frac
		#define Texture2D tex2D
		#define iResolution _ScreenParams

		float4 _parameters;
		float4 _Color;
		float4 _backgroundColor;

		struct v2f{
			float4 pos:SV_POSITION;
			float4 srcPos:TEXCOORD0;
		};

		v2f vert(appdata_base v){
			v2f o;
			o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
			o.srcPos=ComputeScreenPos(o.pos);
			return o;
		}
		vec4 main(vec2 fragCoord);
		float4 frag(v2f iParam):COLOR{
			//获取uv对应的当前分辨率下的点   uv范围(0-1) 与分辨率相乘
			vec2 fragCoord=((iParam.srcPos.xy/iParam.srcPos.w)*_ScreenParams.xy);
			return main(fragCoord);
		}
		//要先定义方法声明才能使用
		vec4 cicle(vec2 pos,vec2 center,float radius,float3 col,float antialias){
			//求出点到圆心距离,如果为正则在圆外 负在圆内 我们需要对圆内的点进行上色 即对负值进行处理
			float d=length(pos-center)-radius;
			//判断d的大小 如果小于0则返回0 如果大于antialias返回1 返回值在0-1之间
			//smoothstep(a,b,t) 判断t t<a返回0,t>b返回1,t在a-b之间反差值返回0-1 
			float t=smoothstep(0,antialias,d);
			//返回颜色值 在圆外的设置alpha=0透明 
			return vec4(col,1.0-t);

		}
		vec4 main(vec2 fragCoord){
			vec2 pos=fragCoord;
			//给背景一个动态的颜色
			vec3 temp = 0.5 + 0.5*cos(iGlobalTime+pos.xyx/_ScreenParams.y+vec3(0,2,4));
			//获取背景的颜色
			vec4 layer1=vec4(temp,1.0);
			//获取圆
			vec4 layer2=cicle(pos,_parameters.xy*iResolution.xy,_parameters.z,_Color.rgb,_parameters.w);
			//插值处理,使边界更模糊化,layer2中的_parameters.w值越大越模糊
			return mix(layer1,layer2,layer2.a);
		}



		ENDCG
		}
	}
	FallBack "Diffuse"
}

        The code looks like a very long and very long section, but it is actually a template for shadertoy to shader. The description of the template can be viewed here . The key code is the circle function for drawing a circle. The general principle of shadertoy is to draw layers one by one, and then mix them up with various effects, which is similar to the PS drawing. This knows why the better the effect, the more stuck the shadetoy webpage looks, and I don’t know how many layers are stacked. Up.

        In order to make the Unity effect the same as the shadertoy side, the default variable color background is specially added. The code is as follows

//给背景一个动态的颜色
vec3 temp = 0.5 + 0.5*cos(iGlobalTime+pos.xyx/_ScreenParams.y+vec3(0,2,4));

        Using the cosine function with a constantly changing time value iGlobalTime, the background can change color continuously. The running effect on Unity is as follows

 

ShaderToy section

        I thought that shadertoy would be done quickly. After all, Unity wrote a bunch of defined codes for compatibility with shadertoy. I didn’t expect to find grammatical errors for half an hour, and it’s still the same error, as if I’m back to someone who just learned programming. Times. . . The content of the error is as follows

        

        Don't be scared by these red boxes, the two errors are the same reason, the parameter type is wrong. On shadertoy, as long as you define a float type, the parameter must be a float type, otherwise you will directly no matching overloaded function found. When I reported the error, I didn’t realize the problem. I thought it was a normal built-in function. Why did it suddenly report that there is no overloading method? For the time, I went to read the code written by other people, but I still haven’t found the problem. , In the end, I don’t know why I changed the 1.0-t of the return value to 1-t. The red all the error content only woke me up, it turned out that the parameter type was wrong! ! ! ! The smoothstep method must be floating point! ! Will not help you convert! ! ! Even if you are 0, you have to write 0.0! ! !

        Below is the wrong shadertoy code

float t=smoothstep(0,antialias,d);

        Below is the correct shadertoy code

float t=smoothstep(0.0,antialias,d);

        It is quite. . . Strict. . . Paste the code of shadertoy below

//输入参数(当前点位置,中心点位置,点的半径,颜色,与背景过渡的平滑值)
vec4 cicle(vec2 pos,vec2 center,float radius,vec3 col,float antialias){
    //求圆心距离
    float d=length(pos-center)-radius;
    //smoothstep(a,b,t)函数 t<a return a, t>b return b
    float t=smoothstep(0.0,antialias,d);
    return vec4(col,1.0-t);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    //获取点的位置
    //iResolution为屏幕的分辨率
    //fragCoord为当前点的位置 原点是左下角
    //返回的uv是以屏幕中心为原点
    vec2 uv =(2.0*fragCoord.xy-iResolution.xy) /iResolution.y;
    //中心点
    vec2 point1 = vec2(0,0);
    //圆的颜色
    vec3 color=vec3(1,0,0);
    // layer1 cos函数
    vec3 temp = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
    vec4 layer1= vec4(temp,1);
    //layer2 平滑的圆
    vec4 layer2 = cicle(uv,point1,0.8,color,0.03);
    // 输出像素
    fragColor = mix(layer1,layer2,layer2.a);
}

       

        A very simple effect, basically different from unity, but it is really inconvenient to write coloring smoothly on the browser! ! webGL is really easy to crash! ! And the input parameters are not very easy to change. . . Once again realize the convenience of unity. .

to sum up

        Here are some differences between shader and shadertoy code under unity.

        1. The character type on shadetoy will not be automatically forced. If there is a parameter of float type in the function you define, an error will definitely be reported if you use the int type when calling; the value 0 is an integer, and 0.0 is the symbol type. (Unity tried on the type and forced the transfer without problems)

        2. The input positions of the two shaders are different.

        The input of the fragment function frag() code of the shader in unity is the projection coordinates of the vertices. The coordinates need to be normalized and then multiplied by the screen resolution to obtain the corresponding coordinate points.

//(iParam.srcPos.xy/iParam.srcPos.w)获取归一化的点 范围在(0-1)
//与屏幕分辨率相乘获得实际的像素坐标,坐标原点在正中心
vec2 fragCoord=((iParam.srcPos.xy/iParam.srcPos.w)*_ScreenParams.xy);

        The input of the main method in shadertoy is the pixel position corresponding to the vertex. The origin is the lower left corner of the screen. It needs to be converted to the origin at the center. This operation of converting the original range from (0,a) to (-b,b) is the original The position of the coordinate will become y=bx-b (0<x<a). But in this way, the operand value will be enlarged many times, so a unified zoom is required, and the obtained position coordinate is divided by an axis of the screen.

//获取点的位置
//iResolution为屏幕的分辨率
//fragCoord为当前点的位置 原点是左下角
//返回的uv是以屏幕中心为原点 并且除以分辨率的一个轴进行缩放
vec2 uv =(2.0*fragCoord.xy-iResolution.xy) /iResolution.y;

PS: It is not easy to describe what you understand. . .

Guess you like

Origin blog.csdn.net/ssssssilver/article/details/81129441