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?
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?
Réponses:
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/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"
}
Pour ajouter de la distorsion à votre reflet, vous pouvez multiplier la carte normale et le worldRefl
:
float3 distortion = tex2D(_Distortion, IN.uv_Distortion);
o.Emission = texCUBE(_Cube, IN.worldRefl*distortion).rgb
Vous pouvez utiliser le bruit pour créer une forme procédurale :
Voici un tutoriel 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
}
}
}
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.
Vous pouvez faire un masque épais et lisse avec ces fonctions:
Les sorties 1 si [A]
est inférieur ou égal à [B]
, sinon, les sorties 0.
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.
/* 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"
}
Voici une définition utile:
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 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.
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"
}
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.
https://80.lv/articles/how-to-create-wet-mud-in-substance-designer/