为什么我的预制件放置在场景中时位置会发生变化?

Why does the position of my prefab is changed when dropped in the scene?

我有问题,我制作了一个立方体的预制件,我想将其放置在平台上。 我的预制件的 y 值为 1。但是,当我尝试将其放置在平台上时,立方体的 y 值为 0.5,这将它置于地面内部。 我尝试重置预制件、地面和立方体中的变换,但 none 成功了。

我的 unity window 与预制件及其值如何更改的屏幕截图。

我假设您将预制件拖到 Scene window 中,而不使用代码或类似的东西。

为什么位置被修改了

你的立方体一半到地面的原因可能是由于 Unity 试图让它以你在场景中的地面对象的 Y 轴为中心,因为这很可能是你拖动预制件的对象。

解决方案 1

如果您希望将东西拖入 Scene window 但希望避免立方体进入地面,一种解决方案是更改立方体的中心位置。一种方法是将立方体放入空 GameObject 并修改立方体在其中的位置,并将此 GameObject 用作预制件。这是一张屏幕截图,说明了预制件的修改版本的外观:

解决方案 2

如果希望在不修改任何位置的情况下将立方体移动到场景中,请将其拖动到 Hierarchy window 中。

解决方案 3

创建自定义脚本来修改立方体预制实例的 Y 位置。 OnValidate() 可能值得研究此解决方案。

您需要相对于变换的位置“冻结”网格(重新计算网格的顶点)以符合您的需要。

这通常在生成网格的程序中完成,但您也可以在 Unity 中使用简单的编辑器脚本。如果您 google 可能有几个非常好的代码 - 但这是我在需要调整或冻结网格时自己使用的代码。

在您的情况下,您只是想对齐底部的网格,因此您可以 select“对齐 y”的“最小值”(取消选中 x、y 和 z 旁边的复选框) .这会将所有网格置于变换位置上方。 (对齐是一种简单的冻结方式,无需先根据需要手动定位网格)。

将以下两个脚本放在名为“Editor”的文件夹中(这样它就可以用作Unity编辑器)。然后您将在 Unity“工具 - 简单网格编辑器”中有一个新的菜单选项。

SimpleMeshEditor.cs

using UnityEditor;
using UnityEngine;

namespace com.andulfgames
{
    public class SimpleMeshEditor : EditorWindow
    {
        [MenuItem("Tools/Simple Mesh Editor")]
        public static void ShowWindow()
        {
            GetWindow<SimpleMeshEditor>(false, "Simple Mesh Editor", true);
        }

        bool freezeRotation = true;

        SimpleMeshTools.MeshAlign alignX;
        SimpleMeshTools.MeshAlign alignY;
        SimpleMeshTools.MeshAlign alignZ;

        bool freezeX = false;
        bool freezeY = false;
        bool freezeZ = false;

        bool adjustColliders = true;

        void OnGUI()
        {
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Freeze", EditorStyles.boldLabel);
            freezeRotation = EditorGUILayout.Toggle("Rotation", freezeRotation); 
            freezeX = EditorGUILayout.Toggle("x", freezeX );
            freezeY = EditorGUILayout.Toggle("y", freezeY);
            freezeZ = EditorGUILayout.Toggle("z", freezeZ);
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Align", EditorStyles.boldLabel);
            alignX = (SimpleMeshTools.MeshAlign)EditorGUILayout.EnumPopup("Align x", alignX);
            alignY = (SimpleMeshTools.MeshAlign)EditorGUILayout.EnumPopup("Align y", alignY);
            alignZ = (SimpleMeshTools.MeshAlign)EditorGUILayout.EnumPopup("Align z", alignZ);

            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Colliders", EditorStyles.boldLabel);
            adjustColliders = EditorGUILayout.Toggle("Adjust colliders", adjustColliders);

            if (GUILayout.Button("UpdateMesh"))
            {
                UpdateMesh();
            }
        }


        private void UpdateMesh()
        {
            foreach (GameObject obj in Selection.gameObjects)
            {
                MeshFilter meshFilter = obj.GetComponent<MeshFilter>(); //6

                if (meshFilter != null)
                {
                    SimpleMeshTools.FreezeTransformation(obj, freezeRotation, freezeX, alignX, freezeY, alignY, freezeZ, alignZ, adjustColliders);
                }
            }
        }
    }
}

SimpleMeshEditor.cs

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;

