Shader "Custom/Triplanar"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Top("Top", 2D) = "white" {}
        _Side("Side", 2D) = "white" {}
        _Front("Front", 2D) = "white" {}

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Top;
        sampler2D _Front;
        sampler2D _Side;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldPos;
            float3 worldNormal;
            INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            //fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

            float2 topUV = float2(IN.worldPos.x, IN.worldPos.z);
            float2 sideUV = float2(IN.worldPos.z, IN.worldPos.y);
            float2 frontUV = float2(IN.worldPos.x, IN.worldPos.y);




            float4 topColor = tex2D(_Top, topUV); // green = 1

            float4 sideColor = tex2D(_Side, sideUV); // red = 1

            float4 frontColor = tex2D(_Front, frontUV); // blue = 1

            //float3 n = WorldNormalVector(IN, o.Normal); //해당 면의 normal 벡터 => 값이 1이 된다.
            
            //혼합 lerp
            
            //float3 e = lerp(0, 1, topColor.g);
            //o.Emission = topColor.rgb;
            //o.Albedo = sideColor.rgb;
            //o.Emission = n.rgb;
            o.Albedo = lerp(topColor, frontColor,abs(IN.worldNormal.z));
            //위쪽 면의 색상과 앞면의 색상을 표면의 기울기에 따라 가중 평균화하여 새로운 색상을 생성
            //기울기가 높을수록 앞면의 색상이 더 많이 나타나며, 기울기가 낮을수록 위쪽 면의 색상이 더 많이 나타낸다.
            o.Albedo = lerp(o.Albedo, sideColor, abs(IN.worldNormal.x));
            o.Alpha = 1;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

그림과 같이 각 면이 해당하는 벡터를 확인한 후 색상을 집어 넣어야 한다.

 

Shader "Custom/Triplanar"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Top("Top", 2D) = "white" {}
        _Side("Side", 2D) = "white" {}
        _Front("Front", 2D) = "white" {}

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Top;
        sampler2D _Front;
        sampler2D _Side;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldPos;
            float3 worldNormal;
            INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            //fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

            float2 topUV = float2(IN.worldPos.x, IN.worldPos.z);
            float2 sideUV = float2(IN.worldPos.z, IN.worldPos.y);
            float2 frontUV = float2(IN.worldPos.x, IN.worldPos.y);




            float4 topColor = tex2D(_Top, topUV); // green = 1

            float4 sideColor = tex2D(_Side, sideUV); // red = 1

            float4 frontColor = tex2D(_Front, frontUV); // blue = 1

            float3 n = WorldNormalVector(IN, o.Normal); //해당 면의 normal 벡터 => 값이 1이 된다.
            
            //혼합 lerp
            
            //float3 e = lerp(0, 1, topColor.g);
            //e = lerp (e, topColor.r, sideColor);
            //e = lerp (e, topColor.b, frontColor);
            //o.Emission = topColor.rgb;
            //o.Albedo = sideColor.rgb;
            o.Emission = n.rgb;
            //o.Albedo = lerp(topColor, frontColor,abs(IN.worldNormal.z));
            //위쪽 면의 색상과 앞면의 색상을 표면의 기울기에 따라 가중 평균화하여 새로운 색상을 생성
            //기울기가 높을수록 앞면의 색상이 더 많이 나타나며, 기울기가 낮을수록 위쪽 면의 색상이 더 많이 나타낸다.
            //o.Albedo = lerp(o.Albedo, sideColor, abs(IN.worldNormal.x));
            o.Alpha = 1;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html

 

Unity - Scripting API: Vector3.Lerp

Interpolates between the points a and b by the interpolant t. The parameter t is clamped to the range [0, 1]. This is most commonly used to find a point some fraction of the way along a line between two endpoints (e.g. to move an object gradually between t

docs.unity3d.com

 

'산대특 > 게임 UIUX 프로그래밍' 카테고리의 다른 글

Shader - Cubemap Reflection  (0) 2024.02.22
Shader - Diffuse Warping  (0) 2024.02.22
Shader -Blinn Phong 스펙큘러  (0) 2024.02.22
Shader - Lambert  (0) 2024.02.20
Shader - Vertex  (0) 2024.02.19

3D 오브젝트 2pass로 테두리 생성

Shader "Custom/CubeMap"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _CubeMap ("CubeMap", CUBE) = ""{}
    }
    SubShader
    {   
        Tags { "RenderType"="Opaque" }
        //1Pass
        Cull Front
        CGPROGRAM
        #pragma surface surf _NoLight vertex:vert
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        void vert(inout appdata_full v){
            v.vertex.xyz = v.vertex.xyz + v.normal.xyz * 0.01;
            }

        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb * 0.5;
            o.Alpha = c.a;
        }

        float4 Lighting_NoLight(SurfaceOutput s, float3 lightDir, float atten){
            return float4(0,0,0,1);
            }
        ENDCG

        //2Pass
        CGPROGRAM
        #pragma surface surf Lambert
        #pragma target 3.0

        sampler2D _MainTex;
        samplerCUBE _CubeMap;
        sampler2D _NormalMap;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldRefl; //float2의 uv가아닌 반사벡터를 받는다. => 예약어
            float2 uv_NormalMap;
            INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            //텍스쳐
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            float3 n = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            o.Normal = n;


            float3 ref = WorldReflectionVector(IN, o.Normal);
            float4 d = texCUBE(_CubeMap, ref);
            o.Albedo = c.rgb * 0.5;
            o.Emission = d.rgb * 0.5 ;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

