Skip to content

Commit

Permalink
Unity Blender Decimate
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexeyTaranov committed May 21, 2022
1 parent a63b97b commit 0a24173
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 0 deletions.
21 changes: 21 additions & 0 deletions Decimate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import bpy
import sys

argv = sys.argv
#Get only our arguments
argv = argv[argv.index("--") + 1:]
print(argv)
objPath = argv[0]
decimateValue = argv[1]

#Delete default objects:cube,camera,light
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

imported_object = bpy.ops.import_scene.obj(filepath=objPath)
obj_object = bpy.context.selected_objects[0]
decimate = obj_object.modifiers.new(name="Decimate", type = 'DECIMATE')
decimate.ratio = float(decimateValue)

#Export as obj
bpy.ops.export_scene.obj(filepath=objPath)
7 changes: 7 additions & 0 deletions Decimate.py.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 128 additions & 0 deletions UnityBlenderDecimate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System;
using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;

namespace Editor.UnityBlenderDecimate
{
public class UnityBlenderDecimate : EditorWindow
{
[MenuItem("Tools/Unity To Blender")]
public static void ShowExample()
{
UnityBlenderDecimate window = GetWindow<UnityBlenderDecimate>();
window.titleContent = new GUIContent("Unity Blender Decimate");
}

[SerializeField] private VisualTreeAsset visualTreeAsset;
[SerializeField] private string blenderPath;
private Button BlenderPathSelectButton => rootVisualElement.Q<Button>("blenderPathSelect");
private Label BlenderPathLabel => rootVisualElement.Q<Label>("blenderPath");
private ObjectField PythonScriptField => rootVisualElement.Q<ObjectField>("pythonScript");
private ObjectField InputObject => rootVisualElement.Q<ObjectField>("inputObject");

private GameObject selectedGameObject;
private string pythonScriptPath;

public void CreateGUI()
{
rootVisualElement.Add(visualTreeAsset.Instantiate());
#if UNITY_EDITOR_OSX
SetupOSXBlenderPath();
#else
BlenderPathSelectButton.RegisterCallback<ClickEvent>(OnBlenderSelectPathClick);
#endif

PythonScriptField.RegisterValueChangedCallback(OnPythonScriptSelect);
InputObject.RegisterValueChangedCallback(CheckSelectedInputObject);
rootVisualElement.Q<Button>("execute").RegisterCallback<ClickEvent>(Execute);

UpdateNextStep();
}

private void SetupOSXBlenderPath()
{
BlenderPathSelectButton.SetEnabled(false);
BlenderPathLabel.text = IsAvailableBlender() ? blenderPath : "Can't find Blender in Applications folder =(";

bool IsAvailableBlender()
{
blenderPath = Path.Combine("/Applications", "Blender.app", "Contents", "MacOS", "Blender");
return File.Exists(blenderPath);
}
}

private void UpdateNextStep()
{
Func<(bool isValidStep, string stepName)>[] steps =
{
() => (File.Exists(blenderPath), "blenderPathStep"),
() => (string.IsNullOrEmpty(pythonScriptPath) == false, "pythonScript"),
() => (selectedGameObject != null, "inputObjectStep"),
() => (true, "blenderExecuteStep")
};

var failedStep = Array.FindIndex(steps, func => func.Invoke().isValidStep == false);
for (var i = 0; i < steps.Length; i++)
{
var stepName = steps[i].Invoke().stepName;
var element = rootVisualElement.Q<VisualElement>(stepName);
element?.SetEnabled(failedStep >= i || failedStep == -1);
}
}

private void OnBlenderSelectPathClick(ClickEvent @event)
{
var path = string.IsNullOrEmpty(blenderPath) ? Application.dataPath : blenderPath;
var executableExtension = "exe";
blenderPath = EditorUtility.OpenFilePanel("Select Blender executable", path, executableExtension);
BlenderPathLabel.text = blenderPath;

UpdateNextStep();
}

private void OnPythonScriptSelect(ChangeEvent<Object> @event)
{
var path = AssetDatabase.GetAssetPath(@event.newValue);
pythonScriptPath = Path.GetExtension(path) == ".py" ? Path.GetFullPath(path) : null;

UpdateNextStep();
}

private void CheckSelectedInputObject(ChangeEvent<Object> @event)
{
PrefabAssetType prefabType = PrefabAssetType.NotAPrefab;
var go = @event.newValue as GameObject;
if (go != null)
{
var prefabAssetType = PrefabUtility.GetPrefabAssetType(go);
var fileExtension = Path.GetExtension(AssetDatabase.GetAssetPath(go));
var isObjModel = prefabAssetType == PrefabAssetType.Model && fileExtension == ".obj";
prefabType = isObjModel ? PrefabAssetType.Model : PrefabAssetType.NotAPrefab;
}
selectedGameObject = prefabType == PrefabAssetType.Model ? go : null;
InputObject.value = selectedGameObject;

UpdateNextStep();
}

private void Execute(ClickEvent @event)
{
var decimateValue = rootVisualElement.Q<Slider>("decimate").value;
var absolutePathToObj = Path.GetFullPath(AssetDatabase.GetAssetPath(selectedGameObject));
absolutePathToObj = '"' + absolutePathToObj + '"';
var blenderProcess = new Process();
blenderProcess.StartInfo.FileName = blenderPath;
var bgBlenderArgs = $"--background --python {pythonScriptPath} -- {absolutePathToObj} {decimateValue}";
blenderProcess.StartInfo.Arguments = bgBlenderArgs;
blenderProcess.Start();
//TODO: Don't lock Unity
blenderProcess.WaitForExit();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
}
}
14 changes: 14 additions & 0 deletions UnityBlenderDecimate.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions UnityToBlender.uxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" editor-extension-mode="True">
<ui:Label text="Unity Blender Decimate" style="-unity-text-align: upper-center; font-size: 20px; -unity-font-style: bold;" />
<ui:VisualElement style="height: 4px; width: 504px;" />
<ui:VisualElement name="blenderPathStep" style="flex-direction: row;">
<ui:Button name="blenderPathSelect" text="Edit Blender Path" />
<ui:Label name="blenderPath" style="-unity-text-align: middle-left;" />
</ui:VisualElement>
<uie:ObjectField label="Python Script" name="pythonScript" type="UnityEditor.DefaultAsset, UnityEditor.CoreModule" />
<ui:VisualElement name="inputObjectStep">
<uie:ObjectField name="inputObject" label="OBJ Model" type="UnityEngine.GameObject, UnityEngine.CoreModule" allow-scene-objects="false" />
</ui:VisualElement>
<ui:VisualElement name="blenderExecuteStep">
<ui:Slider name="decimate" label="Decimate" value="1" high-value="1" show-input-field="true" />
<ui:Button name="execute" text="Run" display-tooltip-when-elided="true" />
</ui:VisualElement>
</ui:UXML>
10 changes: 10 additions & 0 deletions UnityToBlender.uxml.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0a24173

Please sign in to comment.