Vector2 GetOffsetForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, Vector2 scale, float width, float height) { Vector2 offset = Vector2.zero; if (currentOverride == null) { return(offset); } switch (currentOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.BottomLeft) { offset = new Vector2(Mathf.Round((settings.nativeResolutionWidth * scale.x - width) / 2.0f), Mathf.Round((settings.nativeResolutionHeight * scale.y - height) / 2.0f)); } break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentOverride.offsetPixels; break; } return(offset); }
private Vector2 GetOffsetForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, Vector2 scale, float width, float height) { Vector2 zero = Vector2.zero; if (currentOverride == null) { return zero; } tk2dCameraResolutionOverride.FitMode fitMode = currentOverride.fitMode; if ((fitMode != tk2dCameraResolutionOverride.FitMode.Constant) && (fitMode == tk2dCameraResolutionOverride.FitMode.Center)) { if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.BottomLeft) { zero = new Vector2(Mathf.Round(((settings.nativeResolutionWidth * scale.x) - width) / 2f), Mathf.Round(((settings.nativeResolutionHeight * scale.y) - height) / 2f)); } return zero; } return -currentOverride.offsetPixels; }
void DrawOverrideGUI(tk2dCamera _camera) { var frameBorderStyle = EditorStyles.textField; EditorGUIUtility.LookLikeControls(64); tk2dCamera _target = _camera.SettingsRoot; if (_target.CameraSettings.projection == tk2dCameraSettings.ProjectionType.Perspective) { tk2dGuiUtility.InfoBox("Overrides not supported with perspective camera.", tk2dGuiUtility.WarningLevel.Info); } else { GUI.enabled = _target == _camera; tk2dCameraResolutionOverride usedOverride = _target.CurrentResolutionOverride; if (_target.resolutionOverride.Length == 0) { EditorGUILayout.HelpBox("There are no overrides on this tk2dCamera.\n\nThe camera will always scale itself to be pixel perfect at any resolution. " + "Add an override if you wish to change this behaviour.", MessageType.Warning); } else { EditorGUILayout.HelpBox("Matching is performed from top to bottom. The first override matching the current resolution will be used.", MessageType.Info); } System.Action <int> deferredAction = null; for (int i = 0; i < _target.resolutionOverride.Length; ++i) { tk2dCameraResolutionOverride ovr = _target.resolutionOverride[i]; EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(8); GUILayout.BeginHorizontal(); ovr.name = EditorGUILayout.TextField("Name", ovr.name); GUI.enabled = (i != _target.resolutionOverride.Length - 1); if (GUILayout.Button("", tk2dEditorSkin.SimpleButton("btn_down"))) { int idx = i; deferredAction = delegate(int q) { _target.resolutionOverride[idx] = _target.resolutionOverride[idx + 1]; _target.resolutionOverride[idx + 1] = ovr; }; } GUI.enabled = (i != 0); if (GUILayout.Button("", tk2dEditorSkin.SimpleButton("btn_up"))) { int idx = i; deferredAction = delegate(int q) { _target.resolutionOverride[idx] = _target.resolutionOverride[idx - 1]; _target.resolutionOverride[idx - 1] = ovr; }; } GUI.enabled = true; if (GUILayout.Button("", tk2dEditorSkin.GetStyle("TilemapDeleteItem"))) { int idx = i; deferredAction = delegate(int q) { List <tk2dCameraResolutionOverride> list = new List <tk2dCameraResolutionOverride>(_target.resolutionOverride); list.RemoveAt(idx); _target.resolutionOverride = list.ToArray(); }; } GUILayout.EndHorizontal(); ovr.matchBy = (tk2dCameraResolutionOverride.MatchByType)EditorGUILayout.EnumPopup("Match By", ovr.matchBy); int tmpIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; switch (ovr.matchBy) { case tk2dCameraResolutionOverride.MatchByType.Wildcard: break; case tk2dCameraResolutionOverride.MatchByType.Resolution: Vector2 res = new Vector2(ovr.width, ovr.height); res = ResolutionControl(" ", res); ovr.width = (int)res.x; ovr.height = (int)res.y; break; case tk2dCameraResolutionOverride.MatchByType.AspectRatio: GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); ovr.aspectRatioNumerator = EditorGUILayout.FloatField(ovr.aspectRatioNumerator, GUILayout.Width(40)); GUILayout.Label(":", GUILayout.ExpandWidth(false)); ovr.aspectRatioDenominator = EditorGUILayout.FloatField(ovr.aspectRatioDenominator, GUILayout.Width(40)); GUILayout.EndHorizontal(); break; } EditorGUI.indentLevel = tmpIndent; ovr.autoScaleMode = (tk2dCameraResolutionOverride.AutoScaleMode)EditorGUILayout.EnumPopup("Auto Scale", ovr.autoScaleMode); if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.None) { EditorGUI.indentLevel++; ovr.scale = EditorGUILayout.FloatField("Scale", ovr.scale); EditorGUI.indentLevel--; } if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { string msg = "The native resolution image will be stretched to fit the target display. " + "Image quality will suffer if non-uniform scaling occurs."; tk2dGuiUtility.InfoBox(msg, tk2dGuiUtility.WarningLevel.Info); } else { ovr.fitMode = (tk2dCameraResolutionOverride.FitMode)EditorGUILayout.EnumPopup("Fit Mode", ovr.fitMode); if (ovr.fitMode == tk2dCameraResolutionOverride.FitMode.Constant) { EditorGUI.indentLevel++; ovr.offsetPixels.x = EditorGUILayout.FloatField("X", ovr.offsetPixels.x); ovr.offsetPixels.y = EditorGUILayout.FloatField("Y", ovr.offsetPixels.y); EditorGUI.indentLevel--; } } GUILayout.Space(4); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (ovr == usedOverride) { GUI.color = Color.green; GUIContent content = new GUIContent("ACTIVE", "The active override is the one that matches the current resolution, and is being used in the tk2dCamera game window."); GUILayout.Label(content, EditorStyles.miniBoldLabel, GUILayout.ExpandWidth(false)); GUI.color = Color.white; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } if (deferredAction != null) { deferredAction(0); GUI.changed = true; Repaint(); } EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(32); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add override", GUILayout.ExpandWidth(false))) { tk2dCameraResolutionOverride ovr = new tk2dCameraResolutionOverride(); ovr.name = "New override"; ovr.matchBy = tk2dCameraResolutionOverride.MatchByType.Wildcard; ovr.autoScaleMode = tk2dCameraResolutionOverride.AutoScaleMode.FitVisible; ovr.fitMode = tk2dCameraResolutionOverride.FitMode.Center; System.Array.Resize(ref _target.resolutionOverride, _target.resolutionOverride.Length + 1); _target.resolutionOverride[_target.resolutionOverride.Length - 1] = ovr; GUI.changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(32); EditorGUILayout.EndVertical(); GUI.enabled = true; } }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { if (!this.viewportClippingEnabled) inst = this; if (!mainCamera.orthographic) { // Must be orthographic Debug.LogError("tk2dCamera must be orthographic"); mainCamera.orthographic = true; } tk2dCamera settings = inheritSettings != null ? inheritSettings : this; bool viewportClippingEnabled = this.viewportClippingEnabled && this.screenCamera != null && this.screenCamera.rect == unitRect; Camera screenCamera = viewportClippingEnabled ? this.screenCamera : mainCamera; float pixelWidth = screenCamera.pixelWidth; float pixelHeight = screenCamera.pixelHeight; #if UNITY_EDITOR if (settings.forceResolutionInEditor) { pixelWidth = settings.forceResolution.x; pixelHeight = settings.forceResolution.y; } #endif _targetResolution = new Vector2(pixelWidth, pixelHeight); // Find an override if necessary if (!settings.enableResolutionOverrides) currentResolutionOverride = null; if (settings.enableResolutionOverrides && (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) )) { currentResolutionOverride = null; // find one if it matches the current resolution if (settings.resolutionOverride != null) { foreach (var ovr in settings.resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } Vector2 scale = new Vector2(1, 1); Vector2 offset = new Vector2(0, 0); float s = 0.0f; if (currentResolutionOverride != null) { switch (currentResolutionOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: s = pixelHeight / nativeResolutionHeight; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: s = pixelWidth / nativeResolutionWidth; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit: float nativeAspect = (float)nativeResolutionWidth / nativeResolutionHeight; float currentAspect = pixelWidth / pixelHeight; if (currentAspect < nativeAspect) s = pixelWidth / nativeResolutionWidth; else s = pixelHeight / nativeResolutionHeight; if (currentResolutionOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit) { if (s > 1.0f) s = Mathf.Floor(s); // round number else s = Mathf.Pow(2, Mathf.Floor(Mathf.Log(s, 2))); // minimise only as power of two } scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: scale.Set(pixelWidth / nativeResolutionWidth, pixelHeight / nativeResolutionHeight); break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: s = currentResolutionOverride.scale; scale.Set(s, s); break; } scale *= zoomScale; // no offset when ScaleToFit if (currentResolutionOverride.autoScaleMode != tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { switch (currentResolutionOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: offset = new Vector2(Mathf.Round((nativeResolutionWidth * scale.x - pixelWidth ) / 2.0f), Mathf.Round((nativeResolutionHeight * scale.y - pixelHeight) / 2.0f)); break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentResolutionOverride.offsetPixels; break; } } } float left = offset.x, bottom = offset.y; float right = pixelWidth + offset.x, top = pixelHeight + offset.y; // Correct for viewport clipping rendering // Coordinates in subrect are "native" pixels, but origin is from the extrema of screen if (viewportClippingEnabled) { float vw = (right - left) / scale.x; float vh = (top - bottom) / scale.y; Vector4 sr = new Vector4((int)viewportRegion.x, (int)viewportRegion.y, (int)viewportRegion.z, (int)viewportRegion.w); float viewportLeft = sr.x / vw; float viewportBottom = sr.y / vh; float viewportWidth = sr.z / vw; float viewportHeight = sr.w / vh; Rect r = new Rect( viewportLeft, viewportBottom, viewportWidth, viewportHeight ); if (mainCamera.rect.x != viewportLeft || mainCamera.rect.y != viewportBottom || mainCamera.rect.width != viewportWidth || mainCamera.rect.height != viewportHeight) { mainCamera.rect = r; } float maxWidth = Mathf.Min( 1.0f - r.x, r.width ); float maxHeight = Mathf.Min( 1.0f - r.y, r.height ); float rectOffsetX = sr.x * scale.x; float rectOffsetY = sr.y * scale.y; if (r.x < 0.0f) { rectOffsetX += -r.x * pixelWidth; maxWidth = (r.x + r.width); } if (r.y < 0.0f) { rectOffsetY += -r.y * pixelHeight; maxHeight = (r.y + r.height); } left += rectOffsetX; bottom += rectOffsetY; right = pixelWidth * maxWidth + offset.x + rectOffsetX; top = pixelHeight * maxHeight + offset.y + rectOffsetY; } else { mainCamera.rect = new Rect(0, 0, 1, 1); } _screenExtents.Set(left / scale.x, top / scale.y, (right - left) / scale.x, (bottom - top) / scale.y); float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (top - bottom) / 2.0f; _scaledResolution = new Vector2((right - left) / scale.x, (top - bottom) / scale.y); _screenOffset = offset; // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale.x; float y = (2.0f) / (top - bottom) * scale.y; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(bottom + top - halfTexelOffsetAmount) / (top - bottom); float c = -(far + near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0,0] = x; m[0,1] = 0; m[0,2] = 0; m[0,3] = a; m[1,0] = 0; m[1,1] = y; m[1,2] = 0; m[1,3] = b; m[2,0] = 0; m[2,1] = 0; m[2,2] = z; m[2,3] = c; m[3,0] = 0; m[3,1] = 0; m[3,2] = 0; m[3,3] = 1; mainCamera.projectionMatrix = m; }
void DrawOverrideGUI(tk2dCamera _camera) { var frameBorderStyle = EditorStyles.textField; EditorGUIUtility.LookLikeControls(64); tk2dCamera _target = _camera.SettingsRoot; if (_target.CameraSettings.projection == tk2dCameraSettings.ProjectionType.Perspective) { tk2dGuiUtility.InfoBox("Overrides not supported with perspective camera.", tk2dGuiUtility.WarningLevel.Info); } else { GUI.enabled = _target == _camera; tk2dCameraResolutionOverride usedOverride = _target.CurrentResolutionOverride; if (_target.resolutionOverride.Length == 0) { EditorGUILayout.HelpBox("There are no overrides on this tk2dCamera.\n\nThe camera will always scale itself to be pixel perfect at any resolution. " + "Add an override if you wish to change this behaviour.", MessageType.Warning); } else { EditorGUILayout.HelpBox("Matching is performed from top to bottom. The first override matching the current resolution will be used.", MessageType.Info); } System.Action<int> deferredAction = null; for (int i = 0; i < _target.resolutionOverride.Length; ++i) { tk2dCameraResolutionOverride ovr = _target.resolutionOverride[i]; EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(8); GUILayout.BeginHorizontal(); ovr.name = EditorGUILayout.TextField("Name", ovr.name); GUI.enabled = (i != _target.resolutionOverride.Length - 1); if (GUILayout.Button("", tk2dEditorSkin.SimpleButton("btn_down"))) { int idx = i; deferredAction = delegate(int q) { _target.resolutionOverride[idx] = _target.resolutionOverride[idx+1]; _target.resolutionOverride[idx+1] = ovr; }; } GUI.enabled = (i != 0); if (GUILayout.Button("", tk2dEditorSkin.SimpleButton("btn_up"))) { int idx = i; deferredAction = delegate(int q) { _target.resolutionOverride[idx] = _target.resolutionOverride[idx-1]; _target.resolutionOverride[idx-1] = ovr; }; } GUI.enabled = true; if (GUILayout.Button("", tk2dEditorSkin.GetStyle("TilemapDeleteItem"))) { int idx = i; deferredAction = delegate(int q) { List<tk2dCameraResolutionOverride> list = new List<tk2dCameraResolutionOverride>(_target.resolutionOverride); list.RemoveAt(idx); _target.resolutionOverride = list.ToArray(); }; } GUILayout.EndHorizontal(); ovr.matchBy = (tk2dCameraResolutionOverride.MatchByType)EditorGUILayout.EnumPopup("Match By", ovr.matchBy); int tmpIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; switch (ovr.matchBy) { case tk2dCameraResolutionOverride.MatchByType.Wildcard: break; case tk2dCameraResolutionOverride.MatchByType.Resolution: Vector2 res = new Vector2(ovr.width, ovr.height); res = ResolutionControl(" ", res); ovr.width = (int)res.x; ovr.height = (int)res.y; break; case tk2dCameraResolutionOverride.MatchByType.AspectRatio: GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); ovr.aspectRatioNumerator = EditorGUILayout.FloatField(ovr.aspectRatioNumerator, GUILayout.Width(40)); GUILayout.Label(":", GUILayout.ExpandWidth(false)); ovr.aspectRatioDenominator = EditorGUILayout.FloatField(ovr.aspectRatioDenominator, GUILayout.Width(40)); GUILayout.EndHorizontal(); break; } EditorGUI.indentLevel = tmpIndent; ovr.autoScaleMode = (tk2dCameraResolutionOverride.AutoScaleMode)EditorGUILayout.EnumPopup("Auto Scale", ovr.autoScaleMode); if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.None) { EditorGUI.indentLevel++; ovr.scale = EditorGUILayout.FloatField("Scale", ovr.scale); EditorGUI.indentLevel--; } if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { string msg = "The native resolution image will be stretched to fit the target display. " + "Image quality will suffer if non-uniform scaling occurs."; tk2dGuiUtility.InfoBox(msg, tk2dGuiUtility.WarningLevel.Info); } else { ovr.fitMode = (tk2dCameraResolutionOverride.FitMode)EditorGUILayout.EnumPopup("Fit Mode", ovr.fitMode); if (ovr.fitMode == tk2dCameraResolutionOverride.FitMode.Constant) { EditorGUI.indentLevel++; ovr.offsetPixels.x = EditorGUILayout.FloatField("X", ovr.offsetPixels.x); ovr.offsetPixels.y = EditorGUILayout.FloatField("Y", ovr.offsetPixels.y); EditorGUI.indentLevel--; } } GUILayout.Space(4); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (ovr == usedOverride) { GUI.color = Color.green; GUIContent content = new GUIContent("ACTIVE", "The active override is the one that matches the current resolution, and is being used in the tk2dCamera game window."); GUILayout.Label(content, EditorStyles.miniBoldLabel, GUILayout.ExpandWidth(false)); GUI.color = Color.white; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } if (deferredAction != null) { deferredAction(0); GUI.changed = true; Repaint(); } EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(32); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add override", GUILayout.ExpandWidth(false))) { tk2dCameraResolutionOverride ovr = new tk2dCameraResolutionOverride(); ovr.name = "New override"; ovr.matchBy = tk2dCameraResolutionOverride.MatchByType.Wildcard; ovr.autoScaleMode = tk2dCameraResolutionOverride.AutoScaleMode.FitVisible; ovr.fitMode = tk2dCameraResolutionOverride.FitMode.Center; System.Array.Resize(ref _target.resolutionOverride, _target.resolutionOverride.Length + 1); _target.resolutionOverride[_target.resolutionOverride.Length - 1] = ovr; GUI.changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(32); EditorGUILayout.EndVertical(); GUI.enabled = true; } }
public override void OnInspectorGUI() { //DrawDefaultInspector(); tk2dCamera _target = (tk2dCamera)target; var frameBorderStyle = EditorStyles.textField; // sanity if (_target.resolutionOverride == null) { _target.resolutionOverride = new tk2dCameraResolutionOverride[0]; GUI.changed = true; } _target.enableResolutionOverrides = EditorGUILayout.Toggle("Resolution overrides", _target.enableResolutionOverrides); if (_target.enableResolutionOverrides) { EditorGUILayout.LabelField("Native resolution", EditorStyles.boldLabel); EditorGUI.indentLevel++; _target.nativeResolutionWidth = EditorGUILayout.IntField("Width", _target.nativeResolutionWidth); _target.nativeResolutionHeight = EditorGUILayout.IntField("Height", _target.nativeResolutionHeight); EditorGUI.indentLevel--; // Overrides EditorGUILayout.LabelField("Overrides", EditorStyles.boldLabel); EditorGUI.indentLevel++; int deleteId = -1; for (int i = 0; i < _target.resolutionOverride.Length; ++i) { var ovr = _target.resolutionOverride[i]; EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(8); ovr.name = EditorGUILayout.TextField("Name", ovr.name); ovr.width = EditorGUILayout.IntField("Width", ovr.width); ovr.height = EditorGUILayout.IntField("Height", ovr.height); ovr.autoScaleMode = (tk2dCameraResolutionOverride.AutoScaleMode)EditorGUILayout.EnumPopup("Auto Scale", ovr.autoScaleMode); if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.None) { EditorGUI.indentLevel++; ovr.scale = EditorGUILayout.FloatField("Scale", ovr.scale); EditorGUI.indentLevel--; } ovr.fitMode = (tk2dCameraResolutionOverride.FitMode)EditorGUILayout.EnumPopup("Fit Mode", ovr.fitMode); if (ovr.fitMode == tk2dCameraResolutionOverride.FitMode.Constant) { EditorGUI.indentLevel++; ovr.offsetPixels.x = EditorGUILayout.FloatField("X", ovr.offsetPixels.x); ovr.offsetPixels.y = EditorGUILayout.FloatField("Y", ovr.offsetPixels.y); EditorGUI.indentLevel--; } GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (GUILayout.Button("Delete", EditorStyles.miniButton)) deleteId = i; GUILayout.EndHorizontal(); GUILayout.Space(4); EditorGUILayout.EndVertical(); } if (deleteId != -1) { List<tk2dCameraResolutionOverride> ovr = new List<tk2dCameraResolutionOverride>(_target.resolutionOverride); ovr.RemoveAt(deleteId); _target.resolutionOverride = ovr.ToArray(); GUI.changed = true; Repaint(); } EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(32); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add override", GUILayout.ExpandWidth(false))) { tk2dCameraResolutionOverride ovr = new tk2dCameraResolutionOverride(); ovr.name = "Wildcard Override"; ovr.width = -1; ovr.height = -1; ovr.autoScaleMode = tk2dCameraResolutionOverride.AutoScaleMode.FitVisible; ovr.fitMode = tk2dCameraResolutionOverride.FitMode.Center; System.Array.Resize(ref _target.resolutionOverride, _target.resolutionOverride.Length + 1); _target.resolutionOverride[_target.resolutionOverride.Length - 1] = ovr; GUI.changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(32); EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Camera resolution", EditorStyles.boldLabel); GUIContent toggleLabel = new GUIContent("Force Editor Resolution", "When enabled, forces the resolution in the editor regardless of the size of the game window."); EditorGUI.indentLevel++; _target.forceResolutionInEditor = EditorGUILayout.Toggle(toggleLabel, _target.forceResolutionInEditor); if (_target.forceResolutionInEditor) { _target.forceResolution.x = EditorGUILayout.IntField("Width", (int)_target.forceResolution.x); _target.forceResolution.y = EditorGUILayout.IntField("Height", (int)_target.forceResolution.y); } else { EditorGUILayout.FloatField("Width", _target.resolution.x); EditorGUILayout.FloatField("Height", _target.resolution.y); } EditorGUI.indentLevel--; if (GUI.changed) { EditorUtility.SetDirty(target); tk2dCameraAnchor[] allAlignmentObjects = GameObject.FindObjectsOfType(typeof(tk2dCameraAnchor)) as tk2dCameraAnchor[]; foreach (var v in allAlignmentObjects) { EditorUtility.SetDirty(v); } } GUILayout.Space(16.0f); EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("Create Anchor", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { tk2dCamera cam = (tk2dCamera)target; GameObject go = new GameObject("Anchor"); go.transform.parent = cam.transform; tk2dCameraAnchor cameraAnchor = go.AddComponent<tk2dCameraAnchor>(); cameraAnchor.tk2dCamera = cam; cameraAnchor.mainCamera = cam.mainCamera; EditorGUIUtility.PingObject(go); } EditorGUILayout.EndHorizontal(); }
public override void OnInspectorGUI() { //DrawDefaultInspector(); tk2dCamera _target = (tk2dCamera)target; var frameBorderStyle = EditorStyles.textField; // sanity if (_target.resolutionOverride == null) { _target.resolutionOverride = new tk2dCameraResolutionOverride[0]; GUI.changed = true; } _target.enableResolutionOverrides = EditorGUILayout.Toggle("Resolution overrides", _target.enableResolutionOverrides); if (_target.enableResolutionOverrides) { EditorGUILayout.LabelField("Native resolution", EditorStyles.boldLabel); EditorGUI.indentLevel++; _target.nativeResolutionWidth = EditorGUILayout.IntField("Width", _target.nativeResolutionWidth); _target.nativeResolutionHeight = EditorGUILayout.IntField("Height", _target.nativeResolutionHeight); EditorGUI.indentLevel--; // Overrides EditorGUILayout.LabelField("Overrides", EditorStyles.boldLabel); EditorGUI.indentLevel++; int deleteId = -1; for (int i = 0; i < _target.resolutionOverride.Length; ++i) { var ovr = _target.resolutionOverride[i]; EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(8); ovr.name = EditorGUILayout.TextField("Name", ovr.name); ovr.width = EditorGUILayout.IntField("Width", ovr.width); ovr.height = EditorGUILayout.IntField("Height", ovr.height); ovr.autoScaleMode = (tk2dCameraResolutionOverride.AutoScaleMode)EditorGUILayout.EnumPopup("Auto Scale", ovr.autoScaleMode); if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.None) { EditorGUI.indentLevel++; ovr.scale = EditorGUILayout.FloatField("Scale", ovr.scale); EditorGUI.indentLevel--; } if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { string msg = "The native resolution image will be stretched to fit the target display. " + "Image quality will suffer if non-uniform scaling occurs."; tk2dGuiUtility.InfoBox(msg, tk2dGuiUtility.WarningLevel.Info); } else { ovr.fitMode = (tk2dCameraResolutionOverride.FitMode)EditorGUILayout.EnumPopup("Fit Mode", ovr.fitMode); if (ovr.fitMode == tk2dCameraResolutionOverride.FitMode.Constant) { EditorGUI.indentLevel++; ovr.offsetPixels.x = EditorGUILayout.FloatField("X", ovr.offsetPixels.x); ovr.offsetPixels.y = EditorGUILayout.FloatField("Y", ovr.offsetPixels.y); EditorGUI.indentLevel--; } } GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (GUILayout.Button("Delete", EditorStyles.miniButton)) { deleteId = i; } GUILayout.EndHorizontal(); GUILayout.Space(4); EditorGUILayout.EndVertical(); } if (deleteId != -1) { List <tk2dCameraResolutionOverride> ovr = new List <tk2dCameraResolutionOverride>(_target.resolutionOverride); ovr.RemoveAt(deleteId); _target.resolutionOverride = ovr.ToArray(); GUI.changed = true; Repaint(); } EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(32); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add override", GUILayout.ExpandWidth(false))) { tk2dCameraResolutionOverride ovr = new tk2dCameraResolutionOverride(); ovr.name = "Wildcard Override"; ovr.width = -1; ovr.height = -1; ovr.autoScaleMode = tk2dCameraResolutionOverride.AutoScaleMode.FitVisible; ovr.fitMode = tk2dCameraResolutionOverride.FitMode.Center; System.Array.Resize(ref _target.resolutionOverride, _target.resolutionOverride.Length + 1); _target.resolutionOverride[_target.resolutionOverride.Length - 1] = ovr; GUI.changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(32); EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Camera resolution", EditorStyles.boldLabel); GUIContent toggleLabel = new GUIContent("Force Editor Resolution", "When enabled, forces the resolution in the editor regardless of the size of the game window."); EditorGUI.indentLevel++; bool cameraOverrideChanged = false; tk2dGuiUtility.BeginChangeCheck(); _target.forceResolutionInEditor = EditorGUILayout.Toggle(toggleLabel, _target.forceResolutionInEditor); if (tk2dGuiUtility.EndChangeCheck()) { cameraOverrideChanged = true; } if (_target.forceResolutionInEditor) { tk2dGuiUtility.BeginChangeCheck(); int selectedResolution = EditorGUILayout.Popup("Preset", 0, presetListStr); if (selectedResolution != 0) { var preset = presets[selectedResolution - 1]; _target.forceResolution.x = preset.width; _target.forceResolution.y = preset.height; GUI.changed = true; } _target.forceResolution.x = EditorGUILayout.IntField("Width", (int)_target.forceResolution.x); _target.forceResolution.y = EditorGUILayout.IntField("Height", (int)_target.forceResolution.y); // clamp to a sensible value _target.forceResolution.x = Mathf.Max(_target.forceResolution.x, 50); _target.forceResolution.y = Mathf.Max(_target.forceResolution.y, 50); Rect r = GUILayoutUtility.GetRect(1, 1, GUILayout.ExpandWidth(true), GUILayout.MinHeight(43)); EditorGUI.HelpBox(new Rect(r.x + 4, r.y, r.width - 8, r.height), "Ensure that the the game view resolution is the same as the override chosen here, otherwise the game window will not display correctly.", MessageType.Warning); if (tk2dGuiUtility.EndChangeCheck()) { cameraOverrideChanged = true; } } else { EditorGUILayout.FloatField("Width", _target.TargetResolution.x); EditorGUILayout.FloatField("Height", _target.TargetResolution.y); } EditorGUI.indentLevel--; if (cameraOverrideChanged) { // Propagate values to all tk2dCameras in scene tk2dCamera[] otherCameras = Resources.FindObjectsOfTypeAll(typeof(tk2dCamera)) as tk2dCamera[]; foreach (tk2dCamera thisCamera in otherCameras) { thisCamera.forceResolutionInEditor = _target.forceResolutionInEditor; thisCamera.forceResolution = _target.forceResolution; thisCamera.UpdateCameraMatrix(); } // Update all anchors after that tk2dCameraAnchor[] anchors = Resources.FindObjectsOfTypeAll(typeof(tk2dCameraAnchor)) as tk2dCameraAnchor[]; foreach (var anchor in anchors) { anchor.ForceUpdateTransform(); } } if (GUI.changed) { EditorUtility.SetDirty(target); tk2dCameraAnchor[] allAlignmentObjects = GameObject.FindObjectsOfType(typeof(tk2dCameraAnchor)) as tk2dCameraAnchor[]; foreach (var v in allAlignmentObjects) { EditorUtility.SetDirty(v); } } GUILayout.Space(16.0f); EditorGUILayout.LabelField("Tools", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("Create Anchor", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { tk2dCamera cam = (tk2dCamera)target; GameObject go = new GameObject("Anchor"); go.transform.parent = cam.transform; tk2dCameraAnchor cameraAnchor = go.AddComponent <tk2dCameraAnchor>(); cameraAnchor.tk2dCamera = cam; EditorGUIUtility.PingObject(go); } EditorGUILayout.EndHorizontal(); // { // tk2dCamera cam = (tk2dCamera)target; // cam.zoomScale = EditorGUILayout.FloatField("Zoom scale", cam.zoomScale); // } }
Matrix4x4 GetProjectionMatrixForOverride( tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, float pixelWidth, float pixelHeight, bool halfTexelOffset, out Rect screenExtents, out Rect unscaledScreenExtents ) { Vector2 scale = GetScaleForOverride( settings, currentOverride, pixelWidth, pixelHeight ); Vector2 offset = GetOffsetForOverride( settings, currentOverride, scale, pixelWidth, pixelHeight); float left = offset.x, bottom = offset.y; float right = pixelWidth + offset.x, top = pixelHeight + offset.y; Vector2 nativeResolutionOffset = Vector2.zero; // Correct for viewport clipping rendering // Coordinates in subrect are "native" pixels, but origin is from the extrema of screen if (this.viewportClippingEnabled && this.InheritConfig != null) { float vw = (right - left) / scale.x; float vh = (top - bottom) / scale.y; Vector4 sr = new Vector4((int)this.viewportRegion.x, (int)this.viewportRegion.y, (int)this.viewportRegion.z, (int)this.viewportRegion.w); float viewportLeft = -offset.x / pixelWidth + sr.x / vw; float viewportBottom = -offset.y / pixelHeight + sr.y / vh; float viewportWidth = sr.z / vw; float viewportHeight = sr.w / vh; Rect r = new Rect( viewportLeft, viewportBottom, viewportWidth, viewportHeight ); if (UnityCamera.rect.x != viewportLeft || UnityCamera.rect.y != viewportBottom || UnityCamera.rect.width != viewportWidth || UnityCamera.rect.height != viewportHeight) { UnityCamera.rect = r; } float maxWidth = Mathf.Min( 1.0f - r.x, r.width ); float maxHeight = Mathf.Min( 1.0f - r.y, r.height ); float rectOffsetX = sr.x * scale.x - offset.x; float rectOffsetY = sr.y * scale.y - offset.y; if (r.x < 0.0f) { rectOffsetX += -r.x * pixelWidth; maxWidth = (r.x + r.width); } if (r.y < 0.0f) { rectOffsetY += -r.y * pixelHeight; maxHeight = (r.y + r.height); } left += rectOffsetX; bottom += rectOffsetY; right = pixelWidth * maxWidth + offset.x + rectOffsetX; top = pixelHeight * maxHeight + offset.y + rectOffsetY; } else { if (UnityCamera.rect != CameraSettings.rect) { UnityCamera.rect = CameraSettings.rect; } } // By default the camera is orthographic, bottom left, 1 pixel per meter if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { float w = (right - left) * 0.5f; left -= w; right -= w; float h = (top - bottom) * 0.5f; top -= h; bottom -= h; nativeResolutionOffset.Set(-nativeResolutionWidth / 2.0f, -nativeResolutionHeight / 2.0f); } float orthoSize = settings.cameraSettings.orthographicSize; switch (settings.cameraSettings.orthographicType) { case tk2dCameraSettings.OrthographicType.OrthographicSize: orthoSize = 2.0f * settings.cameraSettings.orthographicSize / settings.nativeResolutionHeight; break; case tk2dCameraSettings.OrthographicType.PixelsPerMeter: orthoSize = 1.0f / settings.cameraSettings.orthographicPixelsPerMeter; break; } float zoomScale = 1.0f / ZoomFactor; // Only need the half texel offset on PC/D3D bool needHalfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexel = (halfTexelOffset && needHalfTexelOffset) ? 0.5f : 0.0f; float s = orthoSize * zoomScale; screenExtents = new Rect(left * s / scale.x, bottom * s / scale.y, (right - left) * s / scale.x, (top - bottom) * s / scale.y); unscaledScreenExtents = new Rect(nativeResolutionOffset.x * s, nativeResolutionOffset.y * s, nativeResolutionWidth * s, nativeResolutionHeight * s); // Near and far clip planes are tweakable per camera, so we pull from current camera instance regardless of inherited values return OrthoOffCenter(scale, orthoSize * (left + halfTexel) * zoomScale, orthoSize * (right + halfTexel) * zoomScale, orthoSize * (bottom - halfTexel) * zoomScale, orthoSize * (top - halfTexel) * zoomScale, UnityCamera.nearClipPlane, UnityCamera.farClipPlane); }
Matrix4x4 GetProjectionMatrixForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, float pixelWidth, float pixelHeight, bool halfTexelOffset, out Rect screenExtents, out Rect unscaledScreenExtents) { Vector2 scale = GetScaleForOverride(settings, currentOverride, pixelWidth, pixelHeight); Vector2 offset = GetOffsetForOverride(settings, currentOverride, scale, pixelWidth, pixelHeight); float left = offset.x, bottom = offset.y; float right = pixelWidth + offset.x, top = pixelHeight + offset.y; Vector2 nativeResolutionOffset = Vector2.zero; // Correct for viewport clipping rendering // Coordinates in subrect are "native" pixels, but origin is from the extrema of screen if (this.viewportClippingEnabled && this.InheritConfig != null) { float vw = (right - left) / scale.x; float vh = (top - bottom) / scale.y; Vector4 sr = new Vector4((int)this.viewportRegion.x, (int)this.viewportRegion.y, (int)this.viewportRegion.z, (int)this.viewportRegion.w); float viewportLeft = -offset.x / pixelWidth + sr.x / vw; float viewportBottom = -offset.y / pixelHeight + sr.y / vh; float viewportWidth = sr.z / vw; float viewportHeight = sr.w / vh; if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { viewportLeft += (pixelWidth - settings.nativeResolutionWidth * scale.x) / pixelWidth / 2.0f; viewportBottom += (pixelHeight - settings.nativeResolutionHeight * scale.y) / pixelHeight / 2.0f; } Rect r = new Rect(viewportLeft, viewportBottom, viewportWidth, viewportHeight); if (UnityCamera.rect.x != viewportLeft || UnityCamera.rect.y != viewportBottom || UnityCamera.rect.width != viewportWidth || UnityCamera.rect.height != viewportHeight) { UnityCamera.rect = r; } float maxWidth = Mathf.Min(1.0f - r.x, r.width); float maxHeight = Mathf.Min(1.0f - r.y, r.height); float rectOffsetX = sr.x * scale.x - offset.x; float rectOffsetY = sr.y * scale.y - offset.y; if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { rectOffsetX -= settings.nativeResolutionWidth * 0.5f * scale.x; rectOffsetY -= settings.nativeResolutionHeight * 0.5f * scale.y; } if (r.x < 0.0f) { rectOffsetX += -r.x * pixelWidth; maxWidth = (r.x + r.width); } if (r.y < 0.0f) { rectOffsetY += -r.y * pixelHeight; maxHeight = (r.y + r.height); } left += rectOffsetX; bottom += rectOffsetY; right = pixelWidth * maxWidth + offset.x + rectOffsetX; top = pixelHeight * maxHeight + offset.y + rectOffsetY; } else { if (UnityCamera.rect != CameraSettings.rect) { UnityCamera.rect = CameraSettings.rect; } // By default the camera is orthographic, bottom left, 1 pixel per meter if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { float w = (right - left) * 0.5f; left -= w; right -= w; float h = (top - bottom) * 0.5f; top -= h; bottom -= h; nativeResolutionOffset.Set(-nativeResolutionWidth / 2.0f, -nativeResolutionHeight / 2.0f); } } float zoomScale = 1.0f / ZoomFactor; // Only need the half texel offset on PC/D3D bool needHalfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexel = (halfTexelOffset && needHalfTexelOffset) ? 0.5f : 0.0f; float orthoSize = settings.cameraSettings.orthographicSize; switch (settings.cameraSettings.orthographicType) { case tk2dCameraSettings.OrthographicType.OrthographicSize: orthoSize = 2.0f * settings.cameraSettings.orthographicSize / settings.nativeResolutionHeight; break; case tk2dCameraSettings.OrthographicType.PixelsPerMeter: orthoSize = 1.0f / settings.cameraSettings.orthographicPixelsPerMeter; break; } float s = orthoSize * zoomScale; screenExtents = new Rect(left * s / scale.x, bottom * s / scale.y, (right - left) * s / scale.x, (top - bottom) * s / scale.y); unscaledScreenExtents = new Rect(nativeResolutionOffset.x * s, nativeResolutionOffset.y * s, nativeResolutionWidth * s, nativeResolutionHeight * s); // Near and far clip planes are tweakable per camera, so we pull from current camera instance regardless of inherited values return(OrthoOffCenter(scale, orthoSize * (left + halfTexel) * zoomScale, orthoSize * (right + halfTexel) * zoomScale, orthoSize * (bottom - halfTexel) * zoomScale, orthoSize * (top - halfTexel) * zoomScale, UnityCamera.nearClipPlane, UnityCamera.farClipPlane)); }
public override void OnInspectorGUI() { //DrawDefaultInspector(); tk2dCamera _target = (tk2dCamera)target; var frameBorderStyle = EditorStyles.textField; // sanity if (_target.resolutionOverride == null) { _target.resolutionOverride = new tk2dCameraResolutionOverride[0]; GUI.changed = true; } _target.enableResolutionOverrides = EditorGUILayout.Toggle("Resolution overrides", _target.enableResolutionOverrides); if (_target.enableResolutionOverrides) { EditorGUILayout.LabelField("Native resolution", EditorStyles.boldLabel); EditorGUI.indentLevel++; _target.nativeResolutionWidth = EditorGUILayout.IntField("Width", _target.nativeResolutionWidth); _target.nativeResolutionHeight = EditorGUILayout.IntField("Height", _target.nativeResolutionHeight); EditorGUI.indentLevel--; // Overrides EditorGUILayout.LabelField("Overrides", EditorStyles.boldLabel); EditorGUI.indentLevel++; int deleteId = -1; for (int i = 0; i < _target.resolutionOverride.Length; ++i) { var ovr = _target.resolutionOverride[i]; EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(8); ovr.name = EditorGUILayout.TextField("Name", ovr.name); ovr.width = EditorGUILayout.IntField("Width", ovr.width); ovr.height = EditorGUILayout.IntField("Height", ovr.height); ovr.autoScaleMode = (tk2dCameraResolutionOverride.AutoScaleMode)EditorGUILayout.EnumPopup("Auto Scale", ovr.autoScaleMode); if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.None) { EditorGUI.indentLevel++; ovr.scale = EditorGUILayout.FloatField("Scale", ovr.scale); EditorGUI.indentLevel--; } ovr.fitMode = (tk2dCameraResolutionOverride.FitMode)EditorGUILayout.EnumPopup("Fit Mode", ovr.fitMode); if (ovr.fitMode == tk2dCameraResolutionOverride.FitMode.Constant) { EditorGUI.indentLevel++; ovr.offsetPixels.x = EditorGUILayout.FloatField("X", ovr.offsetPixels.x); ovr.offsetPixels.y = EditorGUILayout.FloatField("Y", ovr.offsetPixels.y); EditorGUI.indentLevel--; } GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (GUILayout.Button("Delete", EditorStyles.miniButton)) { deleteId = i; } GUILayout.EndHorizontal(); GUILayout.Space(4); EditorGUILayout.EndVertical(); } if (deleteId != -1) { List <tk2dCameraResolutionOverride> ovr = new List <tk2dCameraResolutionOverride>(_target.resolutionOverride); ovr.RemoveAt(deleteId); _target.resolutionOverride = ovr.ToArray(); GUI.changed = true; Repaint(); } EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(32); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add override", GUILayout.ExpandWidth(false))) { tk2dCameraResolutionOverride ovr = new tk2dCameraResolutionOverride(); ovr.name = "Wildcard Override"; ovr.width = -1; ovr.height = -1; ovr.autoScaleMode = tk2dCameraResolutionOverride.AutoScaleMode.FitVisible; ovr.fitMode = tk2dCameraResolutionOverride.FitMode.Center; System.Array.Resize(ref _target.resolutionOverride, _target.resolutionOverride.Length + 1); _target.resolutionOverride[_target.resolutionOverride.Length - 1] = ovr; GUI.changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(32); EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Camera resolution", EditorStyles.boldLabel); GUIContent toggleLabel = new GUIContent("Force Editor Resolution", "When enabled, forces the resolution in the editor regardless of the size of the game window."); EditorGUI.indentLevel++; _target.forceResolutionInEditor = EditorGUILayout.Toggle(toggleLabel, _target.forceResolutionInEditor); if (_target.forceResolutionInEditor) { _target.forceResolution.x = EditorGUILayout.IntField("Width", (int)_target.forceResolution.x); _target.forceResolution.y = EditorGUILayout.IntField("Height", (int)_target.forceResolution.y); } else { EditorGUILayout.FloatField("Width", _target.resolution.x); EditorGUILayout.FloatField("Height", _target.resolution.y); } EditorGUI.indentLevel--; if (GUI.changed) { EditorUtility.SetDirty(target); tk2dCameraAnchor[] allAlignmentObjects = GameObject.FindObjectsOfType(typeof(tk2dCameraAnchor)) as tk2dCameraAnchor[]; foreach (var v in allAlignmentObjects) { EditorUtility.SetDirty(v); } } GUILayout.Space(16.0f); EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("Create Anchor", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { tk2dCamera cam = (tk2dCamera)target; GameObject go = new GameObject("Anchor"); go.transform.parent = cam.transform; tk2dCameraAnchor cameraAnchor = go.AddComponent <tk2dCameraAnchor>(); cameraAnchor.tk2dCamera = cam; cameraAnchor.mainCamera = cam.mainCamera; EditorGUIUtility.PingObject(go); } EditorGUILayout.EndHorizontal(); }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { inst = this; if (!mainCamera.orthographic) { // Must be orthographic Debug.LogError("tk2dCamera must be orthographic"); mainCamera.orthographic = true; } float pixelWidth = mainCamera.pixelWidth; float pixelHeight = mainCamera.pixelHeight; #if UNITY_EDITOR if (forceResolutionInEditor) { pixelWidth = forceResolution.x; pixelHeight = forceResolution.y; } #endif _targetResolution = new Vector2(pixelWidth, pixelHeight); // Find an override if necessary if (!enableResolutionOverrides) { currentResolutionOverride = null; } if (enableResolutionOverrides && (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) )) { currentResolutionOverride = null; // find one if it matches the current resolution if (resolutionOverride != null) { foreach (var ovr in resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } Vector2 scale = new Vector2(1, 1); Vector2 offset = new Vector2(0, 0); float s = 0.0f; if (currentResolutionOverride != null) { switch (currentResolutionOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: s = pixelHeight / nativeResolutionHeight; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: s = pixelWidth / nativeResolutionWidth; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit: float nativeAspect = (float)nativeResolutionWidth / nativeResolutionHeight; float currentAspect = pixelWidth / pixelHeight; if (currentAspect < nativeAspect) { s = pixelWidth / nativeResolutionWidth; } else { s = pixelHeight / nativeResolutionHeight; } if (currentResolutionOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit) { if (s > 1.0f) { s = Mathf.Floor(s); // round number } else { s = Mathf.Pow(2, Mathf.Floor(Mathf.Log(s, 2))); // minimise only as power of two } } scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: scale.Set(pixelWidth / nativeResolutionWidth, pixelHeight / nativeResolutionHeight); break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: s = currentResolutionOverride.scale; scale.Set(s, s); break; } scale *= zoomScale; // no offset when ScaleToFit if (currentResolutionOverride.autoScaleMode != tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { switch (currentResolutionOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: offset = new Vector2(Mathf.Round((nativeResolutionWidth * scale.x - pixelWidth) / 2.0f), Mathf.Round((nativeResolutionHeight * scale.y - pixelHeight) / 2.0f)); break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentResolutionOverride.offsetPixels; break; } } } float left = offset.x, bottom = offset.y; float right = pixelWidth + offset.x, top = pixelHeight + offset.y; _screenExtents.Set(left / scale.x, top / scale.y, (right - left) / scale.x, (bottom - top) / scale.y); float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (top - bottom) / 2.0f; _scaledResolution = new Vector2(right / scale.x, top / scale.y); _screenOffset = offset; // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale.x; float y = (2.0f) / (top - bottom) * scale.y; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(bottom + top - halfTexelOffsetAmount) / (top - bottom); float c = -(far + near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0, 0] = x; m[0, 1] = 0; m[0, 2] = 0; m[0, 3] = a; m[1, 0] = 0; m[1, 1] = y; m[1, 2] = 0; m[1, 3] = b; m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = z; m[2, 3] = c; m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = 0; m[3, 3] = 1; mainCamera.projectionMatrix = m; }
private Matrix4x4 GetProjectionMatrixForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, float pixelWidth, float pixelHeight, bool halfTexelOffset, out Rect screenExtents, out Rect unscaledScreenExtents) { Vector2 scale = this.GetScaleForOverride(settings, currentOverride, pixelWidth, pixelHeight); Vector2 vector2 = this.GetOffsetForOverride(settings, currentOverride, scale, pixelWidth, pixelHeight); float x = vector2.x; float y = vector2.y; float num3 = pixelWidth + vector2.x; float num4 = pixelHeight + vector2.y; Vector2 zero = Vector2.zero; bool flag = false; if (this.viewportClippingEnabled && (this.InheritConfig != null)) { float num5 = (num3 - x) / scale.x; float num6 = (num4 - y) / scale.y; Vector4 vector4 = new Vector4((float) ((int) this.viewportRegion.x), (float) ((int) this.viewportRegion.y), (float) ((int) this.viewportRegion.z), (float) ((int) this.viewportRegion.w)); flag = true; float left = (-vector2.x / pixelWidth) + (vector4.x / num5); float top = (-vector2.y / pixelHeight) + (vector4.y / num6); float width = vector4.z / num5; float height = vector4.w / num6; if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { left += ((pixelWidth - (settings.nativeResolutionWidth * scale.x)) / pixelWidth) / 2f; top += ((pixelHeight - (settings.nativeResolutionHeight * scale.y)) / pixelHeight) / 2f; } Rect rect = new Rect(left, top, width, height); if (((this.UnityCamera.rect.x != left) || (this.UnityCamera.rect.y != top)) || ((this.UnityCamera.rect.width != width) || (this.UnityCamera.rect.height != height))) { this.UnityCamera.rect = rect; } float num11 = Mathf.Min(1f - rect.x, rect.width); float num12 = Mathf.Min(1f - rect.y, rect.height); float num13 = (vector4.x * scale.x) - vector2.x; float num14 = (vector4.y * scale.y) - vector2.y; if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { num13 -= (settings.nativeResolutionWidth * 0.5f) * scale.x; num14 -= (settings.nativeResolutionHeight * 0.5f) * scale.y; } if (rect.x < 0f) { num13 += -rect.x * pixelWidth; num11 = rect.x + rect.width; } if (rect.y < 0f) { num14 += -rect.y * pixelHeight; num12 = rect.y + rect.height; } x += num13; y += num14; num3 = ((pixelWidth * num11) + vector2.x) + num13; num4 = ((pixelHeight * num12) + vector2.y) + num14; } else { if (this.UnityCamera.rect != this.CameraSettings.rect) { this.UnityCamera.rect = this.CameraSettings.rect; } if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.Center) { float num15 = (num3 - x) * 0.5f; x -= num15; num3 -= num15; float num16 = (num4 - y) * 0.5f; num4 -= num16; y -= num16; zero.Set(((float) -this.nativeResolutionWidth) / 2f, ((float) -this.nativeResolutionHeight) / 2f); } } float num17 = 1f / this.ZoomFactor; bool flag2 = ((Application.platform == RuntimePlatform.WindowsPlayer) || (Application.platform == RuntimePlatform.WindowsWebPlayer)) || (Application.platform == RuntimePlatform.WindowsEditor); float num18 = (!halfTexelOffset || !flag2) ? 0f : 0.5f; float orthographicSize = settings.cameraSettings.orthographicSize; switch (settings.cameraSettings.orthographicType) { case tk2dCameraSettings.OrthographicType.PixelsPerMeter: orthographicSize = 1f / settings.cameraSettings.orthographicPixelsPerMeter; break; case tk2dCameraSettings.OrthographicType.OrthographicSize: orthographicSize = (2f * settings.cameraSettings.orthographicSize) / ((float) settings.nativeResolutionHeight); break; } if (!flag) { float num20 = Mathf.Min(this.UnityCamera.rect.width, 1f - this.UnityCamera.rect.x); float num21 = Mathf.Min(this.UnityCamera.rect.height, 1f - this.UnityCamera.rect.y); if ((num20 > 0f) && (num21 > 0f)) { scale.x /= num20; scale.y /= num21; } } float num22 = orthographicSize * num17; screenExtents = new Rect((x * num22) / scale.x, (y * num22) / scale.y, ((num3 - x) * num22) / scale.x, ((num4 - y) * num22) / scale.y); unscaledScreenExtents = new Rect(zero.x * num22, zero.y * num22, this.nativeResolutionWidth * num22, this.nativeResolutionHeight * num22); return this.OrthoOffCenter(scale, (orthographicSize * (x + num18)) * num17, (orthographicSize * (num3 + num18)) * num17, (orthographicSize * (y - num18)) * num17, (orthographicSize * (num4 - num18)) * num17, this.UnityCamera.nearClipPlane, this.UnityCamera.farClipPlane); }
private Vector2 GetScaleForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, float width, float height) { Vector2 one = Vector2.one; float scale = 1f; if (currentOverride != null) { switch (currentOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: scale = width / ((float) settings.nativeResolutionWidth); one.Set(scale, scale); return one; case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: scale = height / ((float) settings.nativeResolutionHeight); one.Set(scale, scale); return one; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.ClosestMultipleOfTwo: { float num2 = ((float) settings.nativeResolutionWidth) / ((float) settings.nativeResolutionHeight); float num3 = width / height; if (num3 >= num2) { scale = height / ((float) settings.nativeResolutionHeight); break; } scale = width / ((float) settings.nativeResolutionWidth); break; } case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: one.Set(width / ((float) settings.nativeResolutionWidth), height / ((float) settings.nativeResolutionHeight)); return one; case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfect: scale = 1f; one.Set(scale, scale); return one; case tk2dCameraResolutionOverride.AutoScaleMode.Fill: scale = Mathf.Max((float) (width / ((float) settings.nativeResolutionWidth)), (float) (height / ((float) settings.nativeResolutionHeight))); one.Set(scale, scale); return one; default: scale = currentOverride.scale; one.Set(scale, scale); return one; } if (currentOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.ClosestMultipleOfTwo) { if (scale > 1f) { scale = Mathf.Floor(scale); } else { scale = Mathf.Pow(2f, Mathf.Floor(Mathf.Log(scale, 2f))); } } one.Set(scale, scale); } return one; }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { inst = this; float pixelWidth = mainCamera.pixelWidth; float pixelHeight = mainCamera.pixelHeight; #if UNITY_EDITOR if (forceResolutionInEditor) { pixelWidth = forceResolution.x; pixelHeight = forceResolution.y; } #endif // Find an override if necessary if (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) ) { currentResolutionOverride = null; // find one if it matches the current resolution if (resolutionOverride != null) { foreach (var ovr in resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } float scale = (currentResolutionOverride != null)?currentResolutionOverride.scale:1.0f; float left = 0.0f, top = 0.0f; float right = pixelWidth, bottom = pixelHeight; float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (bottom - top) / 2.0f; resolution = new Vector2(right / scale, bottom / scale); // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale; float y = (2.0f) / (bottom - top) * scale; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(top + bottom - halfTexelOffsetAmount) / (bottom - top); float c = -(2.0f * far * near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0, 0] = x; m[0, 1] = 0; m[0, 2] = 0; m[0, 3] = a; m[1, 0] = 0; m[1, 1] = y; m[1, 2] = 0; m[1, 3] = b; m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = z; m[2, 3] = c; m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = 0; m[3, 3] = 1; mainCamera.projectionMatrix = m; }
Vector2 GetScaleForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, float width, float height) { Vector2 scale = Vector2.one; float s = 1.0f; if (currentOverride == null) { return(scale); } switch (currentOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfect: s = 1; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: s = height / settings.nativeResolutionHeight; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: s = width / settings.nativeResolutionWidth; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.ClosestMultipleOfTwo: float nativeAspect = (float)settings.nativeResolutionWidth / settings.nativeResolutionHeight; float currentAspect = width / height; if (currentAspect < nativeAspect) { s = width / settings.nativeResolutionWidth; } else { s = height / settings.nativeResolutionHeight; } if (currentOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.ClosestMultipleOfTwo) { if (s > 1.0f) { s = Mathf.Floor(s); // round number } else { s = Mathf.Pow(2, Mathf.Floor(Mathf.Log(s, 2))); // minimise only as power of two } } scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: scale.Set(width / settings.nativeResolutionWidth, height / settings.nativeResolutionHeight); break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: s = currentOverride.scale; scale.Set(s, s); break; } return(scale); }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { inst = this; float pixelWidth = mainCamera.pixelWidth; float pixelHeight = mainCamera.pixelHeight; #if UNITY_EDITOR if (forceResolutionInEditor) { pixelWidth = forceResolution.x; pixelHeight = forceResolution.y; } #endif _targetResolution = new Vector2(pixelWidth, pixelHeight); // Find an override if necessary if (!enableResolutionOverrides) currentResolutionOverride = null; if (enableResolutionOverrides && (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) )) { currentResolutionOverride = null; // find one if it matches the current resolution if (resolutionOverride != null) { foreach (var ovr in resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } float scale; Vector2 offset; if (currentResolutionOverride == null) { scale = 1.0f; offset = new Vector2(0, 0); } else { switch (currentResolutionOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: scale = pixelHeight / nativeResolutionHeight; break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: scale = pixelWidth / nativeResolutionWidth; break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: float nativeAspect = (float)nativeResolutionWidth / nativeResolutionHeight; float currentAspect = pixelWidth / pixelHeight; if (currentAspect < nativeAspect) scale = pixelWidth / nativeResolutionWidth; else scale = pixelHeight / nativeResolutionHeight; break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: scale = currentResolutionOverride.scale; break; } switch (currentResolutionOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: offset = new Vector2(Mathf.Round((nativeResolutionWidth * scale - pixelWidth ) / 2.0f), Mathf.Round((nativeResolutionHeight * scale - pixelHeight) / 2.0f)); break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentResolutionOverride.offsetPixels; break; } } float left = offset.x, top = offset.y; float right = pixelWidth + offset.x, bottom = pixelHeight + offset.y; float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (bottom - top) / 2.0f; _scaledResolution = new Vector2(right / scale, bottom / scale); // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale; float y = (2.0f) / (bottom - top) * scale; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(top + bottom - halfTexelOffsetAmount) / (bottom - top); float c = -(2.0f * far * near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0,0] = x; m[0,1] = 0; m[0,2] = 0; m[0,3] = a; m[1,0] = 0; m[1,1] = y; m[1,2] = 0; m[1,3] = b; m[2,0] = 0; m[2,1] = 0; m[2,2] = z; m[2,3] = c; m[3,0] = 0; m[3,1] = 0; m[3,2] = 0; m[3,3] = 1; mainCamera.projectionMatrix = m; }
public override void OnInspectorGUI() { //DrawDefaultInspector(); tk2dCamera _target = (tk2dCamera)target; var frameBorderStyle = EditorStyles.textField; // sanity if (_target.resolutionOverride == null) { _target.resolutionOverride = new tk2dCameraResolutionOverride[0]; GUI.changed = true; } _target.enableResolutionOverrides = EditorGUILayout.Toggle("Resolution overrides", _target.enableResolutionOverrides); if (_target.enableResolutionOverrides) { EditorGUILayout.LabelField("Native resolution", EditorStyles.boldLabel); EditorGUI.indentLevel++; _target.nativeResolutionWidth = EditorGUILayout.IntField("Width", _target.nativeResolutionWidth); _target.nativeResolutionHeight = EditorGUILayout.IntField("Height", _target.nativeResolutionHeight); EditorGUI.indentLevel--; // Overrides EditorGUILayout.LabelField("Overrides", EditorStyles.boldLabel); EditorGUI.indentLevel++; int deleteId = -1; for (int i = 0; i < _target.resolutionOverride.Length; ++i) { var ovr = _target.resolutionOverride[i]; EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(8); ovr.name = EditorGUILayout.TextField("Name", ovr.name); ovr.width = EditorGUILayout.IntField("Width", ovr.width); ovr.height = EditorGUILayout.IntField("Height", ovr.height); ovr.autoScaleMode = (tk2dCameraResolutionOverride.AutoScaleMode)EditorGUILayout.EnumPopup("Auto Scale", ovr.autoScaleMode); if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.None) { EditorGUI.indentLevel++; ovr.scale = EditorGUILayout.FloatField("Scale", ovr.scale); EditorGUI.indentLevel--; } if (ovr.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { string msg = "The native resolution image will be stretched to fit the target display. " + "Image quality will suffer if non-uniform scaling occurs."; tk2dGuiUtility.InfoBox(msg, tk2dGuiUtility.WarningLevel.Info); } else { ovr.fitMode = (tk2dCameraResolutionOverride.FitMode)EditorGUILayout.EnumPopup("Fit Mode", ovr.fitMode); if (ovr.fitMode == tk2dCameraResolutionOverride.FitMode.Constant) { EditorGUI.indentLevel++; ovr.offsetPixels.x = EditorGUILayout.FloatField("X", ovr.offsetPixels.x); ovr.offsetPixels.y = EditorGUILayout.FloatField("Y", ovr.offsetPixels.y); EditorGUI.indentLevel--; } } GUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (GUILayout.Button("Delete", EditorStyles.miniButton)) deleteId = i; GUILayout.EndHorizontal(); GUILayout.Space(4); EditorGUILayout.EndVertical(); } if (deleteId != -1) { List<tk2dCameraResolutionOverride> ovr = new List<tk2dCameraResolutionOverride>(_target.resolutionOverride); ovr.RemoveAt(deleteId); _target.resolutionOverride = ovr.ToArray(); GUI.changed = true; Repaint(); } EditorGUILayout.BeginVertical(frameBorderStyle); GUILayout.Space(32); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add override", GUILayout.ExpandWidth(false))) { tk2dCameraResolutionOverride ovr = new tk2dCameraResolutionOverride(); ovr.name = "Wildcard Override"; ovr.width = -1; ovr.height = -1; ovr.autoScaleMode = tk2dCameraResolutionOverride.AutoScaleMode.FitVisible; ovr.fitMode = tk2dCameraResolutionOverride.FitMode.Center; System.Array.Resize(ref _target.resolutionOverride, _target.resolutionOverride.Length + 1); _target.resolutionOverride[_target.resolutionOverride.Length - 1] = ovr; GUI.changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(32); EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Camera resolution", EditorStyles.boldLabel); GUIContent toggleLabel = new GUIContent("Force Editor Resolution", "When enabled, forces the resolution in the editor regardless of the size of the game window."); EditorGUI.indentLevel++; bool cameraOverrideChanged = false; tk2dGuiUtility.BeginChangeCheck(); _target.forceResolutionInEditor = EditorGUILayout.Toggle(toggleLabel, _target.forceResolutionInEditor); if (tk2dGuiUtility.EndChangeCheck()) cameraOverrideChanged = true; if (_target.forceResolutionInEditor) { tk2dGuiUtility.BeginChangeCheck(); int selectedResolution = EditorGUILayout.Popup("Preset", 0, presetListStr); if (selectedResolution != 0) { var preset = presets[selectedResolution - 1]; _target.forceResolution.x = preset.width; _target.forceResolution.y = preset.height; GUI.changed = true; } _target.forceResolution.x = EditorGUILayout.IntField("Width", (int)_target.forceResolution.x); _target.forceResolution.y = EditorGUILayout.IntField("Height", (int)_target.forceResolution.y); // clamp to a sensible value _target.forceResolution.x = Mathf.Max(_target.forceResolution.x, 50); _target.forceResolution.y = Mathf.Max(_target.forceResolution.y, 50); Rect r = GUILayoutUtility.GetRect(1, 1, GUILayout.ExpandWidth(true), GUILayout.MinHeight(43)); EditorGUI.HelpBox(new Rect(r.x + 4, r.y, r.width - 8, r.height), "Ensure that the the game view resolution is the same as the override chosen here, otherwise the game window will not display correctly.", MessageType.Warning); if (tk2dGuiUtility.EndChangeCheck()) cameraOverrideChanged = true; } else { EditorGUILayout.FloatField("Width", _target.TargetResolution.x); EditorGUILayout.FloatField("Height", _target.TargetResolution.y); } EditorGUI.indentLevel--; if (cameraOverrideChanged) { // Propagate values to all tk2dCameras in scene tk2dCamera[] otherCameras = Resources.FindObjectsOfTypeAll(typeof(tk2dCamera)) as tk2dCamera[]; foreach (tk2dCamera thisCamera in otherCameras) { thisCamera.forceResolutionInEditor = _target.forceResolutionInEditor; thisCamera.forceResolution = _target.forceResolution; thisCamera.UpdateCameraMatrix(); } // Update all anchors after that tk2dCameraAnchor[] anchors = Resources.FindObjectsOfTypeAll(typeof(tk2dCameraAnchor)) as tk2dCameraAnchor[]; foreach (var anchor in anchors) anchor.ForceUpdateTransform(); } if (GUI.changed) { EditorUtility.SetDirty(target); tk2dCameraAnchor[] allAlignmentObjects = GameObject.FindObjectsOfType(typeof(tk2dCameraAnchor)) as tk2dCameraAnchor[]; foreach (var v in allAlignmentObjects) { EditorUtility.SetDirty(v); } } GUILayout.Space(16.0f); EditorGUILayout.LabelField("Tools", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("Create Anchor", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { tk2dCamera cam = (tk2dCamera)target; GameObject go = new GameObject("Anchor"); go.transform.parent = cam.transform; tk2dCameraAnchor cameraAnchor = go.AddComponent<tk2dCameraAnchor>(); cameraAnchor.tk2dCamera = cam; EditorGUIUtility.PingObject(go); } EditorGUILayout.EndHorizontal(); // { // tk2dCamera cam = (tk2dCamera)target; // cam.zoomScale = EditorGUILayout.FloatField("Zoom scale", cam.zoomScale); // } }
Vector2 GetOffsetForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, Vector2 scale, float width, float height) { Vector2 offset = Vector2.zero; if (currentOverride == null) { return offset; } switch (currentOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: if (settings.cameraSettings.orthographicOrigin == tk2dCameraSettings.OrthographicOrigin.BottomLeft) { offset = new Vector2(Mathf.Round((settings.nativeResolutionWidth * scale.x - width ) / 2.0f), Mathf.Round((settings.nativeResolutionHeight * scale.y - height) / 2.0f)); } break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentOverride.offsetPixels; break; } return offset; }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { inst = this; float pixelWidth = mainCamera.pixelWidth; float pixelHeight = mainCamera.pixelHeight; #if UNITY_EDITOR if (forceResolutionInEditor) { pixelWidth = forceResolution.x; pixelHeight = forceResolution.y; } #endif // Find an override if necessary if (!enableResolutionOverrides) { currentResolutionOverride = null; } if (enableResolutionOverrides && (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) )) { currentResolutionOverride = null; // find one if it matches the current resolution if (resolutionOverride != null) { foreach (var ovr in resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } float scale; Vector2 offset; if (currentResolutionOverride == null) { scale = 1.0f; offset = new Vector2(0, 0); } else { switch (currentResolutionOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: scale = pixelHeight / nativeResolutionHeight; break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: scale = pixelWidth / nativeResolutionWidth; break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: float nativeAspect = (float)nativeResolutionWidth / nativeResolutionHeight; float currentAspect = pixelWidth / pixelHeight; if (currentAspect < nativeAspect) { scale = pixelWidth / nativeResolutionWidth; } else { scale = pixelHeight / nativeResolutionHeight; } break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: scale = currentResolutionOverride.scale; break; } switch (currentResolutionOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: offset = new Vector2(Mathf.Round((nativeResolutionWidth * scale - pixelWidth) / 2.0f), Mathf.Round((nativeResolutionHeight * scale - pixelHeight) / 2.0f)); break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentResolutionOverride.offsetPixels; break; } } float left = offset.x, top = offset.y; float right = pixelWidth + offset.x, bottom = pixelHeight + offset.y; float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (bottom - top) / 2.0f; resolution = new Vector2(right / scale, bottom / scale); // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale; float y = (2.0f) / (bottom - top) * scale; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(top + bottom - halfTexelOffsetAmount) / (bottom - top); float c = -(2.0f * far * near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0, 0] = x; m[0, 1] = 0; m[0, 2] = 0; m[0, 3] = a; m[1, 0] = 0; m[1, 1] = y; m[1, 2] = 0; m[1, 3] = b; m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = z; m[2, 3] = c; m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = 0; m[3, 3] = 1; mainCamera.projectionMatrix = m; }
Vector2 GetScaleForOverride(tk2dCamera settings, tk2dCameraResolutionOverride currentOverride, float width, float height) { Vector2 scale = Vector2.one; float s = 1.0f; if (currentOverride == null) { return scale; } switch (currentOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfect: s = 1; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: s = height / settings.nativeResolutionHeight; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: s = width / settings.nativeResolutionWidth; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.ClosestMultipleOfTwo: float nativeAspect = (float)settings.nativeResolutionWidth / settings.nativeResolutionHeight; float currentAspect = width / height; if (currentAspect < nativeAspect) s = width / settings.nativeResolutionWidth; else s = height / settings.nativeResolutionHeight; if (currentOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.ClosestMultipleOfTwo) { if (s > 1.0f) s = Mathf.Floor(s); // round number else s = Mathf.Pow(2, Mathf.Floor(Mathf.Log(s, 2))); // minimise only as power of two } scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: scale.Set(width / settings.nativeResolutionWidth, height / settings.nativeResolutionHeight); break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: s = currentOverride.scale; scale.Set(s, s); break; } return scale; }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { inst = this; if (!mainCamera.orthographic) { // Must be orthographic Debug.LogError("tk2dCamera must be orthographic"); mainCamera.orthographic = true; } float pixelWidth = mainCamera.pixelWidth; float pixelHeight = mainCamera.pixelHeight; #if UNITY_EDITOR if (forceResolutionInEditor) { pixelWidth = forceResolution.x; pixelHeight = forceResolution.y; } #endif _targetResolution = new Vector2(pixelWidth, pixelHeight); // Find an override if necessary if (!enableResolutionOverrides) currentResolutionOverride = null; if (enableResolutionOverrides && (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) )) { currentResolutionOverride = null; // find one if it matches the current resolution if (resolutionOverride != null) { foreach (var ovr in resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } Vector2 scale = new Vector2(1, 1); Vector2 offset = new Vector2(0, 0); float s = 0.0f; if (currentResolutionOverride != null) { switch (currentResolutionOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: s = pixelHeight / nativeResolutionHeight; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: s = pixelWidth / nativeResolutionWidth; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit: float nativeAspect = (float)nativeResolutionWidth / nativeResolutionHeight; float currentAspect = pixelWidth / pixelHeight; if (currentAspect < nativeAspect) s = pixelWidth / nativeResolutionWidth; else s = pixelHeight / nativeResolutionHeight; if (currentResolutionOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit) { if (s > 1.0f) s = Mathf.Floor(s); // round number else s = Mathf.Pow(2, Mathf.Floor(Mathf.Log(s, 2))); // minimise only as power of two } scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: scale.Set(pixelWidth / nativeResolutionWidth, pixelHeight / nativeResolutionHeight); break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: s = currentResolutionOverride.scale; scale.Set(s, s); break; } scale *= zoomScale; // no offset when ScaleToFit if (currentResolutionOverride.autoScaleMode != tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { switch (currentResolutionOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: offset = new Vector2(Mathf.Round((nativeResolutionWidth * scale.x - pixelWidth ) / 2.0f), Mathf.Round((nativeResolutionHeight * scale.y - pixelHeight) / 2.0f)); break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentResolutionOverride.offsetPixels; break; } } } float left = offset.x, bottom = offset.y; float right = pixelWidth + offset.x, top = pixelHeight + offset.y; _screenExtents.Set(left / scale.x, top / scale.y, (right - left) / scale.x, (bottom - top) / scale.y); float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (top - bottom) / 2.0f; _scaledResolution = new Vector2(right / scale.x, top / scale.y); _screenOffset = offset; // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale.x; float y = (2.0f) / (top - bottom) * scale.y; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(bottom + top - halfTexelOffsetAmount) / (top - bottom); float c = -(far + near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0,0] = x; m[0,1] = 0; m[0,2] = 0; m[0,3] = a; m[1,0] = 0; m[1,1] = y; m[1,2] = 0; m[1,3] = b; m[2,0] = 0; m[2,1] = 0; m[2,2] = z; m[2,3] = c; m[3,0] = 0; m[3,1] = 0; m[3,2] = 0; m[3,3] = 1; mainCamera.projectionMatrix = m; }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { if (!this.viewportClippingEnabled) { inst = this; } if (!mainCamera.orthographic) { // Must be orthographic Debug.LogError("tk2dCamera must be orthographic"); mainCamera.orthographic = true; } tk2dCamera settings = Settings; bool viewportClippingEnabled = this.viewportClippingEnabled && this.screenCamera != null && this.screenCamera.rect == unitRect; Camera screenCamera = viewportClippingEnabled ? this.screenCamera : mainCamera; float pixelWidth = screenCamera.pixelWidth; float pixelHeight = screenCamera.pixelHeight; #if UNITY_EDITOR if (settings.forceResolutionInEditor) { pixelWidth = settings.forceResolution.x; pixelHeight = settings.forceResolution.y; } #endif _targetResolution = new Vector2(pixelWidth, pixelHeight); // Find an override if necessary if (!settings.enableResolutionOverrides) { currentResolutionOverride = null; } if (settings.enableResolutionOverrides && (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) )) { currentResolutionOverride = null; // find one if it matches the current resolution if (settings.resolutionOverride != null) { foreach (var ovr in settings.resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } Vector2 scale = new Vector2(1, 1); Vector2 offset = new Vector2(0, 0); float s = 0.0f; if (currentResolutionOverride != null) { switch (currentResolutionOverride.autoScaleMode) { case tk2dCameraResolutionOverride.AutoScaleMode.FitHeight: s = pixelHeight / settings.nativeResolutionHeight; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitWidth: s = pixelWidth / settings.nativeResolutionWidth; scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.FitVisible: case tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit: float nativeAspect = (float)settings.nativeResolutionWidth / settings.nativeResolutionHeight; float currentAspect = pixelWidth / pixelHeight; if (currentAspect < nativeAspect) { s = pixelWidth / settings.nativeResolutionWidth; } else { s = pixelHeight / settings.nativeResolutionHeight; } if (currentResolutionOverride.autoScaleMode == tk2dCameraResolutionOverride.AutoScaleMode.PixelPerfectFit) { if (s > 1.0f) { s = Mathf.Floor(s); // round number } else { s = Mathf.Pow(2, Mathf.Floor(Mathf.Log(s, 2))); // minimise only as power of two } } scale.Set(s, s); break; case tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit: scale.Set(pixelWidth / settings.nativeResolutionWidth, pixelHeight / settings.nativeResolutionHeight); break; default: case tk2dCameraResolutionOverride.AutoScaleMode.None: s = currentResolutionOverride.scale; scale.Set(s, s); break; } scale *= zoomScale; // no offset when ScaleToFit if (currentResolutionOverride.autoScaleMode != tk2dCameraResolutionOverride.AutoScaleMode.StretchToFit) { switch (currentResolutionOverride.fitMode) { case tk2dCameraResolutionOverride.FitMode.Center: offset = new Vector2(Mathf.Round((settings.nativeResolutionWidth * scale.x - pixelWidth) / 2.0f), Mathf.Round((settings.nativeResolutionHeight * scale.y - pixelHeight) / 2.0f)); break; default: case tk2dCameraResolutionOverride.FitMode.Constant: offset = -currentResolutionOverride.offsetPixels; break; } } } float left = offset.x, bottom = offset.y; float right = pixelWidth + offset.x, top = pixelHeight + offset.y; // Correct for viewport clipping rendering // Coordinates in subrect are "native" pixels, but origin is from the extrema of screen if (viewportClippingEnabled) { float vw = (right - left) / scale.x; float vh = (top - bottom) / scale.y; Vector4 sr = new Vector4((int)viewportRegion.x, (int)viewportRegion.y, (int)viewportRegion.z, (int)viewportRegion.w); float viewportLeft = -offset.x / pixelWidth + sr.x / vw; float viewportBottom = -offset.y / pixelHeight + sr.y / vh; float viewportWidth = sr.z / vw; float viewportHeight = sr.w / vh; Rect r = new Rect(viewportLeft, viewportBottom, viewportWidth, viewportHeight); if (mainCamera.rect.x != viewportLeft || mainCamera.rect.y != viewportBottom || mainCamera.rect.width != viewportWidth || mainCamera.rect.height != viewportHeight) { mainCamera.rect = r; } float maxWidth = Mathf.Min(1.0f - r.x, r.width); float maxHeight = Mathf.Min(1.0f - r.y, r.height); float rectOffsetX = sr.x * scale.x - offset.x; float rectOffsetY = sr.y * scale.y - offset.y; if (r.x < 0.0f) { rectOffsetX += -r.x * pixelWidth; maxWidth = (r.x + r.width); } if (r.y < 0.0f) { rectOffsetY += -r.y * pixelHeight; maxHeight = (r.y + r.height); } left += rectOffsetX; bottom += rectOffsetY; right = pixelWidth * maxWidth + offset.x + rectOffsetX; top = pixelHeight * maxHeight + offset.y + rectOffsetY; } else { Rect targetRect = new Rect(0, 0, 1, 1); if (mainCamera.rect != targetRect) { mainCamera.rect = targetRect; } } _screenExtents.Set(left / scale.x, top / scale.y, (right - left) / scale.x, (bottom - top) / scale.y); float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (top - bottom) / 2.0f; _scaledResolution = new Vector2((right - left) / scale.x, (top - bottom) / scale.y); _screenOffset = offset; // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale.x; float y = (2.0f) / (top - bottom) * scale.y; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(bottom + top - halfTexelOffsetAmount) / (top - bottom); float c = -(far + near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0, 0] = x; m[0, 1] = 0; m[0, 2] = 0; m[0, 3] = a; m[1, 0] = 0; m[1, 1] = y; m[1, 2] = 0; m[1, 3] = b; m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = z; m[2, 3] = c; m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = 0; m[3, 3] = 1; if (mainCamera.projectionMatrix != m) { mainCamera.projectionMatrix = m; } }
/// <summary> /// Updates the camera matrix to ensure 1:1 pixel mapping /// </summary> public void UpdateCameraMatrix() { inst = this; float pixelWidth = mainCamera.pixelWidth; float pixelHeight = mainCamera.pixelHeight; #if UNITY_EDITOR if (forceResolutionInEditor) { pixelWidth = forceResolution.x; pixelHeight = forceResolution.y; } #endif // Find an override if necessary if (currentResolutionOverride == null || (currentResolutionOverride != null && (currentResolutionOverride.width != pixelWidth || currentResolutionOverride.height != pixelHeight)) ) { currentResolutionOverride = null; // find one if it matches the current resolution if (resolutionOverride != null) { foreach (var ovr in resolutionOverride) { if (ovr.Match((int)pixelWidth, (int)pixelHeight)) { currentResolutionOverride = ovr; break; } } } } float scale = (currentResolutionOverride != null)?currentResolutionOverride.scale:1.0f; float left = 0.0f, top = 0.0f; float right = pixelWidth, bottom = pixelHeight; float far = mainCamera.farClipPlane; float near = mainCamera.near; // set up externally used variables orthoSize = (bottom - top) / 2.0f; resolution = new Vector2(right / scale, bottom / scale); // Additional half texel offset // Takes care of texture unit offset, if necessary. // should be off on all opengl platforms // and on on PC/D3D bool halfTexelOffset = false; halfTexelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); float halfTexelOffsetAmount = (halfTexelOffset)?1.0f:0.0f; float x = (2.0f) / (right - left) * scale; float y = (2.0f) / (bottom - top) * scale; float z = -2.0f / (far - near); float a = -(right + left + halfTexelOffsetAmount) / (right - left); float b = -(top + bottom - halfTexelOffsetAmount) / (bottom - top); float c = -(2.0f * far * near) / (far - near); Matrix4x4 m = new Matrix4x4(); m[0,0] = x; m[0,1] = 0; m[0,2] = 0; m[0,3] = a; m[1,0] = 0; m[1,1] = y; m[1,2] = 0; m[1,3] = b; m[2,0] = 0; m[2,1] = 0; m[2,2] = z; m[2,3] = c; m[3,0] = 0; m[3,1] = 0; m[3,2] = 0; m[3,3] = 1; mainCamera.projectionMatrix = m; }