_Cube("Cubemap", Cube) = "" {}

// 평소와 다르게 큰따옴표 안을 비워주고 프로퍼티를 생성

 

그리고 Input 구조체안에 float2 UV 아닌 반사 벡터를 받아 온다.

CubeMap에서 알베도를 0으로 선택

CubeMap을 사용할 때 주로 환경 맵이나 반사 맵으로 사용됩니다. CubeMap은 여러 방향으로 카메라를 렌더링하여 캡쳐한 이미지입니다. 이것은 6개의 면으로 구성되어 있으며, 각 면은 카메라가 향하는 방향에 대한 이미지입니다. 이러한 이미지는 일반적으로 장면의 주변 환경을 캡쳐하기 위해 사용됩니다.

알베도 (Albedo)는 표면이 받는 광선의 색상을 나타냅니다. 이것은 표면이 얼마나 빛을 흡수하고 반사하는지를 결정합니다. 일반적으로 알베도는 표면의 기본 색상이며, 이것은 표면이 받는 조명과 반사되는 빛의 양에 영향을 줍니다.

CubeMap을 사용하는 경우, 환경의 주변을 반영하기 위해 표면의 알베도를 0으로 선택하는 것은 일반적으로 의미가 없습니다. 왜냐하면 CubeMap은 주변 환경을 나타내는데 사용되며, 표면의 색상에 해당하는 이미지를 제공하기 때문입니다. 따라서 CubeMap을 사용하는 경우, 표면의 알베도를 0으로 선택하더라도 CubeMap에 의해 환경의 색상이 반영될 것입니다.

그러나 특정 상황에서는 CubeMap의 영향을 제거하고 표면의 색상을 완전히 지정하고자 할 수 있습니다. 이런 경우에는 알베도를 0으로 선택하여 CubeMap의 영향을 제거할 수 있습니다. 이는 표면이 주변 환경에 반영되는 것을 방지하고 표면의 색상을 완전히 제어하고자 할 때 사용될 수 있습니다.                                                                  -feat. GPT

 


Shader error in 'Custom/Reflection': Surface shader Input structure needs  INTERNAL_DATA for this WorldNormalVector or WorldReflectionVector usage at  line 144 (on d3d11)

 

이러한 에러가 발생하는 경우 Input에서 float3 worldRefl이나 float3 worldNormal과  같은 버텍스 월드 노멀에 관련된 데이터를 받아와 surf 함수 내부에서 사용하면서, 동시에  탄젠트 노멀인 UnpackNormal함수를 거친 노멀 데이터를 함수 내부에서 같이 사용하면  에러가 발생 한다.

 

 
 

INTERNAL_DATA

 

접선공간, 표면공, 텍스쳐공간등으로 불리는 Tangent Space 텍스쳐 위에서의 좌표계

공간 고유 원점 좌표계 텍스 좌표 지정되 좌표계.

좌표계에서 U 값이 증가하는 방향을 가리키는 X축과 V 값이 증가하는 방향으로 Y축을 나타낸다

노멀맵에 저장된 정보는 tangent space에 있으며,

이것을 사용하기 위해서는 tangent space에서 world space로의 변환이 필요하다.

https://docs.unity3d.com/kr/2021.3/Manual/SL-SurfaceShaders.html

 

표면 셰이더 작성 - Unity 매뉴얼

빌트인 렌더 파이프라인에서 표면 셰이더는 조명과 상호작용하는 셰이더를 더욱 간단하게 작성하는 방법입니다.

docs.unity3d.com

 

'산대특 > 게임 UIUX 프로그래밍' 카테고리의 다른 글

Shader - triplaner  (1) 2024.02.26
Shader - Diffuse Warping  (0) 2024.02.22
Shader -Blinn Phong 스펙큘러  (0) 2024.02.22
Shader - Lambert  (0) 2024.02.20
Shader - Vertex  (0) 2024.02.19

1번.

Diffuse Warping + NormalMap + Texture

