Bagaimana saya bisa membuat "permukaan basah" / "genangan dangkal" shader di Unity?

71

Dalam permainan saya, saya perlu membuat genangan air yang dinamis tetapi saya tidak dapat menemukan tutorial yang menunjukkan bagaimana saya dapat membuat efek seperti itu (contohnya ditunjukkan di bawah). Bagaimana saya bisa melakukannya?

Istirahat kuantum

Sayy Morteza Kamali
sumber
4
Mengganggu melihat pertanyaan dengan suara tinggi dan jawaban yang lebih tinggi tidak ditutup. Tidak apa-apa untuk memilih jawaban Anda sendiri sebagai yang terbaik, meskipun sedikit konyol untuk mengklaim hadiah untuk diri sendiri :)
Tim Holt
@TimHolt Atas dasar apa kita akan menutup pertanyaan seperti ini? Tampaknya tepat pada topik.
Josh
Saya mengatakan bahwa orang yang meminta harus menerima jawabannya sendiri. Maafkan penyalahgunaan bahasa Inggris saya.
Tim Holt

Jawaban:

121

Refleksi

Untuk membuat shader basah, pertama-tama Anda harus memiliki refleksi.

SimpleRoad

Anda dapat menggunakan Reflection Probe atau MirrorReflection3 tetapi, saya menggunakan refleksi palsu (Cube Map) di sini karena shader kemudian dapat digunakan pada ponsel.

Refleksi

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

Distorsi

Untuk menambahkan distorsi pada refleksi Anda, Anda dapat melipatgandakan peta normal dan worldRefl:

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

distorsi

Bentuk prosedural

Anda dapat menggunakan noise untuk membuat bentuk prosedural :

menangkap

Inilah tutorial Fractal Brownian Motion (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 di atas tidak boleh digunakan langsung ke shader Anda karena memiliki banyak perhitungan GPU dan menurunkan kinerja. Alih-alih menggunakan secara langsung, Anda dapat merender hasilnya menjadi tekstur dengan RenderTexture .

Shadertoy menggunakan banyak lintasan , satu per "buffer". Seperti namanya, pass ini menyimpan hasil dalam buffer, yang hanya berupa tekstur. Persatuan akan membiarkan Anda membuat tekstur juga.

2018-01-26_10-18-20

Menciptakan Topeng

Anda dapat membuat topeng tebal dan halus dengan fungsi-fungsi ini:

Langkah

langkah

Output 1 jika [A]kurang dari atau sama dengan [B], jika tidak output 0.

Smoothstep

langkah mulus

Perpaduan halus antara dua nilai, berdasarkan di mana nilai ketiga berada dalam rentang itu, menghasilkan nilai antara 0 dan 1. Anggap saja sebagai lerp terbalik terbalik dengan nilai output yang dihaluskan.

Hasil

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

gambar

Menggunakan Maps

shaderToy Shading Berbasis Fisik

Berikut definisi yang berguna:

Roughness Menjelaskan microsurface objek. Putih 1.0 kasar dan hitam 0.0 halus. Wajah mikro jika kasar dapat menyebabkan sinar cahaya tersebar dan membuat sorot tampak lebih redup dan lebih luas. Jumlah energi cahaya yang sama dipantulkan saat keluar ke permukaan. Peta ini memiliki kebebasan paling artistik. Tidak ada jawaban yang salah di sini. Peta ini memberikan aset yang paling karakter karena benar-benar menggambarkan permukaan misalnya goresan, sidik jari, noda, debu dll.

Glossiness Peta ini adalah kebalikan dari peta kekasaran. Putih 1.0 halus dan 0.0 hitam kasar. Menjelaskan microsurface objek. Wajah mikro jika kasar dapat menyebabkan sinar cahaya tersebar dan membuat sorot tampak lebih redup dan lebih luas. Jumlah energi cahaya yang sama dipantulkan saat keluar ke permukaan. Peta ini memiliki kebebasan paling artistik. Tidak ada jawaban yang salah di sini. Peta ini memberikan aset yang paling karakter karena benar-benar menggambarkan permukaan misalnya goresan, sidik jari, noda, debu dll.

Specular Peta ini berisi informasi reflektansi untuk permukaan logam dan dielektrik (bukan logam). Ini adalah perbedaan utama dalam alur kerja logam / kasar dan spec / gloss. Aturan yang sama berlaku. Anda perlu menggunakan nilai terukur untuk logam dan sebagian besar semua dielektrik akan jatuh dengan kisaran 0,04 - 4%. Jika ada kotoran pada logam, nilai reflektansi juga perlu diturunkan. Namun, Anda dapat menambahkan nilai yang berbeda di peta specular untuk bahan dielektrik karena Anda memiliki kontrol untuk membuat peta.

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

Kekasaran

gambar

Saya tidak tahu mengapa, tetapi standar shader Unity tidak memiliki peta kelancaran, jadi saya menulis shader dasar dan menambahkan peta ini.

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

Saya pikir Unity tidak memiliki kekasaran, hanya memiliki logam, tetapi saluran alfa adalah untuk kekasaran dan saluran merah untuk logam. Anda dapat mengubah intensitas dengan kehalusan.

Sumber di GitHub .

Tautan yang bermanfaat

lumpur-bola-1024x576

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

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

Sayy Morteza Kamali
sumber
39
Wow, Anda telah melakukan seluruh seri tutorial shader di situs Q&A.
Ocelot
6
@Ocelot Saya suka bagaimana Seyed terus menambahkan ini di sini. Saya suka mengutak-atik shader dan ini sangat membantu untuk lebih banyak ide dan juga tutorial. Dia bisa terus memposting ini selamanya menurut saya.
John Hamilton
7
Jawaban yang luar biasa. Shader sangat sulit untuk diajak bekerja sama dan butuh berjam-jam saya mengutak-atik, meneliti, mencoba-coba, dan memeriksa shader lain untuk mendapatkan efek yang saya inginkan. Dan di sini Anda melakukan itu, untuk orang lain, gratis.
Draco18s
1
Untuk Bahan Standar, biasanya yang terbaik adalah menanamkan kekasaran dalam peta metalik atau normal (yang sebelumnya tampaknya menjadi default). Saya akan merekomendasikan menggunakan Photo Shop, Paint Shop atau Gimp untuk membuat logam yang tepat yang menanamkan kekasaran. Atau jika Anda memiliki Substance Painter atau sejenisnya, Anda dapat mengekspor kekasaran Anda tepat seperti yang diinginkan Unity dan mendapatkan manfaat dari memvisualisasikan materi Anda sebelum Anda memasukkannya ke dalam Unity.
David Peterson
seorang sarjana dan seorang pria
Bas Smit