Unityで「ウェットサーフェス」/「シャローパドル」シェーダーを作成するにはどうすればよいですか?


71

私のゲームでは、動的な水たまりを作成する必要がありますが、このような効果を作成する方法を示すチュートリアルは見つかりません(例を以下に示します)。どうすればいいですか?

量子ブレーク


4
このような高得票の質問と高得票の回答が閉じられないのを見るのは面倒です。愚かな少しは:)あなた自身のための恩恵を主張するものの、として最良のあなた自身の答えを選択することで結構です
ティム・ホルト

@TimHoltしかし、このような質問をどのような根拠で閉じますか?それは完全に話題のようです。
ジョシュ

私はそれを聞いた人が彼自身の答えを受け入れるべきだと言っています。英語の誤用を許してください。
ティム・ホルト

回答:


121

反射

ウェットシェーダーを作成するには、最初に反射が必要です。

SimpleRoad

あなたは使用することができる反射プローブMirrorReflection3をシェーダが、モバイル上で使用することができますので、私はここに偽反射(キューブマップ)を使用しますが、。

反射

Shader "Smkgames/TransparentCubeMap" {
Properties {
_Color("Color",Color) = (1,1,1,1)
_Cube ("Cubemap", CUBE) = "" {}
_Metallic("Metallic",Range(0,1)) = 1
_Smoothness("Smoothness",Range(0,1)) = 1
_Alpha("Alpha",Range(0,1)) = 1
}
SubShader {
Tags {"RenderType"="Transparent" "Queue"="Transparent"}
LOD 200
Pass {
ColorMask 0
}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB

CGPROGRAM
#pragma surface surf Standard fullforwardshadows alpha:fade

struct Input {
float2 uv_MainTex;
float3 worldRefl;
};
sampler2D _MainTex;
samplerCUBE _Cube;
float4 _Color;
float _Metallic;
float _Smoothness;
float4 _EmissionColor;
float _Alpha;
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

o.Albedo = c.rgb * 0.5 * _Color;
o.Emission = texCUBE (_Cube, IN.worldRefl).rgb*_Color;
o.Metallic = _Metallic;
o.Smoothness = _Smoothness;
o.Alpha = _Alpha;

}
ENDCG
} 
Fallback "Diffuse"
}

ねじれ

反射に歪みを追加するには、法線マップとworldRefl

float3 distortion = tex2D(_Distortion, IN.uv_Distortion);
o.Emission = texCUBE(_Cube, IN.worldRefl*distortion).rgb

ねじれ

手続き型

ノイズを使用して手続き型を作成できます。

キャプチャー

これが、フラクタルブラウン運動(FBM)チュートリアルです。

Shader "Smkgames/FbmNoise"
{
Properties
{
_TileAndOffset("Tile and Offset",Vector) = (1,1,0,0)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};


float4 _TileAndOffset;
float _Step,_Min,_Ma;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv*_TileAndOffset.xy+_TileAndOffset.zw;
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}

// Author @patriciogv - 2015
// http://patriciogonzalezvivo.com

float random (in float2 st) {
return frac(sin(dot(st.xy,
                    float2(12.9898,78.233)))*
    43758.5453123);
}

// Based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise (in float2 st) {
float2 i = floor(st);
float2 f = frac(st);

// Four corners in 2D of a tile
float a = random(i);
float b = random(i + float2(1.0, 0.0));
float c = random(i + float2(0.0, 1.0));
float d = random(i + float2(1.0, 1.0));

float2 u = f * f * (3.0 - 2.0 * f);

return lerp(a, b, u.x) +
        (c - a)* u.y * (1.0 - u.x) +
        (d - b) * u.x * u.y;
}

#define OCTAVES 6
float fbm (in float2 st) {
// Initial values
float value = 0.0;
float amplitude = .5;
float frequency = 0.;
//
// Loop of octaves
for (int i = 0; i < OCTAVES; i++) {
    value += amplitude * noise(st);
    st *= 2.;
    amplitude *= .5;
}
return value;
}

        fixed4 frag (v2f i) : SV_Target
        {


float2 st =i.uv;

float3 color = float3(0,0,0);
color += fbm(st*3.0);
return float4(color,1.0);

        }
