第4章第5节 任务创建和任务删除钩…

本文介绍了任务创建和删除钩子函数的实现原理及其在实时操作系统中的应用。通过具体代码示例,展示了如何在任务创建和删除时打印相关信息,并新增了任务删除函数。


目前更新到5.3节,请在
http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档

本节源代码请在http://dl.dbank.com/c0t7gmgx2q下载

 

第5节 任务创建和任务删除钩子函数

上节增加了任务切换钩子功能,打印出任务切换的信息,本节将增加任务创建钩子函数和任务删除钩子函数,分别打印出任务创建和删除的信息。

 

任务创建和删除钩子函数的原理与任务切换钩子函数的原理是一样的,都是需要定义一个与被挂接函数类型一致的指针型全局变量,使用钩子添加函数将被执行的函数挂接到钩子变量上,不同的是任务创建钩子函数在任务创建后打印,任务删除钩子函数在任务删除后打印。

钩子变量定义如下:

VFHCRT gvfTaskCreateHook;

VFHDLT gvfTaskDeleteHook;

VFHCRTVFHDLT的定义为:

typedef void    (*VFHCRT)(M_TCB*);

typedef void    (*VFHDLT)(M_TCB*);

被挂接的任务创建函数如下,与任务创建全局变量gvfTaskCreateHook类型一致,它会打印被创建函数的名称及创建的时间。

00071  void TEST_TaskCreatePrint(M_TCB* pstrTcb)

00072  {

00073      

00074      if((M_TCB*)NULL != pstrTcb)

00075      {

00076          DEV_PutStrToMem((U8*)"\r\nTask %s is created! Tick is: %d",

00077                          pstrTcb->pucTaskName, MDS_SystemTickGet());

00078      }

00079      else 

00080      {

00081          DEV_PutStrToMem((U8*)"\r\nFail to create task! Tick is: %d",

00082                          MDS_SystemTickGet());

00083      }

00084  }

 

被挂接的任务删除函数如下,与任务删除全局变量gvfTaskDeleteHook类型一致,它会打印被删除函数的名称及删除的时间。

00104  void TEST_TaskDeletePrint(M_TCB* pstrTcb)

00105  {

00106      DEV_PutStrToMem((U8*)"\r\nTask %s is deleted! Tick is: %d",

00107                      pstrTcb->pucTaskName, MDS_SystemTickGet());

00108  }

 

如果需要使用钩子创建函数则需要在创建任务的函数MDS_TaskCreate里增加钩子函数代码,如下:

00023  M_TCB* MDS_TaskCreate(U8* pucTaskName, VFUNC vfFuncPointer, U8* pucTaskStack,

00024                        U32 uiStackSize, U8 ucTaskPrio, M_TASKOPT* pstrTaskOpt)

00025  {

00026  

……       ……

00094  

00095      

00096      if((MDS_RootTask != vfFuncPointer) && (MDS_IdleTask != vfFuncPointer))

00097      {

00098  #ifdef MDS_INCLUDETASKHOOK

00099  

00100          

00101          if((VFHCRT)NULL != gvfTaskCreateHook)

00102          {

00103              gvfTaskCreateHook(pstrTcb);

00104          }

00105  

00106  #endif

00107  

00108          

00109          MDS_TaskSwiSched();

00110      }

00111  

00112      return pstrTcb;

00113  }

00026~00094行,代码与上节完全一样。

00096行,只有非系统任务才执行任务创建钩子函数。

00101~00104行,若挂接了任务创建钩子函数则执行。

 

本节我们需要增加一个删除任务的函数MDS_TaskDelete,用它来删除任务,在删除任务时可以执行挂接的任务删除钩子函数。

任务创建时在任务栈里创建了TCBTCB中的ready节点和delay节点可能会挂接到ready表和delay表,我们只要将任务从ready表和delay表拆除,操作系统就无法再调度这个任务了,这样就可以删除该任务。删除后任务的任务栈中的数据还是存在的,但由于任务已经无法与ready表和delay表关联,因此这些数据就变成了无效数据。任务删除时,任务所使用的任务栈内存应该也被释放掉,但目前任务栈的内存是由用户申请的而不是由操作系统申请的,因此需要用户自行释放任务栈内存,操作系统不进行管理。以后任务栈由操作系统申请时,MDS_TaskDelete函数才负责释放这部分内存。

