전체 글 (46)
유니티 쉐이더 - 블린퐁

블린 퐁은 퐁쉐이딩을 간단화한 공식이다.

 

퐁 쉐이딩은 다루지 않을 예정이니 간단하게 말하고 넘어가면

 

"내가 보는 방향으로부터 반사된 방향에 조명이 잇으면 그 부분의 하이라이트가 가장 높다"

라는 것이 퐁 쉐이딩의 이론이다.

 

그래서 퐁 쉐이딩은 넘어가고

 

블린 퐁 쉐이딩이라니는 퐁쉐이딩을 간단화한 공식은

H = normalize(lightDir+viewDir):이다 ( 벡터의 방향은 위의 그림과같음 )

 

빛의 강도는

float specLightPower = pow(saturate(dot(H,surface의 NomalVector)),원하는 강도); 이고

빛의 표현은 이렇게 해주면되고

float3 specColor = specColor(입력값)*specLightPower;

 

float4 finalColor = float4(디퓨즈 컬러 + specColor,surface의 알파값);

 

을 해주면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Shader "Custom/BlinPhong"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _BumpMap("NormalMap",2D) = "bump"{}
        _SpecCol("Specular Color", Color) = (1,1,1,1)
        _SpecPow("Specular Pow",Range(10,100)) = 100
    }
            SubShader
            {
                Tags { "RenderType" = "Opaque" }
                LOD 200
 
                CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf Test
 
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
            
        sampler2D _MainTex;
        sampler2D _BumpMap;
        struct Input
        {
            float2 uv_MainTex;
            float2 uv_BumpMap;
        };
        float4 _SpecCol;
        float _SpecPow;
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        float4 LightingTest(SurfaceOutput s, float3 lightDir, float3 viewDir,float atten)
        {
            float nDot = saturate(dot(s.Normal, lightDir));
            float4 diffuse;
            diffuse.rgb= nDot * s.Albedo*_LightColor0.rgb*atten;
            
            float3 h = normalize(lightDir + viewDir);
            float specDot = saturate(dot(h,s.Normal));
            specDot = pow(specDot, _SpecPow);
            float3 specColor = specDot* _SpecCol.rgb;
 
            float4 final;
            final.rgb = diffuse.rgb + specColor.rgb;
            final.a = s.Alpha;
 
            return final;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 
그래서 코딩을 하면 이런식으로 코딩할 수 있다.
참고로 Surface 쉐이딩을 할때,
커스텀 라이팅을 쓰려면 
pragma 부분에 surf 다음에 원하는 이름을 넣고, 커스텀 라이팅 함수이름을
Lighting+prgma부분에서 지정한 이름 을 넣어주면 된다.

그리고 매개변수는 항상 정해져있고 ( 갯수에 따라 다른게 오버로딩 된다)

아래를 가보면 정확하게 알 수 있다.

https://docs.unity3d.com/kr/2018.4/Manual/SL-SurfaceShaderLighting.html

 

 

 

아래는 완성된 스페큘러 + 디퓨즈

 

 

 

  Comments,     Trackbacks
Unity Shader 공부- 림라이트

림라이트는 저렇게 경계면에서 빛나는 듯한 연출을 할때 사용되는 빛이다.

 

게임에서 보면 이렇다

그래서 오늘은 림라이트를 만들어 볼건데..

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Shader "Custom/RimShader"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _BumpMap("NormalMap",2D) = "bump"{}
        _RimColor("RimColor", Color) = (1,1,1,1)
        _RimPower("RimPower",Range(1,10))=3
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
       
 
        CGPROGRAM 
        #pragma surface surf Lambert noambient
 
 
        sampler2D _MainTex;
        sampler2D _BumpMap;
        float4 _RimColor;
        float _RimPower;
        
        struct Input
        {
            float2 uv_MainTex;
            float2 uv_Bump;
            float3 viewDir;
        };
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);//우선 uv에 텍스처를 입힌다.
            o.Albedo = c.rgb;
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_Bump));//노멀맵을 뽑아내서 나중에 빛계산을 위해 노말을 뽑아놓음
            float lightPower = dot(o.Normal, IN.viewDir);//노멀맵에 ViewDir를 내적하면 해당 버텍스의 빛의 세기가 나온다.
            //o.Emission = pow(1 - lightPower, _RimPower) * _RimColor.rgb; //1-lightPower을 해서 빛을 역전시켜줌,거기에 _RimPower만큼 제곱
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

우선 림을 적용시키지 않고 기본적인 람버트 쉐이딩으로 표현하면

요론식으로 된다.

그리고 이때 Rim을 적용시키면? *위의 코드에서 주석만 제거*

 

오웅 이렇게 후광있는듯이 가능해진다.

 

여기까지 아주 간단한 림라이트였고, 이거로 홀로그램을 만들어 보려한다.

 

