I just want to be able to see some text rendered in the world.
The only example code that I've found is this:
GameObject Text = new GameObject();
TextMesh textMesh = Text.AddComponent<TextMesh>();
textMesh.font = new Font();
mat.SetColor("_Color", Color.black);
mat.SetPass(0);
meshRenderer.material = mat;
textMesh.text = "Hello World!";
Where mat is defined by the code:
Shader shader = Shader.Find("Hidden/Internal-Colored");
mat = new Material(shader);
mat.hideFlags = HideFlags.HideAndDontSave;
mat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
mat.SetInt("_ZWrite", 0);
mat.SetColor("_Color", Color.blue);
mat.SetPass(0);
This code is added to the Start of MonoBevaviour. And the script is tied to Game Main camera.
No text appears anywhere that I can see.
Ah I think I might have something.
I am not sure though if this works for VR devices - I know that Unity e.g. doesn't render Screenspace overlay canvas on XR.
But back to the point: There is a legacy UI system which is usually not used anymore except for in editor Inspector scripting IMGUI
I think it might actually fit your very special need using GUILayout.Label you should be able to draw a flat label onto the screen even in VR.
With GUI.Label you have full control over the pixel coordinates and size.
public class YourTextDrawer : MonoBehaviour
{
void OnGUI()
{
var color = GUI.color;
GUI.color = Color.green;
var textPosition = new Rect(Screen.width / 2 - 150, Screen.height / 2 - 100, 300, 200);
GUI.Label(textPosition, "Hello World!");
GUI.color = color;
}
}
Not tested, just scrabbling this down from memory right now
And actually thinking about it, this might even work for your image as well
Related
My goal is to draw simple, colored meshes on a Canvas in Unity. I set up a Canvas and chose Render Mode World Space. I then added a GameObject, set its RectTransform, added a CanvasRenderer (later also a MeshFilter and MeshRenderer) and a script to create my mesh. Creating the mesh works fine but i have to major problems. The first is that the lightning does not work correctly when using CanvasRenderer instead of MeshRenderer:
My second problem is that no matter the order in the hierarchy as soon as i add a second object to my canvas (e.g. an image with the color white) my custom mesh and its color are no longer visible. Only the white image.
Here is the script i used. The last few lines are comments or not based on what Renderer i tried.
using UnityEngine;
public class MeshCanvas : MonoBehaviour
{
public Material material;
Mesh mesh;
Vector3[] vertices;
int[] triangles;
float canvasHeigt;
float canvasWidth;
private void Update()
{
canvasHeigt = FindObjectOfType<Canvas>().GetComponent<RectTransform>().rect.height;
canvasWidth = FindObjectOfType<Canvas>().GetComponent<RectTransform>().rect.width;
vertices = new Vector3[]
{
new Vector3(0, 0),
new Vector3(0, canvasHeigt),
new Vector3(canvasWidth, canvasHeigt),
new Vector3(canvasWidth, 0)
};
triangles = new int[]
{
0, 1, 2,
2, 3, 0
};
mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
/*
this.GetComponent<MeshFilter>().mesh = mesh;
this.GetComponent<MeshRenderer>().material = material;
*/
CanvasRenderer cr = this.GetComponent<CanvasRenderer>();
cr.SetColor(Color.black);
cr.materialCount = 1;
cr.SetMaterial(material, 0);
cr.SetMesh(mesh);
}
}
For problem 1: If you just want a normal unlit UI element, you should be using the UI/Default material, not a Standard material.
If you do want lighting, In your Canvas properties, set 'Additional Shader Channels' to 'Everything'. Otherwise lighting will not be calculated correctly. You can use a Standard material in this case, or one of the UI/Lit materials.
As for problem 2, I'm not sure. Unity batches all UI elements together for performance reasons, so maybe setting the mesh directly on the CanvasRenderer is breaking the batching, or maybe it's to do with the material you're using.
If you just want to be able to add your own custom 2D shapes to a Canvas, the better way is to make a class that derives from Graphic or MaskableGraphic and override the OnPopulateMesh method to provide your custom mesh vertices.
The advantages here are that it will behave like any other UI element with all the same parameters etc. and you can add it to the Create GameObject menus to easily add it to your scene.
I have some code like this:
readonly Rect WORK_SOURCE_RECT = new Rect(0f, 0f, 1f, 1f);
Color[] workPixels;
void Start() {
Texture2D workTexture = new Texture2D(256, 256, GraphicsFormat.R8G8B8A8_UNorm,
TextureCreationFlags.None);
workPixels = workTexture.GetPixels();
}
void OnGUI() {
workTexture.SetPixels(workPixels);
workTexture.Apply();
Graphics.DrawTexture(toRect, workTexture, WORK_SOURCE_RECT,
0, 0, 0, 0, renderColor);
}
void Update() {
// Omitted - Some changes are made by code here to the workPixels array.
}
The call to Graphics.DrawTexture() correctly draws the content of workTexture to the screen, just how I want it. But there is a strange side effect...
Any other GUI that is drawn inside of a scene object containing a Canvas component, will show an extra Y-reversed copy of the work texture. (Nevermind the reversal--not the issue.) I don't know why this extra image is drawn. It seems like there is a shared resource between two GUI things I'd hoped were completely unrelated.
In the image shown below, the reversed-face on the right is the unwanted extra render. Strangely it appears when I move to the right side of my scene, so it's like it is in world space. But it will update when GUI-based elements like subtitles are shown.
On Unity 2019.4.13f1 with MacOS.
The solution I found that resolved my problem was camera stacking. I created a second camera that was culled to just UI layer. The first camera had UI layer removed from culling. And then the calls to Graphics.DrawTexture() no longer appeared on the canvas used for UI.
I am trying to draw a line between two UI GameObjects with Linerenderer. In scene mode everything work fine, but in game mode line is invisible. I tried to change Z position of objects but lines are still invisible. Can anyone help me? Thanks in advance
private LineRenderer lineRenderer;
private float counter;
private float dist;
private Vector3 aPos;
private Vector3 bPos;
public Transform origin;
public Transform destination;
public float lineDrawSpeed = 6f;
// Use this for initialization
void Start()
{
lineRenderer = GetComponent<LineRenderer>();
aPos = new Vector3(origin.position.x, origin.position.y, origin.position.z); // Using these to move the lines back
bPos = new Vector3(destination.position.x, destination.position.y, destination.position.z);
lineRenderer.SetPosition(0, aPos);
lineRenderer.SetWidth(3f, 3f);
dist = Vector3.Distance(origin.position, destination.position);
}
// Update is called once per frame
void Update()
{
if (counter < dist)
{
counter += .1f / lineDrawSpeed;
float x = Mathf.Lerp(0, dist, counter);
Vector3 pointA = aPos;
Vector3 pointB = bPos;
Vector3 pointAloneLine = x * Vector3.Normalize(pointB - pointA) + pointA;
lineRenderer.SetPosition(1, pointAloneLine);
}
}
Unless I'm overlooking some logic error in the code you've posted, I think the problem might be with the material.
Generic debugging help for line renderers:
Try setting the color/material of the line renderer:
lineRenderer.sortingOrder = 1;
lineRenderer.material = new Material (Shader.Find ("Sprites/Default"));
lineRenderer.material.color = Color.red;
If that doesn't work, perhaps you need to specify the number of vertexes manually?
mineLaser.SetVertexCount (2);
Finally, if these both don't work, it might just be a logic error; try setting the transforms for the lineRenderer's position to be some predefined value and see if it shows up.
For this specific question:
Ah, so its on a canvas. Assuming you mean the UI canvas, I believe linerenderer is the wrong tool to use in this situation. Check out this question.
One of the answers there suggests to:
just use a panel filled with any color you want and use Height and Width to set the length and the Width of your line
This is impossible in "Screen Space - Overlay" Canvas mode. In that mode UI overlay draws on top of everything in Scene (including LineRenderer, that actually non UI element).
Try to use "Screen Space - Camera" option for your Canvas and "Use World Space" option for you Line Renderer.
I think you must have forgotten to set sorting layer for the line renderer. As this could only be the possible reason if the line is visible in the scene view and not in the game view.
I'm working on my first game in Unity.
I'm trying to draw lines on my game field.
Code:
private void DrawLine(Vector3 start, Vector3 stop, GameObject template)
{
GameObject toInstiateGridLine = template;
GameObject gridLineInstance = Instantiate(toInstiateGridLine, start, Quaternion.identity) as GameObject;
LineRenderer gridLineRenderer = gridLineInstance.GetComponent<LineRenderer>();
gridLineRenderer.SetVertexCount(2);
gridLineRenderer.SetWidth(0.01f, 0.01f);
gridLineRenderer.SetColors(Color.black, Color.black);
gridLineRenderer.SetPosition(0, start);
gridLineRenderer.SetPosition(1, stop);
}
It works with one problem. I get pink lines instead of black that I expect.
Settings of LineRenderer component that has been created in runtime:
You are missing material. Pink is the standard color when material is missing.
LineRenderer gridLineRenderer = gridLineInstance.GetComponent<LineRenderer>();
Material mat = new Material(Shader.Find("Unlit/Texture"));
gridLineRenderer.material = mat;
Or, you can change material color directly. As I consider, calling directly will cause to create standard default material
gridLineRenderer.material.color = Color.white;
I just wanted to ask what is the proper way to create and display a view on Unity. I'm just a beginner on this and just watched recently tutorials on how to script and learned about creating GUI on the fly which includes buttons, edit text boxes and other view but not sure on how should I really implement it the way it is optimized and won't affect the applications performance. What I tried so far is to create an editText wherein I set it on the MainCamera for display which is I targeted to be reusable so that in case I need to add more editText on the app I can just drag and drop the script. Here's the code so far:
using UnityEngine;
using System.Collections;
public class EditText : MonoBehaviour {
public int width = 150;
public int height = 25;
public int x_position = 0;
public int y_position = 0;
public string text = "Hello World";
public Position position = Position.unset;
public int text_size = 15;
public enum Position{unset,center_screen, center_vertical, center_horizontal};
void OnGUI () {
setPosition ();
GUI.skin.textArea.fontSize = text_size;
GUI.color = Color.red;
}
private void setPosition(){
switch (position) {
case Position.center_screen:
GUI.TextArea (new Rect (Screen.width/2 - width/2, Screen.height/2 - height/2, width, height), text);
GUI.backgroundColor = Color.white;
break;
case Position.center_vertical:
GUI.TextArea (new Rect (x_position, Screen.height/2 - height/2, width, height), text);
GUI.backgroundColor = Color.white;
break;
case Position.center_horizontal:
GUI.TextArea (new Rect (Screen.width/2 - width/2, y_position, width, height), text);
GUI.backgroundColor = Color.white;
break;
default:
GUI.TextArea (new Rect (x_position, y_position, width, height), text);
GUI.backgroundColor = Color.white;
break;
}
}
}
Question is am I doing this right or should I stop and use other implementation? Since I really intended it to be as reusable just like the Android Views. Also if there is any other library or scripts I can use to achieve this so that I'm not reinventing the wheel for this?
On the side note I also searched the NGUI although I'm not that sure on if this will fit my needs or not. Since when I tried creating a UILabel the component has only few options where I am not really sure on how I supposed to use it.
Question: Am I doing this right or should I stop and use other implementation?
It depends. Your implementation is simple but working. If you need more fancy UI, you might consider:
NGUI
NoesisGUI
Unity 4.6+ or Unity 5
According to Unity official blog, the "new GUI system is getting really close and it’ll be included in Unity 4.6, which will also be the last major update in the Unity 4 cycle".
I would prefer the last one, Unity 4.6 or Unity 5, as it is free and official from Unity, and the support and community are the big asset for you!
For your current implementation, I think you can make it even better, without using:
GUI.TextArea (new Rect (...)); // Not the best way
Instead try using:
GUILayout.BeginHorizontal ();
{
GUILayout.FlexibleSpace ();
//label etc., this guarantees centered in your UI and resolution independent.
GUILayout.XXX (...);
GUILayout.FlexibleSpace ();
}
GUILayout.EndHorizontal ();
Interesting links:
http://docs.unity3d.com/ScriptReference/GUILayout.html
GUI Layout tutorial
Unity's GUI system is far from perfect, but it's being improved incrementally. It's a good solution for interfaces with few simple elements. When using Unity's GUI system, i've generally set up each menu or 'display' separately. I never designed the UI elements in a modular fashion in the Unity system. I've not been in a situation where setting the 'Rect' of an element hasn't met my needs of manipulation. I can't say much about the performance of Unity's GUI system apart from that i've never noticed it's impact.
NGUI, like Unity is designed to be modular. To create the ui element that you desire might require you to piece together various scripts. For example an input field would require UILabel, UIInput script and a BoxCollider. Using all the scripts included in NGUI i've been able to create some pretty impressive interface prefabs. Being able to structure my interface visually in the scene view has been helpful as well.
These are the two UI systems i've used and have found uses for both.