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
}
}
}