🟡: 代表个人还有一些理解上的问题
🟢: 代表自己面试中被问到过
🔴: 代表问题内容未完成

Unity 3D 数学

Unity 场景中有两个点连成了一条线,想要旋转这条线,应该怎么做?

首先,将两点相减得到一条向量,然后将该向量乘以所需的旋转四元数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;

public class LineRotation : MonoBehaviour
{
public Transform point1;
public Transform point2;
public Quaternion rotationQuaternion;

void Update()
{
// 计算两点的向量
Vector3 lineVector = point2.position - point1.position;

// 对向量进行旋转
Vector3 rotatedLineVector = rotationQuaternion * lineVector;

// 更新线的位置和方向
transform.position = point1.position;
transform.rotation = Quaternion.LookRotation(rotatedLineVector);
}
}

Unity 中如何将本地坐标转为世界坐标?

手动计算:用本地坐标加上父对象相对世界的坐标。如果有多层父子关系,不停地往上加即可。

Transform.TransformPoint 方法:利用 Transform 中的 TransformPoint 方法,该方法可以将本地坐标转换为世界坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;

public class LocalToWorldConversion : MonoBehaviour
{
void Start()
{
// 获取物体的 Transform 组件
Transform transform = GetComponent<Transform>();

// 本地坐标
Vector3 localPosition = new Vector3(1, 0, 0);

// 方法1:手动计算
Vector3 worldPosition1 = transform.position + transform.TransformDirection(localPosition);

// 方法2:TransformPoint 方法
Vector3 worldPosition2 = transform.TransformPoint(localPosition);

Debug.Log("方法1计算的世界坐标:" + worldPosition1);
Debug.Log("方法2计算的世界坐标:" + worldPosition2);
}
}

Unity 中计算两个向量之间的夹角

请说出两种方式

方法 1:使用 Vector3.Angle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using UnityEngine;

public class AngleCalculation : MonoBehaviour
{
void Start()
{
Vector3 vec1 = new Vector3(1, 0, 0);
Vector3 vec2 = new Vector3(0, 1, 0);

// 计算夹角
float angle = Vector3.Angle(vec1, vec2);

Debug.Log("夹角为:" + angle); // 输出: 夹角为:90
}
}

方法 2:使用点乘和反三角函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;

public class AngleCalculation : MonoBehaviour
{
void Start()
{
Vector3 vec1 = new Vector3(1, 0, 0);
Vector3 vec2 = new Vector3(0, 1, 0);

// 计算点乘结果
float dotProduct = Vector3.Dot(vec1.normalized, vec2.normalized);

// 使用反三角函数计算弧度
float radians = Mathf.Acos(dotProduct);

// 弧度转为角度
float angle = radians * Mathf.Rad2Deg;

Debug.Log("夹角为:" + angle); // 输出: 夹角为:90
}
}

🟡 Unity 中点乘和叉乘对于我们来说的作用是什么?

点乘是两个向量相对应的分量相乘,再将这些乘积相加得到的标量值。

计算两个向量的夹角:点乘的结果和两个向量的夹角有关。通过点乘结果可以判断向量之间的夹角是锐角、直角还是钝角。如果点乘结果为正,夹角为锐角;为零,夹角为直角;为负,夹角为钝角。
投影长度计算:点乘可以用来计算一个向量在另一个向量方向上的投影长度。
光照计算:在光照计算中,用点乘来计算光线和法线之间的角度,从而确定光照强度。
判断对象的方位:点乘可以用来判断两个向量的方位关系。当两个向量同向时,点乘结果为正;当两个向量反向时,点乘结果为负;当两个向量垂直时,点乘结果为零。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using UnityEngine;

public class DotProductExample : MonoBehaviour
{
void Start()
{
Vector3 a = new Vector3(1, 0, 0);
Vector3 b = new Vector3(0, 1, 0);

// 计算点乘
float dotProduct = Vector3.Dot(a, b);

Debug.Log("点乘结果: " + dotProduct); // 输出: 点乘结果: 0
}

}

叉乘是两个向量相乘得到的结果向量,垂直于这两个向量组成的平面。

计算法向量:叉乘常用于计算两个向量组成平面的法向量,这在碰撞检测和物理计算中非常重要。
确定方向:在某些计算中,叉乘可以用来确定方向,例如在相机的方向计算中。
面积计算:叉乘结果向量的长度等于两个向量组成的平行四边形的面积。
得到两向量之间的左右位置关系:在某些情况下,叉乘可以用来确定两个向量的左右位置关系,例如在相机的方向计算中,可以利用叉乘判断目标物体相对于相机的位置关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using UnityEngine;

