自绘制实例
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TRU1EerRVYyYkMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLzAzN4MzN1ITM1IDNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
好处就是通过拖动,能实时看到模型变化,并且是实例化(可保存)
整个结构是好的,构思也是好的,实现也实现了
网上例子还不少,就几个三角面,乍看好像也没啥作用,工作中也不会用到,面试官也不会问到
但这时创造自己3D引擎的第一步
掌握了这个例子,就懂的了如何创建三角面,顶点和UV
下面图,有错,请辩证查看和理解
完整“优化”代码会贴在最后
顶点优化
其实发现网上有2~3个博客是抄这个代码的,原来的代码反而找不到了,
//一个小学生写的。。。。。。MD(这方法会把自己的节点也算进去,会多了1+)。。。。。。。。。
//var ts = this.GetComponentsInChildren<Transform>();
//估计他自己也是抄网上, 然后实现不下去了
//(现在已经纠正)
改成:
var ts_len = transform.childCount;
未优化前的代码有个谬误就是坑了我很久,怎么3个子节点会有4个顶点???
三角面“优化”
解决了上面的谬误了,我们继续
//var tris = new int[] { 0, 1, 2, 0, 1, 3, 1, 2, 3 };
改成
var tris = new int[] { 0, 1, 2, 0, 2, 3 };
这里有2个原则需要知道:(我也是搞这个例子才懂的)
1.三角面按顺时针绘制,相对的,逆时针绘制的是背面
2.顶点数和UV数1:1对应,但是三角面不是,如何确定一个模型外皮三角面??美术每天都干这个,不了解原理也无所谓
3.不确定美术是不是很了解,但是程序是真的不了解
举个栗子
如果 trangles = 0,1,2
如果三角面 trangles = 0,2,3 则透明,需要镜头转到背面才能看到
回到上面的代码:
//var tris = new int[] { 0, 1, 2, 0, 1, 3, 1, 2, 3 };
var tris = new int[] { 0, 1, 2, 0, 2, 3 };
第一句,无论镜头从哪个角度看,基本上不可能同时看到3个面(有点不合常人逻辑),对理解有3D世界有帮助,但入门困难
第二句,简单的隆起的小山丘,解决
UV优化
最后我们再加上贴图
好像5,6年前,UNITY就推荐用sharedMesh, sharedMaterial
不要问为什么。。。。。
MeshFilter filter = this.GetComponent<MeshFilter>();
MeshRenderer render = this.GetComponent<MeshRenderer>();
var mesh = filter.sharedMesh;
最后,完整代码:
/* 自定义Mesh绘制
*
* - 已添加贴图
*
* created by Sidney Lu———————2020:
* CSDN:
* https://blog.csdn.net/avi9111/article/details/105747834
* GITEE:
* https://gitee.com/avi9111/UnityUtils
*
* 开发中:
* uv自动展开
* 贴图列子
* 模型列表
* 自定义顶点数
* 保存模型
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class GenMeshByGameObject : MonoBehaviour
{
public Material mat;
private int genCount = 4;
private void Awake()
{
FullFill(genCount);
}
private void OnEnable()
{
GetComponent<MeshRenderer>().sharedMaterial = mat;
}
public void FullFill() {
FullFill(genCount);
}
public void FullFill(int totalCount)
{
int count = totalCount - transform.childCount;
for (int i = 0; i < count; i++)
{
GameObject gen = new GameObject();
gen.name = "mesh" + (transform.childCount + 1);
gen.transform.SetParent(transform, false);
}
}
void OnDrawGizmos()
{
MeshFilter filter = this.GetComponent<MeshFilter>();
MeshRenderer render = this.GetComponent<MeshRenderer>();
var mesh = filter.sharedMesh;
//一个小学生写的。。。。。。MD(这方法会把自己的节点也算进去,会多了1+)。。。。。。。。。
//var ts = this.GetComponentsInChildren<Transform>();
//估计他自己也是抄网上, 然后实现不下去了
//(现在已经纠正)
var ts_len = transform.childCount;
Vector3[] vers = new Vector3[ts_len];
for (int i = 0; i < ts_len; i++)
{
vers[i] = transform.GetChild(i).position;
}
//var tris = new int[] { 0, 1, 2, 0, 1, 3, 1, 2, 3 };
var tris = new int[] { 0, 1, 2, 0, 2, 3 };
//一个小学生还害我写一大堆,下面这段代码是错误的
//uv(顶点到贴图的映射)数量 == vertex(顶点)数量,
//所以这两兄弟必然需要是相等
//下下的代码才是正确,而且是最简单的
//var uvs = new Vector2[6];
//uvs[0] = new Vector2(0, 0);
//uvs[1] = new Vector2(1, 0);
//uvs[2] = new Vector2(1, 1);
//uvs[3] = new Vector2(0, 0);
//uvs[4] = new Vector2(1, 1);
//uvs[5] = new Vector2(0, 1);
var uvs = new Vector2[] {
new Vector2(0,0)
,new Vector2(1,1)
,new Vector2(0,1)
,new Vector2(1,0)};
// mesh.Clear();
mesh.vertices = vers;
mesh.triangles = tris;
mesh.uv = uvs;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
//MeshCollider的作用是????
//this.GetComponent<MeshCollider>().sharedMesh = mesh;
// var uvs = new[] { };
filter.sharedMesh = mesh;
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(GenMeshByGameObject))]
public class GenMeshByGameObjectInspector : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (GUILayout.Button("Gen"))
{
GenMeshByGameObject _t = target as GenMeshByGameObject;
_t.FullFill();
}
}
}
#endif
谢谢阅读