最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
unity3d面试题及答案
1. 请描述游戏动画有哪几种,以及其原理
主要有以下三种游戏动画:
- 关节动画:把角色分成若干独立部分,每个部分对应一个网格模型,各部分的动画连接成一个整体的动画。这种动画方式使角色比较灵活,例如在Quake2中就使用了这种动画。
- 单一网格模型动画(关键帧动画):由一个完整的网格模型构成。在动画序列的关键帧里记录各个顶点的原位置及其改变量,然后通过插值运算实现动画效果,能让角色动画较为真实。
- 骨骼动画:这是一种广泛应用的动画方式,集成了关节动画和单一网格模型动画的优点。骨骼按角色特点组成一定的层次结构,由关节相连,可做相对运动。皮肤作为单一网格蒙在骨骼之外,决定角色的外观。皮肤网格的每一个顶点都会受到骨骼的影响,从而实现完美的动画。
2. Alpha Blend工作原理
Alpha Blend用于实现半透明效果。其计算公式为:Color = (源颜色 源系数) OP (目标颜色 目标系数)。其中OP(混合方式)有加、减、反减、取最小、取最大等操作。
3. 写光照计算中的Diffuse的计算公式
漫反射光(Diffuse)计算公式
漫反射光的计算公式为:$I{diffuse} = D{intensity} D_{color} (N \cdot L)$。其中,$D{intensity}$表示漫反射强度,$D{color}$表示漫反射光颜色,$N$为该点的法向量,$L$为光源向量。
3D渲染中物体表面光照计算公式
在3D渲染中,物体表面的光照计算公式为:$I = I{ambient} + I{diffuse} + I_{specular}$。
- 环境光(Ambient)计算公式:$I{ambient} = A{intensity} * A{color}$,其中$A{intensity}$表示环境光强度,$A_{color}$表示环境光颜色。
- 漫反射光(Diffuse)计算公式:同上文,$I{diffuse} = D{intensity} D_{color} (N \cdot L)$。
- 镜面光照(Specular)计算公式:$I{specular} = S{intensity} S_{color} (R \cdot V)^n$,其中$S{intensity}$表示镜面光照强度,$S{color}$表示镜面光颜色,$R$为光的反射向量,$V$为观察者向量。
简化公式
将一些值合并,并使用白色作为光照颜色,则上述公式可简化为:$I = A + D * (N \cdot L) + (R \cdot V)^n$。
4. LOD是什么,优缺点是什么
LOD技术即Levels of Detail的简称,意为多细节层次。该技术根据物体模型的节点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。
优点
提高渲染效率,在不显著影响视觉效果的前提下,减少了不必要的计算量,提升游戏性能。
缺点
- 增加了模型管理的复杂度,需要为不同细节层次的模型进行维护和切换处理。
- 如果细节层次切换不恰当,可能会出现画面突变的情况,影响视觉体验。
5. 两种阴影判断的方法工作原理
此处题目表述不够清晰,常见的阴影生成方法有基于阴影映射(Shadow Mapping)和基于体素的阴影等。
- 阴影映射(Shadow Mapping):先从光源的视角渲染场景,记录场景中每个可见点到光源的距离,存储在深度纹理(阴影贴图)中。然后从摄像机视角渲染场景,对于每个像素,计算其在光源视角下的深度,并与阴影贴图中的深度进行比较。如果该像素的深度大于阴影贴图中的深度,则该像素处于阴影中。
- 基于体素的阴影:将场景离散化为体素,通过对体素的处理来确定阴影的范围。这种方法可以处理复杂的阴影效果,但计算量较大。
6. Vertex Shader是什么?怎么计算?
顶点着色器(Vertex Shader)是图形渲染管线中的一个阶段,用于处理每个顶点的位置、颜色、法线等属性。它接收顶点数据作为输入,对其进行变换和计算,然后输出变换后的顶点数据。
顶点着色器的计算通常包括以下几个方面:
- 顶点变换:将顶点从模型空间转换到齐次裁剪空间,通常使用模型 - 视图 - 投影矩阵(MVP矩阵)进行变换。
- 法线变换:对顶点的法线进行变换,以保证光照计算的正确性。
- 光照计算:在顶点着色器中可以进行简单的光照计算,如漫反射和环境光的计算。
以下是一个简单的顶点着色器代码示例(使用GLSL语言):
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 Normal;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
Normal = mat3(transpose(inverse(model))) * aNormal;
}
7. MipMap是什么?作用?
在三维计算机图形的贴图渲染中,Mipmapping是一种常用的技术。为了加快渲染速度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件,这样的贴图被称为MIP map或者mipmap。
作用
- 提高渲染速度:在远距离观察物体时,使用低分辨率的Mipmap可以减少纹理采样的计算量,从而提高渲染效率。
- 减少图像锯齿:通过在不同距离使用合适分辨率的Mipmap,可以避免因纹理采样不足而产生的锯齿现象,提升图像质量。
8. 用U3D实现2D游戏,有几种方式?
使用Unity本身的GUI
可以利用Unity的GUI系统来创建2D界面和元素,实现简单的2D游戏。
将摄像机的Projection调成Orthographic
将摄像机的Projection属性设置为Orthographic(正交投影),此时物体的Z轴不影响其在屏幕上的显示大小,可用于实现2D游戏。
使用Sprite Renderer
Unity提供了Sprite Renderer组件,专门用于渲染2D精灵,结合Sprite Editor可以方便地创建和管理2D图形。
使用2D Toolkit等插件
借助第三方插件可以更高效地实现2D游戏开发,提供了更多的功能和工具。
9. U3D中碰撞器和触发器的区别?
- 碰撞器(Collider):当IsTrigger属性设置为false时,物体之间会产生碰撞效果。可以调用OnCollisionEnter、OnCollisionStay、OnCollisionExit函数来处理碰撞事件。
- 触发器(Trigger):当IsTrigger属性设置为true时,物体之间不会产生实际的碰撞效果,但可以检测到物体的进入、停留和离开。可以调用OnTriggerEnter、OnTriggerStay、OnTriggerExit函数来处理触发事件。
10. 物体发生碰撞的必要条件
其中至少一个物体(运动的)必须带有碰撞器(Collider)和刚体(Rigidbody)或者CharacterController,另一个物体也必须至少带有碰撞器。
11. CharacterController和Rigidbody的区别
- CharacterController:自带胶囊碰撞器,内部封装了一些刚体的功能,但它不是真正的刚体。它更适合用于角色的移动控制,例如在平台游戏中控制角色的行走、跳跃等动作。
- Rigidbody:是真正的刚体组件,使物体带有物理特性,会受到重力、力的作用,遵循物理定律进行运动。
12. 物体发生碰撞时,有几个阶段,分别对应的函数
物体发生碰撞时,有三个阶段,分别对应以下函数:
- 进入碰撞阶段:OnCollisionEnter函数,当两个物体开始碰撞时调用。
- 碰撞持续阶段:OnCollisionStay函数,在两个物体保持碰撞状态时持续调用。
- 离开碰撞阶段:OnCollisionExit函数,当两个物体结束碰撞时调用。
13. U3D中,几种施加力的方式,描述出来。
在Unity中,可以使用Rigidbody组件的以下方法施加力:
- AddForce:向刚体施加一个力,力的方向和大小可以通过参数指定。例如:
rigidbody.AddForce(Vector3.forward * 10f);表示向正前方施加一个大小为10的力。 - AddForceAtPosition:在指定位置向刚体施加一个力,除了力的方向和大小外,还需要指定力的作用点。
14. 什么叫做链条关节
链条关节(Hinge Joint)可以模拟两个物体间用一根链条连接在一起的情况。它能保持两个物体在一个固定距离内不相互移动而不产生作用力,但是达到固定距离后就会产生拉力。
15. 物体自旋转使用的函数叫什么
可以使用transform.Rotate函数来实现物体的自旋转。例如:transform.Rotate(Vector3.up * Time.deltaTime * 30f); 表示物体绕Y轴以每秒30度的速度旋转。
16. 物体绕某点旋转使用函数叫什么
可以使用transform.RotateAround函数来实现物体绕某点旋转。该函数需要指定旋转中心、旋转轴和旋转角度。例如:transform.RotateAround(Vector3.zero, Vector3.up, 30f); 表示物体绕原点绕Y轴旋转30度。
17. U3D提供了一个用于保存读取数据的类(PlayerPrefs),请列出保存读取整形数据的函数
保存整形数据
PlayerPrefs.SetInt("CoinNum", 100); 该函数用于将整数100保存到键为"CoinNum"的位置。
读取整形数据
int coinNum = PlayerPrefs.GetInt("CoinNum"); 该函数用于从键为"CoinNum"的位置读取整数数据。
18. Unity3D提供了几种光源,分别是什么
Unity3D提供了以下几种光源:
- Directional Light(平行光):模拟远距离的光源,如太阳,光线是平行的。
- Point Light(点光源):从一个点向四周发射光线,如灯泡。
- Spot Light(聚光灯):从一个点向一个锥形区域发射光线,如舞台上的聚光灯。
- Area Light(面光源):模拟具有一定面积的光源,在实时渲染中使用较少。
19. Unity3D从唤醒到销毁有一段生命周期,请列出系统自己调用的几个重要方法。
Unity3D的生命周期中系统自动调用的重要方法顺序如下: Awake --> Start --> Update --> FixedUpdate --> LateUpdate --> OnGUI --> Reset --> OnDisable --> OnDestroy
20. 物理更新一般在哪个系统函数里?
物理更新一般在FixedUpdate函数里进行。FixedUpdate每固定帧绘制时执行一次,与Update不同的是,FixedUpdate是基于渲染帧执行的。如果渲染效率低下,FixedUpdate的调用次数不会受到影响,它比较适用于物理引擎的计算,因为物理计算需要稳定的时间间隔。而Update则比较适合做控制,如处理用户输入等。
21. 移动相机动作在哪个函数里,为什么在这个函数里。
移动相机动作通常在LateUpdate函数里进行。LateUpdate在每帧执行完毕后调用,它是在所有Update结束后才执行,比较适合用于命令脚本的执行。例如在摄像机跟随角色的场景中,在所有Update操作完成后再移动摄像机,可以避免出现摄像机已经推进了,但视角里还未有角色的空帧现象。
22. 当游戏中需要频繁创建一个物体对象时,我们需要怎么做来节省内存。
可以使用对象池(Object Pooling)技术来节省内存。对象池的原理是预先创建一定数量的物体对象,将它们存储在一个池中。当需要使用物体时,从池中取出;使用完毕后,将物体放回池中,而不是销毁它。这样可以避免频繁的创建和销毁对象所带来的内存开销。
23. 一个场景放置多个Camera并同时处于活动状态,会发生什么
当一个场景中放置多个Camera并同时处于活动状态时,游戏界面可以看到多个摄像机的混合画面。可以使用以下方法来控制摄像机的显示:
- Depth(深度):每个摄像机都有一个Depth属性,值越大的摄像机越后渲染,会覆盖在值较小的摄像机的画面之上。
- Layer(层)+ Culling Mask:通过设置摄像机的Culling Mask,可以指定摄像机只渲染某些层的物体,从而实现不同摄像机渲染不同部分的场景。
- Enable = false/true:通过启用或禁用摄像机的
enabled属性来控制摄像机是否工作。
24. 简述Prefab的用处和环境
Prefab(预制体)在实例化的时候用到,主要用于经常会用到的物体。使用Prefab的好处是可以方便地修改物体的属性,当修改Prefab时,所有基于该Prefab实例化的物体都会自动更新。适用于需要大量重复使用相同或相似物体的场景,如游戏中的敌人、道具等。
25. 如何销毁一个UnityEngine.Object以及其子类
可以使用Destroy函数来销毁一个UnityEngine.Object以及其子类。例如:Destroy(gameObject); 用于销毁一个游戏对象。
26. 为什么U3D会出现组件上数据丢失的情况
一般是组件上绑定的物体对象被删除了,或者引用的资源被移动、重命名等操作,导致组件无法找到对应的资源,从而出现数据丢失的情况。
27. U3D下如何安全的在不同工程迁移Asset数据
方法一
可以把assets目录和Library目录一起迁移,但这种方法可能会导致项目文件过大,且迁移过程中可能会出现一些兼容性问题。
方法二
导出包(.unitypackage),在目标工程中导入该包。这种方法可以方便地迁移特定的资源,并且可以避免一些不必要的文件迁移。
方法三
使用Unity带的Assets Server功能,通过网络共享和管理资源,实现资源的安全迁移。