没那么简单,但您可以通过以下方式实现类似的目标。 这需要您的 3D 模型正确地进行 UV 映射,以便您可以简单地对其应用平面纹理。 设置可能听起来很复杂,但它真的很酷;)
- 创建一个
RenderTexture:在Asset 中执行鼠标右键 → Create → RenderTexture 并以你喜欢的方式调用它,例如TextTexture
- 为了以后有更好的分辨率,将
size 增加到例如2048*2048 当然取决于您的需求。
- 创建新材质
- 使用刚刚创建的
RenderTexture 作为Albedo
- 并将
RenderingMode 设置为Fade(以便以后使其背景透明)
- 创建一个新的Layer 并将其命名为例如
TEXT
- 在
Culling Mask 下的普通主Camera 排除刚刚创建的TEXT 层。所以它不会渲染我们的文本内容
- 在场景中添加一个新的
Camera(它只会渲染文本)并调用它,例如TextCamera
并进行以下设置:
- 删除其
AudioListener 组件
-
Clear Flags → Solid Color
-
Background → 颜色其实无关紧要,但请确保将 Alpha 级别设置为 0!
-
Culling Mask → 除了创建的TEXT 层之外什么都没有
-
Target Texture → 创建的RenderTexture
现在您已经有了一个材质,它具有动态可变纹理、透明背景和您喜欢的任何内容。所以让我们来吧,例如一个 UI.Text
- 到您的场景中(我只是作为
TextCamera 的子对象完成的,因此我可以在处理其他内容时简单地将其移出SceneView 中)添加Text(包括画布等 - Unity 通常会添加它自动)
- 使所有游戏对象(画布和文本)都具有层
TEXT,这样它们就不会被普通的 Camera 渲染,而只能被 TextCamera 渲染。
- 确保
Canvas 使用RenderMode = WorldSpace(它不适用于覆盖画布)!
- 将
Canvas 放在例如3TextCamera 前面的单位(或您喜欢的任何位置,以便稍后在纹理中看到文本)
- 为了获得更好的文本分辨率,我也会在
Text
- 在
RectTransform上设置width = 1000、height = 1000、Scale = 0.001, 0.001, 0.001
- 在
Text 组件集中Font Size = 300
- 只是为了确保禁用
Raycast Target 选项
现在您可以简单地将创建的材质应用到您的 3D 对象并点击播放,应该会看到它变得完全透明,除了上面有文字。
因此,为了将其用作 3D 对象的叠加层,您可以使用例如只需复制原始对象,调用一个例如Inner 另一个Outer 并使Inner 成为Outer 的孩子。现在在Outer 上设置我们的文本材料。这是有效的,因为使用Fade 作为渲染模式的材质在不同的渲染链上渲染,该渲染链呈现在默认链之上。
→ Tadaaa 3D 对象,其表面应用了文本,甚至可以动态更改文本及其属性,如颜色等
整个事情都是动态的(除了创建图层)
既然您问:是的,您可以在脚本中完成这一切...... 除了创建新层!这在运行时是不可能的!
所以你必须事先知道你将使用的所有图层,然后你才能做类似的事情
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class TextOnObjectManager : MonoBehaviour
{
// reference via Inspector if possible
[SerializeField] private Camera mainCamera;
[SerializeField] private string LayerToUse;
private void Awake()
{
// 0. make the clone of this and make it a child
var innerObject = new GameObject(name + "_original", typeof(MeshRenderer)).AddComponent<MeshFilter>();
innerObject.transform.SetParent(transform);
// copy over the mesh
innerObject.mesh = GetComponent<MeshFilter>().mesh;
name = name + "_textDecal";
// 1. Create and configure the RenderTexture
var renderTexture = new RenderTexture(2048, 2048, 24) { name = name + "_RenderTexture" };
// 2. Create material
var textMaterial = new Material(Shader.Find("Standard"));
// assign the new renderTexture as Albedo
textMaterial.SetTexture("_MainTex", renderTexture);
// set RenderMode to Fade
textMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
textMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
textMaterial.SetInt("_ZWrite", 0);
textMaterial.DisableKeyword("_ALPHATEST_ON");
textMaterial.EnableKeyword("_ALPHABLEND_ON");
textMaterial.DisableKeyword("_ALPHAPREMULTIPLY_ON");
textMaterial.renderQueue = 3000;
// 3. WE CAN'T CREATE A NEW LAYER AT RUNTIME SO CONFIGURE THEM BEFOREHAND AND USE LayerToUse
// 4. exclude the Layer in the normal camera
if (!mainCamera) mainCamera = Camera.main;
mainCamera.cullingMask &= ~(1 << LayerMask.NameToLayer(LayerToUse));
// 5. Add new Camera as child of this object
var camera = new GameObject("TextCamera").AddComponent<Camera>();
camera.transform.SetParent(transform, false);
camera.backgroundColor = new Color(0, 0, 0, 0);
camera.clearFlags = CameraClearFlags.Color;
camera.cullingMask = 1 << LayerMask.NameToLayer(LayerToUse);
// make it render to the renderTexture
camera.targetTexture = renderTexture;
camera.forceIntoRenderTexture = true;
// 6. add the UI to your scene as child of the camera
var Canvas = new GameObject("Canvas", typeof(RectTransform)).AddComponent<Canvas>();
Canvas.transform.SetParent(camera.transform, false);
Canvas.gameObject.AddComponent<CanvasScaler>();
Canvas.renderMode = RenderMode.WorldSpace;
var canvasRectTransform = Canvas.GetComponent<RectTransform>();
canvasRectTransform.anchoredPosition3D = new Vector3(0, 0, 3);
canvasRectTransform.sizeDelta = Vector2.one;
var text = new GameObject("Text", typeof(RectTransform)).AddComponent<Text>();
text.transform.SetParent(Canvas.transform, false);
var textRectTransform = text.GetComponent<RectTransform>();
textRectTransform.localScale = Vector3.one * 0.001f;
textRectTransform.sizeDelta = new Vector2(2000, 1000);
text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
text.fontStyle = FontStyle.Bold;
text.alignment = TextAnchor.MiddleCenter;
text.color = Color.red;
text.fontSize = 300;
text.horizontalOverflow = HorizontalWrapMode.Wrap;
text.verticalOverflow = VerticalWrapMode.Overflow;
Canvas.gameObject.layer = LayerMask.NameToLayer(LayerToUse);
text.gameObject.layer = LayerMask.NameToLayer(LayerToUse);
text.text = "This is a dynamically generated example!";
// 7. finally assign the material to the child object and hope everything works ;)
innerObject.GetComponent<MeshRenderer>().material = textMaterial;
}
}
基本上重现了之前的所有步骤。由于我们无法在运行时创建或编辑图层,因此您必须事先了解它们并将其输入为LayerToUse。
我将所有东西都创建为原始对象的子对象,因此稍后在运行时也可以轻松控制和更改它。
更新
在较新的 Unity 版本中,我建议通过 TextMeshPro 交换 Text,它支持更多的文本格式和自动缩放等。