void OnWillRenderObject() { //Debug.Log("on will" + Camera.current); Camera cam = Camera.current; if (!cam) { return; } PixelPerfectCamera.PixelSnapMode pixelSnapMode = PixelPerfectCamera.PixelSnapMode.Off; PixelPerfectCamera pixelPerfectCamera = null; switch (pixelSnapChoiceMode) { case PixelSnapChoiceMode.Off: pixelSnapMode = PixelPerfectCamera.PixelSnapMode.Off; break; case PixelSnapChoiceMode.LetCameraChoose: pixelPerfectCamera = cam.GetComponent <PixelPerfectCamera>(); if (pixelPerfectCamera == null) { pixelSnapMode = PixelPerfectCamera.PixelSnapMode.Off; break; } pixelSnapMode = pixelPerfectCamera.pixelSnapMode; break; case PixelSnapChoiceMode.ForcePixelSnap: pixelSnapMode = PixelPerfectCamera.PixelSnapMode.PixelSnap; break; } if (pixelSnapMode == PixelPerfectCamera.PixelSnapMode.Off) { return; } shouldRestorePosition = true; actualPosition = transform.position; float cameraPPU = (float)cam.pixelHeight / (2f * cam.orthographicSize); float cameraUPP = 1.0f / cameraPPU; Vector2 camPos = cam.transform.position.xy(); Vector2 pos = actualPosition.xy(); Vector2 relPos = pos - camPos; Vector2 offset = new Vector2(0, 0); // offset for screen pixel edge if screen size is odd offset.x = (cam.pixelWidth % 2 == 0) ? 0 : 0.5f; offset.y = (cam.pixelHeight % 2 == 0) ? 0 : 0.5f; // offset for pivot in Sprites Vector2 pivotOffset = new Vector2(0, 0); if (sprite != null) { pivotOffset = sprite.pivot - new Vector2(Mathf.Floor(sprite.pivot.x), Mathf.Floor(sprite.pivot.y)); // the fractional part in texture pixels if (pixelSnapMode == PixelPerfectCamera.PixelSnapMode.RetroSnap) { // Nothing to do here. Pivot offset is already in asset pixels. } else // PixelSnap { float camPixelsPerAssetPixel = cameraPPU / sprite.pixelsPerUnit; pivotOffset *= camPixelsPerAssetPixel; // convert to screen pixels } } if (pixelSnapMode == PixelPerfectCamera.PixelSnapMode.RetroSnap) { float assetPPU = pixelPerfectCamera.assetsPixelsPerUnit; float assetUPP = 1.0f / assetPPU; float camPixelsPerAssetPixel = cameraPPU / assetPPU; offset.x /= camPixelsPerAssetPixel; // zero or half a screen pixel in texture pixels offset.y /= camPixelsPerAssetPixel; // We don't take into account the pivot offset when rounding to avoid the artifact where 2 sprites appear to move at different times because of the fractional part of their pivots. relPos.x = (Mathf.Round(relPos.x / assetUPP - offset.x) + offset.x + pivotOffset.x) * assetUPP; relPos.y = (Mathf.Round(relPos.y / assetUPP - offset.y) + offset.y + pivotOffset.y) * assetUPP; } else // PixelSnap { // Convert the units to pixels, round them, convert back to units. The offsets make sure that the distance we round is from screen pixel (fragment) edges to texel edges. relPos.x = (Mathf.Round(relPos.x / cameraUPP - offset.x) + offset.x + pivotOffset.x) * cameraUPP; relPos.y = (Mathf.Round(relPos.y / cameraUPP - offset.y) + offset.y + pivotOffset.y) * cameraUPP; } pos = relPos + camPos; transform.position = new Vector3(pos.x, pos.y, actualPosition.z); }
public override void OnInspectorGUI() { // Using serialized objects requires a bit more work, but enables multi-object editing, undo, and Prefab overrides. // https://docs.unity3d.com/ScriptReference/Editor.html // https://stackoverflow.com/questions/55027410/editor-target-vs-editor-serializedobject serializedObject.Update(); // Targeted Size PixelPerfectCamera.Dimension dimensionType = (PixelPerfectCamera.Dimension)Enum.GetValues(typeof(PixelPerfectCamera.Dimension)).GetValue(targetDimension.enumValueIndex); targetDimension.enumValueIndex = (int)(PixelPerfectCamera.Dimension)EditorGUILayout.EnumPopup("Target size", dimensionType); if (targetDimension.enumValueIndex == (int)PixelPerfectCamera.Dimension.Width) { EditorGUILayout.PropertyField(targetCameraWidth, new GUIContent("Width", "The target width of the camera in pixels.")); } else { EditorGUILayout.PropertyField(targetCameraHeight, new GUIContent("Height", "The target height of the camera in pixels.")); } EditorGUILayout.BeginHorizontal(); maxCameraWidthEnabled.boolValue = EditorGUILayout.Toggle(maxCameraWidthEnabled.boolValue, GUILayout.Width(12)); EditorGUI.BeginDisabledGroup(!maxCameraWidthEnabled.boolValue); EditorGUILayout.PropertyField(maxCameraWidth, new GUIContent("Max Width", "The maximum allowed width of the camera in pixels.")); EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); maxCameraHeightEnabled.boolValue = EditorGUILayout.Toggle(maxCameraHeightEnabled.boolValue, GUILayout.Width(12)); EditorGUI.BeginDisabledGroup(!maxCameraHeightEnabled.boolValue); EditorGUILayout.PropertyField(maxCameraHeight, new GUIContent("Max Height", "The maximum allowed height of the camera in pixels.")); EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); // Pixels Per Unit EditorGUILayout.PropertyField(assetsPixelsPerUnit); // Pixel Perfect toggle pixelPerfect.boolValue = EditorGUILayout.Toggle(new GUIContent("Pixel Perfect", "Makes the camera's pixels per unit to be a multiple of the assets' pixels per unit."), pixelPerfect.boolValue); // PixelSnap menu PixelPerfectCamera.PixelSnapMode pixelSnapModeSelected = (PixelPerfectCamera.PixelSnapMode)Enum.GetValues(typeof(PixelPerfectCamera.PixelSnapMode)).GetValue(pixelSnapMode.enumValueIndex); pixelSnapMode.enumValueIndex = (int)(PixelPerfectCamera.PixelSnapMode)EditorGUILayout.EnumPopup(new GUIContent("Pixel Snap mode", "Off: disables Pixel Snap \n" + "RetroSnap: Makes the objects snap to the asset's pixel grid \n" + "PixelSnap: Makes the objects snap to the screen's pixel grid \n\n" + "This option affects only objects that use the PixelSnap script."), pixelSnapModeSelected); // Show HUD toggle EditorGUILayout.PropertyField(showHUD); serializedObject.ApplyModifiedProperties(); // Show results if (!((PixelPerfectCamera)target).isInitialized) { return; } GUILayout.BeginVertical(); GUILayout.Space(5); DrawSizeStats(); GUILayout.EndVertical(); }