关于Unity3D动态生成连续性网格几何体总结【第三部分】(贴图篇)

文章目录

  • 关于Unity3D动态生成连续性网格几何体总结【第三部分】(贴图篇)
  • 前言
  • 一、动态建立UV值
  • 二、贴图的平铺与拉伸
  • 二、法线的计算
  • 总结

前言

前一篇文章已经简绍动态连续网格的生成方式与算法。也算完成了“骨骼”的构建,那边本篇将简绍如果为这个坚强的“骨骼“”贴上一个好看的“皮囊”。

骨骼

一、动态建立UV值

如果构建我的UV值呢?在这里我采用把模型切面方向当成U值方向,而模型走势向方向当成V值方式。然后使用一张贴图,整体贴在设置好UV值的模型上。

模型的UV设置

贴图

  1. 构建V值
    现在素材已经齐备,那我们就来构建V值。由于我们是把整张贴图的映射到模型上面去。因此模型每个顶点的V值的限定范围一定是在【0,1】之间,且起点一点是0,终点一定是1。那么问题来了,我们该如何分配路径上所有顶点的V值。答案是:通过路径的长度占所在该系列顶点的路径总长度的百分比。这样可以完美把V值映射到【0,1】之间。P.S:该系列顶点序号之间永远相差一个模板的顶点总数值
V值 = 当前顶点到起始点的路径长度 / 该系列顶点所在路径的总长度

V值计算示意图

下面展示计算的伪代码:

         //伪代码float[] totalDistanceArray = new float[templteVerticesCount];//声明一个所有总路径的管理数组//开始提前计算所有系列点的总路径//每个模板的顶点就是一组系列点for (int templteIndex = 0; templteIndex < templteVerticesCount;templteIndex++) {float totalDistance = 0;//计算该系列点的总长度for (int vIndex = templteIndex; uIndex < tempVerticeCount; vIndex += templteVerticesCount){int nextIndex = vIndex + templteVerticesCount;//获取下一个系列点if (nextIndex > tempVerticeCount) break;Vector3 curPoint = tunnelShell.Vertices[vIndex];//当前系列点Vector3 nextPoint = tunnelShell.Vertices[nextIndex];//下一个系列点//由于平方比开方性能好很多,且平方不影响百分比计算,因此使用计算路径的平方totalDistance += CaculateSqrDistance(curPoint, nextPoint);//}totalDistanceArray[templteIndex] = totalDistance;//总长度}//计算当前点的V值for (int i = 0; i < tempVerticeCount; i++){Vector3 curPoint = Vertices[i];//获取当前顶点位置int index = i % templteVerticesCount;//获取当前顶点的序号Vector3 BackPoint = curPoint;//获取上一个系列点float currentDistance = 0;//获取目前的路径长度for (int b = i - templteVerticesCount; b >= 0; b -= templteVerticesCount){Vector3 tempPoint = Vertices[b];//获取上一个系列顶点的位置currentDistance += CaculateSqrDistance(tempPoint, BackPoint);//统计当前的路径长度BackPoint = tempPoint;//交换顶点}float t = currentDistance / totalDistanceArray[index];//计算V值UV[i] = new Vector2(UV[i].x, t);//赋值V值}
  1. 构建U值
    下面我们在来看看U值的计算方式。与V值计算方式很类似,也是把当前顶点到起点的长度除以整个顶点的总长度。这样也可以把值映射到【0,1】之间。
U值 = 该顶点到起始顶点的长度 / 整体封闭路径的总长度

截面U值计算示意图

下面我们来看看代码实现

         //伪代码//获取模板所有顶点的总长度float UTotalLength = GetTotalLength(templteVertice);int meshVerticeIndex = 0;//顶点序号for (int pathIndex = 0; pathIndex < pathCount; pathIndex++){Vector3 curNode = pathList[pathIndex];//前一个路径点Vector3 nextNode = pathList[pathIndex + 1];//后一个点路径点//路径之间生成细分节点for (int segmentIndex = pathIndex == 0 ? 0 : 1; segmentIndex < refreshMesh.Segment; segmentIndex++){Vector3 segmentPoint = GetSegmentPoint(curNode, nextNode);//获取细分节点位置//templteVerticesCount 为模型模板的顶点总数float tempLength = 0;//起始路径值for (int verticesIndex = 0; verticesIndex < templteVerticesCount; verticesIndex++){//获取顶点之间的距离长度if (verticesIndex > 0) tempLength += Vector3.Distance(templteVertice[verticesIndex], templteVertice[verticesIndex - 1]);//计算当前路径占整个路径的百分比UV[tempVerticeCount] = new Vector2(tempLength / UTotalLength, 0));meshVerticeIndex++;}}}

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、贴图的平铺与拉伸