참고로 o.Emission은 자체적으로 방출하는 색상으로

 

Albedo에 + 되는 색상이다.

그러므로 o.Emission에 림값을 넣어줌으로써 저렇게 경계면이 하얗게 올라오는 것

 

 

 

이걸 응용해서 홀로그램을 만들 수 있는데.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Shader "Custom/RimShader"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        //_BumpMap("NormalMap",2D) = "bump"{}[제거]
        _RimColor("RimColor", Color) = (1,1,1,1)
        _RimPower("RimPower",Range(1,10))=3
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue" = "Transparent" }
       
 
        CGPROGRAM 
        #pragma surface surf Lambert noambient alpha:fade//[변환]
 
 
        sampler2D _MainTex;
        //sampler2D _BumpMap;[제거]
        float4 _RimColor;
        float _RimPower;
        
        struct Input
        {
            float2 uv_MainTex;
            //float2 uv_Bump; [제거]
            float3 viewDir;
        };
 
        void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);//우선 uv에 텍스처를 입힌다.
            //o.Albedo = c.rgb;[제거]
            //o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_Bump));[제거]
            float lightPower = dot(o.Normal, IN.viewDir);//노멀맵에 ViewDir를 내적하면 해당 버텍스의 빛의 세기가 나온다.
            float rim = pow(1 - lightPower, _RimPower);//1-lightPower을 해서 빛을 역전시켜줌,거기에 _RimPower만큼 
            o.Emission = _RimColor.rgb;
            o.Alpha = rim;//라이트 파워만큼의 알파
        }
        ENDCG
    }
    FallBack "Diffuse"
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

일단은 제거하고 변경해준다. (위처럼)

오오.. 그럼 이렇게 albedo는 투명하게 나오고 Rim이 처리된 부분만 보이는 투명물질이 만들어진다!

 

그리고 여기서 홀로그램같은 느낌을 표현하려면

 

우선 연출을 위한 코드를 구현해야하는데

1
2
o.Emission = frac(IN.worldPos.g);
o.Alpha = 1;//라이트 파워만큼의 알파
 

 우선 Emission 부분을 이런식으로 바꿔보자

frac 내장함수는 소수점 부분만을 표현하는 것이다 즉0~1사이라는 것.

 

그렇다면 오브젝트의 월드좌표에서 y값이 0일시 저런식으로 표현된다.

하얀색이 끝나는부분이 (??,1,??) 인 것.

 

1
o.Emission = pow(frac(IN.worldPos.g*3),30);
 

이 코드에 대해 확실히 알았다면 *3을 해줬을때 컬러의 0~1사이 값을 표현하는게 더 많아 지는 것을 눈치 챌 수 있을거고,

pow를 해주면 림라이트에서 더 경계면쪽으로 색상이 모여들었듯이

 

1아래의 값들이 좀더 작아지면서 어두운 부분이 더 많아 지는것을 눈치 챌것이다.

1
2
3
4
5
6
7
8
void surf (Input IN, inout SurfaceOutput o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);//우선 uv에 텍스처를 입힌다.
            float lightPower = dot(o.Normal, IN.viewDir);//노멀맵에 ViewDir를 내적하면 해당 버텍스의 빛의 세기가 나온다.
            float rim = pow(1 - lightPower, _RimPower)+ pow(frac(IN.worldPos.g * 3 - _Time.y), 30);//1-lightPower을 해서 빛을 역전시켜줌,거기에 _RimPower만큼 
            o.Emission = _RimColor;
            o.Alpha = rim;//라이트 파워만큼의 알파
        }
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

 

그리고 색상을 결정할 때 _Time.y 만큼 빼주면 흰선들이 올라가는걸 표현할 수 있고 Rim에다가 더해주고

아까처럼 코드를 바꿔주면

요로코롬 된다.

 

노멀맵을 적용 시켜주면

완성!

 

역시 쉐이더는 보이는게 있어서 재미있다.

 

내일은 블린퐁 만들어봐야징

  Comments,     Trackbacks
마야로 드래곤 만들기

 

커여운 드래곤과 애니메이션을 만들어 보았다 ㅎㅎ

'3D아트 > 마야' 카테고리의 다른 글

풀바디 IK  (0) 2020.05.10
마야 1일차 (2) - 마야로 팔만들기!  (0) 2020.03.30
마야 1일차 그룹화와 부모!  (0) 2020.03.30
  Comments,     Trackbacks
2020-04-07 그림 모작 러프 끄적끄저

 

이제보니 오른쪽 눈이 좀 올라간거같넹..

귀찮아서 다른 그림으로 넘어감 ㅎㅎ

'아트 > 끄적끄적' 카테고리의 다른 글

