Differences
This shows you the differences between two versions of the page.
Previous revision | |||
— | appwiki:unity [2023/06/18 17:12] (current) – [Pipeline Connection] ying | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Unity Hub as tool to install old Visual Studio community edition ====== | ||
+ | |||
+ | * install old visual studio community edition become hard and hard, now you need microsoft account, join their free dev essential, dig through page of outdated link, found only allow you download latest community edition | ||
+ | * https:// | ||
+ | * while with unity hub, it auto find correct community edition that works with the unity version | ||
+ | * Unity 2022 = visual studio community edition 2019 | ||
+ | * Unity 2018 = visual studio community edition 2017 | ||
+ | * Unity 5.3.1 = visual studio community edition 2015 | ||
+ | |||
+ | ====== Python for Unity ====== | ||
+ | |||
+ | ref: | ||
+ | * https:// | ||
+ | * https:// | ||
+ | * https:// | ||
+ | * https:// | ||
+ | |||
+ | Instruction | ||
+ | * as unity is project based, each project have its own list of copied package (like node.js project, unlike python which use shared modules) | ||
+ | * so, to enable a feather, it is project based, so you need to enable that for each project manually | ||
+ | * to enable python for unity for current project, go Window > Package Manager, change package source drop down on top left as "Unity Registery", | ||
+ | * then, go top left + icon, click and choose "Add package from git url", type name " | ||
+ | * Tell check python app folder, go to (File > Project Setting) or (Building Setting > Player Setting button below - same as project setting); if you use version " | ||
+ | * once you open your project python console, to install PySide2 (which designed for py3.x, so we get latest Qt ui lib), type < | ||
+ | import pip | ||
+ | pip.main([" | ||
+ | </ | ||
+ | * so we are done with basic python setup for the project, you can use same method to install other python modules | ||
+ | * now, we go the unity built python command box, Window > General > Python Console, check python to query unity objects <code python> | ||
+ | import UnityEngine as unity | ||
+ | obj_list = unity.Object.FindObjectsOfType(unity.GameObject) | ||
+ | for each_obj in obj_list: | ||
+ | print(each_obj.name) | ||
+ | </ | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ====== Python and Qt inside Unity ====== | ||
+ | |||
+ | Once above basic setup for python is done for unity, I would like to get Qt working and interaction with unity. \\ (Note, don't launch python Qt code from Python Console inside Unity, it will show Qt window, but it also block Unity UI interaction, | ||
+ | |||
+ | After a bit research, mainly from video of Indie-Pixel' | ||
+ | |||
+ | I got it further into make the PySide2 UI interaction working. the main thing is print(). you need to < | ||
+ | import UnityEngine as unity | ||
+ | unity.Debug.Log(" | ||
+ | </ | ||
+ | |||
+ | Steps: | ||
+ | - create a empty PyTool.cs for attaching to a GameObject | ||
+ | - create a PyToolEditor.cs for making buttons to launch those python script file, and PyToolEditor.cs is actual interface (so called UI file) of PyTool.cs | ||
+ | - so depends on how many python scripts to launch, you make how many button inside PyToolEditor.cs | ||
+ | - I created 2 .py examples, one without UI, one with Qt UI | ||
+ | - I put 2 python script inside Assets' | ||
+ | - PythonScript/ | ||
+ | - PythonScript/ | ||
+ | |||
+ | {{: | ||
+ | |||
+ | <code csharp PyTool.cs> | ||
+ | using System.Collections; | ||
+ | using System.Collections.Generic; | ||
+ | using UnityEngine; | ||
+ | |||
+ | public class PyTool : MonoBehaviour | ||
+ | { | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | <code csharp PyToolEditor.cs> | ||
+ | using System.Collections; | ||
+ | using System.Collections.Generic; | ||
+ | using UnityEngine; | ||
+ | using UnityEditor; | ||
+ | using UnityEditor.Scripting.Python; | ||
+ | |||
+ | [CustomEditor(typeof(PyTool))] | ||
+ | public class PyToolEditor : Editor | ||
+ | { | ||
+ | PyTool targetTool; | ||
+ | private void OnEnable() | ||
+ | { | ||
+ | targetTool = (PyTool)target; | ||
+ | } | ||
+ | public override void OnInspectorGUI() | ||
+ | { | ||
+ | if (GUILayout.Button(" | ||
+ | Debug.Log(" | ||
+ | string cur_path = Application.dataPath; | ||
+ | Debug.Log(cur_path); | ||
+ | string py_file = cur_path + "/ | ||
+ | Debug.Log(py_file); | ||
+ | PythonRunner.RunFile(py_file); | ||
+ | } | ||
+ | if (GUILayout.Button(" | ||
+ | { | ||
+ | Debug.Log(" | ||
+ | string cur_path = Application.dataPath; | ||
+ | string py_file = cur_path + "/ | ||
+ | Debug.Log(py_file); | ||
+ | PythonRunner.RunFile(py_file); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | <code python UnityPythonRun.py> | ||
+ | import UnityEngine as unity | ||
+ | def u_print(info): | ||
+ | unity.Debug.Log(info) | ||
+ | | ||
+ | obj_list = unity.Object.FindObjectsOfType(unity.GameObject) | ||
+ | for each_obj in obj_list: | ||
+ | print(each_obj.name) | ||
+ | u_print(each_obj.name) | ||
+ | print(' | ||
+ | u_print(' | ||
+ | </ | ||
+ | <code python TestQ.py> | ||
+ | import UnityEngine as unity | ||
+ | from PySide2 import QtWidgets | ||
+ | class TestUI(QtWidgets.QMainWindow): | ||
+ | def __init__(self, | ||
+ | QtWidgets.QMainWindow.__init__(self, | ||
+ | # win | ||
+ | self.setWindowTitle(" | ||
+ | # ui part | ||
+ | main_widget = QtWidgets.QWidget() | ||
+ | self.setCentralWidget(main_widget) | ||
+ | main_layout = QtWidgets.QVBoxLayout() | ||
+ | main_widget.setLayout(main_layout) | ||
+ | | ||
+ | test_btn = QtWidgets.QPushButton(" | ||
+ | main_layout.addWidget(test_btn) | ||
+ | # connection | ||
+ | test_btn.clicked.connect(self.list_items) | ||
+ | # function | ||
+ | def list_items(self): | ||
+ | print(' | ||
+ | self.u_print(' | ||
+ | obj_list = unity.Object.FindObjectsOfType(unity.GameObject) | ||
+ | for each_obj in obj_list: | ||
+ | self.u_print(each_obj.name) | ||
+ | def u_print(self, | ||
+ | unity.Debug.Log(info) | ||
+ | # fix QApplication singleton issue for run python inside some app | ||
+ | if not QtWidgets.QApplication.instance(): | ||
+ | app = QtWidgets.QApplication([]) | ||
+ | else: | ||
+ | app = QtWidgets.QApplication.instance() | ||
+ | main_ui = TestUI() | ||
+ | main_ui.show() | ||
+ | </ | ||
+ | ====== About Unity ====== | ||
+ | * a great game dev engine with free option available (previous known as Unity3D) | ||
+ | * https:// | ||
+ | |||
+ | ====== Structure of Unity ====== | ||
+ | |||
+ | * Project Template: ([[https:// | ||
+ | * pre-configured project setting for common type. | ||
+ | * 2d: includes: texture import, sprite packer, scene view, lighting and ortho camera | ||
+ | * 3d: using standard rendering pipeline | ||
+ | * HD render Pipeline: for highend graphics, support dx11+ | ||
+ | * universal render pipeline: for wide range of publish platform support. | ||
+ | |||
+ | |||
+ | * Frame ExecuteOrder: | ||
+ | * ref: https:// | ||
+ | * initialize | ||
+ | * physics update | ||
+ | * input event | ||
+ | * game logic | ||
+ | * scene render | ||
+ | * gizmo render | ||
+ | * gui render | ||
+ | * end of frame | ||
+ | |||
+ | * update order | ||
+ | * Fixed update: more frequenty, before physics, fixed timer | ||
+ | * update: normal update | ||
+ | * LateUpdate: once per frame, after update | ||
+ | ====== Shortcut ====== | ||
+ | |||
+ | ^ viewport navigation | alt-based Mouse navigate, RMB-hold WASD key navigate | | ||
+ | | focus on selected | f | | ||
+ | || | ||
+ | | snap obj to view pos | ctrl+shift+f (good for cam to cam match) | | ||
+ | || | ||
+ | | max view | shift+space (like max) | | ||
+ | |||
+ | Customize view | ||
+ | |||
+ | | asset panel | slide <left to list, >right to grid view | | ||
+ | |||
+ | ====== C# Script' | ||
+ | |||
+ | - C# script' | ||
+ | - C# script' | ||
+ | - once C# script in unity are dragged into Game Object, it is under Unity Game maker' | ||
+ | |||
+ | ====== C# common code for Unity ====== | ||
+ | * attributes <code csharp> | ||
+ | Debug.Log(" | ||
+ | public bool CamSwitch = true; | ||
+ | [Header(" | ||
+ | [Tooltip(" | ||
+ | public float Distance; | ||
+ | public float Radius; | ||
+ | public int Counter; | ||
+ | public Color NewColor; | ||
+ | public string NewName; | ||
+ | if (NewName!=null && NewName!="" | ||
+ | if (char.IsLetter(NewName[0])) {} // first char is letter | ||
+ | public enum Meal { | ||
+ | Breakfast, | ||
+ | Lunch, | ||
+ | Dinner, | ||
+ | Supper | ||
+ | } | ||
+ | int choice = (int)(MyMeal); | ||
+ | public Vector3 MyVector; | ||
+ | public Transform BulletEmiter; | ||
+ | public Object BulletPrefab; | ||
+ | public Light MyLight; | ||
+ | |||
+ | </ | ||
+ | * gameObject common attribute <code csharp> | ||
+ | gameObject.name = " | ||
+ | transform.position = new Vector3(1, | ||
+ | |||
+ | Camera myCam = GetComponent< | ||
+ | myCam.fieldOfView = CameraFov; | ||
+ | myCam.enabled = CamSwitch; | ||
+ | |||
+ | Light cur_light = GetComponent< | ||
+ | cur_light.color = MyColor; | ||
+ | </ | ||
+ | * change color (Render can be MeshRenderer or SpriteRenderer) <code csharp> | ||
+ | gameObject.GetComponent< | ||
+ | // for safe, better check GetComponent return not null | ||
+ | if (compo != null){} | ||
+ | </ | ||
+ | * destroy object <code csharp> | ||
+ | Destroy(gameObject, | ||
+ | </ | ||
+ | |||
+ | * common update functions <code csharp> | ||
+ | // opt check require for rigid body | ||
+ | [RequireComponent(typeof(Rigidbody))] | ||
+ | void Start(){ | ||
+ | // set initial speed after born | ||
+ | Rigidbody rb = GetComponent< | ||
+ | rb.velocity = transform.forward * BulletSpeed; | ||
+ | } | ||
+ | void FixedUpdate(){ | ||
+ | // before physics | ||
+ | float vertical = Input.GetAxis(" | ||
+ | float horizontal = Input.GetAxis(" | ||
+ | //this is inside FixedUpdate, | ||
+ | float deltaTime = Time.fixedDeltaTime; | ||
+ | Quaternion rotationDelta = Quaternion.Euler(0, | ||
+ | Quaternion newRotation = rb.rotation * rotationDelta; | ||
+ | rb.rotation = newRotation; | ||
+ | | ||
+ | Vector3 forward = rb.rotation * Vector3.forward; | ||
+ | Vector3 moveDelta = forward * Speed * vertical * deltaTime; | ||
+ | Vector3 newPos = rb.position + moveDelta; | ||
+ | rb.position = newPos; | ||
+ | } | ||
+ | void Update() | ||
+ | { | ||
+ | float dist = Time.deltaTime * speed; | ||
+ | transform.Translate(0, | ||
+ | | ||
+ | //if (Input.GetKeyDown(KeyCode.Space)) | ||
+ | if (Input.GetButtonDown(" | ||
+ | { | ||
+ | | ||
+ | } | ||
+ | // | ||
+ | float turn_amount_h = Time.deltaTime * RotateSpeed * Input.GetAxis(" | ||
+ | float turn_amount_v = Time.deltaTime * RotateSpeed * Input.GetAxis(" | ||
+ | transform.Rotate(turn_amount_v, | ||
+ | | ||
+ | float turn_amount = Time.deltaTime * RotateSpeed * Input.GetAxis(" | ||
+ | float forward_dist = Time.deltaTime * speed * Input.GetAxis(" | ||
+ | // | ||
+ | transform.Rotate(0, | ||
+ | transform.Translate(0, | ||
+ | | ||
+ | bool jump_start = Input.GetKeyDown(KeyCode.Space); | ||
+ | bool jump_end = Input.GetKeyUp(KeyCode.Space); | ||
+ | bool flying = Input.GetKey(KeyCode.Space); | ||
+ | | ||
+ | if (Input.GetKeyDown(KeyCode.W)) { print(" | ||
+ | if (Input.GetKeyDown(KeyCode.H) ) { | ||
+ | if ((Input.GetKey(KeyCode.RightControl) || Input.GetKey(KeyCode.LeftControl))) | ||
+ | { print(" | ||
+ | else { print(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * input event <code csharp> | ||
+ | Input.GetAxis() | ||
+ | // " | ||
+ | // "Mouse X" and "Mouse Y" : mapped to the mouse delta. | ||
+ | // " | ||
+ | // for any kind of movement behaviour use | ||
+ | Input.GetButton() for action-like events only | ||
+ | //all the Input calls in the Update Loop. | ||
+ | KeyCode : all of the key press, mouse and joystick options. | ||
+ | Input.touches : mobile | ||
+ | Input.acceleration & Input.deviceOrientation: | ||
+ | |||
+ | -property | ||
+ | Input.anyKey: | ||
+ | Input.anyKeyDown: | ||
+ | Input.mousePosition: | ||
+ | -method() | ||
+ | Input.GetAxis(): | ||
+ | Input.GetButton(): | ||
+ | Input.GetButtonDown(): | ||
+ | Input.GetButtonUp(): | ||
+ | Input.GetMouseButton(): | ||
+ | Input.GetMouseButtonDown(): | ||
+ | Input. GetMouseButtonUp(): | ||
+ | Input.GetTouch(): | ||
+ | |||
+ | Input.GetJoystickNames(): | ||
+ | Input.GetKey(KeyCode.Space): | ||
+ | Input.GetKeyDown(): | ||
+ | Input.GetKeyUp(): | ||
+ | |||
+ | |||
+ | |||
+ | if (Input.GetMouseButtonDown(0)){} | ||
+ | // 0 - left button; 1 - right button; 2 - middle button | ||
+ | |||
+ | |||
+ | </ | ||
+ | * other event function <code csharp> | ||
+ | private void OnCollisionEnter(Collision collision) | ||
+ | { | ||
+ | if (collision.gameObject.CompareTag(" | ||
+ | print(" | ||
+ | } | ||
+ | // | ||
+ | Destroy(gameObject);// | ||
+ | } | ||
+ | </ | ||
+ | * scene manager <code csharp> | ||
+ | //require to access SceneManager | ||
+ | using UnityEngine.SceneManagement; | ||
+ | SceneManager.LoadScene(SceneName); | ||
+ | </ | ||
+ | |||
+ | ====== Common package ====== | ||
+ | |||
+ | * LeanTween: https:// | ||
+ | |||
+ | |||
+ | ====== Pipeline Connection ====== | ||
+ | |||
+ | * Maya to fbx to Unity: | ||
+ | * copy texture set to unity first, so unity knows where is texture | ||
+ | * then send fbx, or copy fbx to unity | ||
+ | * then unity will correctly show texture with fbx | ||
+ | * Note, for unit, maya 1 unit is 1cm, Unity 1 unit is 1meter, so either you build in maya in real scale to avoid scale issue | ||
+ | * for one-off case, in unity asset browser, select fbx item, and in right inspector panel, set sale factor to 100 (most case) | ||
+ | * once for all solution, in Maya, set preference unit to meter, then you have to deal with clipping plane of default cameras | ||
+ | * another once for all solution, in fbx export, set Adv options > unit > uncheck auto, file units converted to meter | ||
+ | * best solution, model real world size in Maya, that is cm, so build a cube that is 100 unit as reference. (grid = 120,50) | ||
+ | |||
+ | * Unity to FBX: | ||
+ | * ref: https:// | ||
+ | * install package: FBX Exporter | ||
+ | * setup FBX export integration (need to redo per project base for the config to work) | ||
+ | - in Project Setting, FBX Export tab, choose 3D application to integration (or set manually with browse) | ||
+ | - click Install Unity Integration, | ||
+ | - wait for 3d app to open in background, and close project setting | ||
+ | - (Run Component update for update old unity fbx plugin) | ||
+ | * export outline object as linked fbx prefab | ||
+ | - right click menu on object > Convert to FBX linked prefab | ||
+ | * in 3DS max, | ||
+ | - file > import > Import from Unity, select that fbx file | ||
+ | - make your model edit | ||
+ | - file > export > export to Unity (support animation), model only with no animation | ||
+ | - now, unity window got updated. | ||
+ | - for LOD (setup in unity) | ||
+ | - ObjectNameLOD0 is the object | ||
+ | - ObjectNameLOD1, | ||
+ | - put all LOD object in a empty group called " | ||
+ | - if not detect, add LOD Group component in Unity object, drag each LOD component to LOD component slot. | ||
+ | - for LOD (setup in 3ds max) | ||
+ | - in the group node, go utilites tab, More..> | ||
+ | - now you have Level of Detail property in 3ds max group noe, then click " | ||
+ | - set LOD0 as 50%-100%, LOD1 as 25%-50%, LOD2 as 0-25%; | ||
+ | |||