<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于 Creator 3.0 的 3D 換裝

          共 7386字,需瀏覽 15分鐘

           ·

          2021-05-30 06:06

          需求

          無論是2d或是3d游戲,換裝都是比較受歡迎的游戲體驗,也是游戲開發(fā)者經(jīng)常需要面對的開發(fā)需求,本文主要介紹3D換裝需求,關于2d換裝(spine或龍骨)后續(xù)會向大家介紹。

          1. 從換裝的方式分類,可以分為整體換裝以及局部換裝,整體換裝較為簡單,我們就不做討論,本文主要介紹一下局部換裝(其實理解過后也是非常的簡單)。

          2. 從換裝的模型分類, 主要分為兩種類型:

          • 一種類型是對于靜態(tài)模型的換裝,就是直接將身體需要換的Mesh更新即可。

          • 另一種類型是動態(tài)模型的換裝(有動作的模型)

            本文主要介紹動態(tài)模型的換裝實現(xiàn)。

          效果展示

          (素材僅用于學習交流)

          原理介紹

          在開始描述換裝前,首先要具備骨骼動畫的知識,如果對骨骼動畫的原理不熟悉,換裝是比較難以理解的。換裝的核心其實并不在換上,而是要理解為什么能換,而這些都和骨骼動畫密不可分。

          骨骼動畫的組成:

          圖1(引用于shader實驗室)
          • 網(wǎng)格(Mesh):

            模型(Model)是由一個個三角形組成的,而這種三角形的學名則是網(wǎng)格(Mesh)

          • 網(wǎng)格蒙皮數(shù)據(jù)(Skin Info)

            頂點的Skin數(shù)據(jù)包括頂點受哪些骨骼影響以及這些骨骼影響該頂點時的權(quán)重(weight),另外對于每塊骨骼還需要骨骼偏移矩陣(BoneOffsetMatrix)用來將頂點從Mesh空間變換到骨骼空間。可簡單理解為:SkinMesh = Mesh+Skin Info

          • 骨骼(Skeleton):

            如圖1,骨架由一系列具有層次關系的關節(jié)(骨骼)和關節(jié)鏈組成,是一種樹結(jié)構(gòu),選擇其中一個是根關節(jié),其它關節(jié)是根關節(jié)的子孫,可以通過平移和旋轉(zhuǎn)根關節(jié)移動并確定整個骨架在世界空間中的位置和方向。

          • 骨骼的動畫(關鍵幀)數(shù)據(jù)

          骨骼動畫是通過關鍵幀驅(qū)動骨骼運動,隨之依次調(diào)整每塊骨頭的朝向和坐標,骨頭再帶動頂點運動,蒙皮信息就描述了每個頂點受哪些骨頭的影響,以及他們的權(quán)重,這樣骨骼動畫就實現(xiàn)了運動以及形變。

          實現(xiàn)思路

          導入模型進入creator,可發(fā)現(xiàn)節(jié)點下含有SkinnedMeshRenderer組件,其中含有mesh屬性,按照我的理解這里的Mesh特指SkinMesh = Mesh+Skin Info,而非普通的靜態(tài)mesh。

          動態(tài)模型換裝需要更新SkinnedMeshRenderer組件的中SkinMesh,Skeleton(骨骼資源), SkinningRoot(骨骼根節(jié)點的引用——控制此模型的動畫組件所在節(jié)點)。本案例中采取直接更換蒙皮網(wǎng)格渲染器組件(SkinnedMeshRenderer)的方式實現(xiàn)換裝

          實現(xiàn)步驟

          1. 骨骼動畫及部位裝備prefab的制作,核心——共享一套骨骼。動畫師制作時,同一部位的不同裝備綁定同一根骨骼,整體輸出,在creator中將各部件裝備制作為prefab后從主角刪除,主角只保留一套默認裝備。

          2. 主角節(jié)點需要關閉預烘焙功能,否則無法實時運算以實現(xiàn)換裝功能。

          3. 初始化模型。建立Map<key-PartName, value-Node>,這一步是為了后續(xù)替換裝備時可以檢索到對應部位的節(jié)點

          4. 替換裝備節(jié)點:

            • 刪除舊裝備節(jié)點。檢索Map,根據(jù)部位key-PartName獲得OldNode引用,移除OldNode(保留骨骼根節(jié)點引用SkinningRoot,后續(xù)備用)。
            • 增加新裝備節(jié)點,加載部位A新裝備prefab并實例化為NewNode,添加NewNode,
            • 刷新部位key-PartName的value值為NewNode
          5. 刷新骨骼,取得步驟1中的SkinningRoot來刷新NewNode的SkinningRoot,完成。(我實現(xiàn)到這步,后續(xù)步驟為了節(jié)省性能大家可以研究)

          6. 合并mesh

          7. 合并貼圖(貼圖的寬高最好是2的N次方的值)

          8. 重新計算UV

          核心代碼

          import { _decorator, Component, Node, resources, Prefab, instantiate, SkinnedMeshRenderer, EventTouch, SkeletalAnimation } from 'cc';
          const { ccclass, property } = _decorator;

          @ccclass('ChangeCloth')
          export class ChangeCloth extends Component {
              @property({
                  type: Node
              })
              modelNode!: Node;

              sex: string = "male";
              bodyPart: string[] = ["hair""top""pants""shoes"];
              data: Map<string, Node> = new Map();

              start() {
                  this.initAllData();
              }

              initAllData() {
                  this.data.clear();
                  for (let i = 0; i < this.bodyPart.length; i++) {
                      let partName = this.bodyPart[i];
                      let nodeName = `${this.sex}_${partName}-1`;
                      let nodePart = this.modelNode.getChildByName(nodeName);
                      if (nodePart) {
                          console.debug("init part", nodeName);
                          this.data.set(partName, nodePart);
                      }
                  }
              }

              changeCloth(partName: string, index: number) {
                  resources.load(`prefab/${this.sex}_${partName}-${index}`, Prefab, (err, prefab) => {
                      if (err) {
                          console.debug(err);
                          return;
                      }
                      let oldNode = this.data.get(partName);
                      let oldModel = oldNode?.getComponent(SkinnedMeshRenderer);
                      let newNode = instantiate(prefab);
                      let newModel = newNode.getComponent(SkinnedMeshRenderer);
                      if (oldModel?.skinningRoot && newModel) {
                          newModel.skinningRoot = oldModel?.skinningRoot;

                          oldNode?.removeFromParent();
                          this.modelNode.addChild(newNode);
                          this.data.set(partName, newNode);
                      }
                  })
              }

              onClickChange(touch: EventTouch, data: string) {
                  console.debug("onClickChange", data);
                  let params = data.split("-");
                  this.changeCloth(params[0], parseInt(params[1]));
              }

              onClickAnimation(touch: EventTouch, animationName: string) {
                  console.debug("onClickAnimation", animationName);
                  this.modelNode.getComponent(SkeletalAnimation)!.play(animationName);
              }

              update(deltaTime: number) {
                  // [4]
              }
          }


          小結(jié)

          換裝的核心是要理解為什么能換,理解了骨骼動畫的原理以及構(gòu)成,一旦弄清”為什么“?,換裝的實現(xiàn)就會是非常簡單的一件事了。

          如果羽毛的理解存在錯誤,歡迎回復進行指導。

          更多

          快速實現(xiàn)3d拋物線繪制

          奇形怪狀-不規(guī)則按鈕實現(xiàn)


          今日技能你學廢了嗎?關注公眾號回復“換裝”獲取源碼


          瀏覽 94
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  97任你操 | 操逼视频黄片中国版的中国的 | 日韩无码中文字幕电影 | 大奶美女做爱 | 淫色在线免费视频 |