2020-05-07 황리코 그림  (0) 2020.05.07
2020-04-02 모작!  (0) 2020.04.02
2020-03-21 그림 모작  (0) 2020.03.21
2020-01-28 그림 공부  (0) 2020.01.29
  Comments,     Trackbacks
유니티 쉐이더 공부 - 디퓨즈 , 앰비언트 , 스페큘러 , 텍스처 구현

오늘의 실험체가 될 오리쿤

오늘은 커스텀으로 디퓨즈, 앰비언트 , 스페큘러를 텍스처맵핑을 구현해보려한다.

 

가르쳐주는 블로그가아닌 공부하는 블로그이기 때문에 자세한 내용은 생략하고,

 

우선 차근차근 텍스처부터 씌워보도록 하겠다

 

유니티 Defalut 텍스처가 입혀져있는 오리쿤

위의 모델에 텍스처를 입히려면 일단 머테리얼이 필요한데

일단 DuckMat 머테리얼과 DuckShader라는 언릿 쉐이더를 추가해보았다. 당연히 DuckMat는 DuckShader를 사용

기본 Shader구성

기본적으로 세팅되있는 쉐이더를 깔끔하게 Fog 설정부분을 삭제해준뒤에.. vert frag 쉐이더를 보면..

이와 같은 걸 볼 수 있다.

 _MainTex는 프로퍼티에서 받아온 텍스처!

 

결국 이 부분이 텍스처를 넣는 부분이라는 것!

appdata 의 uv 좌표에 texture를 씌어넣는 작업이

o.uv = TRNASFORM_TEX(v.uv, _MainTex);이고

 

마지막으로 frag쉐이더에서

tex2D(_MainTex, i.uv);를 해줌으로써 해당 픽셀의 색상에 텍스처의 해당 픽셀 색상을 집어넣음으로서 결정!

 

참고 : _MainTex_ST 라는 프로퍼티에 추가도 하지 않은 변수가 있는데 이게 TRNSFORM_TEX를 사용하기 위해 존재한다고합니당 ㅇㅇ 일단 초보니까 넘어가도록 하죵

 

이제 디퓨즈,앰비언트를 계산해보자!

 

디퓨즈를 사용하기 위해선

 

우선 빛의 방향, 노멀벡터 가 필요 ( 빛의 밝기를 정하기 위해서)

 

vert 쉐이더에서

 

worldNormal = float3 worldNormal = UnityObjectToWorldNormal(v.normal);

// 월드 노멀벡터계산
o.worldNormal = worldNormal;
o.vertexWorld = mul(unity_ObjectToWorld, v.vertex);

//mul함수는 두행렬의 곱을 계산하는 것 unity_ObjectToWorld는 오브젝트의 모델행렬

 

frag 쉐이더에서

 

float3 normalVector = normalize(i.worldNormal);
float3 lightDirection = normalize(UnityWorldSpaceLightDir(i.vertexWorld));

 

float nl = max(0.0f, dot(lightDirection, normalVector)); //위를 통해서 밝기를 찾아내서
float diffuseTerm = nl*_Color*tex*_LightColor0;//디퓨즈의 컬러를 구한다!

 

_LightColoor0는 셰이더 내장 변수로 lightColor를 반환함

출처)

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

 

유니티 - 매뉴얼: Built-in shader variables

Built-in shader helper functions Making multiple shader program variants Built-in shader variables Unity provides a handful of built-in global variables for your shaders: things like current object’s transformation matrices, light parameters, current time

docs.unity3d.com

 

디퓨즈는 이대로 되었고

 

다음은 앰비언트인데 앰비언트는 cutOff의 역할을 수행한다고한다 ( 조명이 없어도 최소밝기 )

그래서


float nl = max(_Ambient, dot(lightDirection, normalVector));

 

프로퍼티에_Ambient라는 Range(0,1)값을 추가해서 이런식으로 디퓨즈에서 사용하면 된다.

 

위의 코드를 수행하고나면??

 

오오.. 영롱하군여

앰비언트 값을 변경해주면 이렇게된다

 

이제 마지막으로 스펙큘러!

 

스펙큘러는 퐁쉐이딩을 사용할 예정이고

 

프로퍼티에 추가해야할 값

_Shininess("Shininess", Float) = 10.0
_SpecCol ("SpecColor", Color) = (1,1,1,1)

 

frag 쉐이더에서 처리해줘야할 일


float3 reflectDirection = normalize(reflect(-lightDirection, normalVector));

//정반사 빛의 방향
float3 specularNL = max(0.0, dot(viewDirection, reflectDirection));

//해당 frag의 정반사된 빛의 밝기
float3 specular = pow(specularNL, _Shininess);

//원하는만큼 제곱해서 더밝게하기
float4 specularTerm = float4(specular, 1.0f)*_SpecCol * _LightColor0;

//결과

 

//참고로 specularNL과 specular는 원래 float만 해도되는데 내가 공부했던 책에는 이렇게 되있어서 올림..

