Unity3d 如何使用着色器在网格上映射字母?

Unity3d 如何使用着色器在网格上映射字母?,unity3d,shader,fragment-shader,vertex-shader,shaderlab,Unity3d,Shader,Fragment Shader,Vertex Shader,Shaderlab,我正在尝试创建一个着色器,允许在网格上映射文本。如何水平对齐每个字符?目前,它们都相互重叠 目前看起来是这样的: 使用的纹理: 着色器“unlight/MapText” { 性质 { _MainTex(“纹理”,2D)=“白色”{} _FontTex(“FontTexture”,2D)=“白色”{} _颜色(“颜色”,颜色)=(1,1,1,1) } 子阴影 { 标记{“RenderType”=“不透明”} 通过 { CGP程序 #pragma顶点顶点 #布拉格碎片碎片 #包括“UnityCG

我正在尝试创建一个着色器,允许在网格上映射文本。如何水平对齐每个字符?目前,它们都相互重叠

目前看起来是这样的:

使用的纹理:

着色器“unlight/MapText”
{
性质
{
_MainTex(“纹理”,2D)=“白色”{}
_FontTex(“FontTexture”,2D)=“白色”{}
_颜色(“颜色”,颜色)=(1,1,1,1)
}
子阴影
{
标记{“RenderType”=“不透明”}
通过
{
CGP程序
#pragma顶点顶点
#布拉格碎片碎片
#包括“UnityCG.cginc”
统一整数字符计数;
统一浮点数4个字符[3];
结构appdata
{
浮动4顶点:位置;
float2uv:TEXCOORD0;
浮动2 uv1:TEXCOORD1;
};
结构v2f
{
float2uv:TEXCOORD0;
浮动2 uv1:TEXCOORD1;
浮动4顶点:SV_位置;
};
取样器2D_MainTex;
浮动4(缅特克斯街);;
取样器2D_FontTex;
浮动4(方特克斯街);;
浮色;
v2f垂直(appdata v)
{
v2fo;
o、 顶点=UnityObjectToClipPos(v.vertex);
o、 uv=变换_TEX(v.uv,_MainTex);
o、 uv1=变换_TEX(v.uv1,_FontTex);
返回o;
}
固定4框架(v2f i):SV_目标
{
固定4柱;
_字符[0]=0;
_字符[1]=1;
_字符[2]=2;
用于(uint k=0;k<_Characters.Length;k++)
{
浮动行=(k%1024);
浮动列=(k/1024);
float2字符=(i.uv1+float2(行、列))*0.33;
_字符[k]=tex2D(_FontTex,字符);
}
col=(_字符[0]+_字符[1]+_字符[2])*颜色;
返回列;
}
ENDCG
}
}
}

注释中有解释

Shader "Unlit/MapText"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _FontTex("FontTexture", 2D) = "white" {}
        _FontTextColumns("FontTexture Columns", Int) = 3
        _FontTextRows("FontTexture Rows", Int) = 3
        _StringCharacterCount("Length of String", Int) = 3
        _StringOffset("String offset", Vector) = (0.5,0.5,0,0)
        _StringScale("String scale", Vector) = (0.25,0.25,0,0)
        _CharWidth("Character width", Float) = 1.0
        _Color("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            sampler2D _FontTex;
            float4 _FontTex_ST;

            float4 _Color;

            // font texture information
            int _FontTextColumns;
            int _FontTextRows;

            // string length
            int _StringCharacterCount;

            // float array because there's no SetIntArray in c#
            float _String_Chars[512];

            // string placement & scaling
            float4 _StringOffset;
            float4 _StringScale;

            // Character width - combine with StringScale to change character spacing
            float _CharWidth;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                // discard pixel if _StringCharacterCount < 1
                clip(_StringCharacterCount - 1);

                fixed4 col;

                // Determine what character in the string this pixel is in
                // And what UV of that character we are in
                float charIndex = 0;
                float2 inCharUV = float2(0,0);

                // Avoid i.uv.x = 1 and indexing charIndex[_StringCharacterCount] 
                i.uv.x = clamp(i.uv.x, 0.0, 0.99999);

                // Scale and offset uv
                i.uv = clamp((i.uv - _StringOffset.xy) / _StringScale.xy + 0.5, 0, 1);

                // Find where in the char to sample
                inCharUV = float2(
                    modf(i.uv.x * _StringCharacterCount, charIndex),
                    i.uv.y);

                // Scale inCharUV.x based on charWidth factor
                inCharUV.x = (inCharUV.x-0.5f)/charWidth + 0.5f;

                // Clamp char uv
                // alternatively you could clip if outside (0,0)-(1,1) rect
                inCharUV = clamp(inCharUV, 0, 1);

                // Get char uv in font texture space
                float fontIndex = _String_Chars[charIndex];
                float fontRow = floor(fontIndex / _FontTextColumns);
                float fontColumn = floor(fontIndex % _FontTextColumns);

                float2 fontUV = float2(
                        (fontColumn + inCharUV.x) / _FontTextColumns,
                        1.0 - (fontRow + 1.0 - inCharUV.y) / _FontTextRows);

                // Sample the font texture at that uv
                col = tex2D(_FontTex, fontUV);

                // Modify by color:
                col = col * _Color;

                return col;
            }
           ENDCG
        }
    }
}
确保将
\u String\u Chars
\u StringCharacterCount
初始化为
唤醒中的某个内容,否则可能会产生意外结果。考虑在字体纹理中包含一个“空白”字符,这样您就可以初始化为一个字符串,它只是空白字符。
此着色器产生如下效果(请注意右侧的不同着色器属性):