00121  U32 MDS_TaskDelete(M_TCB* pstrTcb)

00122  {

00123      M_CHAIN* pstrChain;

00124      M_CHAIN* pstrNode;

00125      M_PRIOFLAG* pstrPrioFlag;

00126      U8 ucTaskPrio;

00127      U8 ucTaskSta;

00128  

00129      

00130      if(NULL == pstrTcb)

00131      {

00132          return RTN_FAIL;

00133      }

00134  

00135      

00136      if(pstrTcb == gpstrIdleTaskTcb)

00137      {

00138          return RTN_FAIL;

00139      }

00140  

00141      (void)MDS_IntLock();

00142  

00143      

00144      ucTaskSta pstrTcb->strTaskOpt.ucTaskSta;

00145  

00146      

00147      if(TASKREADY == (TASKREADY ucTaskSta))

00148      {

00149          

00150          ucTaskPrio pstrTcb->ucTaskPrio;

00151          pstrChain &gstrReadyTab.astrChain[ucTaskPrio];

00152          pstrPrioFlag &gstrReadyTab.strFlag;

00153  

00154          

00155          (void)MDS_TaskDelFromSchedTab(pstrChain, pstrPrioFlag, ucTaskPrio);

00156      }

00157  

00158      

00159      if(DELAYQUEFLAG == (pstrTcb->uiTaskFlag DELAYQUEFLAG))

00160      {

00161          

00162          pstrNode &pstrTcb->strDelayQue.strQueHead;

00163  

00164          

00165          (void)MDS_ChainCurNodeDelete(&gstrDelayTab, pstrNode);

00166      }

00167  

00168      (void)MDS_IntUnlock();

00169  

00170  #ifdef MDS_INCLUDETASKHOOK

00171  

00172      

00173      if((VFHDLT)NULL != gvfTaskDeleteHook)

00174      {

00175          gvfTaskDeleteHook(pstrTcb);

00176      }

00177  

00178  #endif

00179  

00180      

00181      MDS_TaskSwiSched();

00182  

00183      return RTN_SUCD;

00184  }

00121行,函数有2种返回值,RTN_SUCD代表任务删除成功,RTN_FAIL代表任务删除失败。入口参数pstrTcb是需要被删除的任务的TCB指针。

00130~00133行,入口参数检查,入口参数为空则返回失败。

00136~00139行,入口参数检查,若删除idle任务则返回失败。

00141行,锁中断。下面将操作ready表和delay表,为防止多个任务同时操作这两个表,需要锁中断。

00144行,获取被删除任务的当前任务状态。

00147~00156行,若该任务在ready表中则从ready表删除。

00159~00166行,若该任务在delay表中则从delay表删除。

00168行,调度表操作完成,解锁中断。

00170~00178行,若挂接了任务删除钩子函数则执行该函数。

00181行,任务已经被删除,需要重新调度一次任务。

 

本节内容较少,主要内容已经介绍完毕。本节仍使用上节的3个功能验证函数,与上节不同的是在8000 ticks的时候TEST_TestTask3任务会被root任务删除,在10000 ticksroot任务也会被自己删除。

00014  void MDS_RootTask(void)

00015  {

00016      M_TCB* pstrTcb;

00017      M_TASKOPT strOption;

00018  

00019      

00020      DEV_SoftwareInit();

00021  

00022      

00023      DEV_HardwareInit();

00024  

00025      

00026      (void)MDS_TaskCreate((U8*)"Test1", (VFUNC)TEST_TestTask1, gaucTask1Stack,

00027                           TASKSTACK, 2, (M_TASKOPT*)NULL);

00028  

00029      

00030      strOption.ucTaskSta TASKREADY;

00031      (void)MDS_TaskCreate((U8*)"Test2", (VFUNC)TEST_TestTask2, gaucTask2Stack,

00032                           TASKSTACK, 3, &strOption);

00033  

00034      

00035      strOption.ucTaskSta TASKDELAY;

00036      strOption.uiDelayTick 2000;

00037      pstrTcb MDS_TaskCreate((U8*)"Test3", (VFUNC)TEST_TestTask3, gaucTask3Stack,

00038                               TASKSTACK, 1, &strOption);

00039  

00040      (void)MDS_TaskDelay(8000);

00041  

00042      

00043      (void)MDS_TaskDelete(pstrTcb);

00044  

00045      (void)MDS_TaskDelay(2000);

00046  

00047      

00048      (void)MDS_TaskDelete(MDS_CurrentTcbGet());

00049  }

