Unity3D面试中遇到的问题

1.骨骼动画实现的原理

  • 蒙皮是指将Mesh中的顶点附着(绑定)在骨骼之上,而且每个顶点可以被多个骨骼所控制。
  • 骨骼是皮肤网格内的不可见对象,它们影响动画过程中网格变形的方式。
    • 其基本思想是将骨骼连接在一起形成一个层次化的“骨架”
    • 动画通过关键帧数据驱动旋转骨架的关节以使其移动。Mesh上的顶点附着在骨骼上。
    • 播放动画时,顶点会随着骨骼或骨骼的连接而移动,因此“皮肤(Mesh)”会跟随骨骼的移动。
  • 在unity中,由骨骼驱动的mesh需要用到SkinnedMeshRenderer
  • SkinnedMeshRenderer中保存了: 

        rootBone:骨骼的跟节点   
        bones:骨骼数组,每一个数据表示一个关节,在mesh中可以用索引找到对应的骨骼         
        sharedMesh:指定要渲染哪个mesh

    在Mesh中,保存了:

        bindposes:绑定姿势。每个索引处的绑定姿势引用索引相同的骨骼。即跟        SkinnedMeshRenderer中的bones是一一对应的。
        vertices:保存每个顶点的位置
        boneWeights:骨骼权重,每个顶点对应一个boneWeights

bindposes

        把关节任意旋转、平移,甚至缩放,就能为骨骼摆出各种姿势。一个关节的姿势定义为关节相对某参考系( frame of reference )的位置、定向和缩放。关节的姿势通常以4×4或4×3矩阵表示,或表示为 SQT 数据结构(缩放/ scale 、四元数旋转/ quaternion 及矢量平移/ translation )。骨骼的姿势仅仅是其所有关节的姿势之集合,并通常简单地以 SQT 数组表示。在unity中Mesh中,保存了的绑定姿势(bindposes)是一个Matrix4x4,即4X4的矩阵,表示了某个骨骼的姿势。其实每一个关节,代表了一个坐标系,其姿势受到父关节的影响,因此我们只需要跟空间变换一样,做矩阵的变换就可以知道某个关节相对于模型空间的姿势了

蒙皮
        我们把三维网格顶点联系至骨骼的过程称为蒙皮。mesh中每个顶点可以绑定至一到多个关节。若某个顶点只绑定到一个关节,也就会完全跟随该关节移动。若绑定至多个关节,该顶点的位置就等于把它逐一绑定至个别关节后的位置,再取其加权平均。
把网格蒙皮至骨骼,三维建模师必须替每个顶点提供以下的额外信息:

该顶点要绑定到的(一个或多个)关节索引。
对于每个绑定的关节,提供一个权重因子( bone weight),以表示该关节对最终顶点位置的影响。
同计算其他加权平均时的习惯,毎个项点的权重因子之和为1。
这些信息就是unity中由Mesh保存的boneWeights所记录。下面以单个骨骼为例子,讲述蒙皮的过程。

        求蒙皮矩阵的“诀窍”在于领会到,顶点绑定至关节的位置时,在该关节空间中是不变的。因此我们可以把项点于模型空间的绑定姿势位置转换至关节空间,再把关节移至当前姿势,最后把该顶点转回模型空间。此模型空间至关节空间再返回模型空间的变换过程,其效果就是把顶点从绑定姿势“变形”至当前姿势。

2.Image的实现原理

        先看到UI渲染的底层结构,UI渲染主要由三个部分组成:CanvasUpdateRegistry, Graphic, CanvasRender

CanvasUpdateRegistry负责通知需要渲染的UI组件
Graphic负责组织mesh和material然后传给底层(CanvasRenderer类)
CanvasRenderer负责连接canvas和render component,把mesh绘制到Canvas上,CR并不是直接渲染,而是交给Canvas,Canvas再要做合批等操作

        1. 继承结构与基类
                Graphic基类:Image继承自MaskableGraphic,后者进一步继承自Graphic。该基类负责处理UI元素的通用渲染逻辑,包括顶点数据生成、材质管理以及与Canvas系统的交互。