由于我们使用的贴图基本上都是正方形,即长宽比永远是 1 : 1。但是我们生成的网格的截面长度与走向长度比是动态的,且不能保证两者的距离比是 1 :1。因此我们要采用纵向平铺贴图的方式来保证贴图不会失真。

//我们以宽为基准,按比例平铺长度
textureTile = new Vector2(1, 走向总长度/ 截面总长度);

纵向平铺值 # 三、贴图制作小技巧 由于我们模型网格与UV值都是动态生成的,因此模型贴图就需要单独制作。那么我们可以把我们的网格导出成单独Object格式模型,提供给美术人员。好让他们在U值方向去根据实际值分配贴图纹理。 下面导出Object格式模型代码:

using UnityEngine;
using System.Collections;
using System.IO;
using System.Text;
using System.Collections.Generic;public class ObjExporter
{public static string MeshToString(Mesh mesh, string ObjName,MeshRenderer mr){//Mesh mesh = mf.mesh;Material[] sharedMaterials = null;if (mr != null)sharedMaterials = mr.sharedMaterials;Vector2 textureOffset = Vector3.one;Vector2 textureScale = Vector3.one;if(sharedMaterials != null) textureOffset = mr.material.GetTextureOffset("_MainTex");if (sharedMaterials != null) textureScale = mr.material.GetTextureScale("_MainTex");StringBuilder stringBuilder = new StringBuilder();stringBuilder.Append("mtllib design.mtl").Append("\n");stringBuilder.Append("g ").Append(ObjName).Append("\n");Vector3[] vertices = mesh.vertices;for (int i = 0; i < vertices.Length; i++){Vector3 vector = vertices[i];stringBuilder.Append(string.Format("v {0} {1} {2}\n", vector.x, vector.z, vector.y));}stringBuilder.Append("\n");Dictionary<int, int> dictionary = new Dictionary<int, int>();if (mesh.subMeshCount > 1){int[] triangles = mesh.GetTriangles(1);for (int j = 0; j < triangles.Length; j += 3){if (!dictionary.ContainsKey(triangles[j])){dictionary.Add(triangles[j], 1);}if (!dictionary.ContainsKey(triangles[j + 1])){dictionary.Add(triangles[j + 1], 1);}if (!dictionary.ContainsKey(triangles[j + 2])){dictionary.Add(triangles[j + 2], 1);}}}for (int num = 0; num != mesh.uv.Length; num++){Vector2 vector2 = Vector2.Scale(mesh.uv[num], textureScale) + textureOffset;if (dictionary.ContainsKey(num)){stringBuilder.Append(string.Format("vt {0} {1}\n", mesh.uv[num].x, mesh.uv[num].y));}else{stringBuilder.Append(string.Format("vt {0} {1}\n", vector2.x, vector2.y));}}for (int k = 0; k < mesh.subMeshCount; k++){stringBuilder.Append("\n");if (k == 0){stringBuilder.Append("usemtl ").Append("Material_design").Append("\n");}if (k == 1){stringBuilder.Append("usemtl ").Append("Material_logo").Append("\n");}int[] triangles2 = mesh.GetTriangles(k);for (int l = 0; l < triangles2.Length; l += 3){stringBuilder.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n", triangles2[l] + 1, triangles2[l + 1] + 1, triangles2[l + 2] + 1));}}return stringBuilder.ToString();}public static void MeshToFile(Mesh mesh, MeshRenderer mr,string ObjName,string path,string filename){if (mesh == null) {Debug.LogError("网格数据不能为空!");return;}if (!Directory.Exists(path)) {Directory.CreateDirectory(path);}using (StreamWriter sw = new StreamWriter(path+filename)){sw.Write(MeshToString(mesh,ObjName, mr));}}
}

二、法线的计算

模型的方向计算也是比较关键,因为会直接影响模型的光照效果。其实我们这里可以使用Unity内置的API完成法线计算:

                meshPlus.MeshData.RecalculateTangents();meshPlus.MeshData.RecalculateNormals();

总结

到目前位置的显示效果:

本篇到此就已经结束了,可以看出动态生成的网格还是有瑕疵的,那么下一篇我们来讲讲路径点之间的平滑显示,以便修复这些问题。

传送门
上一篇 :关于Unity3D动态生成连续性网格几何体总结【第二部分】(算法篇)
下一篇:关于Unity3D动态生成连续性网格几何体总结【第四部分】(曲线平滑篇)

关于Unity3D动态生成连续性网格几何体总结【第三部分】(贴图篇)相关推荐

  1. [Unity3D]动态生成平面网格

    在编写几何着色器的时候发现默认的Plane无法满足需求,并且顶点顺序未知,于是便写了一个网格生成代码,便于生成指定大小的Plane,且顶点顺序可控. 效果如下: 一个单元格由4个顶点,两个三角面组成. ...

  2. Unity3D动态创建地形网格(一)

    Unity3D动态创建地形网格(一) 这次简单的写一个动态创建地形网格的脚本给大家分享一下. 这次是第一部分,仅仅实现了通过高度图动态生成地形的部分.假如以后有心情和时间,再来慢慢的补充多通道刷地形材 ...

  3. JS实现动态生成表格并提交表格数据向后端 表格中数据转为json

    原文地址 需求:在web页面上动态的生成表格,并可以对表格中的数据进行编辑,然后把表格中的数据提交至后端服务器保存. 首先动态生成表格. 1.首先我们需要导入JS库文件.jQuery 2.然后在页面d ...

  4. arcgis fishnet 单位_ArcGIS生成规则网格(Fishnet)

    在利用ArcGIS处理数据时,有时需要对整个工作区域进行规则网格划分,这个在ArcGIS中是一件非常简单的事情,现在就将利用ArcGIS生成规则网格的步骤详细的介绍一下. 首先我有一个工作的范围,比如 ...

  5. arcgis fishnet 单位_【转载】ArcGIS生成规则网格(Fishnet)

    在利用ArcGIS处理数据时,有时需要对整个工作区域进行规则网格划分,这个在ArcGIS中是一件非常简单的事情,现在就将利用ArcGIS生成规则网格的步骤详细的介绍一下. 首先我有一个工作的范围,比如 ...

  6. arcgis fishnet 单位_【转】ArcGIS生成规则网格(Fishnet)

    在利用ArcGIS处理数据时,有时需要对整个工作区域进行规则网格划分,这个在ArcGIS中是一件非常简单的事情,现在就将利用ArcGIS生成规则网格的步骤详细的介绍一下. 首先我有一个工作的范围,比如 ...

  7. unity3d模拟树叶飘动_Unity3D独立游戏开发日记(一):动态生成树木

    目前写的独立游戏是一个沙盒类型的游戏.游戏DEMO视频如下: 提到沙盒类型的游戏,就有人给出了这样的定义: 游戏世界离现实世界越近,自由度.随机度越高才叫沙盒游戏.所谓自由度,就是你在游戏里想干啥就干 ...

  8. unity3d 动态合批设置_Unity动态合批(Dynamic Batching)与静态合批(Static Batching)

    动态合批与静态合批其本质是对将多次绘制请求,在允许的条件下进行合并处理,减少cpu对gpu绘制请求的次数,达到提高性能的目的. 1.静态合批是将静态(不移动)GameObjects组合成大网格,然后进 ...

  9. Unity 代码动态生成模型

    网格由 3D 空间中排列的三角形组成,旨在产生实体对象的效果.三角形由其拐点或者顶点定义.在 Mesh 类中,顶点全部存储在单个数组中,并且每个三角形使用与顶点数组的索引对应的三个整数指定.这些三角形 ...

最新文章

  1. 【Qt】Qt样式表总结(二):冲突和命名空间
  2. linux java 获取路径怎么写_linux中java获取路径的实例代码
  3. 系统管理-第1部分 系统的易管理性
  4. 73.JVM内存基础结构,参数分类,推荐的配置项,参数混用问题,常用工具,常用命令
  5. 如何让你瞬间拥有百万粉丝 前端F12的那些装X小技巧
  6. android 手动签名apk,记录手动签名APK的过程
  7. 数据结构与算法--两个链表中第一个公共节点
  8. [转]Oracle DB管理内存
  9. Java 面向对象:封装详解
  10. 如何理解HTML结构的语义化?
  11. TOMM2018_Unsupervised Person Re-identification: Clustering and Fine-tuning
  12. python的if循环语句_第二个是Python的循环语句,基础,使用,if,条件,判断,while,for
  13. 【Qt串口调试助手】1.3 - 重写ComboBox下拉框的鼠标点击事件,实现点击下拉框扫描可用串口
  14. java通过证书获取CN_java – 从证书DN解析CN [重复]
  15. bzoj 1668: [Usaco2006 Oct]Cow Pie Treasures 馅饼里的财富(DP)
  16. Redis的持久化方式
  17. 基于DTU的工业控制组网方案
  18. 用Python分析1585家电商车厘子销售数据,发现这些秘密
  19. 2021年国企、银行求职面经汇总(更新中)
  20. 对超短脉冲的色散效应的研究

热门文章

  1. (FJWC2020)DTOJ 4681. 楼房搭建
  2. 平安推出智能保险云:AI+大数据加持的保险科技怎么玩?
  3. 【matlab】3.解决library complier没有编译器的问题
  4. Python - Python 操作剪切板,从剪切板读取内容
  5. 中级职称计算机哪几门简单,中级职称计算机选哪些科目
  6. 2022 【阿里】面试真题
  7. matlab使用LAN网口TCP/IP通信对大华可编程电源控制
  8. katalon进行app测试_通过Katalon Automation Recorder 3步实现自动化测试
  9. 在线小游戏:人生重开模拟器
  10. Android 自定义ImageView线型渐变色渲染图片