只需确保字体纹理的“生成Mip贴图”已关闭(未选中),否则您将获得意外的瑕疵:


您不使用TextMeshPro的原因是什么?是的,我需要稍后在蒙皮网格上使用它,而普通网格上的afaik TMPro不会弯曲。会吗?需要帮助吗?@derHugo该方法很有趣,但问题是我需要在场景中的大约10-15个对象上有动态文本,因此我需要许多摄影机、渲染纹理和层,这需要在移动设备上运行。@derHugo这会是性能问题吗?现在垂直居中。。。但是我想用一个滑块或者别的什么东西来动态设置它。它很有效。。但是字符之间有垂直线。是否可以减小字母之间的间距?@Mazhar I添加了一个char width属性,因此可以通过减小字符串x比例和增加char width来减小间距。它仍然是单间距字体。如果你需要比例间距,那就值得问另一个问题
Shader "Unlit/MapText"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _FontTex("FontTexture", 2D) = "white" {}
        _FontTextColumns("FontTexture Columns", Int) = 3
        _FontTextRows("FontTexture Rows", Int) = 3
        _StringCharacterCount("Length of String", Int) = 3
        _StringOffset("String offset", Vector) = (0.5,0.5,0,0)
        _StringScale("String scale", Vector) = (0.25,0.25,0,0)
        _CharWidth("Character width", Float) = 1.0
        _Color("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            sampler2D _FontTex;
            float4 _FontTex_ST;

            float4 _Color;

            // font texture information
            int _FontTextColumns;
            int _FontTextRows;

            // string length
            int _StringCharacterCount;

            // float array because there's no SetIntArray in c#
            float _String_Chars[512];

            // string placement & scaling
            float4 _StringOffset;
            float4 _StringScale;

            // Character width - combine with StringScale to change character spacing
            float _CharWidth;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                // discard pixel if _StringCharacterCount < 1
                clip(_StringCharacterCount - 1);

                fixed4 col;

                // Determine what character in the string this pixel is in
                // And what UV of that character we are in
                float charIndex = 0;
                float2 inCharUV = float2(0,0);

                // Avoid i.uv.x = 1 and indexing charIndex[_StringCharacterCount] 
                i.uv.x = clamp(i.uv.x, 0.0, 0.99999);

                // Scale and offset uv
                i.uv = clamp((i.uv - _StringOffset.xy) / _StringScale.xy + 0.5, 0, 1);

                // Find where in the char to sample
                inCharUV = float2(
                    modf(i.uv.x * _StringCharacterCount, charIndex),
                    i.uv.y);

                // Scale inCharUV.x based on charWidth factor
                inCharUV.x = (inCharUV.x-0.5f)/charWidth + 0.5f;

                // Clamp char uv
                // alternatively you could clip if outside (0,0)-(1,1) rect
                inCharUV = clamp(inCharUV, 0, 1);

                // Get char uv in font texture space
                float fontIndex = _String_Chars[charIndex];
                float fontRow = floor(fontIndex / _FontTextColumns);
                float fontColumn = floor(fontIndex % _FontTextColumns);

                float2 fontUV = float2(
                        (fontColumn + inCharUV.x) / _FontTextColumns,
                        1.0 - (fontRow + 1.0 - inCharUV.y) / _FontTextRows);

                // Sample the font texture at that uv
                col = tex2D(_FontTex, fontUV);

                // Modify by color:
                col = col * _Color;

                return col;
            }
           ENDCG
        }
    }
}