public class CrossProductExample : MonoBehaviour
{
void Start()
{
Vector3 a = new Vector3(1, 0, 0);
Vector3 b = new Vector3(0, 1, 0);

// 计算叉乘
Vector3 crossProduct = Vector3.Cross(a, b);

Debug.Log("叉乘结果: " + crossProduct); // 输出: 叉乘结果: (0.0, 0.0, 1.0)
}
}

transform.forward 和 Vector3.forword 的区别

Vector3.forward:始终是 (0, 0, 1)。
可以认为是世界坐标系的 Z 轴朝向。

transform.forward:是当前物体的局部坐标系的 Z 轴在世界坐标系下的朝向。
可以认为是物体自己的 Z 轴朝向。

🟡 四元数相乘的作用以及四元数乘以向量的作用

当两个四元数相乘时,其效果相当于将两个旋转进行叠加。换句话说,四元数相乘会将第一个旋转的结果再应用上第二个旋转,这对于需要连续旋转的计算非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using UnityEngine;

public class QuaternionMultiplicationExample : MonoBehaviour
{
void Start()
{
Quaternion rotation1 = Quaternion.Euler(0, 30, 0); // 旋转30度
Quaternion rotation2 = Quaternion.Euler(0, 45, 0); // 再旋转45度

Quaternion combinedRotation = rotation1 * rotation2; // 叠加旋转

Debug.Log("Combined Rotation: " + combinedRotation.eulerAngles); // 输出: (0, 75, 0)
}
}

当四元数与向量相乘时,其效果是将向量按照四元数所表示的旋转进行旋转。这对于需要将对象朝特定方向旋转的计算非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using UnityEngine;

public class QuaternionVectorExample : MonoBehaviour
{
void Start()
{
Quaternion rotation = Quaternion.Euler(0, 90, 0); // 旋转90度
Vector3 direction = new Vector3(1, 0, 0); // 原始向量

Vector3 rotatedDirection = rotation * direction; // 旋转向量

Debug.Log("Rotated Direction: " + rotatedDirection); // 输出: (0, 0, 1)
}
}

是不是所有矩阵都有逆矩阵?

如何计算一个矩阵的逆矩阵?

齐次坐标是什么?

对于我们有什么作用?

正交矩阵的基本概念是什么?

它对我们来说有什么意义?

Unity 中使用的是左手还是右手坐标系?我们需要注意什么?

Unity 底层原理

Unity 使用 IL2CPP 打包时,我们应该注意什么?如何避免(可以举例说明)

在使用 IL2CPP 进行 Unity 打包时,需要特别注意代码裁剪问题。IL2CPP 会自动将认为不会被使用的代码裁剪掉,这可能导致在运行时出现异常或错误,特别是在使用 Lua 等脚本语言时。

设置打包时的裁剪等级:Unity 提供了不同的裁剪等级选项,如 Strip Assemblies、Strip ByteCode 等。通过设置适当的裁剪等级,可以控制裁剪的严格程度,避免不必要的代码被裁剪。

通过 xml 文件配置明确规定哪些内容不裁剪:可以通过自定义的 xml 文件配置明确指定哪些代码不应该被裁剪掉。这样可以确保重要的代码不会被误删。

在静态方法中显示调用不想被裁剪的内容:通过在静态方法中显式地调用不想被裁剪的内容,可以告诉 IL2CPP 编译器这部分代码是需要保留的,不要进行裁剪。

使用反射时:举例说明,假设我们使用 Lua 开发某个功能,在 Lua 脚本中调用了 Unity 的 API,但 IL2CPP 可能会将这些在 Lua 中被调用但在 C#中未直接引用的 API 裁剪掉。为了避免这种情况,我们可以设置合适的裁剪等级,或在相关的静态方法中显式调用这些 API,以确保它们不会被裁剪。

🟡 请简要说明 .NET 跨语言原理

在 Unity 中,.NET 跨语言原理基于 CLI(Common Language Infrastructure,公共语言基础结构)的规范。下面是简要的说明:

