Achieve Raycasting in an EditorWindow

Hello friends,

I am trying to create an EditorWindow that will allow me to edit some voxel assets. My final goal is to have the asset displayed in that window, and being able to add/ remove voxels from it directly in editor.

To achieve that, I want to do some Raycast from the editor window, but I have no luck so far in my implementation. This is my sample code :

using UnityEngine;
using UnityEditor;
using System.Collections;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using VoxelCrafter.Core.Voxels;

public class VoxelEditor : EditorWindow
{
  static Scene scene;
  static Camera camera;

  static GameObject target;

  [MenuItem("Window/VoxelCrafter/Editor", false, 10)]
  public static void Open()
  {
    EditorWindow.GetWindow<VoxelEditor>("VoxelEditor", true, typeof(EditorWindow));
  }

  void OnEnable() { CreateScene(); }
  void OnDisable() { EditorSceneManager.ClosePreviewScene(scene); }

  void CreateScene()
  {
    scene = EditorSceneManager.NewPreviewScene();

    if (!scene.IsValid())
      throw new UnityException("Preview scene could not be created");

    if (camera == null)
    {
      GameObject c = new GameObject();
      c.name = "Camera";

      camera = c.AddComponent<Camera>();
      camera.clearFlags = CameraClearFlags.SolidColor;
      camera.backgroundColor = new Color(0.25f, 0.25f, 0.25f, 1);
      camera.cameraType = CameraType.Preview;
      camera.nearClipPlane = 0.3f;
      camera.farClipPlane = 1000f;
      camera.transform.position = new Vector3(-5, 10, -5);
      camera.transform.Rotate(new Vector3(45, 45, 0));
      camera.orthographic = true;
      camera.scene = scene;

      EditorSceneManager.MoveGameObjectToScene(o, scene);
    }
  }

  void OnSelectionChange()
  {
    target = null;

    if (!Selection.activeGameObject)
      return;

    VoxelAssetViewer viewer = Selection.activeGameObject.GetComponent<VoxelAssetViewer>();

    if (!viewer)
      return;

    target = Instantiate(viewer.gameObject);
    EditorSceneManager.MoveGameObjectToScene(target, scene);
  }

  void OnGUI()
  {
    if (!target)
    {
      EditorGUILayout.LabelField("No VoxelAssetViewer selected");
      return;
    }

    camera.targetTexture = new RenderTexture((int)position.width, (int)position.height, 24, RenderTextureFormat.ARGB32);
    camera.Render();

    GUI.DrawTexture(new Rect(0, 0, position.width, position.height), camera.targetTexture);
  }
}

I have no idea how to implement this as every path I try lead me to a dead end.

I tried to :

  • Convert Input.mousePosition into Raycast from Update and OnGUI functions, but it seems like Input.mousePosition always give the exact same position whatever the actual mouse position.
  • Listen for OnSceneGUI() from an Editor script, but the event will not trigger on my PreviewScene, only from main scene
  • Use HandleUtility.GUIPointToWorldRay() but it seems it would no use the correct camera and I found no way to change this.

Any help would be much appreciated, thanks.

For editor UI stuff, I believe you want to use the Event class: Unity - Scripting API: Event

1 Like

Thanks @spiney199 , your proposition helped.

This is what I had to change in order to get it working :
→ Create a new Scene instead of using a PreviewScene
→ Stop rendering camera on a texture
→ Uses HandleUtility.GUIPointToScreenPixelCoordinate(Event.current.mousePosition) to trigger a camera.ScreenPointToRay()

if (Event.current.type == EventType.MouseDown)
    {
      Vector2 position = HandleUtility.GUIPointToScreenPixelCoordinate(Event.current.mousePosition);

      Ray ray = camera.ScreenPointToRay(position);
      RaycastHit hit = new RaycastHit();

      if (Physics.Raycast(ray, out hit, 1000.0f))
      {
        Debug.Log("HIT");
      }
    }