root任务起来后创建了3个任务,我们会看到这3个任务创建过程的打印,随后任务运行的过程与上节一致。当系统运行到8000 ticks时,TEST_TestTask3任务会被删除,我们可以看到TEST_TestTask3任务被删除的打印信息,此后就只有TEST_TestTask1TEST_TestTask2任务在运行了。到10000 ticks时,root任务调用MDS_TaskDelete函数将自己删除,无需再调用MDS_TaskDelay(DELAYWAITFEV)函数进入永久delay状态。

本节运行结果截图如下:

第4章第5节 <wbr>任务创建和任务删除钩子函数

图 48  带有任务创建、切换和删除过程的打印

读者可以访问http://blog.sina.com.cn/ifreecoding网站下载视频,观看全部数据的打印过程,可以看到实际运行的结果与我们上面推断的结果是一致的。

使用工具软件将任务切换过程的数据解析为图形,结果如下图所示:

 第4章第5节 <wbr>任务创建和任务删除钩子函数

图 49  4.5节任务切换过程图

从图中可以清晰的看到2000 ticksTEST_TestTask3任务结束delay状态,开始运行,在8000 ticks时,root任务delay时间耗尽,操作系统切换到root任务,删除了TEST_TestTask3任务,在10000 ticks时,root任务delay时间再次耗尽,操作系统切换到root任务,删除了自己。此后只剩下TEST_TestTask1TEST_TestTask2任务切换运行。

//1.mesh构建 using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))] public class Potteryprototype : MonoBehaviour { &nbsp;&nbsp;&nbsp; MeshFilter meshFilter; &nbsp;&nbsp;&nbsp; MeshRenderer meshRenderer; &nbsp;&nbsp;&nbsp; MeshCollider meshCollider; &nbsp;&nbsp;&nbsp; Mesh mesh; &nbsp; &nbsp;&nbsp;&nbsp; public int details = 40; &nbsp;&nbsp;&nbsp; public int layer = 20; &nbsp;&nbsp;&nbsp; public float Height = 0.1f; &nbsp; &nbsp;&nbsp;&nbsp; public float OuterRadius = 1.0f; &nbsp;&nbsp;&nbsp; public float InnerRadius = 0.9f; &nbsp; &nbsp;&nbsp;&nbsp; List<Vector3> vertices; &nbsp;&nbsp;&nbsp; List<Vector2> UV; &nbsp;&nbsp;&nbsp; List<int> triangles; &nbsp; &nbsp;&nbsp;&nbsp; float EachAngle ; &nbsp;&nbsp;&nbsp; int SideCount; &nbsp; &nbsp;&nbsp;&nbsp; public MouseControl mouse; &nbsp; &nbsp;&nbsp;&nbsp; void Start() &nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshFilter = GetComponent<MeshFilter>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshCollider = GetComponent<MeshCollider>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshRenderer = GetComponent<MeshRenderer>(); &nbsp;&nbsp;&nbsp; } &nbsp; &nbsp;&nbsp;&nbsp; [ContextMenu("GeneratePottery")] &nbsp;&nbsp;&nbsp; void GeneratePrototype() &nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vertices = new List<Vector3>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles = new List<int>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UV = new List<Vector2>(); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EachAngle = Mathf.PI * 2 / details; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i < layer; i++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GenerateCircle(i); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Capping(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh = new Mesh(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.vertices = vertices.ToArray(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.triangles = triangles.ToArray(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.uv = UV.ToArray(); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.RecalculateBounds(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.RecalculateTangents(); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshFilter.mesh = mesh; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.RecalculateNormals(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshCollider.sharedMesh = mesh; &nbsp;&nbsp;&nbsp; } &nbsp; &nbsp;&nbsp;&nbsp; void GenerateCircle(int _layer) &nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //外顶点与内顶点分开存储,方便变化操作时的计算 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List<Vector3> vertices_outside = new List<Vector3>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List<Vector3> vertices_inside = new List<Vector3>(); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List<Vector2> UV_outside = new List<Vector2>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List<Vector2> UV_inside = new List<Vector2>(); &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //外侧内侧顶点计算 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //注意这里让每一圈的首尾重合了,也就是开始结尾的顶点坐标一致 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //目的是计算UV坐标时不会出现空缺 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (float i = 0; i <= Mathf.PI * 2+EachAngle; i += EachAngle) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 v1 = new Vector3(OuterRadius * Mathf.Sin(i),&nbsp; _layer * Height, OuterRadius * Mathf.Cos(i)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 v2 = new Vector3(OuterRadius * Mathf.Sin(i),&nbsp; (_layer +1)* Height, OuterRadius * Mathf.Cos(i)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 v3 = new Vector3(InnerRadius * Mathf.Sin(i),&nbsp; _layer * Height, InnerRadius * Mathf.Cos(i)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 v4 = new Vector3(InnerRadius * Mathf.Sin(i),&nbsp; (_layer+1) * Height, InnerRadius * Mathf.Cos(i)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vertices_outside.Add(v1); vertices_outside.Add(v2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vertices_inside.Add(v3); vertices_inside.Add(v4); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector2 uv1 = new Vector2(i / Mathf.PI*2, _layer*1.0f / layer * 1.0f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector2 uv2 = new Vector2(i / Mathf.PI*2, (_layer + 1)*1.0f / layer * 1.0f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector2 uv3 = new Vector2(i / Mathf.PI*2, _layer*1.0f / layer * 1.0f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector2 uv4 = new Vector2(i / Mathf.PI*2, (_layer + 1) *1.0f/ layer * 1.0f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UV_outside.Add(uv1); UV_outside.Add(uv2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UV_inside.Add(uv3); UV_inside.Add(uv4); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vertices.AddRange(vertices_outside); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vertices.AddRange(vertices_inside); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UV.AddRange(UV_outside); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UV.AddRange(UV_inside); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SideCount = vertices_outside.Count; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int j = vertices_outside.Count * _layer * 2; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int n = vertices_outside.Count; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = j; i < j + vertices_outside.Count - 2; i += 2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(i); triangles.Add(i + 2); triangles.Add(i + 1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(i + 2); triangles.Add(i + 3); triangles.Add(i + 1); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(i + n); triangles.Add(i + n + 1); triangles.Add(i + n + 2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(i + n + 2); triangles.Add(i + n + 1); triangles.Add(i + n + 3); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp; //封顶,底面由于看不见就不用管了 &nbsp;&nbsp;&nbsp; void Capping() &nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (float i = 0; i <= Mathf.PI * 2+EachAngle; i += EachAngle) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 outer = new Vector3(OuterRadius * Mathf.Sin(i),layer * Height, OuterRadius * Mathf.Cos(i)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 inner= new Vector3(InnerRadius * Mathf.Sin(i), layer * Height, InnerRadius * Mathf.Cos(i)); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vertices.Add(outer);vertices.Add(inner); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector2 uv1 = new Vector2(i / Mathf.PI * 2,0); Vector2 uv2 = new Vector2(i / Mathf.PI * 2, 1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UV.Add(uv1); UV.Add(uv2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int j = SideCount * layer * 2; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i=j;i<vertices.Count-2;i+=2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(i);triangles.Add(i + 3);triangles.Add(i + 1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(i);triangles.Add(i + 2);triangles.Add(i + 3); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(vertices.Count - 2);triangles.Add(j + 1);triangles.Add(vertices.Count - 1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; triangles.Add(vertices.Count - 2);triangles.Add(j);triangles.Add(j + 1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } } &nbsp; //2.动态改变形状 //这个函数放在Update()里调用 &nbsp;&nbsp;&nbsp; void GetMouseControlTransform() &nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //从屏幕鼠标位置发射一条射线到模型上,获取这个坐标 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RaycastHit info; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Physics.Raycast(ray.origin, ray.direction, out info)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在Unity中无法直接修改MeshFilter中Mesh的信息,需要新建一个Mesh修改其引用关系 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mesh mesh = meshFilter.mesh; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3[] _vertices = mesh.vertices; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i < _vertices.Length; i++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //x,z平面变换 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //顶点移动与Y值的关系限制在5倍单层高度 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里可以自行修改,限制高度越大,曲线越平滑 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;if (Mathf.Abs(info.point.y - transform.TransformPoint(_vertices[i]).y) < (5 * Height)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //计算顶点移动方向的向量 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector3 v_xz = (transform.TransformPoint(_vertices[i]) - new Vector3(transform.position.x, transform.TransformPoint(_vertices[i]).y, transform.position.z)); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //外顶点与内顶点移动时相对距离应该保持不变 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //因为我们知道顶点数组内的顺序关系,所以可以通过计算总顶点数除以每层单侧顶点数的商的奇偶关系来判断是外顶点还是内顶点 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int n = i / SideCount; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool side = n % 2 == 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //判断顶面顶点内外关系 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool caps = (i - (SideCount * layer * 2)) % 2 == 0; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //限制每个顶点最大最小的移动距离 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float max; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float min; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i < SideCount * layer * 2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; max = side ? 2f * OuterRadius : 2f * OuterRadius - (OuterRadius - InnerRadius); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; min = side ? 0.5f * OuterRadius : 0.5f * OuterRadius - (OuterRadius - InnerRadius); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; max = caps ? 2f * OuterRadius : 2f * OuterRadius - (OuterRadius - InnerRadius); ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; min = caps ? 0.5f * OuterRadius : 0.5f * OuterRadius - (OuterRadius - InnerRadius); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //计算当前顶点到鼠标Y值之间的距离,再用余弦函数算出实际位移距离 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float dif = Mathf.Abs(info.point.y - transform.TransformPoint(_vertices[i]).y); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Input.GetKey(KeyCode.RightArrow)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float outer = max - v_xz.magnitude; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _vertices[i] += v_xz.normalized * Mathf.Min(0.01f * Mathf.Cos(((dif / 5 * Height) * Mathf.PI) / 2), outer); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (Input.GetKey(KeyCode.LeftArrow)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float inner = v_xz.magnitude - min; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _vertices[i] -= v_xz.normalized * Mathf.Min(0.01f * Mathf.Cos(((dif / 5 * Height) * Mathf.PI) / 2), inner); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Y轴变换 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float scale_y = transform.localScale.y; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Input.GetKey(KeyCode.UpArrow)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scale_y = Mathf.Min(transform.localScale.y + 0.000001f, 2.0f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (Input.GetKey(KeyCode.DownArrow)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scale_y = Mathf.Max(transform.localScale.y - 0.000001f, 0.3f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transform.localScale = new Vector3(transform.localScale.x, scale_y, transform.localScale.z); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.vertices = _vertices; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.RecalculateBounds(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh.RecalculateNormals(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshFilter.mesh = mesh; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meshCollider.sharedMesh = mesh; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp; } } &nbsp; //计算时就把顶点坐标系转换为自身坐标系,求得向量后再转换为世界坐标系 &nbsp;&nbsp;&nbsp; Vector3 v_xz = transform.TransformDirection(transform.InverseTransformPoint(_vertices[i]) - transform.InverseTransformPoint(new Vector3(0, _vertices[i].y, 0))); &nbsp; //3.法线平均化 IEnumerator Print_Normals() &nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i < meshFilter.mesh.vertices.Length; i++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i % 2 == 0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.DrawRay(transform.TransformPoint(meshFilter.mesh.vertices[i]), transform.TransformDirection(meshFilter.mesh.normals[i] * 0.3f), Color.green, 1000f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug.DrawRay(transform.TransformPoint(meshFilter.mesh.vertices[i]), transform.TransformDirection(meshFilter.mesh.normals[i] * 0.3f), Color.blue, 1000f); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; yield return new WaitForSeconds(Time.deltaTime); &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp; } &nbsp; //回到项目上来。这段法线计算的代码就不放上来了,大致就是根据顶点在数组中的下标去判断位置是否相同,然后把该顶点的法线相加即可。大家自己构建Mesh时的顶点顺序可能会不太一样。 以上代码是否有问题,请帮我完善
最新发布
08-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值