K-digital traning/3D 콘텐츠 제작

Placid Plastic Duck Simulator - 개발일지3

내꺼블로그 2023. 10. 5. 15:14

이제 좀 더 물처럼 구현하기 위해 wave를 구현해보겠다.

먼저 잔물결을 표현해주고자 normal map을 입혀보았다.

 

 

 

normal map을 입히기 위해 아래와 같은 사진을 다운로드하였다.

normal map 다운로드 링크:

https://www.cadhatch.com/seamless-water-textures

 

Free Seamless Water Textures Normal Mapping

Royalty Free seamless water texture patterns download, water Tileable patterns with matching normal map image

www.cadhatch.com

 

 

normal map

 

 

 

 

 

 

normal map 처리 부분

 

 

흐르는 모습을 구현하기 위해 normal map의 uv 좌표에 _Time을 더함으로써 시간에 따라 uv좌표가 이동시키도록 하였다.

물이 한 방향으로만 흐르면 다소 이질적이므로 사방으로 흐르도록 구현하였다.

4방향을 적절히 합쳐 구현하기 위해 float3 네 값을 다 더한 뒤 값이 너무 커지는 것을 고려하여 4로 나눈 평균값을 o.Normal에 넣어주었다.

 

 

 

 

 

 

 

 

normal map만 입히면 입체적이지 X => vertex에 움직임을 부여하자

 

 

vertex값을 조절하기 위해 위와 같이 선언하였다.

sign함수를 적용하여 구현해보았는데 물이 연속적으로 위아래로 움직이는 모습을 구현하기 위해 적용하였다.

_Time을 더해 흐르는 모습을 구현하였고 이것도 역시 한 방향으로 물결이 흐르는 모습이 아닌 일렁이는 모습을 구현하기 위해 값을 여러 개 두어 그 값들을 다 합쳐서 표현하였다.

 

 

 

 

 

 

vertex 움직임 참고

https://blog.naver.com/ateliersera/220413097549

 

알기 쉬운 유니티 쉐이더 강좌 #017 - 응용편 : Water shader 를 제작해 보자. Ocean Wave 제작

상당히 난이도가 올라갈거 처럼 보이는 응용편 입니다. 이번엔 쉐이더 3.0 모델을 이용해서, 버텍스가 움직...

blog.naver.com

 

 

 

 

 

watershader code

 

Shader "Custom/water"
{
    Properties
    {
        _Color ("Water Color", Color) = (1,1,1,1)
        _SpecCol ("Specular Color", Color) = (1,1,1,1)
        _BumpMap ("Normal Map", 2D)="bump"{}
        _NormalMapSpeed("NormalMap Speed", Range(0, 10)) = 1
        _WaveSpeed("Wave Speed", Range(0, 10)) = 1
        _Amplitude("Amplitude", Range(0, 50))=1
        _SpecInten ("Specular Intencity", Range(0, 100)) = 1
        _SpecPow ("Specular Power", Range(0, 1)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
       
        GrabPass{}

        CGPROGRAM
        #pragma surface surf _WaterShader vertex:vert

        #pragma target 3.0

        sampler2D _GrabTexture;
        sampler2D _BumpMap;

        fixed4 _Color;
        fixed4 _SpecCol;
        float _NormalMapSpeed;
        float _WaveSpeed;
        float _Amplitude;
        float _SpecInten;
        float _SpecPow;

        void vert(inout appdata_full v){
            float moveY1 = sin(v.vertex.x+_Time.y*_WaveSpeed)*_Amplitude*0.02;
            float moveY2 = sin(v.vertex.z+_Time.y*_WaveSpeed)*_Amplitude*0.02;

            float moveY3 = sin((v.vertex.x+_Time.y*_WaveSpeed)*1.5)*_Amplitude*0.02;
            float moveY4 = sin((v.vertex.z+_Time.y*_WaveSpeed)*1.5)*_Amplitude*0.02;

            float moveY5 = sin((v.vertex.x+_Time.y*_WaveSpeed)*(-0.5))*_Amplitude*0.02;
            float moveY6 = sin((v.vertex.z+_Time.y*_WaveSpeed)*(-0.5))*_Amplitude*0.02;

            v.vertex.y+=(moveY1+moveY2+moveY3+moveY4+moveY5+moveY6)/6;  
        }

        struct Input
        {
            float3 viewDir;
            float4 screenPos;
            float2 uv_BumpMap;
        };
       
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = _Color;
            float2 uvBump = float2(IN.uv_BumpMap.x*0.9,IN.uv_BumpMap.y*0.2);
            float3 x1 = UnpackNormal(tex2D(_BumpMap, float2(uvBump.x+_Time.x*_NormalMapSpeed, uvBump.y)));
            float3 x2 = UnpackNormal(tex2D(_BumpMap, float2(uvBump.x-_Time.x*_NormalMapSpeed, uvBump.y)));
            float3 y1 = UnpackNormal(tex2D(_BumpMap, float2(uvBump.x, uvBump.y+_Time.x*_NormalMapSpeed)));
            float3 y2 = UnpackNormal(tex2D(_BumpMap, float2(uvBump.x, uvBump.y-_Time.x*_NormalMapSpeed)));
            float3 normal = (x1+x2+y1+y2)/4;
            o.Normal = normal;
            float rim = saturate(dot(o.Normal, IN.viewDir));
            float lerpRim=pow((1-rim)*0.5, 2);
            float3 scrPos = IN.screenPos.xyz/(IN.screenPos.w+0.00001f);
            float4 grab = tex2D(_GrabTexture, scrPos.xy);
            o.Emission = lerp(grab.rgb, c.rgb, lerpRim+0.2);
            o.Emission+=saturate(pow(rim, 15)-0.1);
            //o.Emission = rim+0.3;
        }

        float4 Lighting_WaterShader(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten){
            float4 result = (0,0,0,1);
            float3 h = normalize(lightDir+viewDir);
            float3 spec = saturate(dot(h, s.Normal));
            spec = pow(spec, 50*_SpecInten)*_SpecCol;
            result.rgb = spec*_SpecPow;
            return result;
            //return float4(0,0,0,1);
        }
        ENDCG
    }
    FallBack "Diffuse"            
}