[シェーダーとシェーダートイ]円を描く

前に書く

        今日は、UnityとShaderToyのウェブサイトでそれぞれ円を描いて、両者の具体的な違いを確認します。

        Unityとshadertoyを実行する前のいくつかの準備作業はスキップされ、コードと表示効果が直接アップロードされます。

ユニティパート

        Unity + VSを使用してシェーダーを作成するのは私のお気に入りで、直感的で高速です。また、パラメーター設定効果をパネルで直接変更することもできます。これはWebページよりもはるかに高いです。シェーダーのコードを下に貼り付けます

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

        コードは非常に長く、非常に長いセクションのように見えますが、実際にはシェーダーからシェーダーへのテンプレートです。テンプレートの説明はここで確認できます。重要なコードは、円を描くための円関数です。シェーダートイの一般的な原理は、レイヤーを1つずつ描画し、それをさまざまな効果と混ぜ合わせることです。これは、PSの描画と同様です。これにより、効果が優れているほど、シェードトイのWebページがスタックしやすくなります。スタックされているレイヤーの数がわかります。

        Unity効果をshadertoy側と同じにするために、デフォルトの可変色の背景が特別に追加されています。コードは次のとおりです。

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

        時間値iGlobalTimeが絶えず変化する余弦関数を使用すると、背景の色を継続的に変更できます。Unityでの実行効果は次のとおりです。

 

ShaderToyセクション

        結局、Unityはshadertoyとの互換性のために定義されたコードをたくさん書いたのですが、30分間文法エラーが見つかるとは思っていませんでしたが、それでも同じエラーです。 mプログラミングの学習に戻ります。エラーの内容は以下のとおりです。

        

        これらの赤いボックスに怖がらないでください。2つのエラーは同じ理由です。パラメータタイプが間違っています。シェーダートイでは、float型を定義している限り、パラメーターはfloat型である必要があります。そうでない場合、一致するオーバーロードされた関数が直接見つかりません。エラーを報告したところ、問題に気づかなかったのですが、通常の組み込み関数だと思っていたのですが、なぜ突然オーバーロードメソッドがないと報告されたのですか?とりあえず、他の人が書いたコードを読みに行きました人々、しかし私はまだ問題を見つけていません。、結局、なぜ私が戻り値の1.0-tを1-tに変更したのか分かりません。赤いすべてのエラー内容は私を目覚めさせただけです、それパラメータタイプが間違っていることが判明しました!Smoothstepメソッドは浮動小数点でなければなりません!あなたが改宗するのを助けません!あなたが0であっても、あなたは0.0を書かなければなりません!

        以下は間違ったshadertoyコードです

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

        以下は正しいshadertoyコードです

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

        それはかなり〜です。厳格。以下にshadertoyのコードを貼り付けます

//输入参数(当前点位置,中心点位置,点的半径,颜色,与背景过渡的平滑值)
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);
}

       

        基本的にユニティとは異なる非常にシンプルな効果ですが、ブラウザでスムーズにカラーリングを書くのは本当に不便です!webGLは本当に簡単にクラッシュします!また、入力パラメータの変更は簡単ではありません。団結の便利さを改めて実感。

総括する

        Unityでのシェーダーコードとシェーダーコードの違いは次のとおりです。

        1.shadetoyのキャラクタータイプは自動的に強制されません。定義する関数にfloat型のパラメーターがある場合、呼び出し時にint型を使用すると、エラーが確実に報告されます。値0は整数、0.0はシンボル型です。(Unityはタイプを強制的に転送しようとしましたが問題はありません)

        2.2つのシェーダーの入力位置が異なります。

        シェーダーのフラグメント関数frag()コードの入力は、頂点の投影座標です。対応する座標点を取得するには、座標を正規化してから画面解像度を掛ける必要があります。

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

        シェーダートイのメインメソッドの入力は、頂点に対応するピクセル位置です。原点は画面の左下隅です。中央の原点に変換する必要があります。元の範囲を(0 、a)から(-b、b)が元の座標の位置はy = bx-b(0 <x <a)になります。ただし、このようにオペランド値が何度も拡大されるため、統一ズームが必要であり、取得した位置座標を画面の軸で割っています。

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

PS:あなたが理解していることを説明するのは簡単ではありません。

おすすめ

転載: blog.csdn.net/ssssssilver/article/details/81129441