성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] How can I tell whether two programs...
[정성태] The case of the fail-fast crashes c...
[정성태] Creating Docker multi-arch images f...
[정성태] BinaryFormatter removed from .NET 9...
[정성태] Extending the Windows Shell Progres...
[우광현] 와..... 범위를 잡았으니 클라이언트가 해당 범위를 확인해본다...
[정성태] 딱히, 그것 이상으로 더 설명할 내용이 없습니다. 동적 포...
[정성태] If Windows 3.11 required a 32-bit p...
[정성태] What is a hard error, and what make...
[괴물신인] 질문작성자인데 이 글을 이제봤네요 ㄷㄷ 이 글처럼 타입별로 인...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Unity Shader - Texture의 UV 좌표에 대응하는 Pixel 좌표</h1> <p> 간단하게 예를 들어서, 0 ~ 1 사이로 정규화되어 있는 UV 좌표계에서 0.1에 해당하는 texture의 pixel(x,y) 위치를 알고 싶다는 것입니다. 이것은 UV 좌표계의 의미를 알면 유추해 낼 수 있습니다.<br /> <br /> 가령, 가로 1024 * 세로 768 이미지의 texture를 (0,0) ~ (1,1) UV 좌표로 매핑한 경우 다음과 같은 의미를 갖게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > u pixel 0 -> 0 1 -> 1024 v pixel 0 -> 0 1 -> 768 </pre> <br /> 따라서, 다음과 같은 비율로 알아낼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > u:x = 1:1024 v:y = 1:768 </pre> <br /> 만약 그중에 (0.1, 0.7) uv 좌표 값을 가지고 있다면 이것을 pixel 위치로 환산하면 다음과 같이 계산할 수 있습니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> 0.1:x = 1:1024<br /> x = 1024 * 0.1 = 102.4<br /> = width of texture * u<br /> <br /> 0.7:y = 1:768<br /> y = 768 * 0.7 = 537.6<br /> = height of texture * v<br /> <br /> uv(0.1, 0.7) == xy(102.4, 537.6) ≈ (102, 538)<br /> </div><br /> <br /> 실제로 그런지 Unity에서 지구본을 texture로 사용했던 예제를 보겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Unity로 실습하는 Shader ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11607'>http://www.sysnet.pe.kr/2/0/11607</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Shader "My/basicShader" { Properties { _MainTex("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } <span style='color: blue; font-weight: bold'>sampler2D _MainTex; fixed4 frag(v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; }</span> ENDCG } } } </pre> <br /> 그러니까, 위의 tex2D 함수는 2048 * 1024 크기의 지구 이미지를 texture로 사용했을 때, uv 좌표에 해당하는 texture의 컬러를 구해주고 있는 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > fixed4 frag(v2f i) : SV_Target { fixed4 col = <span style='color: blue; font-weight: bold'>tex2D(_MainTex, i.uv);</span> return col; } </pre> <br /> 만약, 현재의 i.uv가 가리키고 있는 좌표보다 u 값으로 +10 pixel에 해당하는 컬러 값을 사용하고 싶다면 다음과 같이 하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > fixed4 frag(v2f i) : SV_Target { float uPerX = 1.0 / 2048; // 1 / width float vPerY = 1.0 / 1024; // 1 / height <span style='color: blue; font-weight: bold'>float uOffset = 10 * uPerX;</span> <span style='color: blue; font-weight: bold'>float vOffset = 0 * vPerY;</span> float2 nextUVOffset = <span style='color: blue; font-weight: bold'>float2(uOffset, vOffset);</span> fixed4 col = tex2D(_MainTex, <span style='color: blue; font-weight: bold'>i.uv + nextUVOffset</span>); return col; } </pre> <br /> 저렇게 하면, 지구본이 +10 픽셀만큼 회전한 것처럼 보입니다. 또는, u 값으로 +2048 pixel을 준다면 어떻게 될까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > float uOffset = 2048 * xPerU; </pre> <br /> 결국 제자리로 오기 때문에 화면에는 아무런 변화가 없습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, shader 코드에 2048, 1024이라고 하드 코딩을 하는 것이 좀 그렇군요. ^^ 이것을 없애려면 Properties 영역으로 옮겨 변수 처리를 하면 됩니다. 물론 그래도 되지만, Unity에서는 "_TexelSize"라는 접미사를 붙이면 해당 텍스처의 width, height를 담고 있는 값을 알아서 전달해 줍니다.<br /> <br /> 예를 들어, 위의 코드에서는 텍스처 변수 명이 "_MainTex"였으므로 다음과 같이 선언해 주면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > float2 _MainTex<span style='color: blue; font-weight: bold'>_TexelSize</span>; </pre> <br /> 그리고 그 변수의 값은 각각 다음과 같이 설정이 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Accessing shader properties in Cg/HLSL ; <a target='tab' href='https://docs.unity3d.com/Manual/SL-PropertiesInPrograms.html'>https://docs.unity3d.com/Manual/SL-PropertiesInPrograms.html</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > x contains 1.0/width y contains 1.0/height z contains width w contains height </pre> <br /> 결국 이를 반영하면 다음과 같이 하드 코딩 없이 작성할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > fixed4 frag(v2f i) : SV_Target { float uPerX = _MainTex_TexelSize.x; float vPerY = _MainTex_TexelSize.y; float uOffset = 10 * uPerX; // x축으로 +10 pixel 위치 float vOffset = 10 * vPerY; // y축으로 +10 pixel 위치 float2 nextUVOffset = float2(uOffset, vOffset); fixed4 col = tex2D(_MainTex, i.uv + nextUVOffset); return col; } float2 UVtoXY(float2 uv, float2 texelSize) { return float2(uv.x / texelSize.x, uv.y / texelSize.y); } float2 XYtoUV(float2 pos, float2 texelSize) { return float2(pos.x * texelSize.x, pos.y * texelSize.y); } </pre> <br /> <hr style='width: 50%' /><br /> <br /> 다음의 링크를 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D3D이용 2D출력시 마법의 숫자 -0.5 에 대하여 ; <a target='tab' href='http://blog.daum.net/gamza-net/16'>http://blog.daum.net/gamza-net/16</a> </pre> <br /> 실수 보정을 하는데 아마 이 때문인지 다음의 답글을 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to get precise pixel values form a Texture2D using uv coordinates. ; <a target='tab' href='https://answers.unity.com/questions/1106031/how-to-get-precise-pixel-values-for-a-texture2d-us.html'>https://answers.unity.com/questions/1106031/how-to-get-precise-pixel-values-for-a-texture2d-us.html</a> </pre> <br /> (0.5를 빼지 않고) 더하는 것이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > u = x / width + 0.5 / width; v = y / height + 0.5 / height; </pre> <br /> pixel shader에서 저 작업이 필요한지는... 혹시 아시는 분은 덧글 부탁드립니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1036
(왼쪽의 숫자를 입력해야 합니다.)