Shader "Custom/WarpedDiffuse"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _RampTex ("Ramp Texture", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}
        _OutLine("OutLine", Range(0,1)) = 0.2
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _Warped
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _RampTex;
        sampler2D _NormalMap;
        float _OutLine;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float4 d = tex2D(_NormalMap, IN.uv_NormalMap);
            //float3 normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
            o.Normal = UnpackNormal(d);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 Lighting_Warped(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
        {
            float4 final;
            float ndotl = dot(s.Normal, lightDir);

            float rim = dot(s.Normal, viewDir);
            if(rim >= _OutLine) rim = 1;
            else rim = 0;

            fixed4 ramp = tex2D(_RampTex, float2(ndotl, 0.5));
            
            final.rgb = s.Albedo.rgb * ramp.    rgb * rim;
            final.a = s.Alpha;

            return final;
        }
        ENDCG

    }
    FallBack "Diffuse"
}

 

2.

1번  + 2Pass 외곽선 + RampTex 적용

Shader "Custom/WarpedDiffuse"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _RampTex ("Ramp Texture", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _Warped
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _RampTex;
        sampler2D _NormalMap;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            float3 normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
            o.Normal = normal;
        }

        float4 Lighting_Warped(SurfaceOutput s, float3 lightDir, float atten)
        {
            float ndotl = dot(s.Normal, lightDir);
            float2 uv = float2(ndotl, 0.5);
            float4 c = tex2D(_RampTex, uv);
            return c;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

3.

Fresnel 외곽선 + RampTex

Shader "Custom/WarpedDiffuse"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _RampTex ("Ramp Texture", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}
        _OutLine("OutLine", Range(0,1)) = 0.2
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _Warped
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _RampTex;
        sampler2D _NormalMap;
        float _OutLine;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float4 d = tex2D(_NormalMap, IN.uv_NormalMap);
            //float3 normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
            o.Normal = UnpackNormal(d);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 Lighting_Warped(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
        {
            float4 final;
            float ndotl = dot(s.Normal, lightDir);

            float rim = dot(s.Normal, viewDir);
            if(rim >= _OutLine) rim = 1;
            else rim = 0;

            fixed4 ramp = tex2D(_RampTex, float2(ndotl, 0.5));
            
            final.rgb = s.Albedo.rgb * ramp.    rgb * rim;
            final.a = s.Alpha;

            return final;
        }
        ENDCG

    }
    FallBack "Diffuse"
}

 

4번.

2pass + 커스텀 스페큘러

Shader "Custom/WarpedDiffuse"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _RampTex ("Ramp Texture", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Cull Front
        CGPROGRAM
        #pragma surface surf _NoLight vertex:vert
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _RampTex;
        sampler2D _NormalMap;

        struct Input
        {
            float4 color : COLOR;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
        }

        void vert(inout appdata_full v){
            v.vertex.xyz  = v.vertex.xyz + v.normal.xyz * 0.01;
            }

        float4 Lighting_NoLight(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
        {
            return float4(0,0,0,1);
        }
        ENDCG
        Cull Back


        CGPROGRAM
        #pragma surface surf _Warped
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _RampTex;
        sampler2D _NormalMap;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
            float4 color : COLOR;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float4 d = tex2D(_NormalMap, IN.uv_NormalMap);
            o.Normal = UnpackNormal(d);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

        float4 Lighting_Warped(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
        {
            float4 final;

            //half-lambert
            float ndotl = dot(s.Normal, lightDir) * 0.5 + 0.5;

            //spec
            float3 h = normalize(lightDir + viewDir);
            float spec = saturate(dot(s.Normal,h));
            //spec => pow

            //Ramp
            float4 ramp = tex2D(_RampTex,float2(ndotl, 0.5));

            //final
            final.rgb = s.Albedo.rgb * (ramp.rgb + 0.5) * spec;
            final.a = s.Alpha;



            return final;
        }
        ENDCG

     }
    FallBack "Diffuse"
}

'산대특 > 게임 UIUX 프로그래밍' 카테고리의 다른 글

Shader - triplaner  (1) 2024.02.26
Shader - Cubemap Reflection  (0) 2024.02.22
Shader -Blinn Phong 스펙큘러  (0) 2024.02.22
Shader - Lambert  (0) 2024.02.20
Shader - Vertex  (0) 2024.02.19

Shader "Custom/phong2"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _SpecColor ("Specular Color", Color) = (1,1,1,1)
        _NormalMap ("Normal Map", 2D) = "bump" {}
        _GlossTex ("Gloss Map", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _Phong noambient
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _NormalMap;
        sampler2D _GlossTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float3 n = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            float4 g = tex2D(_GlossTex, IN.uv_MainTex);
            o.Normal = n;
            o.Albedo = c.rgb;
            o.Gloss = g.a;
            o.Alpha = c.a;
        }

        float4 Lighting_Phong(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
        {
            float4 final;

            //diffuse
            //lambert : N · L
            float3 diffuseColor;
            float ndotl = saturate(dot(s.Normal, lightDir));
            //벡터 * 색상 * 감쇠 * 광원컬러
            diffuseColor = ndotl * s.Albedo * atten * _LightColor0.rgb;

            //spec
            float3 specularColor;
            //1. 하프 단위 벡터 구하기 lightDir + viewDir 
            float3 h = normalize(lightDir + viewDir);
            //2. 노멀벡터와 내적 
            float spec = saturate(dot(s.Normal, h));
            //벡터 * 색상 * 글로스 * 색상
            specularColor = pow(spec, 100) * s.Gloss * _SpecColor.rgb;


            //rim 
            float3 rimColor;
            float rim = abs(dot(s.Normal, viewDir));
            float inverseRim = 1-rim;
            rimColor = pow(inverseRim, 3);
            //fake specular 
            float3 fakeSpec = rimColor * s.Gloss * float3(0.1, 0.1, 0.1);
            
            final.rgb = specularColor + diffuseColor + fakeSpec;
            final.a = s.Alpha;

            return final;
        }

        ENDCG
    }
    FallBack "Diffuse"
}