float specularNL = max(0.0f, dot(viewDirection, reflectDirection));
float specular = pow(specularNL, _Shininess);

float4 specularTerm = specular *_SpecCol * _LightColor0;

이렇게해도 상관없음

 

요로코롬 해주면?

 

float4 finalCol = diffuseTerm+specularTerm;
                return finalCol;

해줬을시에

 

완성!

 

역시 쉐이더쪽은 뭔가 보이는게 확실해서 너무 재밌는거같다

 

 

 

번외) 다중 라이팅을 지원하려면 어떻게해야하는가??

오른쪽이 다중라이팅을 지원하지 않는 지금까지 만든 쉐이더이고

왼쪽은 다중라이팅을 지원하는 쉐이더이다.

 

이를 만드려면

기존 페스에
#pragma multi_compile_fwdbase를 추가하고

 

 새로운 페스를 추가하고 복붙한뒤에

"LightMode" = "FowardBase" -> "LightMode" = " ForwardAdd"

Blend One One

#pragma multi_compile_fwdadd

을 추가한 뒤

새로운 페스의 디퓨즈값에 Ambient값을 0.0으로 해주면 된다.

 

'개발 > 쉐이더' 카테고리의 다른 글

노드 툰 쉐이더 멀티라이팅  (0) 2020.06.26
유니티 쉐이더 - 툰 쉐이더  (0) 2020.05.08
유니티 쉐이더 - 블린퐁  (0) 2020.05.04
Unity Shader 공부- 림라이트  (0) 2020.05.04
유니티 쉐이더 공부 - 각종 빛  (0) 2020.04.02
  Comments,     Trackbacks
유니티 쉐이더 공부 - 각종 빛

실제 빛

실제 빛은 x라는 표면에 w방향 마다 모든 빛을 계산해야하지만 이는 연산이 너무많아서..

컴퓨터에서는 근사값으로 처리한다.

 

 

컴퓨터 빛의 종류

디퓨즈-다양항 방향으로 빛을 나타냄(반사)

스펙큘러-특정 방향으로 빛을 나타냄(반사)

엠비언트-씬안에서의 최소의 빛강도

 

 

 

 

밝기를 계산하는 방법

Float brightness = cos(입사각)

Float brightness = dot(normal,lightDir) //중요!

->증명

->Dot(a,b) = |a||b|cos(입사각)  [ |a||b| 가 노멀라이즈되서 1이기 때문에 ] normallightDir의 내적은 cos(입사각)과 같고 밝기와 같다

 

 

위의 확률은 각도에따라 빛이 얼마나 반사되는지를 말해준다.

0도일 때 100%라면 당연히 cos이겠지? 이런식으로 외워두면 좋을것 같다.

 

Vec3 normal = normalize(Normal);

Vec3 lightDir = normalize(lightPos – FragPos);

아까 위에서 말한 밝기 계산공식중

Float brightness = dot(normal,lightDir);

 

아까 위에서도 말했지만 중요하니 다시말하자면 Dot(a,b) = |a||b|cos(입사각)  [ |a||b| 가 노멀라이즈되서 1이기 때문에 ] normallightDir의 내적은 cos(입사각)과 같고 밝기와 같다

 

  Comments,     Trackbacks
2020-04-02 모작!

 

넘 오래걸렸다..ㅠㅠ

'아트 > 끄적끄적' 카테고리의 다른 글

2020-05-07 황리코 그림  (0) 2020.05.07
2020-04-07 그림 모작 러프 끄적끄저  (0) 2020.04.07
2020-03-21 그림 모작  (0) 2020.03.21
2020-01-28 그림 공부  (0) 2020.01.29
  Comments,     Trackbacks
마야 1일차 (2) - 마야로 팔만들기!

 

미리 만들어 놓은 오브젝트들

왼쪽을 보면 Upper_Arm으로 부터 차례로 자식이 되어있다.

 

그래서 오브젝트가 만들어 졌으니 피봇포인트를 정해야하는데!

 

요론식으로 피봇을 옮겨주어야 잘 작동된다.

 

왜 인지는 애니메이션 조금만 만져보면 알겠지만

 

저 피봇을 축으로 회전을 하기때문! 피봇이 중간에 있으면 팔이 해체되겟죵?

 

피봇은 객체를 누른 상태에서 'd'를 누르면 움직일 수 있다.

 

그래서 다 조정해준다.

 

그리고 대충 애니메이션을 만들어주면?

요론느낌으로 관절에서 움직이는 팔을 만들수있다!

'3D아트 > 마야' 카테고리의 다른 글

풀바디 IK  (0) 2020.05.10
마야로 드래곤 만들기  (0) 2020.04.17
마야 1일차 그룹화와 부모!  (0) 2020.03.30
  Comments,     Trackbacks