ENDCG
}
}
}

上記のFBMは、GPU計算が多く、パフォーマンスを低下させるため、シェーダーに直接使用しないでください。直接使用する代わりに、RenderTextureを使用して結果をテクスチャにレンダリングできます。

Shadertoyは、「バッファ」ごとに1つの複数のパスを使用します。名前が示すように、このパスは結果をバッファに保存しますが、これは単なるテクスチャです。Unityは、テクスチャーへのレンダリングも可能にします。

2018-01-26_10-18-20

マスクを作成する

次の機能を使用して、厚く滑らかなマスクを作成できます。

ステップ

ステップ

[A]がより小さいか等しい場合は1を出力し[B]、そうでない場合は0を出力します。

スムーズステップ

スムーズステップ

3番目の値がその範囲内のどこにあるかに基づいて2つの値の間を滑らかにブレンドし、0〜1の値を出力します。

結果

/* Warning: don't use this shader because this is for preview only.
It has many GPU calculations so if you want use this in your game you should 
remove the FBM noise functions or render it to texture, or you can use an FBM texture
*/
//Created By Seyed Morteza Kamaly
Shader "Smkgames/WetShader" {
Properties{
_MainTex("MainTex",2D) = "white"{}
_Distortion("Distortion",2D) = "bump"{}
_Cube("Cubemap", CUBE) = "" {}
_BumpMap("Bumpmap", 2D) = "bump" {}
_Metallic("Metallic",Range(0,1)) = 0
_Smoothness("Smoothness",Range(0,1)) = 1
_ReflectAlpha("ReflectAlpha",Range(0,1)) = 1
scaleX("UV.X scale",Float) = 10.0
scaleY("UV.Y scale",Float) = 10.0
_Smooth("Smooth",Float) = 0.4
_Intensity("Intensity",Float) = 1
}
SubShader{
Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
LOD 200
Pass{
ColorMask 0
}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB

CGPROGRAM
#pragma surface surf Standard fullforwardshadows alpha:fade

struct Input {
float2 uv_MainTex;
float2 uv_Distortion;
float3 worldRefl;
float2 uv_BumpMap;
INTERNAL_DATA
};
sampler2D _MainTex, _Distortion;
samplerCUBE _Cube;
float _Metallic,_Smoothness;
float4 _EmissionColor;
sampler2D _NormalMap;
uniform fixed scaleX, scaleY, _Smooth, _Intensity,_Alpha,_ReflectAlpha;

static const float2x2 m = float2x2(-0.5, 0.8, 1.7, 0.2);

float hash(float2 n)
{
return frac(sin(dot(n, float2(95.43583, 93.323197))) * 65536.32);
}

float noise(float2 p)
{
float2 i = floor(p);
float2 u = frac(p);
u = u*u*(3.0 - 2.0*u);
float2 d = float2 (1.0, 0.0);
float r = lerp(lerp(hash(i), hash(i + d.xy), u.x), lerp(hash(i + d.yx), hash(i + d.xx), u.x), u.y);
return r*r;
}

float fbm(float2 p)
{
float f = 0.0;
f += 0.500000*(0.5 + 0.5*noise(p));
return f;
}

float fbm2(float2 p)
{
float f = 0.0;
f += 0.500000*(0.6 + 0.45*noise(p)); p = p*2.02; p = mul(p, m);
f += 0.250000*(0.6 + 0.36*noise(p));
return f;
}


void surf(Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);

o.Metallic = _Metallic;
o.Smoothness = _Smoothness;
o.Alpha = 1;

float t = fbm2(float2(IN.uv_MainTex.x*scaleX, IN.uv_MainTex.y*scaleY));

float fbmMask = step(t, _Smooth)*_Intensity;
float3 distortion = tex2D(_Distortion, IN.uv_Distortion);
o.Emission = texCUBE(_Cube, IN.worldRefl*distortion).rgb*_ReflectAlpha*fbmMask;

o.Albedo = float4(1.0, 1.0, 1.0, 1.0)*tex2Dlod(_MainTex, float4(IN.uv_MainTex, 0.0, 0.0));


}
ENDCG
}
Fallback "Diffuse"
}

