対象
Shaderやってみたいけど,どう勉強すればよいか分からない人
導入
とりあえず動かしてみる
- Create -> Shader -> ImageEffectShader選択
- ダブルクリックで開き,一行目を
Shader "ShaderTutorial/Tutorial1"
にする. - Materialを作成し,ShaderをShaderTutorial -> Tutorial1にする.
- C#スクリプトを作成,後述するスクリプトを記入
- スクリプトをMainCameraにアタッチ
- Materialがない!ってエラーが出るので,materialをアタッチ
- 終了
手順4
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class Tutorial1 : MonoBehaviour {
public Material mat;
void OnRenderImage(RenderTexture src, RenderTexture dest){
Graphics.Blit (src, dest, mat);
}
}
結果
色が反転します.
以下のチュートリアルはShaderToyの
https://www.shadertoy.com/view/Md23DV
この投稿をUnityで実装したものになります.
数値に関しては,float, half, fixedの3種類がありますが,
このチュートリアルではfixedとfloatのみを使用しています.
Github
Tutorial1
Shader "ShaderTutorial/Tutorial1"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(1.0, 1.0, 0.0, 1.0);
}
ENDCG
}
}
}
fragの中身に注目してください.
fixed4(1.0, 1.0, 0.0, 1.0)
が黄色を示しています.
パラメータはそれぞれ(Red, Green, Blue, Alpha(透明度))を示しています.
値は0~1.0です.
Point
fragの中で色をreturnすることで絵が出る
Tutorial2
ここからはフラグメントシェーダのみスクリプトを示します.
fixed4 frag (v2f i) : SV_Target
{
fixed3 color = fixed3(0.0, 1.0, 1.0);
fixed alpha = 1.0;
fixed4 pixel = fixed4(color, alpha);
return pixel;
}
Point
fixed3型のcolorとfixed型のalphaを合体してfixed4型にできる.
Tutorial3
fixed4 frag (v2f i) : SV_Target
{
fixed redAmount = 0.6;
fixed greenAmount = 0.2;
fixed blueAmount = 0.9;
fixed3 color = fixed3(0.0, 0.0, 0.0);
color.x = redAmount;
color.y = greenAmount;
color.z = blueAmount;
fixed alpha = 1.0;
fixed4 pixel = fixed4(color, alpha);
return pixel;
}
Point
fixed3の3要素には,color.xのように,xyzでアクセスできる.
Tutorial4
fixed4 frag (v2f i) : SV_Target
{
fixed3 color1 = fixed3(0.886, 0.576, 0.898);
fixed3 color2 = fixed3(0.537, 0.741, 0.408);
fixed3 pixel;
if(i.uv.x > 0.5){
pixel = color2;
} else {
pixel = color1;
}
return fixed4(pixel, 1.0);
}
Point
引数であるiを使うことにより,現在処理しているピクセルのuv座標をi.uvで取得することができる.
今回はi.uv.x > 0.5すなわち,画面を横に分断するように色を分けた.
uv座標のx軸は画面の左から一番右端へ0~1.0である.
Tutorial5
fixed4 frag (v2f i) : SV_Target
{
fixed3 color1 = fixed3(0.886, 0.576, 0.898);
fixed3 color2 = fixed3(0.537, 0.741, 0.408);
fixed3 pixel;
float dis = 50;
if(i.uv.x * _ScreenParams.x > dis){
pixel = color2;
} else {
pixel = color1;
}
return fixed4(pixel, 1.0);
}
Point
uv座標に,スクリーンの解像度(_ScreenParams)を掛け算することで,現在処理しているピクセルの位置を取得できる.
Tutorial6 線の引き方
// HORIZONTAL AND VERTICAL LINES
fixed4 frag (v2f i) : SV_Target
{
fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
fixed3 color1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 color2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 color3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
// line1
float leftCoord = 0.54;
float rightCoord = 0.55;
if(i.uv.x < rightCoord && i.uv.x > leftCoord) pixel = color1;
// line2
float lineCoordinate = 0.4;
float lineThickness = 0.003;
if(abs(i.uv.x - lineCoordinate) < lineThickness ) pixel = color2;
// line3
if(abs(i.uv.y - 0.6) < 0.01) pixel = color3;
return fixed4(pixel, 1.0);
}
Point
線の引き方には2種類あり,一つ目は線の端の座標を示す方法(line1).二つ目は線の中心の座標と厚さを示す方法である(line2,3)
後者の場合にはif(abs(i.uv.x - lineCoordinate) < lineThickness )
で表せる.
もし上下が反転していたら
v2f vert(appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y; //この行を加える.
return o;
}
Tutorial7 座標の視覚化
// VISUALISING THE COORDINATE SYSTEM
fixed4 frag (v2f i) : SV_Target
{
fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
fixed3 axesColor = fixed3(0.0, 0.0, 1.0);
fixed3 gridColor = fixed3(0.5, 0.5, 0.5);
fixed3 pixel = backgroundColor;
const float tickWidth = 0.1;
for(float lc=0.0; lc< 1.0; lc+=tickWidth){
if(abs(i.uv.x - lc) < 0.002) pixel = gridColor;
if(abs(i.uv.y - lc) < 0.002) pixel = gridColor;
}
// Draw the axes
if(abs(i.uv.x)<0.005) pixel = axesColor;
if(abs(i.uv.y)<0.006) pixel = axesColor;
return fixed4(pixel, 1.0);
}
Point
for文で線を引く座標を変えることで,等間隔に線を引くことができる.
Tutorial8 座標 軸中心
fragの外にも記入したため,全文
Shader "ShaderTutorial/Tutorial8"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
float mod(float a, float b) { return a-b*floor(a/b); }
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}
// MOVING THE COORDINATE CENTER TO THE CENTER OF THE FRAME
fixed4 frag (v2f i) : SV_Target
{
fixed2 r = 2.0 * fixed2(i.uv.x - 0.5, i.uv.y - 0.5);
fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
fixed3 axesColor = fixed3(0.0, 0.0, 1.0);
fixed3 gridColor = fixed3(0.5, 0.5, 0.5);
fixed3 pixel = backgroundColor;
const float tickWidth = 0.1;
if( mod(r.x, tickWidth) < 0.008 ) pixel = gridColor;
if( mod(r.y, tickWidth) < 0.008 ) pixel = gridColor;
// Draw the axes
if(abs(r.x)<0.006) pixel = axesColor;
if(abs(r.y)<0.007) pixel = axesColor;
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
自前の関数をPassの外側に,CGINCLUDE ~ ENDCG の間に記述している.
このmod関数はaをbで割った余りを返す関数である.
これを使うことで,
if(r.xをtickWidthで割った余り < 0.008) グリッドの色にする.
とすることができている.
また,i.uv.xが0~1の値をとるのに対し,-0.5したものを2倍することによって
r,画面の領域を-1 ~ 1で表すことができる.
Tutorial9 縦横比にあわせる
// MAKING THE ASPECT RATIO OF THE COORDINATE SYSTEM 1.0
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
fixed3 axesColor = fixed3(0.0, 0.0, 1.0);
fixed3 gridColor = fixed3(0.5, 0.5, 0.5);
fixed3 pixel = backgroundColor;
const float tickWidth = 0.2;
if( mod(r.x, tickWidth) < 0.008 ) pixel = gridColor;
if( mod(r.y, tickWidth) < 0.008 ) pixel = gridColor;
// Draw the axes
if(abs(r.x)<0.006) pixel = axesColor;
if(abs(r.y)<0.007) pixel = axesColor;
return fixed4(pixel, 1.0);
}
Point
r.xに_ScreenParamsから求めたaspectRatioを掛け算することで,縦横の目盛りが同じ長さになる.
Tutorial10 DISK
// Draw Disks
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
//Disk1 blue
float radius = 0.8;
if(r.x*r.x + r.y*r.y < radius*radius){
pixel = col1;
}
//Disk2 red
if(length(r) < 0.3){
pixel = col3;
}
//Disk3 yellow
float2 center = fixed2(0.9, -0.4);
float2 d = r - center;
if( length(d) < 0.6){
pixel = col2;
}
return fixed4(pixel, 1.0);
}
Point
Disk1では,2点間の距離求める公式を2乗することで,半径0.8以内を塗るという処理を行っている.
Disk2では,ベクトルの距離を求めるlength関数を用いることで,短く書いている.
Disk3では,移動させたい分だけ引き算することによって円の中心位置を移動している.
例:
y = (x-3)^2
だと,線がx軸正の方向に3移動する.
Tutorial11 Functionを作る
Shader "ShaderTutorial/Tutorial11"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
fixed3 disk(fixed2 r, fixed2 center, fixed radius, fixed3 color, fixed3 pixel){
fixed3 col = pixel;
if(length(r - center) < radius){
col = color;
}
return col;
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
// Functions
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 backgroundColor = fixed3(0.3, 0.3, 0.3);
fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
pixel = disk(r, fixed2(0.1, 0.3), 0.5, col3, pixel);
pixel = disk(r, fixed2(-0.8, -0.6), 1.5, col1, pixel);
pixel = disk(r, fixed2(0.8, 0.0), 0.15, col2, pixel);
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
関数はCGINCLUDE ~ ENDCG内に記述.
return文が使える.
Tutorial12 STEP
// BUILT-IN FUNCTION: STEP
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
float edge, variable, ret;
// divide the screen into five parts horizontally
// for different examples
if(r.x < -0.6 * aspectRatio){ // part1
variable = r.y;
edge = 0.2;
if( variable > edge ){
ret = 1.0;
}else{
ret = 0.0;
}
}
else if(r.x < -0.2 * aspectRatio){ //part2
variable = r.y;
edge = -0.2;
// part1と同じこと
ret = step(edge, variable);
}
else if(r.x < 0.2 * aspectRatio){
// 1.0 - step(a,b) で反転
ret = 1.0 - step(0.5, r.y);
}
else if(r.x < 0.6 * aspectRatio){
// r.yが-0.4以上でretは0.3 + 0.5 = 0.8
ret = 0.3 + 0.5 * step(-0.4, r.y);
}
else{
// stepを二つ使うことでgapを生み出すことができる
ret = step(-0.3, r.y) * (1.0 - step(0.2, r.y));
}
pixel = fixed3 (ret, ret, ret);
return fixed4(pixel, 1.0);
}
Point
名前 | 説明 |
---|---|
step(a,b) | bがaをより大きければ1, そうでなければ0 |
Tutorial13
Shader "ShaderTutorial/Tutorial13"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
#define PI 3.14159
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
// BUILT-IN FUNCTION: CLAMP
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
float edge, variable, ret;
// divide the screen into four parts horizontally
// for different examples
if(i.uv.x < 0.25){ // part1
ret = i.uv.y;
}
else if(i.uv.x < 0.5){ // part2
float minVal = 0.3;
float maxVal = 0.6;
variable = i.uv.y;
if (variable < minVal){
ret = minVal;
}
if( variable > minVal && variable < maxVal){
ret = variable;
}
if( variable > maxVal ){
ret = maxVal;
}
}
else if(i.uv.x < 0.75){ // part3
float minVal = 0.6;
float maxVal = 0.8;
variable = i.uv.y;
ret = clamp(variable, minVal, maxVal);
}
else { // part4
float y = cos(5.0 * 2.0 * PI *i.uv.y);
y = (y+1.0)*0.5; // map [-1,1] to [0,1]
ret = clamp(y, 0.2, 0.8);
}
pixel = fixed3 (ret, ret, ret);
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
名前 | 説明 |
---|---|
float Clamp(float a,float min,float max) | aがminよりも小さければmin, aがmaxよりも大きければmax, それ以外であればaを返す |
Tutorial14 smoothstep
// BUILT-IN FUNCTION: SMOOTHSTEP
fixed4 frag (v2f i) : SV_Target
{
fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
float edge, variable, ret;
// divide the screen into five parts horizontally
// for different examples
if(i.uv.x < 1.0/5.0){ // part1
edge = 0.5;
ret = step(edge, i.uv.y);
}
else if(i.uv.x < 2.0/5.0){ // part2
float edge0 = 0.45;
float edge1 = 0.55;
float t = (i.uv.y - edge0) / (edge1 - edge0);
//when i.uv.y == edge0 => t = 0.0
//when i.uv.y == edge1 => t = 1.0
//0から1に線形に遷移する
float t1 = clamp(t, 0.0, 1.0);
//edge0 未満の時は マイナスの値をとり,
//edge1 より大きい時は1.0より大きい値をとる.
//しかし,0~1の値がほしいのでclampを使います
ret = t1;
}
else if(i.uv.x < 3.0/ 5.0){ // part3
float edge0 = 0.45;
float edge1 = 0.55;
float t = clamp((i.uv.y - edge0)/(edge1 - edge0), 0.0, 1.0);
float t1 = 3.0*t*t - 2.0*t*t*t;
//線形でなくなめらかにする.
ret = t1;
}
else if(i.uv.x < 4.0/5.0){ // part4
ret = smoothstep(0.45, 0.55, i.uv.y);
}
else if(i.uv.x < 5.0/5.0){
float edge0 = 0.45;
float edge1 = 0.55;
float t = clamp((i.uv.y - edge0)/(edge1 - edge0), 0.0, 1.0);
float t1 = t*t*t*(t*(t*6.0 - 15.0) + 10.0);
ret = t1;
}
pixel = fixed3 (ret, ret, ret);
return fixed4(pixel, 1.0);
}
Point
名前 | 説明 |
---|---|
float smoothstep(float min, float max, float a) | aがminとmaxの間の時に,線形でなく,なめらかに補完するような値を返す.min以下であれば0,max以上で1 |
Tutorial15 lerp
// BUILT-IN FUNCTION: LERP
fixed4 frag (v2f i) : SV_Target
{
fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow
fixed3 pixel = backgroundColor;
fixed3 ret;
// divide the screen into five parts horizontally
// for different examples
if(i.uv.x < 1.0/5.0){ // part1
float x0 = 0.2;
float x1 = 0.7;
float m = 0.1;
float val = x0 * (1.0-m) + x1*m;
ret = fixed3(val, val, val);
}
else if(i.uv.x < 2.0/5.0){ // part2
float x0 = 0.2;
float x1 = 0.7;
float m = i.uv.y;
float val = x0*(1.0-m) + x1*m;
ret = fixed3(val, val, val);
}
else if(i.uv.x < 3.0/ 5.0){ // part3
float x0 = 0.2;
float x1 = 0.7;
float m = i.uv.y;
float val = lerp(x0, x1, m);
ret = fixed3(val, val, val);
}
else if(i.uv.x < 4.0/5.0){ // part4
float m = i.uv.y;
ret = lerp(col1, col2, m);
}
else if(i.uv.x < 5.0/5.0){
//smoothstepとlerpを使った色の遷移
float m = smoothstep(0.5, 0.6, i.uv.y);
ret = lerp(col1, col2, m);
}
pixel = ret;
return fixed4(pixel, 1.0);
}
Point
名前 | 説明 |
---|---|
float lerp(a,b,s) | a+s(b-a)を返す.aからbへの線形補完 sは基本0~1で使う |
Tutorial16 COLOR ADDITION AND SUBSTRCTION
Shader "ShaderTutorial/Tutorial18"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
// なめらかなDISK
float disk(float2 r, float2 center, float radius){
float distanceFromCenter = length(r - center);
float outsideOfDisk = smoothstep(radius - 0.005, radius + 0.005, distanceFromCenter);
float insideOfDisk = 1.0 - outsideOfDisk;
return insideOfDisk;
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
// ANTI-ALIASING WITH SMOOTHSTEP
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 black = float3(0.0, 0.0, 0.0); // black
fixed3 white = float3(1.0, 1.0, 1.0);
fixed3 gray = float3(0.3, 0.3, 0.3);
fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
fixed3 col2 = float3(1.00, 0.329, 0.298); // red
fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow
fixed3 ret;
fixed3 pixel;
float d;
if(i.uv.x < 1.0/3.0){ // part1
ret = gray;
d = disk(r, float2(-1.1, 0.3), 0.4);
ret = lerp(ret, col1, d);
d = disk(r, float2(-1.3, 0.0), 0.4);
ret = lerp(ret, col2, d);
d = disk(r, float2(-1.05, -0.3), 0.4);
ret = lerp(ret, col3, d);
}
else if(i.uv.x < 2.0/3.0){ // part2
// Color addition
ret = black;
ret += disk(r, float2(0.1, 0.3), 0.4) * col1;
ret += disk(r, float2(-0.1, 0.0), 0.4) * col2;
ret += disk(r, float2(0.15, -0.3), 0.4) * col3;
}
else if(i.uv.x < 3.0/ 3.0){ // part3
// Color substraction
ret = white;
ret -= disk(r, float2(1.1, 0.3), 0.4) * col1;
ret -= disk(r, float2(1.05, 0.0), 0.4) * col2;
ret -= disk(r, float2(1.35, -0.25), 0.4) * col3;
}
pixel = ret;
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
円の境界をなめらかにしている.
ret に加算減算することで色を変化させている.
Tutorial17 回転
Shader "ShaderTutorial/Tutorial17"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
#define PI 3.14159
// (anti-aliased)Gridを作る関数
float coordinateGrid(float2 r){
float3 axisCol = float3(0.0, 0.0, 1.0);
float3 gridCol = float3(0.5, 0.5, 0.5);
float ret = 0.0;
// Draw grid lines
const float tickWidth = 0.1;
for(float i= -2.0;i<2.0; i+= tickWidth){
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
}
// Draw the axis
ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
return ret;
}
// returns 1.0 if inside circle
float disk(float2 r, float2 center, float radius){
return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
}
// returns 1.0 if inside the disk
float rectangle(float2 r, float2 bottomLeft, float2 topRight){
float ret;
float d = 0.005;
ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
return ret;
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
//COORDINATE TRANSFORMATIONS: ROTATION
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 bgCol = float3(1.0, 1.0, 1.0); // white
fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
fixed3 col2 = float3(1.00, 0.329, 0.298); // red
fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow
fixed3 ret;
float2 q;
float angle;
angle = 0.2*PI; // 単位はラジアン
// 2次元の回転
q.x = cos(angle)*r.x + sin(angle)*r.y;
q.y = -sin(angle)*r.x + cos(angle)*r.y;
ret = bgCol;
// draw the old and new coordinate systems
ret = lerp(ret, col1, coordinateGrid(r)*0.4);
ret = lerp(ret, col2, coordinateGrid(q));
// draw shapes
ret = lerp(ret, col1, disk(r, float2(1.0, 0.0), 0.2));
ret = lerp(ret, col2, disk(q, float2(1.0, 0.0), 0.2));
ret = lerp(ret, col1, rectangle(r, float2(-0.8, 0.2),float2(-0.5, 0.4)));
ret = lerp(ret, col2, rectangle(q, float2(-0.8, 0.2),float2(-0.5, 0.4)));
fixed3 pixel = ret;
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
回転行列をrに掛け算することで,座標を回転させ,その座標上の図形も回転させている.
Tutorial18 スケーリング
Shader "ShaderTutorial/Tutorial18"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
#define PI 3.14159
// (anti-aliased)Gridを作る関数
float coordinateGrid(float2 r){
float3 axisCol = float3(0.0, 0.0, 1.0);
float3 gridCol = float3(0.5, 0.5, 0.5);
float ret = 0.0;
// Draw grid lines
const float tickWidth = 0.1;
for(float i= -2.0;i<2.0; i+= tickWidth){
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
}
// Draw the axis
ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
return ret;
}
// returns 1.0 if inside circle
float disk(float2 r, float2 center, float radius){
return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
}
// returns 1.0 if inside the disk
float rectangle(float2 r, float2 bottomLeft, float2 topRight){
float ret;
float d = 0.005;
ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
return ret;
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
//COORDINATE TRANSFORMATIONS: SCALING
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 bgCol = float3(1.0, 1.0, 1.0); // white
fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
fixed3 col2 = float3(1.00, 0.329, 0.298); // red
fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow
fixed3 ret;
ret = bgCol;
// original
ret = lerp(ret, col1, coordinateGrid(r)/2.0);
// scaled
float2 q = 0.3*r;
ret = lerp(ret, col2, coordinateGrid(q));
// draw shapes
ret = lerp(ret, col2, disk(q, float2(0.0, 0.0), 0.1)); //大
ret = lerp(ret, col1, disk(r, float2(0.0, 0.0), 0.1));
ret = lerp(ret, col1, rectangle(r, float2(-0.5, 0.0),float2(-0.2, 0.2)));
ret = lerp(ret, col2, rectangle(q, float2(-0.5, 0.0),float2(-0.2, 0.2))); //大
fixed3 pixel = ret;
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
rに係数をかけることで,拡大・縮小できる.(0.3をかけることで,大きくなっている.)
Tutorial19 Transform
Shader "ShaderTutorial/Tutorial19"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
#define PI 3.14159
// (anti-aliased)Gridを作る関数
float coordinateGrid(float2 r){
float3 axisCol = float3(0.0, 0.0, 1.0);
float3 gridCol = float3(0.5, 0.5, 0.5);
float ret = 0.0;
// Draw grid lines
const float tickWidth = 0.1;
for(float i= -2.0;i<2.0; i+= tickWidth){
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
}
// Draw the axis
ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
return ret;
}
// returns 1.0 if inside circle
float disk(float2 r, float2 center, float radius){
return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
}
// returns 1.0 if inside the disk
float rectangle(float2 r, float2 bottomLeft, float2 topRight){
float ret;
float d = 0.005;
ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
return ret;
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
//COORDINATE TRANSFORMATIONS
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 bgCol = float3(1.0, 1.0, 1.0); // white
fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
fixed3 col2 = float3(1.00, 0.329, 0.298); // red
fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow
fixed3 ret;
ret = bgCol;
float angle = -0.6;
float2x2 rotationMatrix = float2x2(cos(angle), -sin(angle),
sin(angle), cos(angle));
if(i.uv.x < 1.0/2.0) //part1
{
//座標の中心をuv.x: 1/4の位置にする。
r = r - float2(-aspectRatio/2.0, 0);
float2 rotated = mul(rotationMatrix, r);
float2 rotatedTranslated = rotated - float2(0.4, 0.5);
ret = lerp(ret, col1, coordinateGrid(r) * 0.3);
ret = lerp(ret, col2, coordinateGrid(rotated)*0.3);
ret = lerp(ret, col3, coordinateGrid(rotatedTranslated)*0.3);
ret = lerp(ret, col1, rectangle(r, float2(-0.1, -0.2), float2(0.1, 0.2)));
ret = lerp(ret, col2, rectangle(rotated, float2(-0.1, -0.2), float2(0.1, 0.2)));
ret = lerp(ret, col3, rectangle(rotatedTranslated, float2(-0.1, -0.2), float2(0.1, 0.2)));
}
else if(i.uv.x < 2.0/2.0){ //part2
//座標の中心をuv.x: 1/4の位置にする。
r = r - float2(aspectRatio/2.0, 0);
float2 translated = r - float2(0.4, 0.5);
float2 translatedRotated = mul(rotationMatrix, translated);
ret = lerp(ret, col1, coordinateGrid(r) * 0.3);
ret = lerp(ret, col2, coordinateGrid(translated)*0.3);
ret = lerp(ret, col3, coordinateGrid(translatedRotated)*0.3);
ret = lerp(ret, col1, rectangle(r, float2(-0.1, -0.2), float2(0.1, 0.2)));
ret = lerp(ret, col2, rectangle(translated, float2(-0.1, -0.2), float2(0.1, 0.2)));
ret = lerp(ret, col3, rectangle(translatedRotated, float2(-0.1, -0.2), float2(0.1, 0.2)));
}
fixed3 pixel = ret;
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
float2x2で,2かける2の正方行列を示す.これによって回転行列を表現し,mul関数によって行列の掛け算を行っている.
Tutorial20 Animations
Shader "ShaderTutorial/Tutorial20"
{
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// 追加
CGINCLUDE
#define PI 3.14159
// (anti-aliased)Gridを作る関数
float coordinateGrid(float2 r){
float3 axisCol = float3(0.0, 0.0, 1.0);
float3 gridCol = float3(0.5, 0.5, 0.5);
float ret = 0.0;
// Draw grid lines
const float tickWidth = 0.1;
for(float i= -2.0;i<2.0; i+= tickWidth){
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
}
// Draw the axis
ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
return ret;
}
// returns 1.0 if inside circle
float disk(float2 r, float2 center, float radius){
return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
}
// returns 1.0 if inside the rect
float rectangle(float2 r, float2 bottomLeft, float2 topRight){
float ret;
float d = 0.005;
ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
return ret;
}
float mod(float a, float b) { return a-b*floor(a/b); }
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
o.uv.y = 1-o.uv.y;
return o;
}
//ANIMATION
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
fixed3 bgCol = float3(1.0, 1.0, 1.0); // white
fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
fixed3 col2 = float3(1.00, 0.329, 0.298); // red
fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow
fixed3 ret;
ret = bgCol;
float angle = -0.6;
float2x2 rotationMatrix = float2x2(cos(angle), -sin(angle),
sin(angle), cos(angle));
if(i.uv.x < 1.0/5.0) // part1
{
float2 q = r + float2(aspectRatio*4.0/5.0, 0);
ret = fixed3(0.3, 0.3, 0.3);
//時間は_Time.yで取得できる
float y = _Time.y;
//yを-1 ~ 1の値にする
y = mod(y,2.0) -1.0;
ret = lerp(ret, col1, disk(q, float2(0.0, y), 0.1));
}
else if(i.uv.x < 2.0/5.0) //part2
{
float2 q = r + float2(aspectRatio*2.0/5.0, 0);
ret = fixed3(0.4, 0.4, 0.4);
//振幅
float amplitude = 0.8;
float y = 0.8 * sin(0.5*_Time.y* 2.0 * PI);
float radius = 0.15 + 0.05 * sin(_Time.y * 8.0);
ret = lerp(ret, col1, disk(q, float2(0.0, y), radius));
}
else if(i.uv.x < 3.0/5.0) //part3
{
float2 q = r + float2(aspectRatio*0/5.0, 0);
ret = float3(0.5, 0.5, 0.5);
float x = 0.2*cos(_Time.y*5.0);
float y = 0.3*sin(_Time.y*5.0);
float radius = 0.2 + 0.1*sin(_Time.y*2.0);
fixed3 color = lerp(col1, col2, sin(_Time.y)*0.5 + 0.5);
ret = lerp(ret, color, rectangle(q, float2(x-0.1, y-0.1), float2(x+0.1, y+0.1)));
}
else if(i.uv.x < 4.0/5.0) //part4
{
float2 q = r + float2(-aspectRatio*2.0/5.0, 0);
ret = float3(0.4, 0.4, 0.4);
for(float i=-1.0; i<1.0; i+= 0.2)
{
float x = 0.2 * cos(_Time.y*5.0 + i*PI);
float y = i;
float2 s = q - float2(x, y);
float angle = _Time.y * 3.0 + i;
float2x2 rot = float2x2(cos(angle), -sin(angle),
sin(angle), cos(angle));
s = mul(rot, s);
ret = lerp(ret, col1, rectangle(s, float2(-0.06, -0.06), float2(0.06, 0.06)));
}
}
else if(i.uv.x < 5.0/5.0) //part5
{
float2 q = r + float2(-aspectRatio*4.0/5.0, 0);
ret = float3(0.3, 0.3, 0.3);
float speed = 2.0;
float t = _Time.y * speed;
float stopEveryAngle = PI / 2.0;
float stopRatio = 0.5;
//0.5<frac(t)<1の時,t1は一定となる。そこで止まっている。
float t1 = (floor(t) + smoothstep(0.0, 1.0 - stopRatio, frac(t)))*stopEveryAngle;
float x = -0.2*cos(t1);
float y = 0.3 * sin(t1);
float dx = 0.1 + 0.03 * sin(t*10.0);
float dy = 0.1 + 0.03 * sin(t*10.0+PI);
ret = lerp(ret, col1, rectangle(q, float2(x-dx, y-dy), float2(x+dx, y+dy)));
}
fixed3 pixel = ret;
return fixed4(pixel, 1.0);
}
ENDCG
}
}
}
Point
_Time.yで時間を取得できる.
Tutorial21 Plasma
//Plasma
fixed4 frag (v2f i) : SV_Target
{
float2 r = 2.0 * (i.uv - 0.5);
float aspectRatio = _ScreenParams.x / _ScreenParams.y;
r.x *= aspectRatio;
float t = _Time.y;
r = r*8.0;
float v1 = sin(r.x + t);
float v2 = sin(r.y + t);
float v3 = sin(r.x + r.y + t);
float v4 = sin(sqrt(r.x*r.x + r.y*r.y) + 1.7*t);
float v = v1 + v2 + v3 + v4;
fixed3 ret;
if(i.uv.x < 1.0 / 10.0) // part1
{
//vertical waves
ret = float3(v1, v1, v1);
}
else if(i.uv.x < 2.0/10.0) // part2
{
// horizontal waves;
ret = float3(v2, v2, v2);
}
else if(i.uv.x < 3.0/10.0) // part3
{
// diagonal waves
ret = float3(v3, v3, v3);
}
else if(i.uv.x < 4.0/10.0) // part4
{
// circular waves
ret = float3(v4, v4, v4);
}
else if(i.uv.x < 5.0/10.0) // part5
{
// the sum of all waves
ret = float3(v, v, v);
}
else if(i.uv.x < 6.0/10.0) // part6
{
// Add periodicity to the gradients
ret = float3(sin(2.0 * v), sin(2.0 * v), sin(2.0 * v));
}
else if(i.uv.x < 10.0/10.0) // part7
{
// mix colors
v *= 1.0;
ret = float3(sin(v), sin(v+0.5*PI), sin(v+1.0*PI));
}
ret = 0.5 + 0.5 * ret;
fixed3 pixel = ret;
return fixed4(pixel, 1.0);
}
Point
sin,cosと_Time.yを組み合わせると周期的な模様ができる.