前に書く
今日は、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:あなたが理解していることを説明するのは簡単ではありません。。。