본문 바로가기
카테고리 없음

아티스트를 위한 URP 셰이더 Shader #5 - URP 셰이더 색상 연산 (코드버전)

by 대마왕J 2021. 7. 26.

이번엔 앞에서 해본걸 코드로 해 봅시다. 
여기서 코딩 기본을 설명할 생각은.. 사실 없어요. 그럼 너무 길어짐
만약 굳이 알고 싶다면 ... 이론을 공부하시고 싶으시다면

https://book.naver.com/bookdb/book_detail.nhn?bid=12518820 
를 읽고 오는 것을 추천드린다고 했었잖아요? 후후후 

후후후 여유로운 책광고 타임

 

유니티 쉐이더 스타트업

『유니티 쉐이더 스타트업』은 프로그래밍으로 완성해야 하는 쉐이더의 구현을 아티스트들의 역량으로도 충분히 발휘할 수 있도록 도움을 주는 책입니다. 저자의 오랜 게임그래픽 실무경험과

book.naver.com

그럼 이제부터는 저 책을 한 번 가볍게 떼신 분을 위해 써 보도록 하겠습니다. 

 


 URP 셰이더 기본 

URP 셰이더는 이전에 말씀드린대로, 레거시의 서피스 셰이더를 버리고 정통파의 HLSL(High Level Shader Language) 방식의 셰이더를 채택했어요. 뭐 사실 그래도 ShaderLab이라고 하는 유니티 스크립트 껍데기 사이에 감싸진 HLSL 이지만 말이죠

이걸 다시 보실 때가 되었군요. 저기서 Pass 안의 HLSLPROGRAM ~ ENDHLSL 까지가 진짜 셰이더 코드고요, 
나머지는 다 'ShaderLab' 이라 불리는 유니티 자체 스크립트입니다. 

여기 말이죠. 그래서 여기 안에서는 전부 구문마다 ; 가 붙어 있지요? 밖에는 없는데 말이죠. 
즉 저 영역 안이 진짜 셰이더 코드라는 것을 알 수 있습니다. 

이렇게 유니티 자체 스크립트인 ShaderLab으로 짜는 방식으로 하면 좋은건, 유니티의 특성인 '멀티 플렛폼' 에 대응되기 좋은 방식입니다. 우리가 이 방식으로 하나만 짜두면, 유니티가 알아서 여러 플렛폼 (엑박이나 모바일, PC , 맥, PS4, 스위치 등등) 의 셰이더를 자동으로 변환 생성해 주기 때문이죠 

이 안의 내용은 
https://chulin28ho.tistory.com/644 

 

아티스트를 위한 URP 셰이더 Shader #1

셰이더 처음 만들기 (노드버전) 그럼 맨 먼저 시작해 보죠. 이론 같은거야 좋은 책들이 많을테고, 여기 오시 분들은 그래요.. 서론 싫어하는거 다 안다고요... 하긴 저도 유투브에서 5분 설명할거

chulin28ho.tistory.com

글의 주석을 참고하시면 도움이 될 겁니다. 

뭐 그렇지만 위 글에서 설명하고 있는 주석들을 쬐끔만 더 자세히 볼까요 

 


#pragma

셰이더는 기본적으로 vertex 셰이더와 fragment 셰이더로 이루어져 있습니다. fragment  셰이더는 'pixel' 셰이더라고도 부르는데, 이게 더 알아듣긴 편할지도 모르겠어요. 
어쨌건 저기는,  

지금부터 vertex 셰이더 함수 이름은 vert 로 하겠다.
그리고 fragment 셰이더 함수 이름은 frag로 하겠다 

 

라고 써 있는 겁니다. 이렇게 맨 처음에 선언해 주도록 되어 있어요. 

뭐 기초이므로 이 사이에 있는 지오메트리나 헐 도메인 그런건 패스.. 

 


#include

다음은 include 인데요, 저 인클루드에 선언되어 있는 코드를 찾아가서 직접 보면 
와... 

이런 코드가 열리는데요, 즉 이건 이 긴 코드가 우리 코드에 포함된다 (include) 된다는 얘기입니다. 
각종 선언이나 함수명 등등이 정의되어 있지요. 게다가 저 위에 보면 또 #include 들이 보입니다. 즉 저기에 있는 수많은 코드들도 다 같이 주렁주렁 보따리에 싸서 가지고 오겠다는 뜻. 

 

우리가 셰이더에서 편하게 쓸 수 있는 각종 변수나 함수, 선언들이 주렁주렁 선물보따리로 묶여서 가지고 들어오겠다  라는 뜻입니다.

 

 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
이 한 줄에 말이죠. 
매우 파워풀하고 든든한 동료가 생긴 느낌적인 느낌!!! 

내 코드에 흑염룡이 있다

 

 

 

 


struct Attributes -> vert -> struct Varings -> frag

자 그 다음은 버텍스의 입력구조체 -> 버텍스 셰이더 -> 버텍스 출력구조체 -> 프레그먼트(픽셀) 셰이더 의 구조를 볼께염. 구조체는 잘 모르겠으면 '보따리' 나 '가방 ' 정도로 생각하면 쉽습니다. 안에 쓸모있는게 잔뜩 들어 있는.


일단 버텍스가 가지는 데이터는 일반적으로 인덱스, 위치, 노말, 탄젠트, 칼라, UV(Texcoord) 들인데, 
지금은 기초이므로 버텍스에게서 Position 만 받아와서 Attributes 라고 하는 구조체에 넣어 놨습니다. 나중에는 다른것도 많이 쓸 거예염. 

 
그리고 이 구조체는 Vetex Shader 함수의 입력값, IN으로 들어갑니다.