.NET 制定了 CLI 的规则,该规则定义了在 .NET 相关开发中不同编程语言之间的交互和互操作性。
根据 CLI 规范,不同的编程语言编写的源代码(例如 C#、VB.NET 等)都被编译为一种中间语言,称为 CIL(Common Intermediate Language,通用中间语言)。
因此,无论使用哪种语言进行开发,最终都会得到相同的中间代码。
中间代码由 CLR(Common Language Runtime,公共语言运行时,也称为 .NET 运行时)解释和执行。CLR 将中间代码转换为目标操作系统的本机机器码,然后在操作系统上运行。
这种跨语言原理使得在 Unity 中,不同语言编写的代码可以无缝地交互和调用,为开发者提供了更大的灵活性和选择余地。

🟡 请简要说明 .NET 跨平台原理

在 Unity 中,.NET 的跨平台原理是基于 CLI(Common Language Infrastructure,公共语言基础结构)和 CLR(Common Language Runtime,公共语言运行时)的特性实现的。下面是简要的说明:

.NET Framework 利用 CLI 和 CLR 实现了跨语言的能力。CLI 规范定义了中间语言(CIL)以及规则,而 CLR 负责将中间语言翻译为目标操作系统的本地代码,并在目标平台上执行。
.NET Core 和 Mono 是针对不同操作系统的实现,它们利用了 CLR 的特性,为每个操作系统实现了对应的 CLR(也称为公共语言运行时或 .NET 虚拟机)。
当使用 .NET Core 或 Mono 在不同操作系统上运行时,对应的 CLR 将中间语言(IL)翻译为目标系统可以执行的本机代码(机器码),从而实现了跨平台的目标。
这种跨平台的原理使得 Unity 中使用 .NET 编写的代码可以在不同操作系统上无缝运行,为开发者提供了更大的灵活性和可移植性。

Unity 图形学 Shader

OpenGL 和 DX 的最大区别是什么?

Shader 当中的 Blend 渲染命令主要用来干什么?

Shader 当中的 Blend 渲染命令后面跟的参数是用来干嘛的?

比如:Blend SrcAlpha OneMinusSrcAlpha

Shader 和材质球的关系是什么?

Unity 中线性颜色空间和伽马颜色空间的主要区别是什么?

为什么线性的表现效果更好,Unity 默认还是使用的伽马呢?

Unity Shader 中,深度测试是在做什么?

Unity Shader 中某片元通过了深度测试,但是没有开启深度写入,该片元的颜色信息是否写入到颜色缓冲区?

Shader 当中的顶点和片元着色器有什么作用?

在 Unity 中,什么是 Shader?它有什么作用,以及如何编写一个基本的 Shader?

解释一下 Unity 中的渲染管线(Rendering Pipeline)是什么,如何使用它,并举例说明它在游戏开发中的应用场景。

Unity 中的渲染管线是指一系列的渲染步骤,用于将场景中的 3D 模型转换为屏幕上的可视图像。主要包括以下步骤:

几何图形的准备:将场景中的几何图形转换为渲染引擎可以理解的形式,例如将 3D 模型转换为网格数据(Mesh)和材质信息。

光照计算:计算场景中每个几何图形的光照效果,包括直接光照和间接光照。

视点变换:根据摄像机的位置和方向将场景中的几何图形转换为摄像机的视图空间(View Space)坐标系下的形式。

投影变换:将摄像机的视图空间坐标系下的几何图形转换为投影坐标系下的形式。

图像空间计算:将投影坐标系下的几何图形转换为屏幕上的像素坐标。

着色:根据材质信息和光照信息对几何图形进行着色,计算每个像素的颜色值。

合成:将所有的像素颜色值按照一定的顺序合成为最终的图像,输出到屏幕上。

在 Unity 中,渲染管线是由 Unity 引擎内部实现和控制的,开发者可以通过设置渲染相关的参数和使用着色器来定制渲染效果。渲染管线的应用场景非常广泛,包括但不限于游戏场景的渲染、特效的表现、UI 界面的绘制等。

Unity 中的光照贴图的作用是什么?

渲染管线中的几何阶段是由 CPU 主导还是 GPU 主导?该阶段主要是在做什么?

Shader 开发中的坐标空间变换,主要是在哪几个空间中进行变换?变换顺序是什么?

Unity 目前版本中创建的普通项目、URP 项目、HDRP 项目的区别是什么?

Unity 中场景中一个处于激活状态的物体(场景上只有这一个物体),不能被摄像机渲染出来,可能有几种情况?(至少说出 3 种可能的情况)

Unity 发布后的应用程序的美术表现效果比在编辑器中看起来差,可能原因有哪些?

什么是纹理映射?

Unity 网络

使用 UnityWebRequest 加载音效文件,应该使用什么 API?

UnityWebRequest 可以用来做什么?

网络通讯中分包黏包指的是什么?

我们应该如何解决这些问题?

TCP 和 UDP 通讯最大的区别是什么?

如果想要让 UDP 通讯具备 TCP 的优点,应该如何处理?

游戏开发中,客户端和服务端交互数据,程序中常用方式是什么?

Unity 多平台

Unity 在发布 Android 平台项目时,

在加载 Application.streamingAssetsPath 中文件时我们应该注意什么?

Unity 中安卓主流的纹理压缩格式 ETC 和 ETC2 的主要区别是什么?

Android 平台常用压缩格式 ETC 不支持透明通道,那我们的半透明纹理应该如何处理?

Unity 中针对 IOS 平台我们使用的主流纹理压缩格式是什么?

Unity 中如何调试排查 Android 上运行的项目问题

如果不考虑 IOS 平台,只在 Windows 和 Android 平台上发布游戏,如何在不使用第三方热更新方案的前提下实现热更新功能

在 Android 平台上运行的项目出现问题,我们有几种调试的方式?

 (至少说出 3 种方案,不使用第三方插件)

Unity 数据持久化

请说出 Unity 中如何进行数据持久化,至少说出 5 种方式

Untiy 中的 PlayerPrefs 支持存储什么类型的数据?

 为什么我们一般不会使用它来制作角色数据存档功能?

在进行数据持久化时(存档、数据存储等功能时)

如果使用 Unity 中的 JsonUtility(Json)
C#中的 BinaryFormatter(2 进制)和 XmlSerializer (xml)
这些公共类进行序列化和反序列化时,如果在反序列化时,对应的数据结构类发生变化了,是否影响数据的读取?

Unity 动画 模型 寻路

IK(逆运动学)可以帮助我们完成什么功能?

Unity 中为 Sprite 前后关系排序的常用方式有哪些?(至少说出 3 种)

你之前做过一些项目 那么一般美术同学提供给我们的美术资源,一般分为哪几类?

美术同学提供给我们的模型数据中,包含哪些关键数据?(至少说出 3 点)

Unity 中想要制作角色的连招功能,在制作状态机时我们一般如何处理?

在 Unity 中制作角色的连招功能时,我们通常通过配置状态机和添加条件来实现。

状态机条件设置:添加一个 Trigger 类型的条件,用于触发连招动作。添加一个 Int 类型的条件,用于记录连招的计数。

实现逻辑:当攻击按键被输入时,触发动作并增加攻击计数。每次按键输入时,重新进行攻击计数并设置延迟清零,以允许玩家在短时间内连续输入多次攻击指令来触发连招。

Unity 中如果想要在动作的某一时刻进行伤害检测,我们应该怎么做?(请说出两种做法)

Unity 中想要制作自动寻路逻辑,我们应该怎么做?(请至少说出两种做法)

FSM(有限状态机) 和 BT(行为树)

他们是用来处理什么的?

Unity 中的 Lerp 和 Slerp 分别是什么?

不同后缀的各种文件的本质是什么?

请解释 Unity 中的 Prefab 是什么,以及它在游戏开发中的作用是什么?

请简述一下 Prefab(预制体)的本质是什么?

Prefab 的本质是一个配置文件,它记录了一个 GameObject 对象的所有信息。

Prefab 中详细记录了 GameObject 对象上挂载的所有组件,包括 Transform、Renderer、Collider 以及脚本组件等。同时还记录了每个组件中的所有可配置属性信息。这包括每个脚本组件中的变量值、组件的启用状态、Transform 的位置信息等。

Prefab 允许开发者在项目中反复使用同一个 GameObject 配置,从而避免重复创建相同的对象。
一致性:

使用 Prefab 可以确保多个实例的一致性。如果需要修改对象的配置,只需修改 Prefab 资源,所有实例会自动更新。
简化场景管理:

Prefab 使得场景管理更加简化,可以在运行时动态加载、生成和销毁 GameObject,提高开发效率。

Unity 开发问题

如何在 Unity 中实现多语言支持?

(不同国家的人,看到的游戏内的语言是不一样的)

网络游戏中,有一个数据统计界面,这些数据是由最近 1000 场战斗计算出来的平均数据

你认为以下处理方式合理吗?如果不合理,应该如何改进?我们通过向后端请求这 1000 场战斗的数据,然后在客户端计算相关平均数据,更新显示到统计界面上

如果在 Unity 当中制作 FPS 游戏,如何模拟枪械开枪时的后坐力

如果你要开发一个项目 Assetbundle 和 Addressables 你会如何选择?

该 Unity 中的报错是什么意思?如何定位该问题?我们一般如何排查解决该问题?(至少说出 2 种方案)

游戏编辑器(比如 角色编辑器、关卡编辑器、地图编辑器等工具)的本质是什么?