为什么我的预制件放置在场景中时位置会发生变化?
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;
}
}
}
我有问题,我制作了一个立方体的预制件,我想将其放置在平台上。 我的预制件的 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;
}
}
}