1つは、ShaderToyが機能することです。
Shaderについてある程度理解している場合は、WebサイトshaderToyについて多かれ少なかれ聞いたことがあるでしょう。このWebサイトには多くのエキサイティングなシェーダー効果があり、これらの効果は数行のコードで実現できます。画家の絵のように、フラグメントシェーダーは絵筆で、画面は画用紙です。
Webサイトでの作業には、完全なGLSLフラグメントスターターコードが提供されます。これは、ブラウザーでWebGlを実行することによってこれらの効果を表示します。コードを変更したり、変数や入力を変更したりすることで、変更の影響をWebページで直接表示することもできます。
Unityに転送するのは難しくありません。これらはすべて、フラグメントシェーダーでピクセルごとに描画および処理されるため、Unityでは、ポストスクリーン処理を使用してこれらのシェーダーを処理できます。
2つ、Unityで実装
C#の後処理スクリプトは次のとおりです。
一部の複雑度の高いシェーダーのパフォーマンスを向上させるために、キャンバスの解像度を指定できます
using System;
using UnityEngine;
[ExecuteInEditMode]
public class ForShaderToy: PostEffectsBase
{
public int horizontal = 1920;
public int vertical = 1080;
public Shader shaderToy;
private Material _material;
public Material material
{
get
{
_material = CheckShaderAndCreateMaterial(shaderToy, _material);
return _material;
}
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (material != null)
{
RenderTexture scaled = RenderTexture.GetTemporary(horizontal, vertical, 24);
Graphics.Blit(src, scaled, material);
Graphics.Blit(scaled, dest);
RenderTexture.ReleaseTemporary(scaled);
}
else
Graphics.Blit(src, dest);
}
}
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
//当在物体上添加该脚本时,Camera组件也会被自动被添加上去(如果没有的话)
[RequireComponent(typeof(Camera))]
public class PostEffectsBase: MonoBehaviour
{
protected void Start()
{
//如果显卡支持图像后期处理效果
if (!SystemInfo.supportsImageEffects)
{
//设置当前组件为关闭状态
enabled = false;
}
}
protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
{
//判断当前着色器是否可在当前显卡设备上使用,如果对应的着色器的所有Fallback都不可支持或者传入的着色器就不存在,返回null
if (shader == null || !shader.isSupported)
return null;
if (material && material.shader == shader)
return material;
else
{
material = new Material(shader);
//设置当前材质不会被保存在场景中
material.hideFlags = HideFlags.HideAndDontSave;
if (material)
return material;
else
return null;
}
}
完了したら、ShaderToyでシェーダーを移動します。UnityShaderでHLSLを使用する場合は、GLSLからHLSLへの変換を自分で実装する必要があります。
これは 、https://alastaira.wordpress.com/2015/08/07/unity-shadertoys-aka-converting-glsl-shaders-to-cghlsl/および https://msdn.microsoft.com/en-を参照できます 。 GB / library / windows / apps / dn166865.aspx
問題ありません。次に、上記のC#をカメラの下に吊るし、コンポーネントとしてシェーダーを指定します。例は次のとおりです。
//https://www.shadertoy.com/view/XlfGRj
//https://msdn.microsoft.com/en-GB/library/windows/apps/dn166865.aspx
Shader "ShaderToy/StarNest"
{
Properties
{
_Zoom("Zoom", Float) = 0.8 //缩放
_Speed("Speed", Float) = 0.01 //速度
_Volsteps("Volsteps", Int) = 20
_Tile("Tile", Float) = 0.85
_Iterations("Iterations", Int) = 17
_Formuparam("Formuparam", Float) = 0.53
_Brightness("Brightness", Float) = 0.0015
_Darkmatter("Darkmatter", Float) = 0.300
_Distfading("Distfading", Float) = 0.730
_Saturation("Saturation", Float) = 0.850
_StepSize("StepSize", Float) = 0.1
}
SubShader
{
PASS
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _Zoom;
float _Speed;
int _Volsteps;
float _Tile;
float _Formuparam;
int _Iterations;
float _Brightness;
float _Darkmatter;
float _Distfading;
float _Saturation;
float _StepSize;
struct _2v
{
float4 vertex: POSITION;
};
struct v2f
{
float4 pos: SV_POSITION;
};
v2f vert(_2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i): SV_Target
{
//iResolution -> _ScreenParams
//fragCoord -> pos(SV_POSITION)
//iTime:ShaderToy提供的时间函数 -> _Time.y
fixed2 uv = i.pos.xy / _ScreenParams.xy - 0.5;
uv.y *= _ScreenParams.y / _ScreenParams.x;
float3 dir = float3(uv * _Zoom, 1.0);
float time = _Time.y * _Speed + 0.25;
float a1 = 0.5 + 0.5 / _ScreenParams.x * 2.0;
float a2 = 0.8 + 0.5 / _ScreenParams.y * 2.0;
float2x2 Rot1 = float2x2(cos(a1), sin(a1), -sin(a1), cos(a1));
float2x2 Rot2 = float2x2(cos(a2), sin(a2), -sin(a2), cos(a2));
dir.xz = mul(dir.xz, Rot1);
dir.xy = mul(dir.xy, Rot2);
float3 from = float3(1.0, 0.5, 0.5);
from += float3(time * 2.0, time, -2.0);
from.xz = mul(from.xz, Rot1);
from.xy = mul(from.xy, Rot2);
float s = 0.1;
float fade = 1.0;
float3 v = float3(0.0, 0.0, 0.0);
for (int r = 0; r < _Volsteps; r++)
{
float pa = 0.0;
float a = 0.0;
float3 p = from + s * dir * 0.5;
p = abs(float3(_Tile, _Tile, _Tile) - float3(fmod(p.x, _Tile * 2.0), fmod(p.y, _Tile * 2.0), fmod(p.z, _Tile * 2.0))); //tiling fold
for (int i = 0; i < _Iterations; i++)
{
p = abs(p) / dot(p, p) - _Formuparam; //the magic formula
a += abs(length(p) - pa); //absolute sum of average change
pa = length(p);
}
float dm = max(0.0, _Darkmatter - a * a * 0.001); //dark matter
a *= a*a; //add contrast
if (r > 6)
fade *= 1.0 - dm; //dark matter, don't render near
v += fade;
v += float3(s, s * s, s * s * s * s) * a * _Brightness * fade; //coloring based on distance
fade *= _Distfading; //distance fading
s += _StepSize;
}
//mix -> lerp
v = lerp(float3(length(v), length(v), length(v)), v, _Saturation); //color adjust
fixed4 fragColor = float4(v * 0.01, 1.0);
return fragColor;
}
ENDCG
}
}
}
3.マウス入力制御をサポートします
ShaderToyは、画面上のマウスの座標を常に提供するなど、これらの優れた神レベルのシェーダーをさらにサポートします。したがって、エフェクトプレビューウィンドウでマウスを動かして、動的なエフェクトを楽しむことができます。
同様に、C#スクリプトのInput.mousePositionおよびInput.GetMouseButton()APIを介して、現在のマウス画面の座標をシェーダーに渡すこともできます。完全なバージョンは次のとおりです。
using System;
using UnityEngine;
[ExecuteInEditMode]
public class ForShaderToy: PostEffectsBase
{
public int horizontal = 1920;
public int vertical = 1080;
public bool isMouseScreenPos = false;
public float mouseSpeed = 0.4f;
public Shader shaderToy;
private Material _material;
private float mouse_x = 0.5f;
private float mouse_y = 0.5f;
public Material material
{
get
{
_material = CheckShaderAndCreateMaterial(shaderToy, _material);
return _material;
}
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (material != null)
{
RenderTexture scaled = RenderTexture.GetTemporary(horizontal, vertical, 24);
if (Input.GetMouseButton(0))
{
mouse_x = Mathf.Clamp(Input.mousePosition.x / Screen.width, 0, 1);
mouse_y = Mathf.Clamp(Input.mousePosition.y / Screen.height, 0, 1);
if (!isMouseScreenPos)
{
mouse_x = Input.mousePosition.x;
mouse_y = Input.mousePosition.y;
}
mouse_x *= mouseSpeed;
mouse_y *= mouseSpeed;
}
material.SetFloat("_MouseX", mouse_x);
material.SetFloat("_MouseY", mouse_y);
Graphics.Blit(src, scaled, material);
Graphics.Blit(scaled, dest);
RenderTexture.ReleaseTemporary(scaled);
}
else
Graphics.Blit(src, dest);
}
}
//https://www.shadertoy.com/view/XlfGRj
//https://msdn.microsoft.com/en-GB/library/windows/apps/dn166865.aspx
Shader "ShaderToy/StarNest"
{
Properties
{
_Zoom("Zoom", Float) = 0.8 //缩放
_Speed("Speed", Float) = 0.01 //速度
_Volsteps("Volsteps", Int) = 20
_Tile("Tile", Float) = 0.85
_Iterations("Iterations", Int) = 17
_Formuparam("Formuparam", Float) = 0.53
_Brightness("Brightness", Float) = 0.0015
_Darkmatter("Darkmatter", Float) = 0.300
_Distfading("Distfading", Float) = 0.730
_Saturation("Saturation", Float) = 0.850
_StepSize("StepSize", Float) = 0.1
_MouseX("MouseX", Range(0.0, 1.0)) = 0.5
_MouseY("ouseY", Range(0.0, 1.0)) = 0.5
}
SubShader
{
PASS
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _Zoom;
float _Speed;
int _Volsteps;
float _Tile;
float _Formuparam;
int _Iterations;
float _Brightness;
float _Darkmatter;
float _Distfading;
float _Saturation;
float _StepSize;
float _MouseX;
float _MouseY;
struct _2v
{
float4 vertex: POSITION;
};
struct v2f
{
float4 pos: SV_POSITION;
};
v2f vert(_2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i): SV_Target
{
//iResolution -> _ScreenParams
//fragCoord -> pos(SV_POSITION)
//iTime:ShaderToy提供的时间函数 -> _Time.y
fixed2 uv = i.pos.xy / _ScreenParams.xy - 0.5;
uv.y *= _ScreenParams.y / _ScreenParams.x;
float3 dir = float3(uv * _Zoom, 1.0);
float time = _Time.y * _Speed + 0.25;
float a1 = 0.5 + _MouseX / _ScreenParams.x * 2.0;
float a2 = 0.8 + _MouseY / _ScreenParams.y * 2.0;
float2x2 Rot1 = float2x2(cos(a1), sin(a1), -sin(a1), cos(a1));
float2x2 Rot2 = float2x2(cos(a2), sin(a2), -sin(a2), cos(a2));
dir.xz = mul(dir.xz, Rot1);
dir.xy = mul(dir.xy, Rot2);
float3 from = float3(1.0, 0.5, 0.5);
from += float3(time * 2.0, time, -2.0);
from.xz = mul(from.xz, Rot1);
from.xy = mul(from.xy, Rot2);
float s = 0.1;
float fade = 1.0;
float3 v = float3(0.0, 0.0, 0.0);
for (int r = 0; r < _Volsteps; r++)
{
float pa = 0.0;
float a = 0.0;
float3 p = from + s * dir * 0.5;
p = abs(float3(_Tile, _Tile, _Tile) - float3(fmod(p.x, _Tile * 2.0), fmod(p.y, _Tile * 2.0), fmod(p.z, _Tile * 2.0))); //tiling fold
for (int i = 0; i < _Iterations; i++)
{
p = abs(p) / dot(p, p) - _Formuparam; //the magic formula
a += abs(length(p) - pa); //absolute sum of average change
pa = length(p);
}
float dm = max(0.0, _Darkmatter - a * a * 0.001); //dark matter
a *= a*a; //add contrast
if (r > 6)
fade *= 1.0 - dm; //dark matter, don't render near
v += fade;
v += float3(s, s * s, s * s * s * s) * a * _Brightness * fade; //coloring based on distance
fade *= _Distfading; //distance fading
s += _StepSize;
}
//mix -> lerp
v = lerp(float3(length(v), length(v), length(v)), v, _Saturation); //color adjust
fixed4 fragColor = float4(v * 0.01, 1.0);
return fragColor;
}
ENDCG
}
}
}
4、GLHLからHLSLへのメモ
GLSL(ShaderToy) | HLSL(Unity3D) | |
---|---|---|
iResolution.xy | _ScreenParams.xy | ビューポートの解像度 |
fragCoord | pos(SV_POSITION) | 現在のフラグメント座標 |
iTime | _Time.y | 時間関数 |
vec3 | float3 / fixed3 / half3 | ベクター |
mat3 | float3x3 | マトリックス |
ミックス() | lerp() | スムーズな補間 |
マット* =マット | mul(マット、マット) | 行列/ベクトルの乗算 |
参考資料:
- https://alastaira.wordpress.com/2015/08/07/unity-shadertoys-aka-converting-glsl-shaders-to-cghlsl/
- https://alastaira.wordpress.com/2015/08/07/unity-shadertoys-aka-converting-glsl-shaders-to-cghlsl/