我有一个问题,我制作了一个要放置在平台上的立方体的预制件。我的预制件的 y 值为 1。但是,当我尝试将其放置在平台上时,立方体的 y 值为 0.5,将其放置在地面内。我试图重置预制件、地面和立方体中的变换,但这些都不起作用。
我的统一窗口的屏幕截图,其中包含预制件及其值的更改方式。
我假设您将预制件拖到Scene
窗口中而不使用代码或类似的东西。
您的立方体位于地面一半的原因可能是由于 Unity 试图将其置于场景中地面对象的 Y 轴中心,因为这很可能是您拖动预制件的对象。
如果您希望将东西拖入Scene
窗口但又希望避免立方体进入地面,一种解决方案是更改立方体的中心位置。这样做的一种方法是将立方体放入一个空的GameObject
并修改立方体在其中的位置并将其GameObject
用作预制件。这是一个屏幕截图,说明了您修改后的预制件的外观:
如果希望将立方体移动到场景中而不进行任何位置修改,请将其拖到Hierarchy
窗口中。
创建一个自定义脚本来修改立方体预制实例的 Y 位置。OnValidate()
可能是值得研究的解决方案。
您需要相对于变换的位置“冻结”网格(重新计算网格的顶点),使其符合您的需要。
这通常在生成网格的程序中完成,但您也可以在 Unity 中使用简单的编辑器脚本。如果你用谷歌搜索,可能有几个非常好的——但是当我需要调整或冻结网格时,这是我自己使用的代码。
在您的情况下,您只需要在底部对齐网格,因此您可以为“Align y”选择“Min”(取消选中 x、y 和 z 旁边的复选框)。这会将所有网格置于变换位置之上。(对齐是一种简单的冻结方法,无需先根据需要手动定位网格)。
将以下两个脚本放在一个名为“Editor”的文件夹中(这样它就可以用作 Unity 编辑器)。然后,您将在 Unity“工具 - 简单网格编辑器”中拥有一个新的菜单选项。
简单网格编辑器.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);
}
}
}
}
}
简单网格编辑器.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;
}
}
}