'산대특 > 게임 UIUX 프로그래밍' 카테고리의 다른 글

Shader - Cubemap Reflection  (0) 2024.02.22
Shader - Diffuse Warping  (0) 2024.02.22
Shader - Lambert  (0) 2024.02.20
Shader - Vertex  (0) 2024.02.19
Shader 기초  (0) 2024.02.18

차례대로 Standard, CustomLambert, HalfLambert

 

1. Standard

 

Shader "Custom/lambert"
{
    Properties
    {
        _MainTex("Main Texture", 2D) = "white"{}
        _NormalMap("NormalMap", 2D) = "bump" {}
        _Color("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Standard
        #pragma target 3.0
        sampler2D _MainTex;
        sampler2D _NormalMap;     
        float4 _Color;
        struct Input
        {
            float4 color : COLOR;
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float4 d = tex2D(_NormalMap, IN.uv_NormalMap);
            o.Normal = UnpackNormal (d);
            o.Albedo = c.rgb * _Color;
            o.Alpha = c.a;
        }
        // 빛을 만든다
       
        ENDCG
    }
    FallBack "Diffuse"
}

 

2. CustomLambert

Shader "Custom/customLambert"
{
    Properties
    {
        _MainTex("Main Texture", 2D) = "white"{}
        _NormalMap("NormalMap", 2D) = "bump" {}
        _Color("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _MyLambert
        #pragma target 3.0
        sampler2D _MainTex;
        sampler2D _NormalMap;     
        float4 _Color;
        struct Input
        {
            float4 color : COLOR;
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float4 d = tex2D(_NormalMap, IN.uv_NormalMap);
            o.Normal = UnpackNormal (d);
            o.Albedo = c.rgb * _Color;
            o.Alpha = c.a;
        }
        // 빛을 만든다
        float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float atten)
        {
            float4 final;
            float ndot1 = dot(s.Normal, lightDir);
            final.rgb = ndot1 * s.Albedo.rgb;
            final.a = s.Alpha;
            return final;
            }
        ENDCG
    }
    FallBack "Diffuse"
}

 

2-2. CustomLambert

Shader "Custom/customLambert"
{
    Properties
    {
        _NormalMap("Normal Map",2D) = "bump"{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _MyLambert noambient;
        #pragma target 3.0
        sampler2D _NormalMap;     
        struct Input
        {
            float4 color : COLOR;
            float2 uv_NormalMap;
        };
        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_NormalMap, IN.uv_NormalMap);
            o.Normal = UnpackNormal (c);
            o.Albedo = 1;
            
        }

        float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float atten)
        {
            float4 final;
            //return float4(1,0,0,1);
            //노멀벡터와 조명벡터를 내적해라
            float ndot1 = dot(s.Normal, lightDir);
            final = saturate(ndot1);
            return final;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

3. HalfLambert

Shader "Custom/customLambert2"
{
    Properties
    {
        _MainTex("Main Texture", 2D) = "white"{}
        _NormalMap("NormalMap", 2D) = "bump" {}
        _Color("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf _MyLambert
        #pragma target 3.0
        sampler2D _MainTex;
        sampler2D _NormalMap;     
        float4 _Color;
        struct Input
        {
            float4 color : COLOR;
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            float4 d = tex2D(_NormalMap, IN.uv_NormalMap);
            o.Normal = UnpackNormal (d);
            o.Albedo = c.rgb * _Color;
            o.Alpha = c.a;
        }
        // 빛을 만든다
        float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float atten)
        {
            float4 final;
            float ndot1 = dot(s.Normal, lightDir)* 0.5 + 0.5;
            final = pow(ndot1, 3);
            final.rgb = ndot1 * s.Albedo.rgb * _LightColor0.rgb * atten;
            final.a = s.Alpha;
            return final;
            }
        ENDCG
    }
    FallBack "Diffuse"
}

 


 

CustomLambert의 기본형

 

1. #pragma surface surf _MyLambert

2. void surf (Input IN, inout SurfaceOutput o)

3. float4 Lighting_MyLambert(SurfaceOutput s, float3 lightDir, float atten)
 {
  ;
     return float4(1, 0, 0 , 1);

 }

 

우선 이 3가지로 스탠다드를 바꿔주고 메서드를 만들어준다.

이때 매개변수는 변경하거나 수정할 수 없으며 주어진 대로 사용해야 한다.

 

 

float3 lightDir
조명 방향의 벡터
단, 조명을 편하게 사용하기 위해 뒤집혀지고 길이가 1인 단위 벡터 상태

 

float atten(uation) - 감쇠
그림자를 받거나 거리가 멀어지면 점점 조명이 흐려지는 라이트의 거리별 현상

 

dot : 노멀 벡터와 라이트 벡터를 내적 연산해주는 함수

우리는 o.Normal에 값을 넣지 않았지만 s.Normal의 값을 가져올 수 있다.

 

lightDir

lightDir은 vertex에서 바라보는 조명의 방향을 뒤집은 조명 벡터이므로 두 벡터를 단순히 내적하면 cos값이 나온다.

 

나중에 ambient light 또는 추가라이트를 비출 때 이 음수는 문제를 일으킬수 있는데

이(0아래는 전부 0으로 잘라주는)를 해결해주는 함수 saturate, max가 있다.

saturate
max

이 함수들을 사용하면 빨간선처럼 0보다 작은수는 0으로 지정해준다.

 


 

HalfLambert

 

* 0.5 + 0.5는 마법의 숫자이다.

이 공식은 -1 ~ 1까지의 숫자를 0에서 1까지의 범위로 만들어준다.

그 결과 cos라인을 끌어 올려주어 부드러운 결과 값이 나온다.

 

조명의 색상 or 감쇠를 이용할 수 있다.

ex) final.rgb = ndotl * s.Albedo * _LightColor0.rgb * atten;

 

https://docs.unity3d.com/kr/2021.3/Manual/SL-UnityShaderVariables.html

 

빌트인 셰이더 변수 - Unity 매뉴얼

Unity의 빌트인 포함 파일에는 셰이더에 대한 전역 변수(예: 현재 오브젝트의 변환 매트릭스, 광원 파라미터, 현재 시간 등)가 포함되어 있습니다. 이러한 셰이더 프로그램에서 이러한 전역 변수

docs.unity3d.com

 

이에 따라 조명의 색깔을 변경하고 거리에 따른 그림자를 조절할 수 있다.

https://docs.unity3d.com/kr/530/Manual/StandardShaderMaterialParameterAlbedoColor.html

 

알베도 컬러 및 투명도 - Unity 매뉴얼

Albedo 파라미터는 표면의 베이스 컬러를 제어합니다.

docs.unity3d.com

 

Shader "Custom/fire"
{
    Properties
    {
        _MainTex ("Main Texture", 2D) = "white"{}
        _MainTex2 ("Main Texture2", 2D) = "white"{}
        _Speed("Speed", Range(0,10.0)) = 1
        _BrightNess("BrightNess", Range(0,1)) = 1
        _Color("Color",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}

        CGPROGRAM
        #pragma surface surf Standard alpha:fade
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _MainTex2;
        float _Speed;
        float _BrightNess;
        float _Color;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_MainTex2;
           
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            //데이터 
            float2 d_uv = IN.uv_MainTex2;
            d_uv.y -= _Time.y;
           
            float4 d = tex2D(_MainTex2, d_uv * _Speed);

            //d.rgb
            //d.r => 0 

            //체크 
            float2 c_uv = IN.uv_MainTex;
            float4 c = tex2D(_MainTex, c_uv + d); 

            //체크를 보여주고 있음 
            o.Emission = c.rgb * _BrightNess;
            o.Alpha = c.a ;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 


 

 

 

Shader "Custom/vertexcolor"
{
    Properties
    {
        _MainTex("Main Texture", 2D) = "white"{}
        _MainTex2("Main Texture2", 2D) = "white"{}
        _MainTex3("Main Texture3", 2D) = "white"{}
        _MainTex4("Main Texture4", 2D) = "white"{}
        
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
     

        CGPROGRAM
      
        #pragma surface surf Standard fullforwardshadows

        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _MainTex2;
        sampler2D _MainTex3;
        sampler2D _MainTex4;


        
        struct Input
        {
            float4 color : COLOR;
            float2 uv_MainTex;
            float2 uv_MainTex2;
            float2 uv_MainTex3;
            float2 uv_MainTex4;


        };

       

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
           float4 c =tex2D(_MainTex, IN.uv_MainTex);
           //o.Emission = c.rgb + IN.color.rgb;

           IN.uv_MainTex2 -= _Time.y * 0.2;
           //float2 d_uv2 = IN.uv_MainTex2;
            //d_uv2.y -= _Time.y;
            float4 d = tex2D(_MainTex2,IN.uv_MainTex2);
           o.Emission = lerp(c.r, d.rgb, IN.color.r ); // 보이지 않는 곳을 0 보이는 곳을 1이라고 생각
           

           float4 e = tex2D(_MainTex3, IN.uv_MainTex3);
           o.Emission = lerp(o.Emission, e.rgb, IN.color.g);

           float4 f = tex2D(_MainTex4, IN.uv_MainTex4);
           o.Emission = lerp(o.Emission, f.rgb, IN.color.b);
           
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 


 

Shader "Custom/rock"
{
    Properties
    {
        _MainTex ("Main Texture", 2D) = "white"{}
        _MainTex2 ("Main Texture2", 2D) = "white"{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        CGPROGRAM
        #pragma surface surf Standard
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _MainTex2;

        struct Input
        {
            float4 color : COLOR; //버텍스 컬러 
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            //이끼 
            float4 d = tex2D(_MainTex2, IN.uv_MainTex);
            //돌맹이 
            float4 c = tex2D(_MainTex, IN.uv_MainTex);
            
            //이끼를 버텍스 컬러 R 부분에 출력하자 
            o.Albedo = lerp(c.rgb, d.rgb, IN.color.r);
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 


https://docs.unity3d.com/kr/530/Manual/StandardShaderMaterialParameterMetallic.html

https://docs.unity3d.com/kr/2022.1/Manual/StandardShaderMaterialParameterSmoothness.html

https://docs.unity3d.com/Manual/StandardShaderMaterialParameterNormalMap.html

 

Unity - Manual: Normal map (Bump mapping)

Normal map (Bump mapping) Normal maps are a type of Bump Map. They are a special kind of texture that allow you to add surface detail such as bumps, grooves, and scratches to a model which catch the light as if they are represented by real geometry. Unity

docs.unity3d.com

 

평활도 - Unity 매뉴얼

평활도(Smoothness) 개념은 스페큘러 워크플로우와 메탈릭 워크플로우 모두에 적용되며 매우 비슷한 방식으로 작동합니다. 디폴트로 메탈릭 또는 스페큘러 텍스처 맵이 할당되지 않았다면 슬라이

docs.unity3d.com

 

메탈릭모드: 메탈릭 파라미터 - Unity 매뉴얼

Metallic 워크플로에서 작업하는 경우(스페큘러 워크플로와 달리) 표면의 반사도 및 광원 반응이 메탈릭 레벨과 평활도 레벨에 따라 바뀝니다.

docs.unity3d.com

 

Shader "Custom/Metallic"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _NormalMap ("NormalMap", 2D) = "bump"{}
        _NormalStength("Normal Stength", Range(0.1, 2)) = 0
        _Occlusion("Occlusion", 2D) = "white"{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Standard
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _NormalMap;
        sampler2D _Occlusion;
        float _NormalStength;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        half _Glossiness;
        half _Metallic;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;

            float4 n = tex2D(_NormalMap, IN.uv_NormalMap);
            float3 normal = UnpackNormal(n);
            fixed4 occlusion = tex2D(_Occlusion, IN.uv_MainTex);

            o.Occlusion = occlusion;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;

            o.Normal = float3(normal.x * _NormalStength , normal.y * _NormalStength , normal.z);

            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

Shader "Custom/rockGolem2"
{
    Properties
    {
        _MainTex("MainTex",2D) = "white" {}
        _MainTex2("Left Hand",2D) = "white" {}
        _MainTex3("Right Hand",2D) = "white" {}
        _NormalMap ("NormalMap", 2D) = "bump"{}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _Occlusion ("Occlusion", 2D) = "white"{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
       
        CGPROGRAM
        #pragma surface surf Standard
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _MainTex2;
        sampler2D _MainTex3;
        sampler2D _NormalMap;
        half _Glossiness;
        half _Metallic;
        sampler2D _Occlusion;



        struct Input
        {
            float2 uv_MainTex;
            float2 uv_MainTex2;
            float2 uv_MainTex3;
            float4 color : COLOR;
            float2 uv_NormalMap;
        };
    
        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            //fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
            //o.Albedo = IN.color.rgb;
            //o.Alpha = c.a;
            IN.uv_MainTex2.y += _Time.y * 0.2;
            IN.uv_MainTex3.y += _Time.y * 0.2;
            fixed4 body = tex2D (_MainTex, IN.uv_MainTex);
            fixed4 lHand = tex2D (_MainTex2, IN.uv_MainTex2);
            fixed4 rHand = tex2D (_MainTex3, IN.uv_MainTex3);


            //float2 d_uv2 = IN.uv_MainTex2;
            //d_uv2.y -= _Time.y;




            //o.Albedo = lerp(0, body, IN.color.r);
            o.Albedo = lerp(body, lHand, IN.color.r);
            o.Albedo = lerp(o.Albedo, rHand, IN.color.b);

            float4 n = tex2D(_NormalMap, IN.uv_NormalMap);
            float3 normal = UnpackNormal(n);
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Normal = normal;
            o.Occlusion = tex2D(_Occlusion, IN.uv_MainTex);


        }
        ENDCG
    }
    FallBack "Diffuse"
}

하이어라키에 Sphere 구체 추가

ㅏ이어

폴더를 만든 후 Materials와 Shaders를 추가해준다

그 후

NewSurfaceShader를 New Material로 드래그해서 Assign

그 후

New Material을 Sphere에 드래그해서 Assign

코드 안에 내용들을 지워주는데 Input에 아무것도 없으면 오류가 난다.

이런식으로 프로티에 작성해주면 인스펙터에 생성이된다.

드래그한 코드

즉 o오브젝트에 Albedo를 float3(red, green, blue)를 할당하는데 red에만 1을 선언한 상태와 결과

 

Emission으로 바구면 평면으로 볼 수 있다.

 

Emission에 컬러속성을 할당 한후 값을 넣어주면

인스펙터에서 컬러창으로 색을 변경할 수 있다.

r g b에 각각 red blue green 변수를 선언후 할당한후

pow를 사용 pow(x,y) => x를 y 제곱

Red, Greed, Blue를 각각 이동하여 색을 변경할 수 있다.

BrightDarkness 변수 선언후 + 를 사용해서

Emission값을 flat(r,g,b)와 함께 사용

 

Texture 2D속성을 사용

float4 c = tex2D(_MainTex, IN.uv_MainTex);

그 후 만들어진 텍스쳐 필드에 텍스쳐 할당

https://docs.unity3d.com/Manual/SL-SurfaceShaders.html

 

Unity - Manual: Writing Surface Shaders

Surface Shaders and rendering paths Writing Surface Shaders In the Built-in Render PipelineA series of operations that take the contents of a Scene, and displays them on a screen. Unity lets you choose from pre-built render pipelines, or write your own. Mo

docs.unity3d.com

 

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using System.IO;

public class TangtangMain : MonoBehaviour
{
    void Start()
    {
        TextAsset asset = Resources.Load<TextAsset>("tangtang_data");
        //Debug.Log(asset.text);
        string json = asset.text;
        TangtangData[] datas = JsonConvert.DeserializeObject<TangtangData[]>(json);
        foreach (TangtangData data in datas)
        {
            Debug.LogFormat("{0} {1} {2}", data.id, data.name, data.damage);
        }

        TangtangInfo[] infoArray = new TangtangInfo[datas.Length];
        for (int i = 0; i < datas.Length; i++)
        {
            TangtangData data = datas[i];
            TangtangInfo info = new TangtangInfo(data.damage);
            infoArray[i] = info;
        }

        // 직렬화 시작 (객체 배열 -> 문자열 배열)
        string[] serializedJsonArray = new string[infoArray.Length];
        for (int i = 0; i < infoArray.Length; i++)
        {
            serializedJsonArray[i] = JsonConvert.SerializeObject(infoArray[i]);
        }

        // 파일로 저장 
        // Application.persistentDataPath: 플랫폼 OS에 따라 경로를 자동으로 설정
        string path = Application.persistentDataPath + "/tangtang_info.json";
        Debug.Log(path);
        File.WriteAllLines(path, serializedJsonArray);




    }
}

 

using System;

public class TangtangData
{
      public int id;
      public string name;
      public string damage;
      
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TangtangInfo
{
    public string damage;

    public TangtangInfo(string damage)
    {
        this.damage = damage;
    }
}

'산대특 > 게임 UIUX 프로그래밍' 카테고리의 다른 글

Shader - Vertex  (0) 2024.02.19
Shader 기초  (0) 2024.02.18
Json 역직렬화 -> 직렬화 -> 데이터 저장 -> 경로확인  (0) 2024.02.15
데이터 연동해서 UI 보여주기  (0) 2024.02.13
설날과제 20240212  (0) 2024.02.12

그림에서

name

min_damage

max_damage

item_type

4가지 속성을 가지고 배열을 만들어서 json 파일로저장

 

json파일을 만들때 " "가 중요하다.

 

만들고 나서 Format을 누르면 잘 작성이 됬는지 확인할 수 있다

코드를 작성 후 오류가 나지 않으면 이렇게 생성 된 걸 알 수 있다.

 

그 후 Text를 복사하고 메모장에 저장

저장할 때 주의

 

우선 Unity에 Resources 라는 폴더를 만들고 넣어주면 되는데 이 때 반드시 폴더명을 이렇게 해주어야 한다.

https://www.newtonsoft.com/json

 

Json.NET - Newtonsoft

× PM> Install-Package Newtonsoft.Json or Install via VS Package Management window. ZIP file containing Json.NET assemblies and source code: Json.NET

www.newtonsoft.com

Newtonsoft.Json은 C#에서 JSON 데이터를 처리하는 데 사용되는 강력한 라이브러. 주요 기능은 다음과 같다.

  1. JSON 직렬화(Serialization): C# 객체를 JSON 문자열로 변환합니다.
  2. JSON 역직렬화(Deserialization): JSON 문자열을 C# 객체로 변환합니다.
  3. LINQ를 사용한 JSON 쿼리(Query): LINQ 쿼리를 사용하여 JSON 데이터를 쉽게 쿼리하고 필터링할 수 있습니다.
  4. JSON 스키마(Validation): JSON 데이터가 주어진 스키마에 부합하는지 확인할 수 있습니다.
  5. JSON 파싱(Parsing): JSON 문자열을 해석하고 객체로 변환합니다.
  6. JSON 변환(Transform): JSON 데이터를 다른 형식으로 변환합니다.
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class HelmMain : MonoBehaviour
{
    
    void Start()
    {
        TextAsset asset = Resources.Load<TextAsset>("helm_data");
        string json = asset.text;
        Debug.Log(json);

        HelmData data = JsonConvert.DeserializeObject<HelmData>(json);
        //Debug.Log(data);  
        Debug.LogFormat("{0} {1} {2} {3}", data.name, data.min_damage, data.max_damage, data.item_type);

        //저장
        //직렬화 객체 생성
        HelmInfo info = new HelmInfo(data.min_damage, data.max_damage);
        //직렬화 시작(객체 ->문자열)
        string serializedJson = JsonConvert.SerializeObject(info);

        //파일로 저장
        //Application.persistentDataPath : 플랫폼 OS에 따라 경로를 자동으로 잡아줌
        string path = Application.persistentDataPath + "/helm_info.json";
        Debug.Log(path);
        //문자열을 파일로 저장
        File.WriteAllText(path, serializedJson); //경로, 문자열
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HelmData
{
    public string name;
    public int min_damage;
    public int max_damage;
    public string item_type;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HelmInfo
{
    public int min_damage;
    public int max_damage;

    public HelmInfo(int min_damage, int max_damage)
    {
        this.min_damage = min_damage;
        this.max_damage = max_damage;
    }
}

실행을 시켜보면

1. 데이터를 문자열을 출력

2. 데이터를 역직렬화 후 데이터를 잘 받고 있는지 확인

3. Helminfo클래스를 메인에서 불러온 후 생성자를 생성한뒤 지정한 경로 위치로 생성후 저장 => 그 위치 출력

 

보기와 같이 출력한 경로를 검색하면 지정된 경로에 파일이 저장됨을 확인 할 수 있다.

jsonviewer 사이트를 이용해서 json을 작성 후 format 누르면 제대로 만들어졌는지 유효성 확인이 된다.

그럼 메모장에 복사 후 이와 같이 저장한 다음 만들어둔 Resources 폴더로 저장

주의점 : 폴더명은 Resources여야 한다.

 

빈오브젝트 생성 후 스크립트 할당

json이 유니티에 들어갈 때 텍스트에셋으로 바뀜을 확인할 수 있다.

 

 

텍스트에셋이 잘 받아졌는지 확인

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft;
using Newtonsoft.Json;
public class Test6Main : MonoBehaviour
{
    void Start()
    {
        TextAsset asset = Resources.Load<TextAsset>("nation_data");
        Debug.Log(asset);
    }
}

 

역직렬할 매핑클래스 생성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NationData
{
    public string nation;
    public int population;
    public string religion;
}

중요한 것은 여기는 비모노이기에 상속받는 : Monobehaviour를 제거

 

이제 역직렬화를 해주고 출력되는지 확인할 것이다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft;
using Newtonsoft.Json;
public class Test6Main : MonoBehaviour
{
    void Start()
    {
        TextAsset asset = Resources.Load<TextAsset>("nation_data");
        //Debug.Log(asset);
        string json = asset.text;
        Debug.Log(json);
        //역직렬화
        NationData data = JsonConvert.DeserializeObject<NationData>(json);
        Debug.LogFormat("nation : {0}", data.nation);
        Debug.LogFormat("population : {0}", data.population);
        Debug.LogFormat("religion : {0}", data.religion);
    }

}

아틀라스를 만들어서 국기들을 넣어준다.

 

하다가 무언가 잘못됨을 느꼈다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using UnityEngine.U2D;
public class NationDataCellView : MonoBehaviour
{
    [SerializeField] private SpriteAtlas atlas;
    [SerializeField] private Image nation;
    [SerializeField] private TMP_Text populationText;
    [SerializeField] private TMP_Text religionText;

    public void Init(NationData data)
    {
        this.nation.sprite = atlas.GetSprite(data.nation);
        this.populationText.text = string.Format("{0}", data.population);
        this.religionText.text = data.religion;
    }

    
   
}

Atlas를 사용하여

this.imgIcon.sprite = atlas.GetSprite(data.icon)

이런식으로 이미지를 할당해주어야 하는데

json파일에 이미지를 넣을 공간을 만들지 않았다는 것이다.

 

json을 다시 만들어서 실행해 보아야겠다.

+ Recent posts