CanvasRenderer:每个Image附带的CanvasRenderer组件负责将生成的网格数据提交到Unity的渲染管线中。
        2. 网格生成
                顶点与三角形:Image默认生成四边形网格(两个三角形),顶点位置由RectTransform的尺寸和锚点确定。不同类型的Image(如Simple、Sliced)会动态调整顶点布局。
                九宫格切片(Sliced):通过定义Sprite的九宫格边界,保持四角不变,仅拉伸中间区域。顶点计算时分割为9个子网格,优化拉伸效果。
                平铺(Tiled):重复纹理的UV坐标,生成多个平铺的顶点,适用于无缝贴图。
                填充(Filled):根据fillAmount动态调整顶点位置或UV,支持多种填充方向(水平、垂直、径向),通过数学计算裁剪显示区域。
        3. 动态更新与性能优化
                脏标记机制:当Sprite、Color或尺寸变化时,调用SetVerticesDirty或SetMaterialDirty标记需要更新,延迟至Canvas渲染前重新生成数据,避免频繁计算。
                合批处理:相同材质与纹理的Image由Canvas合批,减少Draw Call。属性差异(如不同材质或颜色)可能导致合批中断。
        4. 特殊类型处理
                Filled模式:通过修改顶点坐标或UV实现部分显示。例如,水平填充逐步扩展右侧顶点位置,径向填充则按角度旋转UV或调整顶点。
                Sprite Atlas:使用图集时,UV坐标对应图集中的子区域,减少纹理切换开销。

3.UGUI中进度条怎么实现的(即Image中Filled的实现原理)

        Filled模式的核心是动态调整顶点位置或UV坐标,以实现部分显示。以下是不同类型的具体实现逻辑:
    a. 水平/垂直填充(Horizontal/Vertical)
    原理:通过fillAmount控制顶点坐标的偏移范围。
    实现步骤:
        根据fillOrigin确定填充起点(如左→右或右→左)。
        计算填充边界:原始矩形宽度/高度 × fillAmount。
        裁剪顶点:将超出边界的顶点坐标截断到边界位置。
    b. 径向填充(Radial)
    原理:通过角度计算裁剪区域,通常结合UV坐标旋转或顶点位置调整。
    实现步骤:
        根据fillOrigin确定起始角度(如0°、90°、180°、270°)。
        计算当前填充角度:360° × fillAmount。
        对每个顶点,判断其相对于圆心的极坐标角度是否在填充范围内。
        超出范围的顶点被移动到边界或隐藏。
        环形填充(Radial360)的特殊处理:
        顶点被分为内外两圈,形成环形结构。
        根据角度动态调整外圈顶点位置,形成缺口。

4.内置管线和URP的区别

1. 架构与灵活性
    内置管线
        固定架构:传统的“一刀切”渲染流程,难以深度定制。
        兼容性强:支持旧版功能(如旧版粒子系统、传统后期处理),但扩展性差。
    URP
        模块化设计:基于可编程渲染管线(SRP),允许通过C#脚本定制渲染流程(如修改渲染顺序、添加自定义Pass)。
        轻量高效:专为优化性能设计,默认支持GPU实例化、SRP Batcher等,减少Draw Call。
2. 性能对比
    URP优势
        移动端优化:默认省电、低发热,适合手机、Switch等性能敏感平台。
        渲染效率:通过动态批处理、剔除优化降低开销,VR项目帧率提升显著。
        SRP Batcher:对材质相近的物体合并渲染,提升CPU到GPU的数据传输效率。
    内置管线
        性能中庸:无针对性优化,复杂场景易出现性能瓶颈。
3. 功能支持
    URP特色功能
        Shader Graph:可视化编写着色器,无需手动写HLSL代码。
        2D渲染增强:原生2D灯光、法线贴图、动态阴影。
        扩展包支持:如2D Pixel Perfect(像素完美适配)、Cinema Pro(电影效果)。
        Volume框架:灵活配置后处理效果(如动态模糊、全局光照调整)。
    内置管线功能
        传统效果:旧版后期处理(需Post-Processing Stack v2)、Legacy Shaders。
        兼容旧资源:Asset Store中老资源(如Toon Shader)可能仅支持内置管线。
4. 图形质量
    URP
        平衡画质与性能:支持软阴影、简单屏幕空间反射,适合风格化或中等画质3D。
        HDRP的轻量版:若需更高画质(如物理级光照、光线追踪),需切换至HDRP。
    内置管线
        上限较低:缺乏现代渲染技术(如基于物理的渲染PBR支持有限)。
5. 适用场景
    选择URP
        移动端/VR项目
        2D游戏(需动态灯光、阴影)
        中小型3D项目(如独立游戏、卡通风格)
        需快速迭代、跨平台部署
    选择内置管线
        依赖旧版插件/资源的项目
        无需高级图形功能的小型项目
        团队熟悉传统Unity工作流且无迁移预算

5.九宫格的实现原理

        网格分割逻辑:
            根据RectTransform的当前尺寸,计算九宫格各区域的实际显示尺寸。
            四角区域:保持原始大小,不进行缩放。
            边区域:根据目标尺寸与原始尺寸的差值,单向拉伸(如左右边水平拉伸,上下边垂直拉伸)。
            中心区域:填充剩余空间,可拉伸或平铺。
            顶点数:九宫格模式生成16个顶点(每个子区域4个顶点,共9个子区域,但有部分顶点重叠)。
       UV坐标映射:
            四角区域的UV保持原始比例。
            边区域的UV在拉伸方向重复(如左右边的U坐标拉伸)。
            中心区域的UV根据拉伸模式调整(平铺时重复UV,拉伸时扩展UV)。