namespace com.andulfgames
{
    public static class SimpleMeshTools
    {
        public static void FreezeTransformation(GameObject gameObject,
            bool freezeRotation,
            bool freezeX, MeshAlign meshPositionX,
            bool freezeY, MeshAlign meshPositionY,
            bool freezeZ, MeshAlign meshPositionZ,
            bool adjustColliders)
        {
            MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();
            Mesh newMesh = GameObject.Instantiate<Mesh>(meshFilter.sharedMesh);
            Quaternion originalRotation = meshFilter.transform.rotation;
            // If we should not freeze the rotation we have to temporarly turn the mesh
            // back to it's identity rotation before we freeze the vertizes.
            if (!freezeRotation)
                meshFilter.transform.rotation = Quaternion.identity;


            Vector3[] vertices = newMesh.vertices;

            Vector3 freeze = new Vector3(
                freezeX ? 0 : gameObject.transform.position.x,
                freezeY ? 0 : gameObject.transform.position.y,
                freezeZ ? 0 : gameObject.transform.position.z);
            Debug.Log("Freeze: " + freeze.ToString());
            Vector3 diff = gameObject.transform.position - freeze;

            Vector3 alignMin = newMesh.bounds.min;
            Vector3 alignCenter = newMesh.bounds.center;
            Vector3 alignMax = newMesh.bounds.max;

            Vector3 align = new Vector3(
                meshPositionX == MeshAlign.KeepCurrent ? 0 :
                (meshPositionX == MeshAlign.Min ? alignMin.x :
                (meshPositionX == MeshAlign.Center ? alignCenter.x : alignMax.x)),

                meshPositionY == MeshAlign.KeepCurrent ? 0 :
                (meshPositionY == MeshAlign.Min ? alignMin.y :
                (meshPositionY == MeshAlign.Center ? alignCenter.y : alignMax.y)),

                meshPositionZ == MeshAlign.KeepCurrent ? 0 :
                (meshPositionZ == MeshAlign.Min ? alignMin.z :
                (meshPositionZ == MeshAlign.Center ? alignCenter.z : alignMax.z)));

            Debug.Log("Freeze by " + diff.ToString() + " and align by " + align.ToString() + ", in total " + (diff + align).ToString());

            Debug.Log("Adjust: " + align.ToString());

            for (int i = 0; i < vertices.Length; i++)
                vertices[i] = gameObject.transform.TransformPoint(newMesh.vertices[i]) - freeze - align;

            newMesh.vertices = vertices;

            // Note that we can't rotate box- or sphere colliders

            BoxCollider boxCollider = adjustColliders ? gameObject.GetComponent<BoxCollider>() : null;
            SphereCollider sphereCollider = adjustColliders ? gameObject.GetComponent<SphereCollider>() : null;
            CapsuleCollider capsuleCollider = adjustColliders ? gameObject.GetComponent<CapsuleCollider>() : null;

            if (adjustColliders && diff + align != Vector3.zero)
            {
                Debug.Log("Adjusting colliders by " + (diff + align).ToString());
                if (boxCollider != null)
                    boxCollider.center += diff + align;
                if (sphereCollider != null)
                    sphereCollider.center += diff + align;
                if (capsuleCollider != null)
                    capsuleCollider.center += diff + align;
            }

            if (freezeRotation && gameObject.transform.rotation != Quaternion.identity)
            {
                Debug.Log("Freezing current rotation which is " + gameObject.transform.rotation.ToString());
                if (boxCollider != null)
                    Debug.LogWarning("Can't rotate box-colliders. They are fixed with the transform.");
                if (sphereCollider != null)
                    Debug.LogWarning("Can't rotate sphere-colliders. They are fixed with the transform.");
                if (capsuleCollider != null)
                    Debug.LogWarning("Can't rotate capsule-colliders. They are fixed with the transform.");

                Vector3[] normals = newMesh.normals;
                if (normals != null)
                {
                    for (int i = 0; i < normals.Length; i++)
                        normals[i] = gameObject.transform.rotation * newMesh.normals[i];
                    newMesh.normals = normals;
                }
            }

            newMesh.RecalculateBounds();
            newMesh.RecalculateNormals();

            Mesh savedMesh = SaveMesh(newMesh, gameObject.name);
            if (savedMesh != null)
                meshFilter.sharedMesh = savedMesh;

            if (freezeRotation)
                meshFilter.transform.rotation = Quaternion.identity;
            else
                meshFilter.transform.rotation = originalRotation; // Restore

            meshFilter.transform.localScale = new Vector3(1, 1, 1);
            meshFilter.transform.position -= diff - align;
        }
    }
}