最近在做编辑器的功能,碰到一个需求是创建任意长度的墙体。思路是点击鼠标,然后拖动鼠标,墙体长度随着鼠标的拖动而增加。
通过实现此功能,感觉其中有几个关键点:
1.绘制矩形顶点
2.绘制矩形三角面
3.绘制矩形纹理
4.绘制矩形法线
5.矩形始终指向鼠标位置
6.在结束绘制矩形时,调用Mesh.Clear(),然后重新给矩形顶点赋值,否则会出现拉近视角,模型消失的情况
目前发现的问题:
在绘制斜着的矩形时,发现贴图会有重影。(因为shader原因)
实现代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateMesh : MonoBehaviour
{
[SerializeField]
private Material wallMat = null;
[SerializeField]
private float width = 1;
[SerializeField]
private float height = 3.4f;
private float length = 0;
private float halfWidth = 0;
private Mesh mesh = null;
private MeshRenderer meshRender = null;
private Vector3[] vertics = new Vector3[24];
private int[] triangles = new int[36];
private Vector2[] UVs = new Vector2[24];
private int clickCount = 0;
private RaycastHit hit;
private bool isStartCreate = false;
private Vector3 originPos = Vector3.zero;
private GameObject curObj = null;
private void Start()
{
halfWidth = width / 2f;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (clickCount == 0)
{
StartCreateCustomObject();
clickCount = 1;
}
else if (clickCount == 1)
{
EndCreateCustomObject();
clickCount = 0;
}
}
CreatingCustomObject();
}
private void StartCreateCustomObject()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
curObj = new GameObject();
meshRender = curObj.AddComponent<MeshRenderer>();
meshRender.sharedMaterial = wallMat;
var vmf = curObj.AddComponent<MeshFilter>();
mesh = vmf.mesh;
curObj.transform.position = hit.point;
originPos = hit.point;
length = 0;
vertics = new Vector3[] {
//left
new Vector3(0,0,halfWidth),
new Vector3(0,height,halfWidth),
new Vector3(0,height,-halfWidth),
new Vector3(0,0,-halfWidth),
//front
new Vector3(0,0,-halfWidth),
new Vector3(0,height,-halfWidth),
new Vector3(0,height,-halfWidth),
new Vector3(0,0,-halfWidth),
//right
new Vector3(0,0,-halfWidth),
new Vector3(0,height,-halfWidth),
new Vector3(0,height,halfWidth),
new Vector3(0,0,halfWidth),
//back
new Vector3(0,0,halfWidth),
new Vector3(0,height,halfWidth),
new Vector3(0,height,halfWidth),
new Vector3(0,0,halfWidth),
//up
new Vector3(0,height,-halfWidth),
new Vector3(0,height,halfWidth),
new Vector3(0,height,halfWidth),
new Vector3(0,height,-halfWidth),
//down
new Vector3(0,0,halfWidth),
new Vector3(0,0,-halfWidth),
new Vector3(0,0,-halfWidth),
new Vector3(0,0,halfWidth)
};
//绘制顶点
mesh.vertices = vertics;
triangles = new int[] {
//left
0,1,2,
2,3,0,
//front
4,5,6,
6,7,4,
//right
8,9,10,
10,11,8,
//back
12,13,14,
14,15,12,
//up
16,17,18,
18,19,16,
//down
20,21,22,
22,23,20
};
//绘制三角面
mesh.triangles = triangles;
UVs = new Vector2[] {
//left
new Vector2(0,0),
new Vector2(0,1),
new Vector2(1,1),
new Vector2(1,0),
//front
new Vector2(0,0),
new Vector2(0,1),
new Vector2(1,1),
new Vector2(1,0),
//right
new Vector2(0,0),
new Vector2(0,1),
new Vector2(1,1),
new Vector2(1,0),
//back
new Vector2(0,0),
new Vector2(0,1),
new Vector2(1,1),
new Vector2(1,0),
//up
new Vector2(0,0),
new Vector2(0,1),
new Vector2(1,1),
new Vector2(1,0),
//down
new Vector2(0,0),
new Vector2(0,1),
new Vector2(1,1),
new Vector2(1,0),
};
//绘制纹理
mesh.uv = UVs;
//计算法线
mesh.RecalculateNormals();
isStartCreate = true;
}
}
private void CreatingCustomObject()
{
if (isStartCreate)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
vertics = mesh.vertices;
var vEndCenterX = hit.point.x - originPos.x;
var vEndCenterZ = hit.point.z - originPos.z;
length = Mathf.Sqrt(vEndCenterX * vEndCenterX + vEndCenterZ * vEndCenterZ);
var vros = hit.point - originPos;
curObj.transform.rotation = Quaternion.FromToRotation(Vector3.right, vros);
vertics[6] = new Vector3(length, height, -halfWidth);
vertics[7] = new Vector3(length, 0, -halfWidth);
vertics[8] = new Vector3(length, 0, -halfWidth);
vertics[9] = new Vector3(length, height, -halfWidth);
vertics[10] = new Vector3(length, height, halfWidth);
vertics[11] = new Vector3(length, 0, halfWidth);
vertics[12] = new Vector3(length, 0, halfWidth);
vertics[13] = new Vector3(length, height, halfWidth);
vertics[18] = new Vector3(length, height, halfWidth);
vertics[19] = new Vector3(length, height, -halfWidth);
vertics[22] = new Vector3(length, 0, -halfWidth);
vertics[23] = new Vector3(length, 0, halfWidth);
mesh.vertices = vertics;
//如果不实时计算法线的话,在创建过程中模型无法正常接收光照和着色
mesh.RecalculateNormals();
}
}
}
private void EndCreateCustomObject()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
//最后结束创建的时候重新赋值一下顶点,否则会出现Bound跟Mesh尺寸不一致的情况
//如果Bound和Mesh尺寸不一致,拉近视角模型则会消失
mesh.Clear();
var vEndCenterX = hit.point.x - originPos.x;
var vEndCenterZ = hit.point.z - originPos.z;
length = Mathf.Sqrt(vEndCenterX * vEndCenterX + vEndCenterZ * vEndCenterZ);
var vros = hit.point - originPos;
curObj.transform.rotation = Quaternion.FromToRotation(Vector3.right, vros);
vertics[6] = new Vector3(length, height, -halfWidth);
vertics[7] = new Vector3(length, 0, -halfWidth);
vertics[8] = new Vector3(length, 0, -halfWidth);
vertics[9] = new Vector3(length, height, -halfWidth);
vertics[10] = new Vector3(length, height, halfWidth);
vertics[11] = new Vector3(length, 0, halfWidth);
vertics[12] = new Vector3(length, 0, halfWidth);
vertics[13] = new Vector3(length, height, halfWidth);
vertics[18] = new Vector3(length, height, halfWidth);
vertics[19] = new Vector3(length, height, -halfWidth);
vertics[22] = new Vector3(length, 0, -halfWidth);
vertics[23] = new Vector3(length, 0, halfWidth);
mesh.vertices = vertics;
mesh.triangles = triangles;
mesh.uv = UVs;
mesh.RecalculateNormals();
curObj.AddComponent<BoxCollider>();
curObj = null;
isStartCreate = false;
}
}
}
墙体Shader:https://download.csdn.net/download/qq_39353597/52010659
参考资料:https://docs.unity.cn/cn/2019.4/Manual/UsingtheMeshClass.html