简体   繁体   English

为什么我的预制件的 position 在场景中掉落时会发生变化?

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

I have a problem, I made a prefab of a cube that I want to place on a platform.我有一个问题,我制作了一个要放置在平台上的立方体的预制件。 The y value of my prefab is 1. However, when I try to place it on the platform the cube takes the y value of 0.5 which puts it inside of the ground.我的预制件的 y 值为 1。但是,当我尝试将其放置在平台上时,立方体的 y 值为 0.5,将其放置在地面内。 I tried to reset the transform in the prefab, the ground and the cubes but none of that worked.我试图重置预制件、地面和立方体中的变换,但这些都不起作用。

Screenshots of my unity window with both the prefab and how its value is changed.我的统一 window 的屏幕截图,其中包含预制件及其值的更改方式。

I'm assuming you're dragging the prefab into the Scene window without using code or anything like that.我假设您将预制件拖入Scene window 而不使用代码或类似的东西。

Why does the position get modified为什么 position 会被修改

The reason your cube is halfway into the ground likely is due to Unity trying to have it centered on the Y axis on the ground object you have in the scene since that's likely the object you're dragging your prefabs on.您的立方体位于地面一半的原因可能是由于 Unity 试图将其置于您在场景中的地面 object 的 Y 轴上,因为这很可能是您正在拖动预制件的 object。

Solution 1解决方案 1

If you wish to drag things into the Scene window but wish to avoid the cubes going into the ground, one solution is to change the center position of the cubes.如果您希望将物体拖入Scene window 但希望避免立方体进入地面,一种解决方案是更改立方体的中心 position。 One way of doing that is by putting the cube into an empty GameObject and modify the cube's position inside it and use this GameObject as a prefab.这样做的一种方法是将立方体放入一个空的游戏对象中,并在其中修改立方体的GameObject并将此GameObject对象用作预制件。 Here's a screenshot illustrating how your modified version of the prefab would look like:这是一个屏幕截图,说明了您修改后的预制件的外观:
在此处输入图像描述

Solution 2解决方案 2

If wish to move a cube into the scene without any position modifications, drag it into the Hierarchy window instead.如果希望将立方体移动到场景中而不进行任何 position 修改,请将其拖动到Hierarchy window 中。

Solution 3解决方案 3

Create a custom script that modifies the Y position of your cube prefab instance.创建修改多维数据集预制实例的 Y position 的自定义脚本。 OnValidate() may be something worth looking into for this solution. OnValidate()可能是值得研究的解决方案。

You need to "freeze" the mesh (recalculate the vertices of the mesh) relative to the position of the transform so it fits your needs.您需要相对于变换的 position 来“冻结”网格(重新计算网格的顶点),以便满足您的需求。

This is usually done in the program that generated the mesh but you could also use a simple editor script inside Unity.这通常在生成网格的程序中完成,但您也可以在 Unity 中使用简单的编辑器脚本。 There are probably several very good ones if you google - but here is the code I use myself when I need to adjust or freeze a mesh.如果你用谷歌搜索,可能有几个非常好的——但是当我需要调整或冻结网格时,这是我自己使用的代码。

在此处输入图像描述

In your case, you simply want to align the mesh at the bottom, so you can select "Min" for "Align y" (let the checkboxes beside x, y, and z be unchecked).在您的情况下,您只需要在底部对齐网格,因此您可以 select “Min” for “Align y”(取消选中 x、y 和 z 旁边的复选框)。 This will put all the mesh above the transform position.这会将所有网格置于变换 position 之上。 (Align is a simple way of freezing without the need to first manually position the mesh as desired). (对齐是一种简单的冻结方法,无需先根据需要手动 position 网格)。

Place the following two scripts in a folder with the name "Editor" (so it can be used as a Unity editor).将以下两个脚本放在一个名为“Editor”的文件夹中(这样它就可以用作 Unity 编辑器)。 You will then have a new menu option in Unity "Tools - Simple Mesh Editor".然后,您将在 Unity“工具 - 简单网格编辑器”中拥有一个新的菜单选项。

SimpleMeshEditor.cs简单网格编辑器.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简单网格编辑器.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;
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在我的脚本中激活GameObject预制时未显示在场景中 - GameObject prefab is not showing in scene when activated in my script 为什么用预制件替换游戏对象时,预制件 position 有点靠后,而不是完全在游戏对象 position 上? - Why when replacing a gameobject with prefab the prefab position is a bit to the back and not exactly on the gameobject position? 为什么在对预制件进行了一些位置更改后,我无法在我的预制件上进行覆盖? - Why I can't make Overrides on my Prefab after made some position changes for the Prefab? 在沙盒游戏的鼠标位置实例化预制件 - Instantiating a prefab at the mouse position for my sandbox game Unity-当场景中有多个预制件时,Raycast无法正常工作 - Unity - Raycast not working when more than one prefab on Scene 实例化的预制件没有按预期工作,但是当预制件放在现场时,一切都按预期运行 - Instantiated prefab is not working as expected but when the prefab is put on the scene then everything runs as expected 在(另一个)场景中实例化预制件 - Instantiate prefab in (another) scene 为什么按下鼠标左键时鼠标的位置不会更新? - Why does my mouse position not update when the left button is pressed? 实例化为什么Unity Prefab值错误? - Why are Unity Prefab values wrong when instantiated? 为什么更改 ItemsSource 时 DataGrid 不更新? - Why does the DataGrid not update when the ItemsSource is changed?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM