/// <summary> /// 获取新生对象 /// </summary> /// <returns></returns> private GameObject GetNewGameObject(PairedIndex <OrganIndex> pairedOrganIndex) { GameObject cloneObject = GameObject.Instantiate(pairedOrganIndex.CurIndex.Belong); /* * 因枝干顶点已经调整完毕 * 故可用后一关键帧中枝干所指的顶点索引确定前一关键帧顶点的位置 */ Vector3 position = TreeModel.GetBranchTopCenter(m_PreGameObjects[0], pairedOrganIndex.CurIndex.From); foreach (GameObject _subObject in GameObjectOperation.GetGameObjects(cloneObject)) { if (!GameObjectValidate.HavaVertices(_subObject)) { continue; } Vector3[] vertices = GameObjectOperation.GetVertices(_subObject); //该对象所有顶点均为该位置 CopyVertices(_subObject.transform.InverseTransformPoint(position), vertices); GameObjectOperation.UpdateMeshInfo(_subObject, vertices); } //设置阈值为0 GameObjectOperation.SetThreshold(cloneObject, 0); return(cloneObject); }
/// <summary> /// 计算叶片面积(Unity单位) /// </summary> private double ComputeLeafArea(GameObject meshModel) { Texture2D texture = GameObjectOperation.GetTexture(meshModel.transform.GetChild(0).gameObject) as Texture2D; VisualPixelCount = 0; PixelCount = texture.width * texture.height; //总像素个数 //统计非透明像素个数 for (int x = 0; x < texture.width; x++) { for (int y = 0; y < texture.height; y++) { if (texture.GetPixel(x, y).a > 0) { VisualPixelCount++; } } } VisibilityRatio = VisualPixelCount * 1.0f / PixelCount; UniformMeshArea = GameObjectOperation.GetOrganArea(meshModel.transform.GetChild(0).gameObject) * MaizeParams.SCALE * MaizeParams.SCALE; //㎡ //获取该模型的面积,并乘以非透明像素所占百分比即得叶片面积 return(UniformMeshArea * VisibilityRatio); }
/// <summary> /// 构建八叉树 /// </summary> public static Octree Build(TreeModel treeModel) { GameObject root = treeModel.TreeModelInstance; //获取根节点表示的模型 if (root == null) { return(null); } /* * 添加包含整个植物的包围盒 * 八叉树则以该包围盒为根节点进行构建 */ Mesh.AddBoxColliderInParent(root); Bounds rootBounds = root.GetComponent <Collider>().bounds; if (IsEmpty(rootBounds)) { return(null); } List <Triangle> triangles = GameObjectOperation.GetTreeTriangles(treeModel); if (triangles == null || triangles.Count == 0) { return(null); } return(new Octree(rootBounds.center, rootBounds.size, GameObjectOperation.GetTreeTriangles(treeModel), 5)); }
private void AddCurObjects(GameObject _object) { foreach (GameObject _subObject in GameObjectOperation.GetGameObjects(_object)) { AddCurObject(_subObject); } }
private void CreateBranchModel() { /* * 更新枝干数据 * 否则不会显示 */ GameObjectOperation.UpdateMeshInfo(BranchModel, temp_Vertices.ToArray(), temp_UV.ToArray(), temp_Triangles.ToArray()); TempVariablesInit(); /* * 养分 */ Material material = GameObjectOperation.GetMaterial(BranchModel); switch (EnvironmentParams.NutrientType) { case LightResponseType.N_LACK: //material.SetColor("_Color", MaizeParams.lackN_Color); break; case LightResponseType.P_LACK: material.SetColor("_Color", MaizeParams.lackP_Color); break; case LightResponseType.K_LACK: material.SetColor("_Color", MaizeParams.lackK_Color); break; } }
private void ComputeWormholeFragment(GameObject preGameObject, GameObject curGameObject) { /* * 从材质中的shader获取其阈值(十进制) * 当后一个关键帧的阈值为0时,说明无虫害变化 * 当后一个关键帧的阈值不为0时,根据阈值变化确定每一帧的阈值的变化 */ Material preMaterial = GameObjectOperation.GetMaterial(preGameObject); Material curMaterial = GameObjectOperation.GetMaterial(curGameObject); if (preMaterial == null || preMaterial.shader.name != "Custom/Leaves") { m_WormholeFragment.Add(new WormholeFragment()); return; } int preThreshold = CellularTexture.Color2DEC(preMaterial.GetColor("_Threshold")); int curThreshold = CellularTexture.Color2DEC(curMaterial.GetColor("_Threshold")); if (curThreshold == 0) { m_WormholeFragment.Add(new WormholeFragment()); } else { m_WormholeFragment.Add(new WormholeFragment(preThreshold, (curThreshold - preThreshold) * 1.0 / m_AnimationMaxIndex)); } }
public static GameObjectOperation GetInstance() { if (instance == null) { instance = GameObject.Find("GameObjectOperation").GetComponent <GameObjectOperation>(); } return(instance); }
/// <summary> /// 计算面积 /// </summary> private void ComputeArea(GameObject _Object) { /* * 计算模型的面积和叶面积 * 用于后续辐射量的计算已经病虫害模拟等 * 其中 MaizeParams.SCALE 将计算出的模型面积的单位从Unity中一单位转换成m */ m_MeshArea = GameObjectOperation.GetOrganArea(_Object) * MaizeParams.SCALE * MaizeParams.SCALE; m_LeafArea_Uninsected = m_MeshArea * VisibilityRatio; }
private Bounds ViewportBounds() { /* * 获取当前植物的所有对象 * 逐个遍历 * 将对象的顶点坐标(世界坐标系下)转换成视窗坐标(viewport 以左下角为原点(0, 0), 右上角为(1, 1)的坐标系) * 根据视窗坐标最大最小值生成包围盒 * 用于确定当前对象在视窗中的位置,便于相机调整其自身位置 * 使视点合适 */ List <GameObject> objects = new List <GameObject>(); foreach (TreeModel treeModel in LScene.GetInstance().TreeModels) { objects.AddRange(GameObjectOperation.GetGameObjects(treeModel.TreeModelInstance)); } Vector3 max = Vector3.zero, min = Vector3.zero; /* * 判断是否初始化 max 和 min */ bool flag = true; foreach (GameObject _object in objects) { //无顶点 if (!GameObjectValidate.HavaVertices(_object)) { continue; } Vector3[] vertices = GameObjectOperation.GetVerticesInWorld(_object); foreach (Vector3 vertex in vertices) { Vector3 viewport = mainCamera.WorldToViewportPoint(vertex); if (flag) { max = viewport; min = viewport; flag = false; continue; } else { max = Vector3.Max(max, viewport); min = Vector3.Min(min, viewport); } } } Bounds bounds = new Bounds((max + min) / 2.0f, max - min); return(bounds); }
public double InsectSim(double insectIntake) { /* * 当该叶片的最低被啃食比例小于细胞纹理的最低被啃食比例时 * 说明该比例无或者存在一定的问题 * 因此将该比例设置为细胞纹理的最低被啃食比例 */ if (LimitRatio < CelluarTex.LimitRatio) { LimitRatio = CelluarTex.LimitRatio; /* * 调整最低被啃食比例 * 减少重复感 */ LimitRatio += (0.8 - LimitRatio) * RandomNumer.Double(); } /* * 叶片当前最大可被进食量 * 用于计算当前实际被进食量 */ double maxInsectIntake = (InsectedRatio - LimitRatio) * LeafArea_Uninsected; /* * 若该叶片已经老去 * 则不会被并病虫啃食 * 若还未老去,则根据叶片最大被进食量计算实际被进食量 * 当最大可被进食量不大于0时,说明无可被进食部分,因此实际被进食量为0 * 当最大可被进食量大于当前病虫进食量,则说明该叶片满足病虫进食需求,因此实际进食量为病虫进食量 * 当最大可被进食量大于0并且小于当前病虫进食量,则说明该叶片有被进食,但无法满足病虫进食需求 * 因此最大可被进食量均被进食,故实际进食量为最大可被进食量 */ double actualInsectIntake = Age >= MaizeParams.LEAF_MAX_DEVELOPMENT_AGE ? 0 : maxInsectIntake <= 0 ? 0 : maxInsectIntake >= insectIntake ? insectIntake : maxInsectIntake; //根据实际进食量计算叶片的面积 LeafArea -= actualInsectIntake; int threshold; //设置纹理 GameObjectOperation.SetTexture(Belong, GetWormholeTex(actualInsectIntake, out threshold)); //设置阈值 GameObjectOperation.SetThreshold(Belong, threshold); //返回剩余的病虫进食量 return(insectIntake - actualInsectIntake); }
private void LeafMorphologicalInheritance() { OrganMorphologicalInheritance(); //基类中的数据继承 LeafIndex curLeafIndex = CurIndex as LeafIndex; LeafIndex preLeafIndex = PreIndex as LeafIndex; curLeafIndex.Width = preLeafIndex.Width; curLeafIndex.LeafArea = preLeafIndex.LeafArea; curLeafIndex.LeafArea_Uninsected = preLeafIndex.LeafArea_Uninsected; curLeafIndex.LimitRatio = preLeafIndex.LimitRatio; curLeafIndex.Texture_PreDay = GameObjectOperation.GetTexture(preLeafIndex.Belong); curLeafIndex.MeshHashCode_PreDay = preLeafIndex.LeafMesh.GetHashCode(); }
/// <summary> /// 调整前后枝干的顶点 /// </summary> private void AdjustBranch() { if (m_PairedBranchIndexes.Count == 1 && m_PairedBranchIndexes[0].PreIndex == null) { AdjustFreshBranch(); return; } /* * 获取前后两个关键帧的枝干对象 * 用于后续获取顶点以及更改顶点 */ GameObject preBranch = m_PairedBranchIndexes[0].PreIndex.Belong; GameObject curBranch = m_PairedBranchIndexes[0].CurIndex.Belong; Vector3[] preVertices = GameObjectOperation.GetVertices(preBranch); Vector3[] vertices = new Vector3[GameObjectOperation.GetVertices(curBranch).Length]; //该顶点数组用于存放修改后的前关键帧顶点 /* * 遍历已经匹配好的Index * 根据PairedIndex中记录的前后Index的数据 * 对前后关键帧中枝干的数据进行修改 */ foreach (PairedIndex <BranchIndex> pairedBranchIndex in m_PairedBranchIndexes) { BranchIndex preBranchIndex = pairedBranchIndex.PreIndex; BranchIndex curBranchIndex = pairedBranchIndex.CurIndex; if (curBranchIndex.IsFirstBranch() && preBranchIndex.IsFirstBranch()) //均为第一个枝干 { CopyVertices(preVertices, preBranchIndex.BottomVerticesIndex, vertices, curBranchIndex.BottomVerticesIndex, 40); } else if (preBranchIndex != null) //若存在匹配的第一个关键帧的枝干索引,则将第一个关键帧枝干索引指向的顶点插入到第二个关键帧枝干索引指向的顶点位置中 { CopyVertices(preVertices, preBranchIndex.TopVerticesIndex, vertices, curBranchIndex.TopVerticesIndex); } else//若第二个关键帧枝干不存在匹配的第一个关键帧枝干索引,则遍历其前驱,直至有存在的第一个关键帧枝干索引,并将该枝干索引指向的顶点插入到第二个关键帧枝干索引指向的顶点位置中 { CopyVertices(vertices, curBranchIndex.Previous.TopVerticesIndex, vertices, curBranchIndex.TopVerticesIndex); } } //更新对象 GameObjectOperation.UpdateMeshInfo(preBranch, vertices, GameObjectOperation.GetUV(curBranch), GameObjectOperation.GetTriangleIndexes(curBranch)); AddPreObject(preBranch); AddCurObject(curBranch); }
private void ClearAllWormholeTex() { if (m_listOrganModels == null) { return; } foreach (GameObject OrganModel in m_listOrganModels) { Texture tex = GameObjectOperation.GetTexture(OrganModel); if (tex.name == "Wormhole Texture") { GameObjectOperation.ClearTexture(OrganModel); GameObject.DestroyObject(tex); } } }
private void ClearOrganModels() { if (m_listOrganModels == null) { return; } foreach (GameObject OrganModel in m_listOrganModels) { GameObjectOperation.ClearMaterials(OrganModel, 0f); GameObjectOperation.ClearMeshes(OrganModel); GameObject.Destroy(OrganModel); } m_listOrganModels.Clear(); }
private void ComputeAnimationFragment() { /* * 初始化动画片段 * 防止数据重复 */ InitialAnimationFragment(); InitialWormholeFragment(); /* * 调整前后两关键帧顶点 * 保证前后两关键帧顶点个数相同 * 方便后续计算顶点的移动 */ AdjustTree(); for (int i = 0; i < m_PreGameObjects.Count; i++) { /* * 检验两个对象的Tag * 保证两个对象的Tag一致 */ GameObjectValidate.ValidateTagOfObject(m_PreGameObjects[i], m_CurGameObjects[i]); /* * 判断该组对象是否有顶点 * 因调整后,前后两对象顶点个数相同 * 故判断前一个对象是否有顶点即可 */ if (!GameObjectValidate.HavaVertices(m_PreGameObjects[i])) { m_AnimationFragment.Add(new List <Vector3>()); m_WormholeFragment.Add(new WormholeFragment()); continue; } //ComputeAnimationFragment(GameObjectOperation.GetVerticesInWorld(m_PreGameObjects[i]), GameObjectOperation.GetVerticesInWorld(m_CurGameObjects[i])); ComputeAnimationFragment(m_PreGameObjects[i], GameObjectOperation.GetVertices(m_PreGameObjects[i]), GameObjectOperation.GetVerticesInWorld(m_CurGameObjects[i])); ComputeWormholeFragment(m_PreGameObjects[i], m_CurGameObjects[i]); } }
/// <summary> /// 射线与三角形求交(有纹理) /// </summary> public static bool IntersectRayTriangleWithTexture(Ray _Ray, Triangle _Triangle, out float Distance) { float u, v; if (!IntersectRayTriangleWithoutTexture(_Ray, _Triangle, out u, out v, out Distance)) { return(false); //射线与面片无交点 } Vector2 UV = _Triangle.GetUV(u, v); //获取该交点的UV坐标 Texture2D Texture = GameObjectOperation.GetTexture(_Triangle.Index.Belong) as Texture2D; //获取纹理 if (Texture.GetPixelBilinear(UV.x, UV.y).a > 0f) //获取该点的透明度,如果大于0.5则有碰撞 { return(true); } else { return(false); } }
/// <summary> /// 模拟天空散射 /// </summary> /// <param name="SolarDayAngle_Deg">太阳日角</param> /// <param name="SolarAltitude_Deg">太阳高度角</param> /// <param name="StartHour">开始的时间</param> /// <param name="EndHour">结束的时间</param> /// <param name="_Octree">八叉树</param> /// <param name="LatitudeNum">纬度方向的剖分个数</param> /// <param name="LongtitudeNum">经度度方向的剖分个数</param> public static void ScatterLightSimulation(TreeModel treeModel, double SolarDayAngle_Rad, double SolarAltitude_Deg, double StartHour, double EndHour, Octree _Octree, int LatitudeNum, int LongtitudeNum) { Triangle[] TreeTriangles = GameObjectOperation.GetTreeTriangles(treeModel).ToArray(); //获取所有的三角面片 double _ScatterIrradiance = ScatterIrradiance(SolarDayAngle_Rad, SolarAltitude_Deg, _Octree.Root.Bounds.center.y); //总散射辐射度 LightCastHemisphere LightHemisphere = null; for (int i = 0; i < TreeTriangles.Length; i++) { if (TreeTriangles[i].Type != OrganType.Leaf) { continue; //非叶片,无需计算散射辐射 } /* * 优化 * 限定天穹半球的大小 * 每次三角面片,天穹半球跟随三角面片移动,无需重新计算 */ if (LightHemisphere == null) { LightHemisphere = new LightCastHemisphere(TreeTriangles[i].Center, _Octree.Root.Bounds); } else { LightHemisphere.MoveTo(TreeTriangles[i].Center); } /* * 通过天穹半球计算出天空散射透过率 * 该面片上的平均散射辐射度(W / m^2) = 天空散射透过率 * 总散射辐射度 * 该面片上的总辐射度(W) = 平均散射辐射度 * 该面片的面积 * 注意:因为存在透明的纹理,因此需要再得到整个叶片模型的散射能量的基础上,再乘以非透明的比例,才能得到真正的散射能量 */ LeafIndex _LeafIndex = TreeTriangles[i].Index as LeafIndex; _LeafIndex.ModelScatterEnergy += (float)(LightHemisphere.GetSkyTransmissivity(LongtitudeNum, LatitudeNum, TreeTriangles, i) * _ScatterIrradiance * TreeTriangles[i].Area()); } }
private void AdjustFreshBranch() { GameObject curBranch = m_PairedBranchIndexes[0].CurIndex.Belong; GameObject preBranch = GameObject.Instantiate(curBranch); /* * 摧毁所有的子对象 * 防止重复 */ GameObjectOperation.DestroyAllChildren(preBranch); Vector3[] vertices = GameObjectOperation.GetVertices(curBranch); //CopyVertices(curBranch.transform.InverseTransformPoint(Vector3.zero), vertices); CopyVertices(TreeModel.GetBranchBottomCenter(curBranch, m_PairedBranchIndexes[0].CurIndex), vertices); GameObjectOperation.UpdateMeshInfo(preBranch, vertices); AddPreObject(preBranch); AddCurObject(curBranch); }
public void UpdateOutlines() { List <GameObject> objects = GameObjectOperation.GetGameObjects(gameObject); foreach (GameObject go in objects) { if (go.GetComponent <Renderer>() == null) { continue; } Outline outline = go.GetComponent <Outline>(); if (outline == null) { outline = go.AddComponent <Outline>(); m_outlines.Add(outline); } outline.defaultColor = DefaultColorID; outline.Unhighlight(); } }
/// <summary> /// 根据当前模型的数据写叶片长度和最大宽度 /// 后续则根据实际需要读取该文件,减少重复计算 /// </summary> private void WriteLeafLengthAndWidth() { if (m_MeshModelInstance == null) { throw new UnityException("Error Mesh Path"); } //实例化,否则无法获取顶点和UV坐标 GameObject meshModel = (GameObject)GameObject.Instantiate(m_MeshModelInstance); /* * 获取顶点坐标和UV坐标 * 用于后续计算长度和宽度 */ Vector3[] vertices = GameObjectOperation.GetVertices(meshModel.transform.GetChild(0).gameObject); Vector2[] uv = GameObjectOperation.GetUV(meshModel.transform.GetChild(0).gameObject); /* * 获取未放大和缩小的模型中 * 叶片的长度、宽度和叶片面积 * 用于后续与实际叶片长度和宽度或叶片面积做比较,确定模型的缩放比例 */ LeafLength = GetLeafLength(vertices, uv); //m LeafWidth = GetLeafWidth(vertices, uv); //m UniformLeafArea = ComputeLeafArea(meshModel); //㎡ /* * 清除GameObject * 防止模型显示 */ GameObject.Destroy(meshModel); /* * 记录叶片长度和宽度 * 用于写入文件中 */ string str = ""; str += "LeafLength " + LeafLength + " m\n"; str += "LeafWidth " + LeafWidth + " m\n"; str += "MeshArea " + UniformMeshArea + " m^2\n"; str += "LeafArea " + UniformLeafArea + " m^2\n"; str += "VisualPixelCount " + VisualPixelCount + "\n"; str += "PixelCount " + PixelCount + "\n"; str += "VisibilityRatio " + VisibilityRatio + "\n"; /* * 将数据写入文件 * 方便后续读取 */ //string filePath = System.Environment.CurrentDirectory + "\\Assets\\Resources\\" + m_strMeshPath.Remove(m_strMeshPath.LastIndexOf('.')) + ".tmp"; string directoryPath = System.Environment.CurrentDirectory + "\\Data"; if (!System.IO.Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } string filePath = directoryPath + "\\" + Path.GetFileNameWithoutExtension(m_strMeshPath) + ".data"; FileStream stream = new FileStream(filePath, FileMode.Create); StreamWriter writer = new StreamWriter(stream); writer.WriteLine(str); //写入 //完成写入,内存释放 writer.Close(); stream.Close(); }
private Texture GetWormholeTex(double actualInsectIntake, out int threshold) { /* * 阈值 * 用于后续关键帧动画中虫洞的模拟 * 当为0时表示虫洞未发生变化 */ threshold = 0; /* * 存在的各种情况: * 1、该叶片不受病虫影响 * 1.1、该叶片原先无病虫害,故现在也无病虫害,即叶面积(LeafArea)与未受病虫害的叶面积(LeafArea_Uninsected)相等 * 故该模型的纹理无需替换 * 1.2、该叶片原先有病虫害,再分两种情况: * 1.2.1、与昨日的模型相同,即今日模型的哈希值与昨日模型的哈希值相同,故叶片形态、纹理与昨日相同 * 故直接调用昨日模型的纹理即可 * 1.2.2、与昨日的模型不同,即该叶片发育到不同的阶段(成熟或衰老),故调用的纹理与昨日不同 * 故重新生成虫洞纹理 * 2、该叶片受病虫影响 * 形态不同,故直接重新生成虫洞纹理 */ if (LeafArea == LeafArea_Uninsected) { return(null); } else if (Texture_PreDay != null && actualInsectIntake <= 0 && LeafMesh.GetHashCode() == MeshHashCode_PreDay) { return(Texture_PreDay); } else { if (Texture_PreDay != null && Texture_PreDay.name == "Wormhole Texture") { if (LScene.GetInstance().HaveAnimator) { GameObjectOperation.DestroyTexWithoutAnimation(Texture_PreDay); } else { GameObject.Destroy(Texture_PreDay); } Texture_PreDay = null; } Texture leafTex = GameObjectOperation.GetTexture(Belong); Texture wormholeTex = CelluarTex.CreateWormhole(InsectedRatio, leafTex, out threshold); wormholeTex.name = "Wormhole Texture"; /* * 清除纹理 * 释放内存 */ if (leafTex.name == "Wormhole Texture") { GameObject.DestroyObject(leafTex); } return(wormholeTex); } }
private void CreateLeafModel(LeafIndex index, Vector3 position) { /* * 计算形态数据:长度和最大宽度 * 用于后续生成GameObject */ index.MorphologicalSim(); GameObject leafModel = (GameObject)GameObject.Instantiate(index.LeafMesh.Instance); //模型实例化 leafModel.name = index.LeafMesh.Name; leafModel.tag = "Organ"; SetTagInParent(leafModel.transform, "Organ"); /* * 设置空间信息 */ leafModel.transform.position = position; RotationGameObject(leafModel, position, index.Rotation); /* * 养分 */ List <Material> materials = GameObjectOperation.GetMaterials(leafModel); switch (EnvironmentParams.NutrientType) { case LightResponseType.N_LACK: //SetIllnessColor(materials, MaizeParams.lackN_Color); break; case LightResponseType.P_LACK: SetIllnessColor(materials, MaizeParams.lackP_Color); break; case LightResponseType.K_LACK: SetIllnessColor(materials, MaizeParams.lackK_Color); break; } /* * 设置形态信息 * 受病虫害影响后,叶面积变化较大 * 而整体比例影响较小 * 故采用未受到病虫害影响的叶面积计算比例 */ float scale = Mathf.Sqrt((float)(index.LeafArea_Uninsected / index.UniformLeafArea)); leafModel.transform.localScale = Vector3.one * scale; /* * 设置父节点 */ leafModel.transform.SetParent(BranchModel.transform); /* * 信息补齐 */ index.Belong = leafModel; m_listOrganModels.Add(leafModel); }
private Vector3 RecordBranchModel(BranchIndex index, Vector3 bottom) { /* * 计算形态数据 * 根据形态数据即可绘制对应的GameObject */ index.MorphologicalSim(); if (cylinderObject.activeSelf) { cylinderObject.SetActive(false); } cylinderObject.transform.localRotation = Quaternion.Euler(Vector3.zero); cylinderObject.transform.position = bottom + new Vector3(0, index.Length / 2f, 0) * SCALE; //该节间的中心位置 cylinderObject.transform.localScale = new Vector3(index.Radius / DEFAULT_RADIUS, index.Length / DEFAULT_HEIGHT, index.Radius / DEFAULT_RADIUS) * SCALE; //尺寸 RotationGameObject(cylinderObject, bottom, index.Rotation); //旋转该圆柱体 Vector3[] vertices = GameObjectOperation.GetVerticesInWorld(cylinderObject); Vector2[] uv = GameObjectOperation.GetUV(cylinderObject); if (temp_Vertices.Count == 0) //最底端的节间 { for (int i = 0; i < 40; i++) { temp_Vertices.Add(vertices[i]); temp_UV.Add(uv[i]); } AddTriangles(0, 20); } else //非最底端节间 { for (int i = 0; i < 20; i++) { /* * 添加顶点 * 由于底端的顶点与前驱节间的顶点相同 * 故只用添加后20个顶点即可 */ temp_Vertices.Add(vertices[i + 20]); /* * 添加UV坐标 * 需要颠倒纹理(与上一个节间的纹理相反) * 确保连接处的纹理过渡不会突兀 */ temp_UV.Add(temp_UV[index.Previous.TopVerticesIndex - 20 + i]); } AddTriangles(index.Previous.TopVerticesIndex, temp_Vertices.Count - 20); } //删除GameObject,防止重复 //GameObject.Destroy(cylinderObject); /* * 补齐index的数据 * 用于后续生成节间 */ index.BottomVerticesIndex = index.Previous.TopVerticesIndex == -1 ? 0 : index.Previous.TopVerticesIndex; index.TopVerticesIndex = temp_Vertices.Count - 20; /* * 返回当前顶端的中心位置 * 由于枝干旋转,故根据顶端的顶点位置计算 */ return(GetCenterPoint(index.TopVerticesIndex, temp_Vertices)); }
/// <summary> /// 更新该帧内的对象 /// </summary> private void UpdateGameObject(GameObject preGameObject, GameObject curGameObject, List <Vector3> veticesFragment, WormholeFragment wormholeFragment) { if (m_AnimationIndex < m_AnimationMaxIndex) { /* * 若该片段为NULL或该片段的个数为0 * 则说明该对象无顶点 * 不继续进行计算 */ if (!GameObjectValidate.HavaVertices(preGameObject) || veticesFragment == null) { return; //09-05 } //09-05 if (veticesFragment.Count != 0) { Vector3[] vertices = GameObjectOperation.GetVertices(preGameObject); /* * 根据片段中记录的顶点偏移数据 * 计算对象在该帧移动后的位置 * 其中该片段记录的是世界坐标系下的数据 * 因此要转换成对象所在的局部坐标系下 */ for (int i = 0; i < vertices.Length; i++) { vertices[i] += veticesFragment[i]; } /* * 更新该对象 * 防止渲染出现异常 */ GameObjectOperation.UpdateMeshInfo(preGameObject, vertices); } /* * 虫洞逐帧变化模拟 * 当阈值增量为0,说明不变化 * 当阈值增量不为0 * 开启虫洞模拟 (_SimWormhole的值为1),并赋予相应的阈值 */ if (wormholeFragment.ThresholdDetla == 0) { return; } Material material = GameObjectOperation.GetMaterial(preGameObject); if (material == null || material.shader.name != "Custom/Leaves") { return; } material.SetFloat("_SimWormhole", 1); material.SetColor("_Threshold", CellularTexture.DEC2Color(wormholeFragment.InitThreshold + (int)(wormholeFragment.ThresholdDetla * m_AnimationIndex)) ); } else //最后一帧 { /* * 无需计算 * 只需设置前一关键帧的对象不可见 * 后一帧对象可见即可 */ preGameObject.SetActive(false); curGameObject.SetActive(true); GameObjectOperation.ClearMaterials(preGameObject); GameObjectOperation.ClearMeshes(preGameObject); GameObject.Destroy(preGameObject); } }