using Pumkin.AvatarTools; using Pumkin.DataStructures; using Pumkin.Dependencies; using Pumkin.HelperFunctions; using Pumkin.PoseEditor; using System; using UnityEditor; using UnityEngine; #if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON) using VRC.SDKBase; #endif namespace Pumkin.Presets { [Serializable] public class PumkinsCameraPreset : PumkinPreset { #if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON) public enum CameraOffsetMode { Viewpoint, AvatarRoot, Transform } public CameraOffsetMode offsetMode = CameraOffsetMode.Viewpoint; #else public enum CameraOffsetMode { AvatarRoot = 1, Transform } public CameraOffsetMode offsetMode = CameraOffsetMode.AvatarRoot; #endif public enum CameraBackgroundOverrideType { Color, Skybox, Image } public Vector3 positionOffset = Vector3.zero; public Vector3 rotationAnglesOffset = Vector3.zero; public string transformPath = ""; public bool useOverlay = false; public string overlayImagePath = ""; public Color overlayImageTint = Color.white; public bool useBackground = false; public CameraBackgroundOverrideType backgroundType = CameraBackgroundOverrideType.Color; public Color backgroundColor = Color.white; public string backgroundImagePath = ""; public Color backgroundImageTint = Color.white; public Material backgroundMaterial = null; private PumkinsCameraPreset() { } /// /// Applies preset to selected camera /// public override bool ApplyPreset(GameObject avatar) { Camera cam = PumkinsAvatarTools.SelectedCamera; if(!cam || !avatar) return false; Undo.RegisterFullObjectHierarchyUndo(cam.gameObject, "Apply Camera Preset"); Helpers.FixCameraClippingPlanes(cam); Transform dummy = null; try { #if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON) if(offsetMode == CameraOffsetMode.Viewpoint) { dummy = new GameObject("Dummy").transform; var desc = avatar.GetComponent(); if(desc) { dummy.localPosition = desc.transform.position + desc.ViewPosition; cam.transform.localPosition = positionOffset + dummy.transform.localPosition; cam.transform.localEulerAngles = rotationAnglesOffset + dummy.transform.localEulerAngles; } else { PumkinsAvatarTools.Log(Strings.Log.descriptorIsMissingCantGetViewpoint); } } #endif if(offsetMode > 0) { Transform t = avatar.transform.Find(transformPath); dummy = new GameObject("Dummy").transform; if(t) { Transform oldCamParent = cam.transform.parent; cam.transform.parent = dummy; cam.transform.localPosition = positionOffset; cam.transform.localEulerAngles = rotationAnglesOffset; dummy.SetPositionAndRotation(t.position, t.rotation); cam.transform.parent = oldCamParent; } } } catch(Exception e) { Debug.LogError(e.Message); if(dummy) Helpers.DestroyAppropriate(dummy.gameObject); return false; } finally { if(dummy) Helpers.DestroyAppropriate(dummy.gameObject); } PumkinsAvatarTools.Instance.bThumbnails_use_camera_overlay = useOverlay; if(useOverlay) { PumkinsAvatarTools.Instance.SetOverlayToImageFromPath(overlayImagePath); } PumkinsAvatarTools.Instance.bThumbnails_use_camera_background = useBackground; if(useBackground) { PumkinsAvatarTools.Instance.cameraBackgroundType = backgroundType; switch(backgroundType) { case CameraBackgroundOverrideType.Color: PumkinsAvatarTools.Instance.SetCameraBackgroundToColor(backgroundColor); break; case CameraBackgroundOverrideType.Image: PumkinsAvatarTools.Instance.cameraBackgroundImageTint = backgroundImageTint; PumkinsAvatarTools.Instance.SetBackgroundToImageFromPath(backgroundImagePath); break; case CameraBackgroundOverrideType.Skybox: PumkinsAvatarTools.Instance.SetCameraBackgroundToSkybox(backgroundMaterial); break; default: break; } } PumkinsAvatarTools.Instance.RefreshBackgroundOverrideType(); return true; } /// /// Creates new preset based on camera and reference, applies all settings from this object then saves it to assets /// public bool SavePreset(GameObject referenceObject, Camera camera, bool overwriteExisting) { PumkinsCameraPreset p = ScriptableObjectUtility.CreateAndSaveAsset(name, PumkinsAvatarTools.MainFolderPath + "/Resources/Presets/Cameras/", overwriteExisting) as PumkinsCameraPreset; if(!p) return false; p.name = name; p.offsetMode = offsetMode; if(p.offsetMode == CameraOffsetMode.AvatarRoot) CalculateOffsets(referenceObject.transform.root, camera); else if(p.offsetMode == CameraOffsetMode.Transform) CalculateOffsets(referenceObject.transform, camera); #if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON) else CalculateOffsets(PumkinsAvatarTools.SelectedAvatar.GetComponent(), camera); #endif p.positionOffset = positionOffset; p.rotationAnglesOffset = rotationAnglesOffset; p.transformPath = transformPath; p.useOverlay = PumkinsAvatarTools.Instance.bThumbnails_use_camera_overlay; if(p.useOverlay) { p.overlayImagePath = PumkinsAvatarTools.Instance._overlayPath; p.overlayImageTint = PumkinsAvatarTools.Instance.cameraOverlayImageTint; } p.useBackground = PumkinsAvatarTools.Instance.bThumbnails_use_camera_background; p.backgroundType = PumkinsAvatarTools.Instance.cameraBackgroundType; if(p.useBackground) { switch(p.backgroundType) { case CameraBackgroundOverrideType.Color: p.backgroundColor = PumkinsAvatarTools.Instance._thumbsCamBgColor; break; case CameraBackgroundOverrideType.Image: p.backgroundImagePath = PumkinsAvatarTools.Instance._backgroundPath; p.backgroundImageTint = PumkinsAvatarTools.Instance.cameraBackgroundImageTint; break; case CameraBackgroundOverrideType.Skybox: p.backgroundMaterial = RenderSettings.skybox; break; default: break; } } EditorUtility.SetDirty(p); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); PumkinsPresetManager.LoadPresets(); return true; } /// /// Returns position and rotation offsets from target transform to camera /// public void CalculateOffsets(Transform target, Camera cam) { if(!target || !cam) return; if(target == target.root) offsetMode = CameraOffsetMode.AvatarRoot; else offsetMode = CameraOffsetMode.Transform; Transform dummy = null; try { dummy = new GameObject("Dummy").transform; dummy.position = target.position; dummy.rotation = target.rotation; Transform oldParent = cam.transform.parent; cam.transform.parent = dummy; positionOffset = cam.transform.localPosition; rotationAnglesOffset = cam.transform.localEulerAngles; transformPath = Helpers.GetGameObjectPath(target); cam.transform.parent = oldParent; } finally { if(dummy) Helpers.DestroyAppropriate(dummy.gameObject); } } /// /// Gets camera offsets from transform and returns a SerialTransform /// /// SerialTransform only holds values, it doesn't reference a real transform public static SerialTransform GetOffsetsFromTransform(Transform transform, Camera cam) { if(!cam || !transform) return null; Transform oldCamParent = cam.transform.parent; cam.transform.parent = transform; SerialTransform offsets = new SerialTransform() { localPosition = cam.transform.localPosition, localRotation = cam.transform.localRotation, localEulerAngles = cam.transform.localEulerAngles, }; cam.transform.parent = oldCamParent; return offsets; } /// /// Sets camera position and rotation focusing focusTransform with position and rotation offsets /// /// Transform to focus /// Camera to move /// Position offset /// Rotation offset /// Not working yet public static void ApplyPositionAndRotationWithTransformFocus(Transform focusTransform, Camera cam, Vector3 pos, Vector3 rotationAngles, bool moveSceneCameraAsWell) { if(!cam || !focusTransform) return; Transform dummy = new GameObject("dummy").transform; try { dummy.SetPositionAndRotation(focusTransform.position, focusTransform.rotation); cam.transform.parent = dummy; cam.transform.localPosition = pos; cam.transform.localEulerAngles = rotationAngles; cam.transform.parent = null; if(moveSceneCameraAsWell) { Transform t = SceneView.lastActiveSceneView.camera.transform; t.SetPositionAndRotation(cam.transform.position, cam.transform.rotation); } } catch(Exception e) { Debug.LogError(e.Message); } finally { if(dummy) Helpers.DestroyAppropriate(dummy.gameObject); } } /// /// Returns the name of the preset /// public override string ToString() { return name; } #if VRC_SDK_VRCSDK2 || (VRC_SDK_VRCSDK3 && !UDON) /// /// Returns position and rotation offsets from viewpoint to camera /// public void CalculateOffsets(VRC_AvatarDescriptor desc, Camera cam) { if(!desc || !cam) return; SerialTransform offsets = GetOffsetsFromViewpoint(desc, cam); if(offsets) { offsetMode = CameraOffsetMode.Viewpoint; positionOffset = offsets.localPosition; rotationAnglesOffset = offsets.localEulerAngles; } } //Static Functions /// /// Sets camera position and rotation focusing viewpoint with position and rotation offsets /// /// Not working yet public static void ApplyPositionAndRotationWithViewpointFocus(GameObject avatar, Camera cam, Vector3 position, Vector3 rotationAngles, bool moveSceneCameraAsWell) { if(!cam || !avatar) return; Transform dummy = null; try { dummy = new GameObject("Dummy").transform; var desc = avatar.GetComponent(); dummy.localPosition = desc.ViewPosition + desc.gameObject.transform.position; cam.transform.localPosition = position + dummy.transform.position; cam.transform.localEulerAngles = rotationAngles + dummy.transform.eulerAngles; if(moveSceneCameraAsWell) SceneView.lastActiveSceneView.camera.transform.SetPositionAndRotation(cam.transform.position, cam.transform.rotation); } catch(Exception e) { Debug.LogError(e.Message); } finally { if(dummy) Helpers.DestroyAppropriate(dummy.gameObject); } } /// /// Gets camera offsets from viewpoint and returns a SerialTransform /// /// SerialTransform only holds values, it doesn't reference a real transform public static SerialTransform GetOffsetsFromViewpoint(VRC_AvatarDescriptor desc, Camera cam) { SerialTransform offsets = new SerialTransform(); Transform dummy = null; try { dummy = new GameObject("Dummy").transform; dummy.localPosition = desc.ViewPosition + desc.gameObject.transform.position; offsets.localPosition = cam.transform.localPosition - dummy.localPosition; offsets.localEulerAngles = cam.transform.localEulerAngles - dummy.localEulerAngles; } catch(Exception e) { Debug.LogError(e.Message); } finally { if(dummy) Helpers.DestroyAppropriate(dummy.gameObject); } return offsets; } /// /// Gets camera offset from viewpoint and returns a SerialTransform /// /// SerialTransform only holds values, it doesn't reference a real transform public static SerialTransform GetCameraOffsetFromViewpoint(GameObject avatar, Camera cam) { VRC_AvatarDescriptor desc = avatar.GetComponent(); SerialTransform offsets = null; if(desc) offsets = GetOffsetsFromViewpoint(desc, cam); return offsets; } /// /// Sets camera position and rotation based on position and rotation offsets from transform /// public static void ApplyTransformWithViewpointFocus(GameObject avatar, Camera cam, SerialTransform trans) { ApplyPositionAndRotationWithViewpointFocus(avatar, cam, trans.position, trans.localEulerAngles, true); } #endif } }