- Home /
How to flush mesh batch in editor OR how to draw a mesh for single frame in editor?
Short version: I'm drawing mesh from EditorWindow in edit mode, scene view and the mesh is not drawn for single frame, but instead it remains in scene until certain event (like saving scene) occurs - how can I make the mesh to be rendered for single frame? (For next frame I move it, so I need to be rendered in different place so original mesh is not needed to be rendered anymore.)
See the image bellow: I want to draw the blue box only once!
Long version: I want to add following functionality: user selects a Game Object (from either current scene or prefabs) and then puts it into the scene. But when the object is put there (and only at that time), I want to run some code to transform it (especially position, but I have other reasons (currently not implemented) why drag and drop from Prefabs is not enough).
For this purpose I created a EditorWindow object which creates gui to select the object to be added (I plan in future to make a list for simple fast selection) and this window also renders the mesh as preview when user moves mouse over scene view. For this reason, I do not want to create the object before user confirms it by clicking.
This is code I use (please note that instantiating the new object and transforming it is not implemented yet):
using UnityEngine;
using System.Collections;
using UnityEditor;
[ExecuteInEditMode]
public class BlockAdderWindow : EditorWindow
{
struct CurrentSelection
{
public bool isSelected;
public Vector3 position;
}
[SerializeField]
Material previewMaterial;
[SerializeField]
bool enabled;
[SerializeField]
GameObject parentObject = null;
[SerializeField]
GameObject templateObject = null;
Mesh renderMesh;
CurrentSelection currentSelection;
[MenuItem("Window/Block Adder")]
static void Init()
{
EditorWindow.GetWindow(typeof(BlockAdderWindow)).Show();
}
void OnEnable()
{
SceneView.onSceneGUIDelegate += OnSceneGUI;
}
void OnDisable()
{
SceneView.onSceneGUIDelegate -= OnSceneGUI;
}
void OnSceneGUI(SceneView sceneView)
{
if(enabled)
{
Camera camera = sceneView.camera;
Vector2 mousePosition = Event.current.mousePosition;
mousePosition.y = sceneView.camera.pixelHeight - mousePosition.y;
CalcSelection(camera, mousePosition);
}
RenderSelection();
}
void Update()
{
//RenderSelection();
}
void OnGUI()
{
EditorGUILayout.BeginVertical();
{
GameObject oldTemplate = templateObject;
enabled = EditorGUILayout.Toggle("Enabled", enabled);
previewMaterial = EditorGUILayout.ObjectField("Preview material", previewMaterial, typeof(Material), true) as Material;
parentObject = EditorGUILayout.ObjectField("Parent", parentObject, typeof(GameObject), true) as GameObject;
templateObject = EditorGUILayout.ObjectField("Template", templateObject, typeof(GameObject), true) as GameObject;
renderMesh = EditorGUILayout.ObjectField("Render mesh", renderMesh, typeof(Mesh), true) as Mesh;
if( (oldTemplate != templateObject) || ((templateObject != null) && (renderMesh == null)) )
{
renderMesh = null;
if(templateObject)
{
MeshFilter meshFilter = templateObject.GetComponent<MeshFilter>();
if(meshFilter)
{
renderMesh = meshFilter.sharedMesh;
}
}
enabled = enabled && (renderMesh != null);
}
}
EditorGUILayout.EndVertical();
}
void CalcSelection(Camera camera, Vector2 mousePosition)
{
//currentSelection.isSelected = false;
if(camera != null)
{
Ray ray = camera.ScreenPointToRay(mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
currentSelection.isSelected = true;
currentSelection.position = hit.point;
//Debug.Log("Selected " + hit.collider.gameObject.name);
}
}
}
void RenderSelection()
{
if(enabled && currentSelection.isSelected)
{
Graphics.DrawMesh(renderMesh, currentSelection.position,
Quaternion.identity, previewMaterial, 0);
}
}
}
Problem is with line Graphics.DrawMesh(...) - it does not draw the mesh for single frame only - instead, it remains there so when user moves with mouse, it looks like adding multiple objects:
Image on left displays standard scene, image on right displays the problem - I moved the mouse over the scene (only one blue box is expected).
All the meshes disappears when:
I save the scene
I select item which is displayed in inspector but it wasn't selected before
Game is started
When the game is running and I switch to Scene View, the code works as expected: only one mesh in a frame is rendered.
I created simple project for reproducing the error, you can download it here.
To reproduce the problem, follow these steps:
Open the project
Open scene Assets/Scenes/Scene
Open my window: Window / Block Adder
Drag and drop Game Object named "Box" to "Template" field in the Block Adder Window
Drag and drop Assets/Materials/preview_mat to "Preview material" field in the Block Adder Window
Toggle "Enabled" (in the Block Adder Window) to enable the functionality
Move the mouse over the scene in Scene View Window.
Observe the issue.
My environment:
Windows 7 Professional SP1
Unity 4.3.0f4 (Free version currently)
Did you ever make any progress on this? I've been having this issue for a while. Initially, I switched to using OnDrawGizmosSelected which does clear the meshes each frame, but has other side effects (such as rendering after OnGUI).
@guavaman I apologize for not answering to you sooner - for some reason, I received e-mail notification about this now, three days later. Anyway, answer is no, but (during work on other project) I found work-around: create game object for this purpose (displaying the mesh and everything) in root of the scene with hide-flags set to hide-and-dont-save (important note: it must be in root, otherwise when scene is saved, any attempt to load the scene will end with crash (it's a Unity bug).
Answer by guavaman · May 27, 2014 at 06:13 AM
I found the solution:
Make all your Graphics.DrawMeshNow calls from within there and it will work as expected.
@guavaman I apologize for late reply - see my comment above. Thank you, I can confirm it's working!
Note: with new Unity (currently 4.3.4f1) the behavior is little different: the scene is unchanged during mouse move until you press a button. It can be solved by SceneView.RepaintAll();
and combined with your fix it works well.
Btw. how can I accept this answer? I cannot find the button anywhere...
I use a separate gameobject, set its hideflags HideAndDontSave and draw in the Update method, but using SetDirty that gameobject everytime i want to refresh. It works fine and you can also use Graphics.Draw$$anonymous$$esh(). The only inconvenience is that it will make your scene dirty and ask you before closing unity if you want to save.
For those that might have thought of checking the source code and search where to hijack the rendering via render textures and so on, don't, there are many things that are hardcoded and will end up in dead ends, internal calls to the C side of Unity and such. I wasted a lot of time searching and in the end it's better to just play inside the Unity box.
Answer by pvaananen · Jun 28, 2017 at 10:51 AM
Here's a workaround (Unity 5.6.1f1) that allows you to use regular Graphics.DrawMesh instead of DrawMeshNow. It relies on checking when the "frame" (you don't really have the frame loop in editor) changed and submitting new draw calls only then.
int lastRenderedFrame;
void Start() {
SceneView.onSceneGUIDelegate += OnSceneGUI;
}
void OnSceneGUI(SceneView view)
{
if (Event.current.type == EventType.Layout)
{
// Force the view to update.
EditorUtility.SetDirty(gameObject);
// Only update if we know that the queue was cleared.
if (lastRenderedFrame != Time.renderedFrameCount)
{
drawMyMeshes(); // Uses Graphics.DrawMesh()
lastRenderedFrame = Time.renderedFrameCount;
}
}
}
Answer by mustmiekieke · Feb 26 at 01:36 PM
This answer is for people who are running into the same problem but are drawing inside the OnToolGUI()
method of an EditorTool
!
I am using the new EditorTool
clas for creating a custom tool that can place blocks in a grid. I am drawing previews of the blocks with Graphics.DrawMesh()
but i was running into similar problems as the OP. I have found many threads discussing this problem but none of the solutions worked for me. That is, until I tried the answer of @pvaananen in this thread. I can't seem to reply directly to his/her comment so I'm posting this here.
So: If you are trying to draw meshes directly inside the OnToolGUI()
of an EditorTool
, try the answer of @pvaananen! I've replaced the EditorUtility.SetDirty(gameObject);
part with EditorUtility.SetDirty(this);
and that seems to do the trick.
Your answer
![](https://koobas.hobune.stream/wayback/20220613123925im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Unity Editor Event System 1 Answer
Changes to Object made in custom Editor Window don't persist 0 Answers
Keep equal width for panels in EditorGUILayout.HorizontalScope 0 Answers
Execute editor window scripts when project errors are present 0 Answers
Is interraction between EditorWindow and php file possible? 1 Answer