bool CanModelBeEdited(VoxelModel model) { if (model.blocks == null || model.palette == null || model.voxelModelRenderer == null || model.voxelSize == 0) { return(false); } return(true); }
void Update() { VoxelModel model = (VoxelModel)target; if (!CanModelBeEdited(model)) { return; } float voxelHalfSize = model.voxelSize / 2.0f; //Repaint(); }
void OnSceneGUI() { VoxelModel model = (VoxelModel)target; if (!CanModelBeEdited(model)) { return; } float voxelHalfSize = model.voxelSize / 2.0f; Handles.DrawWireCube(new Vector3(model.width * (voxelHalfSize), model.height * (voxelHalfSize), model.depth * (voxelHalfSize)), new Vector3(model.width * (model.voxelSize), model.height * (model.voxelSize), model.depth * (model.voxelSize))); if (wasFirstHit) { Handles.color = Color.red; Handles.DrawWireCube(firstHitPosition * model.voxelSize + new Vector3(voxelHalfSize, voxelHalfSize, voxelHalfSize), new Vector3(model.voxelSize, model.voxelSize, model.voxelSize)); Handles.color = Color.white; } // TODO(Brajan): Refactor this to avoid double Raycast function call Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 1000)) { Vector3 rawPosition; if (editMode == EditMode.Place) { rawPosition = hit.point + (hit.normal * voxelHalfSize); } else { rawPosition = hit.point - (hit.normal * voxelHalfSize); } int x = Mathf.FloorToInt(rawPosition.x / model.voxelSize); int y = Mathf.FloorToInt(rawPosition.y / model.voxelSize); int z = Mathf.FloorToInt(rawPosition.z / model.voxelSize); Handles.color = Color.gray; Handles.DrawWireCube(new Vector3(x, y, z) * model.voxelSize + new Vector3(voxelHalfSize, voxelHalfSize, voxelHalfSize), new Vector3(model.voxelSize, model.voxelSize, model.voxelSize)); Handles.color = Color.white; } if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.control) { if (Physics.Raycast(ray, out hit, 1000)) { if (!wasFirstHit) { Vector3 rawPosition; if (editMode == EditMode.Place) { rawPosition = hit.point + (hit.normal * voxelHalfSize); } else { rawPosition = hit.point - (hit.normal * voxelHalfSize); } int x = Mathf.FloorToInt(rawPosition.x / model.voxelSize); int y = Mathf.FloorToInt(rawPosition.y / model.voxelSize); int z = Mathf.FloorToInt(rawPosition.z / model.voxelSize); firstHitPosition = new Vector3(x, y, z); wasFirstHit = true; } else { Vector3 rawPosition = hit.point + (hit.normal * voxelHalfSize); if (editMode == EditMode.Place) { rawPosition = hit.point + (hit.normal * voxelHalfSize); } else { rawPosition = hit.point - (hit.normal * voxelHalfSize); } int secondX = Mathf.FloorToInt(rawPosition.x / model.voxelSize); int secondY = Mathf.FloorToInt(rawPosition.y / model.voxelSize); int secondZ = Mathf.FloorToInt(rawPosition.z / model.voxelSize); int startX = (int)firstHitPosition.x > secondX ? secondX : (int)firstHitPosition.x; int startY = (int)firstHitPosition.y > secondY ? secondY : (int)firstHitPosition.y; int startZ = (int)firstHitPosition.z > secondZ ? secondZ : (int)firstHitPosition.z; int endX = (int)firstHitPosition.x > secondX ? (int)firstHitPosition.x : secondX; int endY = (int)firstHitPosition.y > secondY ? (int)firstHitPosition.y : secondY; int endZ = (int)firstHitPosition.z > secondZ ? (int)firstHitPosition.z : secondZ; for (int x = startX; x <= endX; ++x) { for (int y = startY; y <= endY; ++y) { for (int z = startZ; z <= endZ; ++z) { if (editMode == EditMode.Place) { if (x >= 0 && y >= 0 && z >= 0 && x < model.width && y < model.height && z < model.depth && model.GetBlock(x, y, z) == 0) { model.SetBlock(colorIndex >= 0 ? colorIndex + 1 : 1, x, y, z); } } else { if (x >= 0 && y >= 0 && z >= 0 && x < model.width && y < model.height && z < model.depth && model.GetBlock(x, y, z) > 0) { if (editMode == EditMode.Erase) { model.SetBlock(0, x, y, z); } else if (editMode == EditMode.Paint) { if (colorIndex >= 0) { model.SetBlock(colorIndex + 1, x, y, z); } } } } } } } wasFirstHit = false; } } model.voxelModelRenderer.Regenerate(); Event.current.Use(); } if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { wasFirstHit = false; if (Physics.Raycast(ray, out hit, 1000)) { if (hit.transform.GetComponent <VoxelModel>() == model) { if (editMode == EditMode.Place) { Vector3 rawPosition = hit.point + (hit.normal * voxelHalfSize); int x = Mathf.FloorToInt(rawPosition.x / model.voxelSize); int y = Mathf.FloorToInt(rawPosition.y / model.voxelSize); int z = Mathf.FloorToInt(rawPosition.z / model.voxelSize); if (x >= 0 && y >= 0 && z >= 0 && x < model.width && y < model.height && z < model.depth && model.GetBlock(x, y, z) == 0) { model.SetBlock(colorIndex >= 0 ? colorIndex + 1 : 1, x, y, z); } } else { Vector3 rawPosition = hit.point - (hit.normal * voxelHalfSize); int x = Mathf.FloorToInt(rawPosition.x / model.voxelSize); int y = Mathf.FloorToInt(rawPosition.y / model.voxelSize); int z = Mathf.FloorToInt(rawPosition.z / model.voxelSize); if (x >= 0 && y >= 0 && z >= 0 && x < model.width && y < model.height && z < model.depth && model.GetBlock(x, y, z) > 0) { if (editMode == EditMode.Erase) { model.SetBlock(0, x, y, z); } else if (editMode == EditMode.Paint) { if (colorIndex >= 0) { model.SetBlock(colorIndex + 1, x, y, z); } } } } model.voxelModelRenderer.Regenerate(); Event.current.Use(); } } } else if (Event.current.type == EventType.layout) { HandleUtility.AddDefaultControl(GUIUtility.GetControlID(GetHashCode(), FocusType.Passive)); } SceneView.RepaintAll(); }
public override void OnInspectorGUI() { VoxelModel model = (VoxelModel)target; model.voxelModelRenderer = (VoxelModelRenderer)EditorGUILayout.ObjectField("Voxel Model Renderer", model.voxelModelRenderer, typeof(VoxelModelRenderer), true); if (model.voxelModelRenderer == null) { GUILayout.Label("Please set VoxelModelRenderer reference to continue"); return; } GUILayout.Label("Size"); model.width = EditorGUILayout.IntField("Width", model.width); model.height = EditorGUILayout.IntField("Height", model.height); model.depth = EditorGUILayout.IntField("Depth", model.depth); model.voxelSize = EditorGUILayout.FloatField("Voxel Size", model.voxelSize); if (GUILayout.Button("Apply new dimensions (WARNING it will destroy current progress)")) { model.blocks = new int[model.width * model.height * model.depth]; model.voxelModelRenderer.Regenerate(); } if (GUILayout.Button("Regenerate mesh")) { model.voxelModelRenderer.Regenerate(); } EditorGUILayout.Space(); model.palette = (VoxelColorPalette)EditorGUILayout.ObjectField("Color palette", model.palette, typeof(VoxelColorPalette), false); if (model.palette == null) { GUILayout.Label("We need palette to continue our work!"); return; } EditorGUILayout.Space(); if (model.blocks == null) { GUILayout.Label("Blocks are not initialized, please apply new dimensions"); return; } if (GUILayout.Button("Randomize")) { Random.InitState(System.DateTime.Now.Millisecond); for (int x = 0; x < model.width; ++x) { for (int y = 0; y < model.height; ++y) { for (int z = 0; z < model.depth; ++z) { model.SetBlock(Random.Range(0, model.palette.colors.Count + 1), x, y, z); } } } model.voxelModelRenderer.Regenerate(); } EditorGUILayout.Space(); GUILayout.Label("Tools (Current mode: " + editMode.ToString() + ")", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Place mode", GUILayout.Width(96), GUILayout.Height(32))) { editMode = EditMode.Place; //colorIndex = -1; } if (GUILayout.Button("Erasing mode", GUILayout.Width(96), GUILayout.Height(32))) { editMode = EditMode.Erase; colorIndex = -1; } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Reset position(must be at 0, 0, 0)")) { model.transform.position = Vector3.zero; } if (GUILayout.Button("Fill")) { for (int x = 0; x < model.width; ++x) { for (int y = 0; y < model.height; ++y) { for (int z = 0; z < model.depth; ++z) { model.SetBlock(colorIndex + 1, x, y, z); } } } model.voxelModelRenderer.Regenerate(); } if (GUILayout.Button("Generate sphere")) { float radius = Mathf.Min(model.width, model.height, model.depth) / 2.0f; for (int x = 0; x < model.width; ++x) { for (int y = 0; y < model.height; ++y) { for (int z = 0; z < model.depth; ++z) { if (Vector3.Distance(new Vector3(model.width / 2.0f, model.height / 2.0f, model.depth / 2.0f), new Vector3(x, y, z)) <= radius) { model.SetBlock(colorIndex + 1, x, y, z); } } } } model.voxelModelRenderer.Regenerate(); } if (GUILayout.Button("Generate base")) { float radius = Mathf.Min(model.width, model.height, model.depth) / 2.0f; for (int x = 0; x < model.width; ++x) { for (int z = 0; z < model.depth; ++z) { model.SetBlock(colorIndex + 1, x, 0, z); } } model.voxelModelRenderer.Regenerate(); } EditorGUILayout.Space(); GUILayout.Label("Palette", EditorStyles.boldLabel); for (int i = 0; i < model.palette.colors.Count; ++i) { EditorGUILayout.BeginVertical(GUILayout.Height(48)); EditorGUILayout.BeginHorizontal(GUILayout.Width(Screen.width / 2.0f)); if (GUILayout.Button("Select", GUILayout.Height(32))) { colorIndex = i; editMode = EditMode.Paint; } Rect buttonRect = GUILayoutUtility.GetLastRect(); if (colorIndex == i) { EditorGUI.DrawRect(new Rect(buttonRect.x + buttonRect.width + 4, buttonRect.y - 4, 40, 40), Color.red); } EditorGUI.DrawRect(new Rect(buttonRect.x + buttonRect.width + 8, buttonRect.y, 32, 32), model.palette.colors[i]); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } EditorGUILayout.Space(); if (GUILayout.Button("Save as mesh asset")) { Mesh meshToSave = (Mesh)Instantiate(model.mesh); string path = EditorUtility.SaveFilePanelInProject("Saving voxel mesh", "VM_Unknown", "asset", "Choose path where you wanna save model"); Debug.Log(path); AssetDatabase.CreateAsset(meshToSave, path); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); // create and save prefab with pivot at the center GameObject modelParent = new GameObject(path.Substring(path.LastIndexOf('/'))); GameObject modelPrefab = new GameObject("GFX"); modelPrefab.AddComponent <MeshRenderer>().sharedMaterial = model.GetComponent <MeshRenderer>().sharedMaterial; modelPrefab.GetComponent <MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.TwoSided; modelPrefab.AddComponent <MeshFilter>().mesh = meshToSave; modelPrefab.AddComponent <MeshCollider>().sharedMesh = meshToSave; modelPrefab.transform.parent = modelParent.transform; modelPrefab.transform.localPosition = new Vector3(model.width * (model.voxelSize / 2.0f), model.height * (model.voxelSize / 2.0f), model.depth * (model.voxelSize / 2.0f)) * -1; EditorUtility.SetDirty(modelParent); PrefabUtility.CreatePrefab(path.Substring(0, path.LastIndexOf('.')) + ".prefab", modelParent); DestroyImmediate(modelParent); DestroyImmediate(modelPrefab); } }