Unity에서 MSDF를 사용하여 Shader로 벡터 이미지를 그리는 방법
어느 때 Twitter를 보케로 바라보고 있을 때 MSDF(Multi-channel signed distance field)라는 존재를 알았습니다.
MSDF는 뭐야? 분명히 설명하면 벡터 이미지 (SVG 등)의 데이터를 일반 이미지로 인코딩하여 표시 할 때 디코딩하여 벡터 이미지처럼 보이는 알고리즘으로 Multi-channel로 RGB 채널 를 사용하여 Single-channel (그레이 스케일)을 사용했을 때에 비해 날카로운 각도 등의 재현성이 비약적으로 향상하고 있다고합니다.
벡터 화상으로서 디코드 하기 때문에 통상의 화상과 같이 확대해도 쟈기쟈기가 되지 않고, 거의 무한하게 매끄럽고 필요한 화상의 사이즈도 작기 때문에 빌드 용량의 삭감에 연결됩니다. 또, 이번은 Shader로 디코드를 실시하기 때문에 고속입니다.
msdfgen에서 인용
그러므로 SVG 파일을 일반 이미지로 빠르게 인코딩해 보겠습니다. releases 페이지에서 컴파일 된 바이너리를 얻을 수 있습니다.
명령 프롬프트를 시작하고 실행 파일이 있는 위치로 이동합니다. 거기서
msdfgen.exe msdf -svg "C:\test.svg" -o msdf.png -size 64 64 -pxrange 4 -autoframe
실행하면 현재 디렉토리에 msdf.png
가 생성됩니다.사용하는 SVG 파일에 따라 다르지만 이런 느낌의 이미지가 생성됩니다.
나중에 Unity로 가져와 Inspector에서 이미지 가져 오기 설정을 다음과 같이
압축을 비활성화하고 해상도를 맞춥니다.
그런 다음 이 이미지 파일에서 벡터 이미지로 디코딩할 Shader를 준비합니다.
앞의 github에 GLSL 샘플 코드가 탑재되어 있으므로 HLSL로 다시 씁니다.
in vec2 pos;
out vec4 color;
uniform sampler2D msdf;
uniform float pxRange;
uniform vec4 bgColor;
uniform vec4 fgColor;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec2 msdfUnit = pxRange/vec2(textureSize(msdf, 0));
vec3 sample = texture(msdf, pos).rgb;
float sigDist = median(sample.r, sample.g, sample.b) - 0.5;
sigDist *= dot(msdfUnit, 0.5/fwidth(pos));
float opacity = clamp(sigDist + 0.5, 0.0, 1.0);
color = mix(bgColor, fgColor, opacity);
}
이런 식으로 적절하게
MSDF.shader
Shader "Unlit/MSDF"
{
Properties
{
[NoScaleOffset]_MainTex("MSDF Texture", 2D) = "white" {}
[HDR]_Color_0("Color 0", Color) = (1,1,1,0)
[HDR]_Color_1("Color 1", Color) = (0,0,0,1)
[Toggle] _Show_Original_Texture("Show Original Texture", Float) = 0
}
SubShader
{
Tags {"Queue"="Transparent" "RenderType"="Transparent"}
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
Cull off
ZWrite off
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma shader_feature _SHOW_ORIGINAL_TEXTURE_ON
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform float4 _Color_0, _Color_1;
float median (float3 col)
{
return max(min(col.r, col.g), min(max(col.r, col.g), col.b));
}
float fwidth(float2 p)
{
return abs(ddx(p)) + abs(ddy(p));
}
float4 frag (v2f_img i) : SV_Target
{
float3 tex = tex2D(_MainTex, i.uv);
float dist = median(tex) - .5;
float sigDist = fwidth(dist);
float opacity = smoothstep(-sigDist, sigDist, dist);
float4 o;
#ifdef _SHOW_ORIGINAL_TEXTURE_ON
o = float4(tex, 1);
#else
o = lerp(_Color_0, _Color_1, opacity);
#endif
return o;
}
ENDCG
}
}
}
Shader를 Quad 등에 적용해
MSDF Texture
에 앞의 이미지를 밀어넣으면 다음과 같이 됩니다.또한
"Show Original Texture"
에 체크를 하면 그대로의 화상을 출력합니다. (오른쪽 녀석)확대해도 원래 이미지의 크기가 64✕64라고는 생각되지 않을 정도로 매끄럽습니다.
VR 게임의 UI 등에 사용하면 극단적으로 접근했을 때 쟈기하지 않기 때문에 좋을지도?
링크
msdfgen
Reference
이 문제에 관하여(Unity에서 MSDF를 사용하여 Shader로 벡터 이미지를 그리는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Feyris/items/3c5b227eb27e0d6a8305텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)