- Home /
Draw texture in editor with size less than a single unit
I am using Graphics.DrawTexture
on a custom editor's OnSceneGUI to draw a texture in the scene, and I can't get a texture drawn in less than a unity unit. Basically I am getting the following result:
The code I am using is this:
Graphics.DrawTexture(new Rect(2f, 0f, 0.5f, 0.5f), tex);
Graphics.DrawTexture(new Rect(new Vector2(0, 0), new Vector2(1f, 1f)), tex);
I reckon that the Rect is in screen coordinates, and it's taking a unity unit as a "pixel", but there is no way then to draw a texture programatically on the editor of less than 1 unit of size?
EDIT: finally, I took this (drawtexture with less than unit in scene) for impossible, and accepted @Xarbrough 's answer that somehow showed how to accomplish part of the final intended behaviour and has a lot of good information to lead people who might find this question.
Answer by Xarbrough · Aug 26, 2017 at 11:20 PM
Just to make sure: Do you want to draw the texture in world space unity? Then you can do this: Create a primitive and place it in the scene. You should set the HideFlags to HideAndDontSave and destroy the object yourself, when you are done (you don't want it to be saved with the scene, so you control its lifetime manually). I've did this approach for my custom tile-based map editor and it worked quite well for preview objects. This is also the way Unity handles a lot of internal things, like the scene view camera for example.
Indeed, I can confirm that Graphics.DrawTexture kind of works in the scene view, but only in increments of 1 unit. It probably isn't intended for this use. Maybe this even ties in why the Canvas object has to be a thousand units wide, assuming 1 unit = 1 pixel, but I'm just guessing.
If you want your texture to work like a Gizmo or Icon, you can use BeginGUI or other methods like DrawIcon.
Here is some code for the approach with a preview GameObject:
using UnityEngine;
using UnityEditor;
public class MyScript : MonoBehaviour
{
public Texture tex;
public Rect rect;
}
[CustomEditor(typeof(MyScript))]
public class MyScriptEditor : Editor
{
private GameObject previewObj;
private Material material;
private void OnEnable()
{
MyScript script = (MyScript)target;
// Create a temporary object in the scene.
previewObj = GameObject.CreatePrimitive(PrimitiveType.Plane);
previewObj.hideFlags = HideFlags.HideAndDontSave;
// Also copy the default material (we don't want to change that for all Unity default objects)
material = new Material(previewObj.GetComponent<Renderer>().sharedMaterial)
{
hideFlags = HideFlags.HideAndDontSave,
mainTexture = script.tex,
};
previewObj.GetComponent<Renderer>().sharedMaterial = material;
// Rotate to the 2D plane, assuming the texture UV's are flipped in this case.
previewObj.transform.Rotate(90f, 180f, 0f);
}
private void OnDisable()
{
if (previewObj != null)
DestroyImmediate(previewObj);
if (material != null)
DestroyImmediate(material);
}
private void OnSceneGUI()
{
MyScript script = (MyScript)target;
if (previewObj)
{
previewObj.transform.position = script.rect.position;
previewObj.transform.localScale = new Vector3(script.rect.width, 1f, script.rect.height);
}
}
}
Result
It draws a Quad that can be rotate and scaled to show your texture. Different objects and transformations might apply, but the important parts are the memory management with HideFlags, as to not cause leaks in the editor.
First of all, thank you very much for your elaborated answer.
Yes, I am doing some kind of tilemap editor, and I did want to draw a texture directly so that I didn't have to have a lot of objects (one for each tile). I can also use a mesh and modify UVs procedurally, but I saw the option of just drawing textures in the UI to be very clean because you don't need to create anything, and my maps will be so small that it's not worth.
Having said that, if I understood your way correctly, you would have a gameobject instanced for each tile, is this correct? I guess the object is around in the hierarchy then.
Finally, what I was going to do is just spawn gameobjects with an assigned quad as you are saying. This way, ins$$anonymous$$d of previewObj
I would have a sort of previewObjList
.
Thanks again for your answer!
EDIT: re-reading your answer, do you meant at first that with the HideFlags
parameters I won't see them in the hierarchy? oO I am just going to test that. If that's what I will get, I will just be so damn happy.
EDIT2: this is part of what I wanted to achieve. I still don't get the easiness of just going through the matrix of tiles and drawing a texture depending on the content of each cell like I would do in raw coding, but at least this keeps your hierarchy clean anyway. Thanks for this.
Glad I could help. :) $$anonymous$$y example assumes, that you want to draw something like a brush cursor (preview tile of what you are going to paint). In my own editor, I had one GameObject and SpriteRenderer per tile (sounds wasteful, but isn't, because of batching; I could have more than a million tiles in my scene and render a big enough portion of them with very good performance). HideFlags hides the preview object(s) in the hierarchy, but also makes sure, that they are not saved with the scenes. Once you click/draw you instantiate your tile prefab or create your batched mesh, whatever the system is. You can probably do the preview system the same, if it only modifies UVs on one big plane. In any case, you can think about how you want to store and create the map. If you have all objects saved with the scene, it can become pretty big; in my case, I decided to use the preview system for the entire map, basically only writing the actual data into a big array with ints and then at runtime instantiate all tiles again. This was purely to save on scene size. If you are drawing your tile matrix in code, you have a lot of options; I'd vote for sprites, because they are easy (new GameObject, attach SpriteRenderer, get image, set sprite, move to position, done), this way, my example wouldn't be any different from game code, other than HideFlags. I'd actually use a TileFactory and some kind of $$anonymous$$ap$$anonymous$$anager to create and lay out tiles in the game, and just call that in the editor and set HideFlags on everything.
Yes! The approach of using these hidden quads is what I am going to use for the editor. I don't really $$anonymous$$d about performance because my maps now are of a maximum size of 7x11. And yes, I also want to just generate a 2D int matrix, that is enough to recreate the level when a level starts.
For bigger maps, the approach I would take would be to separate the map in chunks (meshes), and regenerating the UVs properly depending on it, but having read what you said, it seems to be worth to try with this approach you say.
Also, thanks for the other suggestions and clarifications. Seems like a good approach you are defining there.
Answer by hexagonius · Aug 26, 2017 at 01:01 PM
I would say you've zoomed into a pixel grid. And since there's no half pixel, both are equally sized. Since its pixel coordinates you need to calculate the pixel per unit radio yourself.
I am not zoo$$anonymous$$g it into a pixel grid. Here is another screenshot with the bounds of the mobile camera. If this is a pixel grid, then the mobile resolution is 6 x 10 pixels.
yes you're right, I apologize. Then why is it that the quads start at 0,0,0 when the docs say that position is in the upper left corner? The only reason for that is that we ARE talking pixels here and they are just equal to one unit like with the default Overlay GUI. What does the game view show? Are there 2 tiny pixels in the upper left?
No worries! I am using this in the editor for the scene view, so this doesn't appear in the Game view. I had a smell that it could be something related to that, like that DrawTexture is not prepared to be used in the scene editor.
Your answer
Follow this Question
Related Questions
Importing FBX with textures 1 Answer
2 textures on one object 1 Answer
Delta event out of Editor Problem 4 Answers
Editor Script Selection thinks Sprites are Texture2Ds. 2 Answers
Leaking Textures in custom editor 2 Answers