Unity에서 "습식 표면"/ "얕은 웅덩이"쉐이더를 어떻게 만들 수 있습니까?


71

내 게임에서는 역동적 인 물웅덩이를 만들어야하지만 그러한 효과를내는 방법을 보여주는 자습서를 찾을 수 없습니다 (아래 예제 참조). 내가 어떻게 해?

양자 브레이크


4
투표율이 높은 질문과 투표율이 높은 답변이 닫히지 않은 것을보고 짜증이납니다. 어리석은 조금 : 자신을 위해 현상금 항에 불구하고, 최선을 다해 자신의 답을 선택하는 괜찮
팀 홀트

@TimHolt 우리는 이런 질문을 어떤 근거로 끝내겠습니까? 완벽하게 주제에 보인다.
Josh

요청한 사람은 자신의 답변을 받아 들여야한다고 말합니다. 영어 오용을 용서하십시오.
팀 홀트

답변:


121

반사

습식 셰이더를 만들려면 먼저 반사가 필요합니다.

심플로드

리플렉션 프로브 또는 MirrorReflection3을 사용할 수 있지만 여기서는 모바일에서 셰이더를 사용할 수 있기 때문에 가짜 반사 (큐브 맵)를 사용합니다.

반사

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 (Fractal Brownian Motion) 자습서는 다음과 같습니다 .

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

마스크 만들기

다음 기능으로 두껍고 부드러운 마스크를 만들 수 있습니다.

단계

단계

[A]보다 작거나 같으면 1을 출력 하고 [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"
}

영상

지도 사용

셰이더 물리 기반 음영

유용한 정의는 다음과 같습니다.

거칠기 개체의 미세 표면을 설명합니다. 흰색 1.0은 거칠고 검은 0.0은 매끄 럽습니다. 표면이 거칠면 광선이 산란되어 하이라이트가 더 어둡고 넓게 보일 수 있습니다. 같은 양의 빛 에너지가 표면으로 들어오는 것처럼 반사됩니다. 이지도는 가장 예술적인 자유를 가지고 있습니다. 여기에는 오답이 없습니다. 이 맵은 스크래치, 지문, 번짐, 때 등 표면을 설명 할 때 자산에 가장 특징이 있습니다.

광택 이 맵은 거칠기 맵의 반대입니다. 흰색 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의 소스 .

유용한 링크

진흙 구체 -1024x576

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

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


39
와우, 당신은 Q & A 사이트에서 전체 쉐이더 튜토리얼 시리즈를 끝냈습니다.
Ocelot

6
@Ocelot 나는 Seyed가 여기에 점점 더 많은 것을 추가하는 방법을 좋아합니다. 나는 셰이더로 땜질하는 것을 좋아하며 더 많은 아이디어와 튜토리얼에도 도움이됩니다. 그는 내 의견으로는 이것을 영원히 계속 게시 할 수 있습니다.
존 해밀턴

7
놀라운 답변입니다. 셰이더는 작업하기가 매우 어려우므로 원하는 효과를 얻으려면 몇 시간의 조사, 연구, 시행 착오 및 다른 셰이더 검사가 필요합니다. 그리고 여기서 당신은 다른 사람을 위해 무료로 그렇게하고 있습니다.
Draco18s

1
표준 재료의 경우 일반적으로 거칠기를 금속 또는 노멀 맵에 포함시키는 것이 가장 좋습니다 (전자가 기본값 인 것 같습니다). 거칠기를 포함하는 적절한 금속을 만들기 위해 Photo Shop, Paint Shop 또는 Gimp를 사용하는 것이 좋습니다. 또는 Substance Painter 등을 사용하는 경우 Unity가 원하는대로 거칠기를 내보내고 재질을 Unity에 배치하기 전에 시각화 할 수 있습니다.
David Peterson

학자와 신사
Bas Smit
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.