Comment créer un shader «Surface humide» / «Flaque d'eau peu profonde» dans Unity?
71
Dans mon jeu, j'ai besoin de créer des flaques d'eau dynamiques, mais je ne trouve pas de tutoriel qui montre comment créer un tel effet (un exemple est présenté ci-dessous). Comment puis-je le faire?
Ennuyeux de voir une question aussi votée élevée et une réponse votée plus élevée ne pas être clôturée. C'est bien de choisir sa propre réponse, mais un peu idiot de réclamer cette prime pour soi-même :)
Tim Holt le
@ Timholt Sur quelle base fermerions-nous une question comme celle-ci? Il semble parfaitement sur le sujet.
Josh
Je dis que la personne qui l'a demandé devrait accepter sa propre réponse. Pardon mon mauvais usage de l'anglais.
Tim Holt
Réponses:
121
Réflexion
Pour créer un shader humide, vous devez d’abord avoir une réflexion.
Vous pouvez utiliser une sonde de réflexion ou un miroirReflection3, mais j'utilise ici une fausse réflexion (Cube Map) car le shader peut ensuite être utilisé sur mobile.
Shader"Smkgames/FbmNoise"{Properties{_TileAndOffset("Tile and Offset",Vector)=(1,1,0,0)}SubShader{Tags{"RenderType"="Opaque"}
LOD 100Pass{
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.comfloat 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/4dS3Wdfloat noise (in float2 st){
float2 i = floor(st);
float2 f = frac(st);// Four corners in 2D of a tilefloat 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 6float fbm (in float2 st){// Initial valuesfloat value =0.0;float amplitude =.5;float frequency =0.;//// Loop of octavesfor(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
}}}
La FBM ci-dessus ne doit pas être utilisée directement dans votre shader, car elle comporte de nombreux calculs de GPU et diminue les performances. Au lieu d'utiliser directement, vous pouvez rendre le résultat en une texture avec RenderTexture .
Shadertoy utilise plusieurs passes , une par "tampon". Comme son nom l’indique, cette passe stocke les résultats dans un tampon, qui n’est qu’une texture. Unity vous permettra également de rendre des textures.
Créer un masque
Vous pouvez faire un masque épais et lisse avec ces fonctions:
Les mélanges entre deux valeurs se font en douceur, en fonction du lieu où une troisième valeur se situe dans cette plage, générant des valeurs comprises entre 0 et 1. Considérez-le comme un lerp inverse verrouillé avec une valeur de sortie lissée.
Résultat
/* 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 KamalyShader"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 200Pass{ColorMask0}ZWriteOffBlendSrcAlphaOneMinusSrcAlphaColorMask RGB
CGPROGRAM
#pragma surface surf Standard fullforwardshadows alpha:fade
structInput{
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;staticconst 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"}
Rugosité
Décrit la microsurface de l'objet. Le blanc 1.0 est rugueux et le noir 0.0 est lisse. Si elle est rugueuse, la microsurface peut disperser les rayons lumineux et rendre la surbrillance plus sombre et plus large. La même quantité d'énergie lumineuse est reflétée sortant de la surface. Cette carte a la plus grande liberté artistique. Il n'y a pas de mauvaise réponse ici. Cette carte donne à l’actif le plus de caractère possible car il décrit véritablement la surface, par exemple des rayures, des empreintes de doigt, des taches, de la crasse, etc.
Brillance
Cette carte est l'inverse de la carte de rugosité. Le blanc 1,0 est lisse et 0,0 noir est rugueux. Décrit la microsurface de l'objet. Si elle est rugueuse, la microsurface peut disperser les rayons lumineux et rendre la surbrillance plus sombre et plus large. La même quantité d'énergie lumineuse est reflétée sortant de la surface. Cette carte a la plus grande liberté artistique. Il n'y a pas de mauvaise réponse ici. Cette carte donne à l’actif le plus de caractère possible car il décrit véritablement la surface, par exemple des rayures, des empreintes de doigt, des taches, de la crasse, etc.
Spéculaire
Cette carte contient les informations de réflectance pour les surfaces métalliques et diélectriques (non métalliques). Il s'agit d'une différence essentielle entre les flux de travail métal / rugueux et spéc / brillant. Les mêmes règles s'appliquent. Vous devez utiliser les valeurs mesurées pour les métaux et la plupart des diélectriques tomberont dans la plage de 0,04 à 4%. S'il y a de la saleté sur le métal, la valeur de réflectance doit également être abaissée. Cependant, vous pouvez ajouter différentes valeurs dans la carte spéculaire pour les matériaux diélectriques, car vous avez le contrôle pour créer la carte.
Je pense qu'Unity n'a pas de rugosité, il n'a que des métaux, mais le canal alpha est destiné à la rugosité et le canal rouge est destiné aux métaux. Vous pouvez modifier l'intensité avec douceur.
Wow, vous avez fait toute une série de tutoriels sur les shader sur le site de questions / réponses.
Ocelot
6
@Ocelot J'adore la façon dont Seyed continue d'en ajouter de plus en plus ici. J'aime bricoler avec des shaders et ceux-ci sont vraiment utiles pour plus d'idées et comme tutoriels. Il peut continuer à les afficher pour toujours, à mon avis.
John Hamilton
7
Réponse étonnante. Il est très difficile de travailler avec des shaders et il me faut des heures de violon, de recherche, d’essais et d’erreur et l’examen d’autres shaders pour obtenir les effets souhaités. Et ici, vous faites cela, pour quelqu'un d'autre, gratuitement.
Draco18s
1
Pour les matériaux standard, il est généralement préférable d’intégrer la rugosité dans la carte métallique ou normale (la première semble être la valeur par défaut). Je recommanderais d'utiliser Photo Shop, Paint Shop ou Gimp pour créer un métal adéquat qui incorpore une rugosité. Alternativement, si vous avez Substance Painter ou similaire, vous pouvez exporter votre rugosité exactement comme Unity le désire et avoir l’avantage de visualiser vos matériaux avant de les placer dans Unity.
Réponses:
Réflexion
Pour créer un shader humide, vous devez d’abord avoir une réflexion.
Vous pouvez utiliser une sonde de réflexion ou un miroirReflection3, mais j'utilise ici une fausse réflexion (Cube Map) car le shader peut ensuite être utilisé sur mobile.
Distorsion
Pour ajouter de la distorsion à votre reflet, vous pouvez multiplier la carte normale et le
worldRefl
:Forme procédurale
Vous pouvez utiliser le bruit pour créer une forme procédurale :
Voici un tutoriel Fractal Brownian Motion (FBM) .
La FBM ci-dessus ne doit pas être utilisée directement dans votre shader, car elle comporte de nombreux calculs de GPU et diminue les performances. Au lieu d'utiliser directement, vous pouvez rendre le résultat en une texture avec RenderTexture .
Shadertoy utilise plusieurs passes , une par "tampon". Comme son nom l’indique, cette passe stocke les résultats dans un tampon, qui n’est qu’une texture. Unity vous permettra également de rendre des textures.
Créer un masque
Vous pouvez faire un masque épais et lisse avec ces fonctions:
Étape
Les sorties 1 si
[A]
est inférieur ou égal à[B]
, sinon, les sorties 0.Smoothstep
Les mélanges entre deux valeurs se font en douceur, en fonction du lieu où une troisième valeur se situe dans cette plage, générant des valeurs comprises entre 0 et 1. Considérez-le comme un lerp inverse verrouillé avec une valeur de sortie lissée.
Résultat
Utiliser des cartes
Ombrage Physique
Voici une définition utile:
Rugosité
Je ne sais pas pourquoi, mais le shader standard d'Unity n'a pas de carte de finesse. J'ai donc écrit un shader de base et ajouté cette carte.
Je pense qu'Unity n'a pas de rugosité, il n'a que des métaux, mais le canal alpha est destiné à la rugosité et le canal rouge est destiné aux métaux. Vous pouvez modifier l'intensité avec douceur.
Source sur GitHub .
Liens utiles
https://80.lv/articles/how-to-create-wet-mud-in-substance-designer/
https://www.fxguide.com/featured/game-environments-partc/
la source