6.Text的实现原理

字体与字形处理
    字体资源:
        动态字体(如 Arial):使用操作系统安装的 TrueType/OpenType 字体文件,运行时动态生成字形纹理(Glyph Atlas)。
        位图字体(如 BMFont):预先生成包含固定大小字符的纹理图集(通过 .fontsettings 配置)。
    字形生成:
        动态字体会根据文本内容按需生成字形(Glyph),并缓存在纹理图集中(通过 Font.textureRebuilt 事件更新)。
        使用 FontEngine 类(底层基于 FreeType 库)解析字体文件,提取字形轮廓并栅格化为纹理。
文本布局与网格生成
    文本解析:
        处理换行符、空格、富文本标签(如 <color=#ff0000>Red</color>)。
        计算文本对齐方式(左对齐、居中对齐、右对齐)和自动换行(HorizontalOverflow 和 VerticalOverflow 控制)。
    网格生成:
        使用 TextGenerator 类生成顶点数据(位置、UV、颜色等)。
        每个字符对应一个四边形(两个三角形),UV 坐标映射到字体纹理图集中的对应字形区域。
        富文本标签(如颜色、大小、字体样式)会修改顶点属性(如颜色值、顶点偏移)。
性能优化
    纹理图集管理:
        动态字体的字形按需生成,可能导致图集扩容(触发纹理重建,可能引起卡顿)。
        通过 Font.maxTextureSize 和 Font.characterPadding 配置图集参数。
        预加载常用字符:在 Font 的导入设置中指定需要预生成的字符集(如 ASCII 范围)。
    合批(Batching):
        相同材质和纹理的 Text 组件可能合批,减少 Draw Call。
        频繁变化的文本(如计数器)可能导致合批失败,需谨慎使用。
局限性
    性能问题:动态字体在首次显示新字符时需生成字形,可能导致卡顿。
    功能限制:原生 Text 不支持高级排版(如连字、复杂文本布局),字体效果(如描边、阴影)需叠加多个组件实现。

7.TextMeshPro的实现原理

字体预处理与SDF技术
    Signed Distance Field(SDF)生成:
        在导入字体时,TMP将字符轮廓转换为距离场纹理图集。每个像素存储到字符轮廓的最近距离,正值表示外部,负值表示内部。
        SDF允许通过着色器动态调整边缘平滑度,实现高质量的抗锯齿和缩放效果(如放大字体无锯齿)。
    字体图集缓存:
        预生成常用字符的SDF图集,减少运行时计算。支持动态添加字符(如生僻字),但可能触发图集重建,需权衡性能。
网格生成
    动态网格构建:
        每个字符生成四边形(Quad),顶点包含位置、UV、颜色等数据。
        对特殊效果(如粗体、斜体)应用顶点偏移,避免额外几何体。
        合并相邻字符的顶点以减少Draw Call(需相同材质和效果)。
    顶点数据优化:
        静态文本缓存网格,动态文本(如频繁更新的计数器)可能触发网格重建,需谨慎使用。

8.UGUI合批相关

       UGUI合批的触发需要满足以下条件(按优先级排序):
    相同材质与纹理
        UI元素必须使用相同的材质和相同的纹理(或图集内的同一张子图)。
        如果使用图集(Atlas),需确保UI元素引用的是图集中的不同区域(Sprite),但共享同一材质。
    层级顺序连续
        在Hierarchy中,相邻的UI元素必须处于同一Canvas层级下,且中间没有插入其他不满足合批条件的元素(如不同材质、Mask组件等)。
    无渲染打断因素
        避免使用会打断合批的组件或效果,例如:
        Mask 或 RectMask2D(遮罩)
        自定义Shader中的特殊渲染逻辑(如透明度裁剪)
        不同渲染队列(Render Queue)的材质
        重叠的UI元素(部分情况下可能拆分批次)
    渲染顺序:
        UI元素按Hierarchy中的顺序从上到下渲染,合批仅在连续且符合条件的元素间生效
常见打断合批的情况
    ❌ 两个Image使用同一图集,但中间插入了一个不同材质的Text组件。
    ❌ 某个Image启用了Mask组件,导致后续元素无法合批。
    ❌ 两个UI元素虽然材质相同,但分别位于不同的Canvas中。
    ❌ 自定义Shader修改了渲染队列或透明度计算方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值