이제 버텍스 셰이더에서 이 구조체 안의 정보를 사용하려면 IN.을 쓰고 정보를 부르면 되는 겁니다. IN.positionOS 처럼 말이죠. 이름앞에 호 붙이는 느낌으로 

그리고 지금은 IN.positionOS.xyz 를 받아와서, TransformObjectToHClip 함수를 통해 Position을 homogenous clip space 로 바로 변환한 것을 볼 수 있습니다.  (버텍스의 오브젝트 -> 월드 -> 뷰 -> 프로젝션 좌표계 변환입니다. 마지막 공간을 클립스페이스라고도 하지요. ...  자세한 이론은 역시 책을 참고하세요 ) 

그리고 버텍스 셰이더에서 계산이 끝난 값을 받아올 Varyings 라는 구조체를 만들고, 

버텍스 셰이더는 이 구조체에 OUT 하도록 만들어 주는 겁니다. 
이 Varyings 구조체에 나중에 추가적인 값을 버텍스 셰이더에서 연산해서 넣어주면 fragment 셰이더에서도 받아올 수 있습니다. 지금은 뭐 받아올게 없네요 .

그래서 fragment 셰이더 함수의 입력값은 비어 있습니다. 받아올게 없으니까요. 
즉 버텍스 셰이더는 가장 기본적인, 없으면 안되는 , 버텍스 포지션 변환만 완료한거고 
픽셀 셰이더 (fragment Shader) 에서는 customColor 라고 하는 float4 변수를 만들어서 0.5, 0, 0, 1 이라고 하는 '약간 어둡게 붉으면서 불투명한 ' 색을 만들어서 return으로 출력하게 되는 것입니다. 

프로그래밍 기본은 안다고 생각하고 설명하였습니다. 역시 책을 한 번 대충이라도 떼셨다고 생각을... 

 


 

색의 연산 

이제 다시 간단하게 색 연산을 해 보겠습니다. 
뭐,  이건 너무 간단해서 금방 하겠네요 

자 일단 frag( ) 함수가 픽셀셰이더이므로 오늘 볼 건 여기뿐입니다. 

half4 frag() : SV_Target
            {     
                           
                return half4(1,0,0,1);
            }

일단 이렇게 해 놓고 시작할께요. 

출력은  half4 로 해야 하니까, 1,0,0,1 로 하면 RGBA 순서라 붉은색에 불투명 - 어차피 알파는 지금 가동되지도 않겠지만 - 입니다. 그럼 이 셰이더를 적용하면 붉은 공이 나오겠지요 ? 잘 나옵니다. 좋아요 좋아요 

자 그러면 이번엔 회색을 출력해 보기로 해요. 

half4 frag() : SV_Target
            {
                half4 graycol = half4(0.5,0.5,0.5,1);    

                return graycol;
            }

오호라 확실히, 리니어 회색이라서 우리가 일반적으로 알고 있던 회색보다 밝아요. 그렇죠? 
이전시간 감마 얘기를 생각해 보시면 무슨 말인지 아실겁니다. 

리니어가 아닌, 우리가 아는 감마 적용된 회색을 굳이 만들어 보시려면 
half4 frag() : SV_Target {
                half4 graycol = half4(0.5,0.5,0.5,1);
                return pow(graycol, 2.2);
            }
요렇게 하심 됨다.
와 어둡다

그러므로 사칙연산은 심하게 간단하게 됩니다. 칼라 노드 같은게 없어서욤.

 

 

덧셈 

회색 + 회색은 흰색이고요

half4 frag() : SV_Target
            {
                half4 graycol = half4(0.5,0.5,0.5,1);
                half4 finalcol = graycol + graycol;    

                return finalcol;
            }

빨강 + 노랑은 노랑(으로 보입니다) 
하지만 숫자로는 half4(1,0,0,1) + half4(1,1,0,1) 이므로
half4(2,1,0,2) 가 되어 있겠지요. 1 이상은 모니터에서 안 보일뿐 (알파 채널은 아예 가동도 안되는 상태이고) 이지만.  

half4 frag() : SV_Target
            {
                half4 redcol = half4(1,0,0,1);
                half4 yellowcol = half4(1,1,0,1);
                half4 finalcol = redcol + yellowcol;    

                return finalcol;
            }

하지만 1이 넘은 상태이므로, HDR Bloom을 가동시키면 빛나게 됩니다. 빠밤

야호 반짝

 

 

곱셈

회색 * 회색은 어두운 회색이겠지요 half4(0.5,0.5,0.5,1) * half4(0.5,0.5,0.5,1) = half4(0.25,0.25,0.25,1)

half4 frag() : SV_Target
            {
                half4 graycol = half4(0.5,0.5,0.5,1);
                half4 finalcol = graycol * graycol;  

                return finalcol;
            }

헤에 리니어 회색은 밝아 보이니까 어두워진 회색도 좀 밝은 느낌이네요. 그 근데 이게 맞겠... 지요? 맞는거다 이게 진짜다 이게 진짜라고.. 

계속 보다 보니 이게 진짜 회색같다 

빨강.. 노랑은 뭐.. half4(1,0,0,1) * half4(1,1,0,1) = half4(1,0,0,1) 빨강이 되네요?!?

half4 frag() : SV_Target
            {
                half4 redcol = half4(1,0,0,1);
                half4 yellowcol = half4(1,1,0,1);
 
                half4 finalcol = redcol * yellowcol;  

                return finalcol;
            }

 

뺄셈과 나눗셈

뺄셈과 나눗셈.. 은 뭐 동일하니까 생략합니다. 원리 똑같아요.  이건 숙제로 내볼께요. 
사실 계산중 85% 확률로 덧셈과 곱셈만 함 (...) 

자 그럼 오늘은 여기까지! 

블로그 주인장에게 커피값을 후원할 수 있습니다! 

donaricano-btn

반응형

댓글