├── LICENSE ├── SignalManager.cs ├── CameraController.cs ├── README.md ├── WorldToScreen.cs ├── FaceDirectionManager.cs └── Rotator.cs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 NoiR_CCC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SignalManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class SignalManager : MonoBehaviour 6 | { 7 | // For non-HDR colors, remove [ColorUsageAttribute...] 8 | [SerializeField] [ColorUsageAttribute(true, true, 0f, 8f, 0.125f, 3f)] private Color color1; 9 | [SerializeField] [ColorUsageAttribute(true, true, 0f, 8f, 0.125f, 3f)] private Color color2; 10 | [SerializeField] [ColorUsageAttribute(true, true, 0f, 8f, 0.125f, 3f)] private Color color3; 11 | 12 | private void Awake() 13 | { 14 | // Limit framerate to 60fps; 15 | //QualitySettings.vSyncCount = 0; 16 | //Application.targetFrameRate = 60; 17 | } 18 | 19 | public void UpdateAmbientColor(int i) 20 | { 21 | switch(i){ 22 | case 1: 23 | RenderSettings.ambientLight = color1; 24 | break; 25 | case 2: 26 | RenderSettings.ambientLight = color2; 27 | break; 28 | case 3: 29 | RenderSettings.ambientLight = color3; 30 | break; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /CameraController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class CameraController : MonoBehaviour 6 | { 7 | private List cameras; 8 | [SerializeField] private Transform target; 9 | [SerializeField] private float baseFOV = 20f; 10 | [SerializeField] private float minFOV = 10f; 11 | [SerializeField] private float maxFOV = 120f; 12 | 13 | 14 | private void Awake() 15 | { 16 | // Get Camera component of each children; 17 | for(int i=0; i< transform.childCount; i++) 18 | { 19 | cameras.Add(transform.GetChild(i).GetComponent()); 20 | } 21 | 22 | // Initialize camera FoV; 23 | foreach (Camera cam in cameras) 24 | { 25 | cam.fieldOfView = baseFOV; 26 | } 27 | 28 | // Set background video height = camera height; 29 | target.position = new Vector3(target.position.x, transform.position.y, target.position.z); 30 | } 31 | 32 | private void Update() 33 | { 34 | // Update camera FoV (with clamping) according to self position z; 35 | foreach (Camera cam in cameras) 36 | { 37 | cam.fieldOfView = Mathf.Clamp(baseFOV + 5 * (transform.position.z - 30f), minFOV, maxFOV); 38 | } 39 | } 40 | 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unity-mmd-utils 2 | 3 | Some of the stagework scripts for unity, used in https://www.bilibili.com/video/BV1ZA411s7Tx 4 | 5 | ## CameraController 6 | Updates FoV of all child cameras based on distance to target, useful for creating a 3D feel when using video backgrounds on some flat surface. Works with Cinemachine. 7 | 8 | ### Usage 9 | - Assign to empty GameObject. 10 | 11 | - Assign cameras as children. 12 | 13 | - Set target, tweak baseFoV. 14 | 15 | - If you wish to use Cinemachine & vcams, simply assign CinemachineBrain to this parent GameObject. 16 | 17 | ## SignalManager 18 | 19 | A simple management script for timeline signals. 20 | 21 | - Updates ambient lighting colors on-demand. 22 | 23 | ### Usage 24 | - Assign to empty GameObject. 25 | 26 | - Create a SignalReceiver with Signals 27 | 28 | - For each Signal, set the SignalManager, select the SignalManager.UpdateAmbientColor function and assign an integer to each: 1 corresponds to Color1; 2 corresponds to Color2, etc. 29 | 30 | - On the SignalReceiver track, place SignalEmitter tags where you want to update ambient lighting color, select some Signal for each tag to emit 31 | 32 | ## Rotator 33 | Rotates Transform at set speed or smoothly swing back and forth. 34 | 35 | ### Usage 36 | - Assign to GameObject and set parameters. 37 | 38 | ## FaceDirectionManager 39 | 40 | Originally used for debugging Genshin style face shading. Sends GameObject/bone's current heading to some shader. 41 | 42 | ### Usage 43 | - Shader needs to accept _DirectionVector. 44 | 45 | - Set target transform and name of target material. 46 | -------------------------------------------------------------------------------- /WorldToScreen.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | 4 | public class WorldToScreen : MonoBehaviour 5 | { 6 | public Transform targetObject; 7 | public Canvas canvas; 8 | private RectTransform rectTransform; 9 | 10 | void Start() 11 | { 12 | rectTransform = GetComponent(); 13 | } 14 | private void Update() 15 | { 16 | rectTransform.position = Vector2.Lerp(rectTransform.position, WorldToCanvasPosition(targetObject, canvas, Camera.main), 8*Time.deltaTime); 17 | } 18 | /// 19 | /// Get the WorldToScreenPosition translated to be used with UI elements inside a Canvas. 20 | /// 21 | /// Object in the world to follow. 22 | /// Canvas transform that holds the UI object we want to move. 23 | /// Camera to calculate the screen position. If null will use Camera.main (optional). 24 | /// 25 | static public Vector2 WorldToCanvasPosition(Transform worldObj, Canvas canvas, Camera cam = null) 26 | { 27 | 28 | if (!cam) 29 | { 30 | cam = Camera.main; 31 | } 32 | 33 | float canvasScale = Screen.width / canvas.GetComponent().referenceResolution.x; 34 | 35 | Vector3 screenPointUnscaled = cam.WorldToScreenPoint(worldObj.position); 36 | 37 | Vector2 screenPointScaled = new Vector2(screenPointUnscaled.x, screenPointUnscaled.y / canvas.scaleFactor); 38 | 39 | 40 | return screenPointScaled; 41 | } 42 | } -------------------------------------------------------------------------------- /FaceDirectionManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | public class FaceDirectionManager : MonoBehaviour 7 | { 8 | [SerializeField] private Transform TargetTransform; 9 | private Renderer r; 10 | [SerializeField] private string TargetMaterialName = ""; 11 | [SerializeField] private Material targetMat; 12 | private Vector4 targetDir = Vector4.zero; 13 | 14 | private void Awake() 15 | { 16 | // Get renderer; 17 | r = gameObject.GetComponentInChildren(); 18 | 19 | // Get target material; 20 | foreach (Material mat in r.materials) 21 | { 22 | if (mat.name == TargetMaterialName) 23 | { 24 | targetMat = mat; 25 | break; 26 | } 27 | } 28 | 29 | } 30 | 31 | private void Update() 32 | { 33 | targetDir = UnityEditor.TransformUtils.GetInspectorRotation(TargetTransform.transform); 34 | SendDirection(targetDir); 35 | } 36 | private void FixedUpdate() 37 | { 38 | Debug.Log(targetDir); 39 | } 40 | 41 | private void SendDirection(Vector4 dir) 42 | { 43 | targetMat.SetVector("_DirectionVector",dir); 44 | } 45 | 46 | private static float WrapAngle(float angle) 47 | { 48 | angle %= 360; 49 | if (angle > 180) 50 | return angle - 360; 51 | 52 | return angle; 53 | } 54 | 55 | private static float UnwrapAngle(float angle) 56 | { 57 | if (angle >= 0) 58 | return angle; 59 | 60 | angle = -angle % 360; 61 | 62 | return 360 - angle; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Rotator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | public class Rotator : MonoBehaviour 7 | { 8 | public float speed = 10.0f; 9 | public bool swingMode = false; 10 | public float maxRotation = 70f; 11 | public float swingSpeed = 1f; 12 | Quaternion targetRotation = Quaternion.identity; 13 | public bool turningCounterClockwise = false; 14 | 15 | // Update is called once per frame 16 | void Update() 17 | { 18 | if(swingMode) 19 | { 20 | if (UnityEditor.TransformUtils.GetInspectorRotation(transform).y < maxRotation - 5f && !turningCounterClockwise) 21 | { 22 | targetRotation = Quaternion.Euler(0f, maxRotation, 0f); 23 | transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, swingSpeed * Time.deltaTime); 24 | //transform.rotation = Quaternion.Lerp(transform.rotation, new Quaternion.Euler(0f, maxRotation, 0f), 0.5f * Time.deltaTime); 25 | } 26 | else 27 | { 28 | turningCounterClockwise = true; 29 | targetRotation = Quaternion.Euler(0f, -maxRotation, 0f); 30 | transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, swingSpeed * Time.deltaTime); 31 | if (UnityEditor.TransformUtils.GetInspectorRotation(transform).y < -maxRotation + 5f) turningCounterClockwise = false; 32 | } 33 | } 34 | else 35 | { 36 | transform.Rotate(0.0f, speed * Time.deltaTime, 0.0f, Space.Self); 37 | } 38 | } 39 | 40 | private static float WrapAngle(float angle) 41 | { 42 | angle %= 360; 43 | if (angle > 180) 44 | return angle - 360; 45 | 46 | return angle; 47 | } 48 | 49 | private static float UnwrapAngle(float angle) 50 | { 51 | if (angle >= 0) 52 | return angle; 53 | 54 | angle = -angle % 360; 55 | 56 | return 360 - angle; 57 | } 58 | } 59 | --------------------------------------------------------------------------------