我在上篇博客寫出瞭如何用代碼創建一個我們可以任意控制頂點得圓柱體。本片博客着重記錄如何在空間創建類似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創建屬於我們的平移座標軸。原理類似。