Wie kann ich in Unity einen Shader für "nasse Oberflächen" / "flache Pfützen" erstellen?

71

In meinem Spiel muss ich dynamische Wasserpfützen erstellen, aber ich kann kein Tutorial finden, das zeigt, wie ich einen solchen Effekt erzielen kann (ein Beispiel dafür ist unten dargestellt). Wie kann ich es tun?

Quantenbruch

Seyed Morteza Kamali
quelle
4
Es ist ärgerlich zu sehen, dass eine so hoch gestimmte Frage und eine höher gestimmte Antwort nicht geschlossen werden. Es ist in Ordnung, Ihre eigene Antwort als die beste zu wählen, obwohl es ein wenig albern ist, das Kopfgeld für sich selbst zu beanspruchen :)
Tim Holt
@TimHolt Auf welcher Basis würden wir eine solche Frage schließen? Es scheint perfekt zum Thema.
Josh
Ich sage, dass die Person, die danach gefragt hat, seine eigene Antwort akzeptieren sollte. Verzeihen Sie meinen Missbrauch von Englisch.
Tim Holt

Antworten:

121

Reflexion

Um einen nassen Shader zu erstellen, müssen Sie zuerst eine Reflektion haben.

SimpleRoad

Sie können eine Reflection Probe oder eine MirrorReflection3 verwenden, aber ich verwende hier eine gefälschte Reflection (Cube Map), da der Shader dann auf Mobilgeräten verwendet werden kann.

Reflexion

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

Verzerrung

Um die Reflexion zu verzerren, können Sie die normale Karte und Folgendes multiplizieren worldRefl:

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

Verzerrung

Verfahrensform

Sie können Rauschen verwenden, um eine prozedurale Form zu erstellen:

Erfassung

Hier ist ein Fractal Brownian Motion (FBM) Tutorial .

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

Das oben genannte FBM sollte nicht direkt in Ihrem Shader verwendet werden, da es viele GPU-Berechnungen enthält und die Leistung verringert. Anstatt direkt zu verwenden, können Sie das Ergebnis mit RenderTexture in eine Textur rendern .

Shadertoy verwendet mehrere Durchläufe , einen pro "Puffer". Wie der Name schon sagt, speichert dieser Durchlauf die Ergebnisse in einem Puffer, der nur eine Textur ist. Mit Unity können Sie auch Texturen rendern.

2018-01-26_10-18-20

Maske erstellen

Mit diesen Funktionen können Sie eine dicke und glatte Maske erstellen:

Schritt

Schritt

Gibt 1 aus, wenn [A]kleiner oder gleich [B], andernfalls 0 aus.

Gleichmäßiger Schritt

glatter Schritt

Überblendet problemlos zwei Werte, basierend darauf, wo sich ein dritter Wert in diesem Bereich befindet, und gibt Werte zwischen 0 und 1 aus. Stellen Sie sich dies als eingespanntes inverses Lerp mit geglättetem Ausgabewert vor.

Ergebnis

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

Bild

Verwenden von Karten

shaderToy Physikalisch basiertes Shading

Hier ist eine nützliche Definition:

Rauheit Beschreibt die Mikrooberfläche des Objekts. Weiß 1.0 ist rau und Schwarz 0.0 ist glatt. Die rauhe Mikrooberfläche kann dazu führen, dass die Lichtstrahlen gestreut werden und die Hervorhebung dunkler und breiter erscheint. Die gleiche Menge an Lichtenergie wird reflektiert, als würde sie in die Oberfläche gelangen. Diese Karte hat die größte künstlerische Freiheit. Hier gibt es keine falschen Antworten. Diese Karte verleiht dem Objekt den meisten Charakter, da sie die Oberfläche wirklich beschreibt, z. B. Kratzer, Fingerabdrücke, Flecken, Schmutz usw.

Glanz Diese Karte ist das Gegenteil der Rauheitskarte. Weiß 1.0 ist glatt und 0.0 Schwarz ist rau. Beschreibt die Mikrooberfläche des Objekts. Die rauhe Mikrooberfläche kann dazu führen, dass die Lichtstrahlen gestreut werden und die Hervorhebung dunkler und breiter erscheint. Die gleiche Menge an Lichtenergie wird reflektiert, als würde sie in die Oberfläche gelangen. Diese Karte hat die größte künstlerische Freiheit. Hier gibt es keine falschen Antworten. Diese Karte verleiht dem Objekt den meisten Charakter, da sie die Oberfläche wirklich beschreibt, z. B. Kratzer, Fingerabdrücke, Flecken, Schmutz usw.

Specular Diese Karte enthält die Informationen zum Reflexionsgrad für Metall- und dielektrische (nichtmetallische) Oberflächen. Dies ist ein wesentlicher Unterschied in den Arbeitsabläufen für Metall / Rau und Spezifikation / Glanz. Es gelten die gleichen Regeln. Sie müssen Messwerte für Metalle verwenden, und die meisten Dielektrika liegen im Bereich von 0,04 bis 4%. Wenn sich Schmutz auf dem Metall befindet, muss auch der Reflexionsgrad verringert werden. Sie können jedoch der Spiegelkarte für dielektrische Materialien andere Werte hinzufügen, da Sie die Kontrolle haben, die Karte zu erstellen.

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

Rauheit

Bild

Ich weiß nicht warum, aber der Unity-Standard-Shader hat keine Glättungs-Map. Deshalb habe ich einen einfachen Shader geschrieben und diese Map hinzugefügt.

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

Ich denke, Unity hat keine Rauheit, es hat nur Metallic, aber der Alpha-Kanal ist für Rauheit und der Rote Kanal ist für Metallic. Sie können die Intensität mit Glätte ändern.

Quelle auf GitHub .

Nützliche Links

Schlamm-Kugel-1024x576

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

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

Seyed Morteza Kamali
quelle
39
Wow, Sie haben eine ganze Reihe von Shader-Tutorials auf der Q & A-Site erstellt.
Ocelot
6
@Ocelot Ich liebe es, wie Seyed hier immer mehr davon hinzufügt. Ich bastele gerne an Shadern herum und diese sind wirklich hilfreich für mehr Ideen und auch als Tutorials. Er kann diese meiner Meinung nach für immer veröffentlichen.
John Hamilton
7
Erstaunliche Antwort. Es ist sehr schwierig, mit Shadern zu arbeiten, und ich brauche Stunden, um zu fummeln, zu recherchieren, zu probieren und andere Shader zu untersuchen, um die gewünschten Effekte zu erzielen. Und hier machst du das, für jemand anderen, kostenlos.
Draco18s
1
Bei Standardmaterialien ist es normalerweise am besten, die Rauheit in die metallische oder normale Abbildung einzubetten (die erstere scheint die Standardeinstellung zu sein). Ich würde empfehlen, Photo Shop, Paint Shop oder Gimp zu verwenden, um ein geeignetes Metallic zu erstellen, das Rauheit einbettet. Wenn Sie über Substance Painter oder Ähnliches verfügen, können Sie Ihre Rauheit genau so exportieren, wie es Unity wünscht, und haben den Vorteil, dass Sie Ihre Materialien visualisieren können, bevor Sie sie in Unity einfügen.
David Peterson
ein Gelehrter und ein Gentleman
Bas Smit