前沿

今天菜鸟和大家一起来讨论一下3D入门的基础性知识:「Mesh」它是3D模型能正常展现的重要因素。(文末有奖问卷调查,感谢各位老铁支持!)

上边这个小姐姐模型,大家想知道它是怎么构成的吗?今天菜鸟带大家了解一下3D模型组成之顶点数据,UV 数据,法线数据等一系列数据。

数据结构

首先,咱们基于 Cococ Creator 3.x 中几何体信息数据结构,了解一下,一个普通的 Mesh 中到底有哪些数据:

export interface IGeometry {positions: number[];normals?: number[];uvs?: number[];tangents?: number[];colors?: number[];attributes?: gfx.Attribute[];customAttributes?: {attr: gfx.Attribute;values: number[];}[];boundingRadius?: number;minPos?:{x: number;y: number;z: number;};maxPos?: {x: number;y: number;z: number;};indices?: number[];primitiveMode?: gfx.PrimitiveMode;doubleSided?: boolean;
}

上边的数据结构是直接从引擎代码拷贝过来的,其实从字面意思也可以理解到其中包含了:「顶点,法线,uv切线,顶点颜色,索引,包围盒坐标等一系列数据」

数据解析

关键的来了,下边我们就会对以上主要的的数据结构进行解释。

1. 顶点positions

大家可能都知道,一个网格体(Mesh)是由多个彼此相连的三角面组成,而三角面则是由三个顶点组成,就比如一个简单的平面,大家看一下下边的图:

所以顶点数据决定了网格体的基本形状。下面我们通过顶点数据创建一个简单的三角形:

let point = [0, 0, 0,  //点1  x,y,z0, 0, 1,  //点2  x,y,z1, 0, 1   //点3  x,y,z
];
let mesh = utils.createMesh({positions:point
});

通过上边的代码,我们就可以创建一个简单的三角形,我们需要注意的是:

  • 1. positions 是一个数字类型的数组

  • 2. 每3个数据组成一个点,分别表示x,y,z

  • 3. 每3个点组成一个面

  • 4. 组成面的3个应是逆时针方向

2. UV

UV 实际上是U、V纹理贴图的坐标简称。所有的图像文件都是二维的一个平面,水平方向是U,垂直方向是V。UV 就是将图像上每一个点精确对应到模型物体的表面.在点与点之间的间隙位置由软件进行图像光滑插值处理。

接下来咱们简单介绍一下 UV 坐标的原理,在 Cocos 中 UV 的分布是这样的:

左上角为(0,0)点,那么对于下边的三角形:

我们已知三个顶点分别是:

let point = [0, 0, 0,  //点1  x,y,z0, 0, 1,  //点2  x,y,z1, 0, 0,  //点3  x,y,z];

我们需要将顶点坐标和 UV 坐标相对应,为顶点设置对应 UV 的坐标:

let uvs = [0,0, //对应第一个顶点0,1, //第二个顶点1,0, //第三个顶点
];

最终的效果就是这样

再看看咱们的立方体

3. 法线 normals

法线:它是一个向量,和 UV 一样,它都属于顶点的属性。它的数量和 UV 一样都是与顶点一一对应的。在网格中,法线通常被用来进行光照效果计算,同时在一些自定义的材质中也会用到法线去实现一些效果

let point = [0, 0, 0,  //点1  x,y,z0, 0, 1,  //点2  x,y,z1, 0, 0, //点3  x,y,z1, 0, 0, //点3  x,y,z0, 0, 1,  //点2  x,y,z1, 0, 1,
];
let uvs = [0, 0,0, 1,1, 0,1, 0,0, 1,1, 1,
];
let normals = [0, 1, 0,0, 1, 0,0, 1, 0,0, 1, 0,0, 1, 0,0, 1, 0,
];
let mesh = utils.createMesh({positions: point,uvs: uvs,normals: normals,
});

4. 索引indices

接下来咱们说说索引,索引到底是干什么用的呢,下边咱们用一个立方体来给大家展示一下:

先给大家看看代码:

let point = [//bottom0, 0, 0,    0, 0, 1,    1, 0, 0,1, 0, 0,    0, 0, 1,    1, 0, 1,//top0, 1, 0,    0, 1, 1,    1, 1, 0,1, 1, 0,    0, 1, 1,    1, 1, 1,//left0, 0, 0,    0, 0, 1,    0, 1, 0,0, 1, 0,    0, 0, 1,    0, 1, 1,//right1, 0, 0,    1, 0, 1,    1, 1, 0,1, 1, 0,    1, 0, 1,    1, 1, 1,//back0, 0, 0,    1, 0, 0,    0, 1, 0,0, 1, 0,    1, 0, 0,    1, 1, 0,//front0, 0, 1,    1, 0, 1,    0, 1, 1,0, 1, 1,    1, 0, 1,    1, 1, 1,
];
let mesh = utils.createMesh({positions: point
});

一个立方体6个面。一个面最少两个三角形,那么就是6个顶点。6个面36个顶点,但是仔细的小伙伴会发现有好多点是重复出现的,那么有一种方式可以避免顶点的重复出现嘛,答案当然是有的,就是咱们要说的索引。

索引的原理就是 positions 中的坐标点都是唯一的,通过索引来代替重复的点,直接看使用吧:

let point = [0, 0, 0,  //00, 0, 1,  //11, 0, 0,  //21, 0, 1,  //30, 1, 0,  //41, 1, 0,  //50, 1, 1,  //61, 1, 1,  //7
];
let indices = [//bottom0, 1, 2,2, 1, 3,//top4,6,5,5,6,7,//left0,1,4,4,1,6,//right2,3,5,5,3,7,//back0,2,4,4,2,5,//front1,3,6,6,3,7,];
let mesh = utils.createMesh({positions: point,indices:indices,
});

需要注意的是,「position中每三个值代表一组,也就是一个坐标点,uv中每两个值代表一个坐标点」,indices 中的值代表的是 position,UV 中的「第几个坐标点」,而不是直观的下标。

利用索引,咱们就可以将 position 中的重复点优化掉。通过索引来控制,作为顶点属性的 UV 和法线,以至于顶点颜色都会同时也会受到索引的影响,也就是索引同时控制了顶点以及uv和法线,简单的平面:

let point = [0, 0, 0,0, 0, 1,1, 0, 0,1, 0, 1,
];
let uvs = [0, 0,0, 1,1, 0,1, 1,
];
let normals = [0, 1, 0,0, 1, 0,0, 1, 0,0, 1, 0,
];
let indices = [0, 1, 2, 2, 1, 3
];
let mesh = utils.createMesh({positions: point,uvs: uvs,normals: normals,indices: indices,
});

5.minPos,maxPos

minPos、maxPos 字面意思就是最大点和最小点,那么什么是最大点和最小点呢?
先看看源码:

let minPosition = geometry.minPos;
if (!minPosition && options.calculateBounds) {minPosition = Vec3.set(new Vec3(), Infinity, Infinity, Infinity);for (let iVertex = 0; iVertex < vertCount; ++iVertex) {Vec3.set(v3_1, positions[iVertex * 3 + 0], positions[iVertex * 3 + 1], positions[iVertex * 3 + 2]);Vec3.min(minPosition, minPosition, v3_1);}
}
let maxPosition = geometry.maxPos;
if (!maxPosition && options.calculateBounds) {maxPosition = Vec3.set(new Vec3(), -Infinity, -Infinity, -Infinity);for (let iVertex = 0; iVertex < vertCount; ++iVertex) {Vec3.set(v3_1, positions[iVertex * 3 + 0], positions[iVertex * 3 + 1], positions[iVertex * 3 + 2]);Vec3.max(maxPosition, maxPosition, v3_1);}
}

通过模型的顶点数据,计算顶点中x、y、z三个方向同时最小和最大的坐标,通过最大点和 最小点可以模拟出一个将整个模型包含在内的矩形来,也就是咱们所说的包围盒。至于包围盒的作用,首先想到的就是相机对物体的剔除,也上一段源码吧!

if (model.node && ((visibility & model.node.layer) === model.node.layer)|| (visibility & model.visFlags)) {// shadow render Objectif (dirShadowObjects != null && model.castShadow && model.worldBounds) {// frustum cullingif (shadows.fixedArea) {AABB.transform(_ab, model.worldBounds, shadows.matLight);if (intersect.aabbFrustum(_ab, camera.frustum)) {dirShadowObjects.push(getDirShadowRenderObject(model, camera));}} else {// eslint-disable-next-line no-lonely-ifif (intersect.aabbFrustum(model.worldBounds, _dirLightFrustum)) {dirShadowObjects.push(getDirShadowRenderObject(model, camera));}}}// frustum cullingif (model.worldBounds && !intersect.aabbFrustum(model.worldBounds, camera.frustum)) {continue;}renderObjects.push(getRenderObject(model, camera));
}

同时一直有一个问题,在原生平台进行静态合批后,网格的包围盒貌似有问题,场景中的模型剔除会出现异常。

实操

上面说了这么多,那么在实际开发中都会有哪些操作呢?

1. NavMesh 数据

顺带在这里给自己的导航寻路打个广告导航寻路
在集成 NavMesh 时,最常见的需求就是:我的场景中存在好多子物体,有从外部导入的,也有用引擎自带的,在构建导航数据之前我们需要将这些子物体进行网格数据的整理

public addStaticModle (node: Node): void;

我们只需要拿到顶点,索引就可以进行数据整理

let position = mesh.readAttribute(0, gfx.AttributeName.ATTR_POSITION);
let indices = [];
mesh.copyIndices(0, indices);

接下来的大家可以去菜鸟的寻路源码中了解奥

2.mesh数据导出obj

需求永远是那么的奇怪!在一个比较大的游戏场景中。

会出现使用大量的相同物体,拼凑出一个布局。那么一个场景中可能会出现大量的节点个数,节点数量过多会导致一些性能问题,比如序列化慢等。

平时我们都是用三方软件建好模型,导入到编辑器中,那么反之是不是可以「将我们场景中的模型导出为三方软件识别的模型文件」答案肯定是可以的。

  • 首先 OBJ 文件是一种文本文件,文本编辑器打开就可以看见内容,而且大多数建模软件都可以打开

v 0.123 0.234 0.345 1.0
v ...
vt 0.500 1 [0]
vt ...
vn 0.707 0.000 0.707
vn ...
f 3/1 4/2 5/3
f 6/4/1 3/5/3 7/6/5
f 7//1 8//2 9//3
f ..
  • 我们我可拿到场景中网格的基本数据

let positions = mesh.readAttribute(0, gfx.AttributeName.ATTR_POSITION);
let normals = mesh.readAttribute(0, gfx.AttributeName.ATTR_NORMAL);
let uvs = mesh.readAttribute(0, gfx.AttributeName.ATTR_TEX_COORD);
let indices = mesh.readIndices(0);

菜鸟整理了一下,通过一个简单的脚本对所有的子物体先进行了网格数据的合并,然后点击保存数据将网格数据导出为obj

源码

链接:
https://store.cocos.com/app/detail/3666


2022 年即将结束,2023 年即将到来。

感恩老铁们对公众号的支持!

在此叨扰下各位,填写一份 Cocos Store 问卷调查(有奖)!

 2023年我们会倍加努力,一起共绘成长蓝图~

3D 小姐姐模型是怎么“捏”成的? 初识 Mesh 知识点!相关推荐

  1. 纸片人算什么?教你造真“3D小姐姐”!可以动的模型

    要说现在什么行业最赚钱,非游戏莫属!要说游戏中什么类型最赚钱?非3D建模莫属! 据统计,刚入行的从业人员均薪1万-1.3万,如果做到总监,行业平均年薪30万+!他们的日常就是创造游戏里各种各样的小姐姐 ...

  2. 3D模型展示 | 黏土捏成的世界杯吉祥物,居然和实物这么像

    世界杯正在如火如荼的进行中,目前八强名单已经出炉.不知道大家有没有熬夜看球呢,本届世界杯吸引大家目光的除了足球,还有那个极具中东色彩的吉祥物. 2022卡塔尔世界杯官方吉祥物是一个外形酷似头巾的卡通人 ...

  3. 什么是3D建模?3D“小姐姐”是如何创建出来的呢

    D建模是计算机图形中用于产生任何对象或表面的3D数字表示的技术. 艺术家使用特殊的软件来操控虚拟空间中的点(称为顶点)以形成网络:形成对象的一组顶点 这些3D对象可以自动生成,也可以通过使网格变形或以 ...

  4. 为什么小姐姐能摇一晚上不倒?

    引言 西安大唐不夜城"不倒翁"女孩街头表演的视频曾一夜走红网络.在大唐不夜城步行街,"不倒翁"小姐姐身姿轻盈眼神妩媚令人梦回大唐,一颦一笑将中国唐朝美人的妩媚娇 ...

  5. CSDN公众号新功能上线,居然还能搜出小姐姐???

    为了给各位打工人更好的搜索体验 CSDN总是在学习新技能 这次CSDN公众号又给大家带来了一项全新的搜索技能 在CSDN旗下的公众号内回复消息 就能自动回复想搜索的内容啦 小编来给大家演示一下,在公众 ...

  6. CSDN公众号新功能上线,居然还能搜出小姐姐???(文末有福利)

    为了给各位打工人更好的搜索体验 CSDN总是在学习新技能 这次CSDN公众号又给大家带来了一项全新的搜索技能 在CSDN旗下的公众号内回复消息 就能自动回复想搜索的内容啦 小编来给大家演示一下,在公众 ...

  7. DirectX12(D3D12)基础教程(十七)——让小姐姐翩翩起舞(3D骨骼动画渲染【3】)

    目录 6.骨骼绑定 6.1.Shader中的骨骼绑定 6.2.aiMesh中的骨骼绑定信息 6.3.骨骼绑定信息的解算 7.骨骼树(骨架) 6.骨骼绑定   搞清楚了基本的骨骼动画的基本原理,那么就直 ...

  8. 谷歌小姐姐开源姿势动画师项目,组合现有TF模型,只需一张SVG图片便可配置...

    梅宁航 发自 凹非寺  量子位 报道 | 公众号 QbitAI 姿势动画师,自己做动作就可以生成矢量角色动画. 打开摄像头,你的姿态随之摇摆,一道道线.一个个点,刻画你的面部轮廓和完美身材. △效果图 ...

  9. 小姐姐,你的发丝高光怎么用 Creator 3D 实现?

    Introduction PRB 材质改变了人们对于引擎实时渲染画面的理解,让玩家在游戏中,也能够体验到锈蚀的金属,厚重的皮革,精细的纹理,感受更加真实的世界.在正式发布的 Cocos Creator ...

最新文章

  1. python 怎么读-Python怎么读
  2. PHP各种数据类型转换
  3. php 打印对象到文件,php实现将数组或对象写入到文件的方法小结【三种方法】...
  4. 使用Java EE和OIDC构建Java REST API
  5. PiFlow大数据流水线系统v0.9源码
  6. 快讯:Oracle 19c 新特性及官方文档抢鲜下载
  7. cad怎么快速算面积_微信收到CAD图纸打不开怎么办?2种方法教你手机CAD快速看图...
  8. [Java] 蓝桥杯ALGO-147 算法训练 4-3水仙花数
  9. Shiro自定义realm实现密码验证及登录、密码加密注册、修改密码的验证
  10. 一些开源的统计机器翻译系统简要介绍
  11. VMThread占CPU高基本上是JVM在频繁GC导致,原因基本上是冰法下短时间内创建了大量对象堆积造成频繁GC。...
  12. bbsmax mysql_MySQL中自己不太常用的命令
  13. 使用vue开发的网页游戏
  14. 2017滴滴校招 数字和为sum的方法数(DP)
  15. amdr7-4700linux,Yoga14s 2021 ARH R7 4800H 安装Arch Linux
  16. 如何用python画爱心?
  17. excel插件开发,Smartbi免费版安装流程
  18. android 按钮回弹效果,Android仿IOS回弹效果 支持任何控件
  19. 图书管理系统功能需求的用例分析
  20. 群晖存储服务器型号,群晖存储服务器

热门文章

  1. 数字音乐生财:月入10万不是梦
  2. Android下拉筛选DropDownMenu
  3. SQLite.Interop.dll 没有拷贝到输出目录
  4. 线段树 (更新区间查询点)秋实大哥与小朋友
  5. b站网页html,bilibili注册页面html简单分析
  6. webpack基本使用
  7. 从程序员到架构师的转型思维的转变 NLP思维利器(二)
  8. 房车接父母“反向过年”成春运新亮点
  9. Base64(本地存储加密解密)
  10. 计算机如何校准颜色,Win7电脑如何校准显示器|电脑显示器颜色校准