画像

マップを使用する

シェーダー 物理ベースのシェーディング

便利な定義は次のとおりです。

さオブジェクトの微小表面を表します。白1.0は粗く、黒0.0は滑らかです。粗い場合、マイクロサーフェスは光線を散乱させ、ハイライトをより暗く、より広く見せます。同じ量の光エネルギーが反射され、表面に入ってくると出て行きます。このマップには最も芸術的な自由があります。ここに間違った答えはありません。このマップは、スクラッチ、指紋、スマッジ、汚れなどの表面を正確に表すため、アセットに最も特徴を与えます。

光沢 このマップは、粗さマップの逆です。白1.0は滑らかで、0.0黒は粗いです。オブジェクトのマイクロサーフェスを記述します。粗い場合、マイクロサーフェスは光線を散乱させ、ハイライトをより暗く、より広く見せます。同じ量の光エネルギーが反射され、表面に入ってくると出て行きます。このマップには最も芸術的な自由があります。ここに間違った答えはありません。このマップは、スクラッチ、指紋、スマッジ、汚れなどの表面を正確に表すため、アセットに最も特徴を与えます。

鏡面 反射このマップには、金属および誘電体(非金属)表面の両方の反射率情報が含まれています。これは、メタル/ラフワークフローとスペック/グロスワークフローの重要な違いです。同じルールが適用されます。金属の測定値を使用する必要があり、ほとんどすべての誘電体は0.04〜4%の範囲に収まります。金属に汚れがある場合、反射率の値も下げる必要があります。ただし、マップを作成する制御があるため、誘電体材料の鏡面反射マップに異なる値を追加できます。

https://forum.allegorithmic.com/index.php?topic=3243.0

粗さ

画像

理由はわかりませんが、Unityの標準シェーダーにはスムーズマップがないため、基本的なシェーダーを作成してこのマップを追加しました。

Shader "Smkgames/SimpleSurface" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _GlossMap("GlossMap",2D) = "white"{}
        _Glossiness ("Smoothness", Float) = 1.5
        _Metallic ("Metallic", Float) = 0.5
        _MetallicMap("MetallicMap",2D) = "white"{}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows

        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness,_Metallic;
        fixed4 _Color;
        sampler2D _GlossMap,_MetallicMap;

        UNITY_INSTANCING_CBUFFER_START(Props)
        UNITY_INSTANCING_CBUFFER_END

        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Metallic = _Metallic*tex2D(_MetallicMap,IN.uv_MainTex);
            o.Smoothness = _Glossiness*tex2D(_GlossMap,IN.uv_MainTex);
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Unityには粗さはなく、メタリックのみであると思いますが、アルファチャネルは粗さ用で、赤いチャネルはメタリック用です。強度を滑らかに変更できます。

GitHubのソース

便利なリンク

mud-sphere-1024x576

https://80.lv/articles/how-to-create-wet-mud-in-substance-designer/

https://www.fxguide.com/featured/game-environments-partc/


39
わあ、Q&Aサイトでシェーダーチュートリアルシリーズ全体を完了しました。
オセロット

6
@Ocelot Seyedがこれらをどんどん追加していくのが大好きです。私はシェーダーをいじるのが好きで、これらはより多くのアイデアやチュートリアルとしても非常に役立ちます。私の意見では、彼はこれらを永遠に投稿し続けることができます。
ジョンハミルトン

7
すばらしい答え。シェーダーの操作は非常に困難であり、必要な効果を得るためには、いじり、研究、試行錯誤、および他のシェーダーの調査に何時間もかかります。そして、ここであなたはそれを、他の誰かのために、無料でやっています。
Draco18s

1
通常、標準マテリアルの場合、金属マップまたは法線マップに粗さを埋め込むのが最適です(前者がデフォルトのようです)。Photo Shop、Paint Shop、またはGimpを使用して、粗さを埋め込む適切なメタリックを作成することをお勧めします。あるいは、Substance Painterなどを使用している場合、Unityが望んでいるとおりにラフネスをエクスポートし、Unityに配置する前にマテリアルを視覚化するという利点があります。
デビッドピーターソン

学者と紳士
バススミット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.