Як я можу зробити шейдер для «мокрої поверхні» / «неглибокої калюжі» в Unity?


71

У моїй грі мені потрібно створити динамічні калюжі з водою, але я не можу знайти підручник, який показує, як я можу зробити такий ефект (приклад цього показано нижче). Як я можу це зробити?

Квантова перерва


4
Прикро бачити, що таке запитання з високим рівнем голосу та відповідь вищого рівня не закриваються. Добре вибрати власну відповідь як найкращу, хоч і трохи нерозумно вимагати виграшів для себе :)
Тім Холт

@TimHolt На основі чого ми б закрили таке питання? Це здається ідеально тематичним.
Джош

Я кажу, що людина, яка її запитала, повинна прийняти власну відповідь. Вибачте моє зловживання англійською мовою.
Тім Холт

Відповіді:


121

Рефлексія

Щоб створити мокрий шейдер, спочатку потрібно мати відображення.

SimpleRoad

Ви можете використовувати датчик відбиття або MirrorReflection3, але тут я використовую фальшиве відображення (Cube Map), оскільки шейдер потім можна використовувати на мобільному пристрої.

Рефлексія

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 використовує кілька проходів , один на "буфер". Як видно з назви, цей пропуск зберігає результати в буфері, який є лише текстурою. Єдність дозволить вам і текстури.

2018-01-26_10-18-20

Створення маски

Можна зробити густу і гладку маску за допомогою цих функцій:

Крок

крок

Виходи 1, якщо [A]менше або дорівнює [B], інакше виводиться 0.

Плавний крок

гладкий крок

Плавно поєднується між двома значеннями, виходячи з того, де третє значення знаходиться в цьому діапазоні, виводячи значення від 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"
}

зображення

Використання карт

shaderToy Затінення фізично засноване

Ось корисні визначення:

Шорсткість Описує мікроповерхня об'єкта. Білий 1,0 - шорсткий, а чорний - 0,05. Мікроповерхня, якщо шорстка, може призвести до розсіювання світлових променів і зробити виділення більш тьмяним та широким. Така ж кількість світлової енергії відбивається, що виходить на поверхню. Ця карта має найбільшу художню свободу. Тут немає неправильних відповідей. Ця карта надає активу найбільше символів, оскільки він справді описує поверхню, наприклад, подряпини, відбитки пальців, плями, бруд тощо.

Глянцевість Ця карта є оберненою картою шорсткості. Білий 1,0 гладкий, а 0,0 чорний - шорсткий. Описує мікроповерхня об'єкта. Мікроповерхня, якщо груба, може спричинити розсіювання світлових променів і зробити виділення більш тьмяним та широким. Така ж кількість світлової енергії відбивається, що виходить на поверхню. Ця карта має найбільшу художню свободу. Тут немає неправильних відповідей. Ця карта надає активу найбільше символів, оскільки він справді описує поверхню, наприклад, подряпини, відбитки пальців, плями, бруд тощо.

Specular Ця карта містить інформацію про відбиття як для металевих, так і для діелектриків (неметалічних) поверхонь. Це ключова відмінність робочого процесу метал / шорсткість та специфікація / блиск. Діють ті самі правила. Вам потрібно використовувати вимірювані значення для металів, і більшість діелектриків впаде з діапазоном 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 .

Корисні посилання

грязьова сфера-1024х576

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

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


39
Вау, ви зробили цілу серію підручників на сайті Q&A.
Оцелот

6
@Ocelot Мені подобається, як Seyed продовжує додавати сюди все більше й більше. Мені подобається майструвати шейдерами, і вони дуже корисні для отримання більшої кількості ідей, а також підручників. На мою думку, він може постійно публікувати їх.
Джон Гамільтон

7
Дивовижна відповідь. Працювати з шейдерами дуже складно, і для мене потрібні години хитрощів, досліджень, проб і помилок, а також вивчення інших шейдерів, щоб отримати бажані ефекти. І ось ви це робите, для когось іншого, безкоштовно.
Draco18s

1
Для стандартних матеріалів зазвичай найкраще вбудовувати шорсткість у металеву або звичайну карту (перша здається, що це за замовчуванням). Я рекомендую використовувати Photo Shop, Paint Shop або Gimp, щоб створити належний металік, який вбудовує шорсткість. Крім того, якщо у вас є "Художник речовин" або подібне, ви можете експортувати ваші шорсткості саме так, як їх бажає Unity, і матимете перевагу візуалізувати свої матеріали, перш ніж розміщувати їх у Unity.
Девід Петерсон

вчений і джентльмен
Бас Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.