我在上篇博客写出了如何用代码创建一个我们可以任意控制顶点得圆柱体。本片博客着重记录如何在空间创建类似unity可以控制物体的坐标轴。由于我们要控制圆柱体的长度,所以我们设计的坐标轴是两个方块在圆柱体的两端。效果图如下:
首先我们要绘制两个方块,我们知道空间显示在我们眼前的物体都是通过由多个三角面组成的mesh显示在我们面前的。所以我们首先创建一个属于我们的BOXmesh。代码如下:
public static Mesh CreateBoxMesh(float width, float height, float depth)
{
// Clamp dimensions
width = Mathf.Max(width, 0.0001f);
height = Mathf.Max(height, 0.0001f);
depth = Mathf.Max(depth, 0.0001f);
// Store half dimension values for easy access
float halfWidth = width * 0.5f;
float halfHeight = height * 0.5f;
float halfDepth = depth * 0.5f;
// Prepare the vertex attribute arrays
Vector3[] boxVertexPositions = new Vector3[24];
Vector3[] boxVertexNormals = new Vector3[24];
// Generate the vertices. Start with the front face
boxVertexPositions[0] = new Vector3(-halfWidth, -halfHeight, -halfDepth);
boxVertexPositions[1] = new Vector3(-halfWidth, halfHeight, -halfDepth);
boxVertexPositions[2] = new Vector3(halfWidth, halfHeight, -halfDepth);
boxVertexPositions[3] = new Vector3(halfWidth, -halfHeight, -halfDepth);
boxVertexNormals[0] = -Vector3.forward;
boxVertexNormals[1] = boxVertexNormals[0];
boxVertexNormals[2] = boxVertexNormals[0];
boxVertexNormals[3] = boxVertexNormals[0];
// Back face
boxVertexPositions[4] = new Vector3(-halfWidth, -halfHeight, halfDepth);
boxVertexPositions[5] = new Vector3(halfWidth, -halfHeight, halfDepth);
boxVertexPositions[6] = new Vector3(halfWidth, halfHeight, halfDepth);
boxVertexPositions[7] = new Vector3(-halfWidth, halfHeight, halfDepth);
boxVertexNormals[4] = Vector3.forward;
boxVertexNormals[5] = boxVertexNormals[4];
boxVertexNormals[6] = boxVertexNormals[4];
boxVertexNormals[7] = boxVertexNormals[4];
// Left face
boxVertexPositions[8] = new Vector3(-halfWidth, -halfHeight, halfDepth);
boxVertexPositions[9] = new Vector3(-halfWidth, halfHeight, halfDepth);
boxVertexPositions[10] = new Vector3(-halfWidth, halfHeight, -halfDepth);
boxVertexPositions[11] = new Vector3(-halfWidth, -halfHeight, -halfDepth);
boxVertexNormals[8] = -Vector3.right;
boxVertexNormals[9] = boxVertexNormals[8];
boxVertexNormals[10] = boxVertexNormals[8];
boxVertexNormals[11] = boxVertexNormals[8];
// Right face
boxVertexPositions[12] = new Vector3(halfWidth, -halfHeight, -halfDepth);
boxVertexPositions[13] = new Vector3(halfWidth, halfHeight, -halfDepth);
boxVertexPositions[14] = new Vector3(halfWidth, halfHeight, halfDepth);
boxVertexPositions[15] = new Vector3(halfWidth, -halfHeight, halfDepth);
boxVertexNormals[12] = Vector3.right;
boxVertexNormals[13] = boxVertexNormals[12];
boxVertexNormals[14] = boxVertexNormals[12];
boxVertexNormals[15] = boxVertexNormals[12];
// Top face
boxVertexPositions[16] = new Vector3(-halfWidth, halfHeight, -halfDepth);
boxVertexPositions[17] = new Vector3(-halfWidth, halfHeight, halfDepth);
boxVertexPositions[18] = new Vector3(halfWidth, halfHeight, halfDepth);
boxVertexPositions[19] = new Vector3(halfWidth, halfHeight, -halfDepth);
boxVertexNormals[16] = Vector3.up;
boxVertexNormals[17] = boxVertexNormals[16];
boxVertexNormals[18] = boxVertexNormals[16];
boxVertexNormals[19] = boxVertexNormals[16];
// Bottom face
boxVertexPositions[20] = new Vector3(-halfWidth, -halfHeight, -halfDepth);
boxVertexPositions[21] = new Vector3(halfWidth, -halfHeight, -halfDepth);
boxVertexPositions[22] = new Vector3(halfWidth, -halfHeight, halfDepth);
boxVertexPositions[23] = new Vector3(-halfWidth, -halfHeight, halfDepth);
boxVertexNormals[20] = -Vector3.up;
boxVertexNormals[21] = boxVertexNormals[20];
boxVertexNormals[22] = boxVertexNormals[20];
boxVertexNormals[23] = boxVertexNormals[20];
// Generate the indices
int[] vertexIndices = new int[]
{
// Front face
0, 1, 2, 0, 2, 3,
// Back face
4, 5, 6, 4, 6, 7,
// Left face
8, 9, 10, 8, 10, 11,
// Right face
12, 13, 14, 12, 14, 15,
// Top face
16, 17, 18, 16, 18, 19,
// Bottom face
20, 21, 22, 20, 22, 23
};
// Create the mesh and return it to the client code
var boxMesh = new Mesh();
boxMesh.vertices = boxVertexPositions;
boxMesh.normals = boxVertexNormals;
boxMesh.SetIndices(vertexIndices, MeshTopology.Triangles, 0);
return boxMesh;
}
创建后的静态函数供我们需要绘制的时候调用。下面我们要设置Boxmesh 的位置,欧拉角以及缩放比。Unity中绘制mesh或者gl线段一般都在OnRenderObject函数中进行。
protected void OnRenderObject()
{
Matrix4x4[] BoxWorldTransforms = GetLengthWorldTransform();
DrawControlLineLengthAxis(BoxWorldTransforms);
}
首先我们要设置boxmesh的Transform信息给保存到4*4矩阵中,
private Matrix4x4[] GetLengthWorldTransform()
{
Matrix4x4[] worldTransforms = new Matrix4x4[2];
Vector3[] localPosition = GetBoxesGizmoLocalPositions(CalculateGizmoScale());
Quaternion[] localQuaternion = GetBoxesGizmoLocalRotations();
// Loop through each axis
for (int i = 0; i < 2; ++i)
{
Vector3 worldPosition = _gizmoTransform.position + localPosition[i];
Quaternion worldRotation = localQuaternion[i];
// Construct the world transform matrix
worldTransforms[i] = new Matrix4x4();
worldTransforms[i].SetTRS(worldPosition, worldRotation, Vector3.Scale(_gizmoTransform.lossyScale, new Vector3(_BoxWidth, _BoxHeight, _BoxDepth)));
}
return worldTransforms;
}
首先来获取boxmesh的位置。我们知道这个自制的坐标轴要在圆柱的两端。而且在上篇博客我们看到我们的圆柱体的左右两侧就是圆柱的forward和-forward,所以获取局部坐标代码如下(lastSelectedGameObject就是我们的圆柱体,tempLeftGizmoPos就是我们在上节所说的leftPos,我们可以在坐标轴显示的初始化函数中获取圆柱体的长度Length,即tempLeftGizmoPos=leftPos=Length/2。gizmoScale就是我们根据摄像机和Boxmesh的距离来自动调节Boxmesh大小的比例系数):
private Vector3[] GetBoxesGizmoLocalPositions(float gizmoScale)
{
return new Vector3[]
{
lastSelectedGameObject.transform.forward* tempLeftGizmoPos,
-lastSelectedGameObject.transform.forward * tempRightGizmoPos,
};
}
CalculateGizmoScale函数代码如下:
float _gizmoBaseScale =0.77f;
protected float CalculateGizmoScale()
{
if (_camera.orthographic)
{
float scaleConstant = 0.02f;
return _gizmoBaseScale * _camera.orthographicSize / (_camera.pixelRect.height * scaleConstant);
}
else
{
const float scaleConstant = 0.045f;
Vector3 cameraPositionToGizmoOrigin = (this.transform.position - _cameraTransform.position);
return _gizmoBaseScale * cameraPositionToGizmoOrigin.magnitude / (_camera.pixelRect.height * scaleConstant);
}
}
private Quaternion[] GetBoxesGizmoLocalRotations()
{
return new Quaternion[]
{
Quaternion.identity,
Quaternion.identity
};
}
以上方法我们就可以获取到坐标轴的Transform信息。接下来就将boxmesh的信息给赋值上。
private void DrawControlLineLengthAxis(Matrix4x4[] worldTransforms)
{
Material material = MaterialPool.Instance.GizmoSolidComponent;
material.SetInt("_ZWrite", 1);
material.SetInt("_ZTest", 0);
material.SetInt("_IsLit", 1);
material.SetFloat("_LightIntensity", 1.5f);
material.SetVector("_LightDir", _cameraTransform.forward);
Mesh boxMesh = MeshPool.Instance.BoxMesh;
for (int axisIndex = 3; axisIndex < 5; ++axisIndex)//这里是因为枚举类型里我多添加了两种 X Y Z Left Right
{
Color axisColor = axisIndex == (int)selectGizmo ? SelectedAxisColor : _axesColors[2];//当坐标轴被点选后 坐标轴颜色设置高亮的颜色
//Debug.Log(selectGizmo);
material.SetColor("_Color", axisColor);
material.SetInt("_StencilRefValue", _axesStencilRefValues[0]);
material.SetPass(0);
Graphics.DrawMeshNow(boxMesh, worldTransforms[axisIndex-3]);
}
}
以上就是对自己设计的坐标轴chua创建,当然我们可以仿照unity的XYZ创建属于我们的平移坐标轴。原理类似。