Unity笔试题【20181025】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/itsxwz/article/details/83378045

1、简述delegate和event关键字
答:delegate 委托,是C#的一种类型,持有对某个方法的引用的类,能够拥有一个签名,引用只能与签名方法相匹配。实现:1、声明一个委托对象,与传递方法具有相同参数列表和返回值类型。2、创建委托对象,将要传递的函数作为参数传入。3、在实现异步调用地方,通过上一步创建对象调用方法。event 事件,在类中声明且生成,通过使用同一个类或其他类的委托与事件处理程序关联。包含事件的类用于发布事件,称为发布器(publisher)类;接受该事件的类称为订阅器(subscriber)类。事件使用发布-订阅模型。两者的区别:1、委托允许直接访问相应处理函数,事件只能通过公布的回调函数去调用。2、事件只能通过“+=”、“-=”方式注册和取消处理函数,委托除此之外还可以“=”直接赋值处理函数。

2、请列举Unity3D脚本生命周期的几个重要方法
答:Awake(){} 脚本唤醒,系统执行的第一个方法,用于脚本初始化,只执行一次。Start(){} 在Awake之后、Update之前执行,只执行一次。Update(){} 用于逻辑正常更新,每帧由系统自动调用一次。FixedUpdate(){} 固定更新。LateUpdate(){} 推迟更新,每帧调用,在Update之后调用。OnGUI(){} 绘制界面,每帧调用。OnDestroy(){} 当前脚本销毁时调用。

3、什么是AssetBundle?谈谈对AssetBundle内存分配情况的理解
答:可以把多个游戏对象或资源二进制文件封装到AssetBundle中,提供封装与解包的方法使用很方便。
在这里插入图片描述
加载资源三个步骤:
1、www/LoadFromFile/LoadFromMemory等接口加载AssetBundle本身
2、AssetBundle.LoadAsset()等接口从AssetBundle中加载资源
3、对于GameObject类资源,需要通过GameObject.Instantiate()创建Clone

黑色区域:www类本身占用内存,还保留了一份对WebStream数据的引用。使用www = null或www.dispose()释放。前者等待GC,后者立即释放。释放后WebStream引用计数会减一。

橙色区域:WebStream数据,数据真正的存储区域。AssetBundle被加载进来后,这部分内存就被分配了。包含三个内容:1、压缩后的AssetBundle本身。2、解压后的资源。3、一个解压缓冲区。www或AssetBundle对象都只是有一个结构指向了WebStream数据,从而对外部提供操作真正资源数据的方法。当WebStream数据引用为0时,系统会自动释放。为了不频繁的开辟和销毁解压Buffer,绿色Decompression解压缓冲区Unity会至少保留一份。

粉色区域:AssetBundle对象,引用WebStream数据部分,提供从WebStream数据中加载资源的接口。AssetBundle.Unload(bool unloadAllLoadedObjects)释放资源。AssetBundle.Unload(false)释放AssetBundle对象本身,可能引起WebStream释放,导致无法通过接口或依赖关系从该AssetBundle加载资源,但已加载资源可以正常使用。AssetBundle(true)不仅释放WebStream部分,所有被加载出来的资源将被释放。

红色部分:通过Instantiate()创建的GameObject所包含的资源。这些资源根据类型与AssetBundle原始资源(WebStream资源部分)有不同关系。如Texture、shader资源,通常只是使用,不会做出改动,所以仅仅是引用关系;每个GameObject是特殊的,所以是完全复制一份;Mesh和Material,则是引用+复制的关系。

4、什么是DrawCall,有什么方法可以减少DrawCall
答:CPU通过调用绘制命令来告诉GPU开始进行一个渲染过程(一次DrawCall)。
CPU方面减少DrawCall:
1、使用Draw Call Batching 、Dynamic Batching动态批处理
2、纹理打包成图集减少材质使用
3、少用反光、阴影
4、设置一个合适的Fixed Timestep
5、不要使用网格碰撞器(Mesh Collider)
6、大量或频繁的字符串连接操作一定要用StringBuilder
7、某些可能情况,使用结构体代替类
8、使用对象池重复利用空间
9、尽量不要用foreach,用for
10、不要直接访问GameObjcet的tag属性
11、不要频繁使用GetComponent,访问一次后保留其引用
12、使用OnBecameVisible()和OnBecameInVisible(),控制物体update()函数的执行减少开销
13、使用内建数组,如Vector3.zero而不是new Vector3(0,0,0)
14、使用ref关键字对方法的参数进行优化
15、关闭所有update中的log操作
16、不在update中调用GetComponent、SendMessage、FindWithTag等方法
17、不在update中使用临时变量

GPU方面减少DrawCall:
1、使用纹理图集代替一系列单独小贴图
2、保持材质数目尽可能少
3、如果使用纹理图集和共享材质,用Renderer.sharedMaterial代替Renderer.material
4、使用光照纹理(lightmap)而非实时灯光
5、使用LOD
6、使用mobile版的shader
7、尽可能减少顶点数、背面删减
8、压缩图片,减少显存带宽压力

5、谈谈你对u3d渲染管线的理解
答:渲染管线(Rendering Pipeline)就是GPU渲染。流程:顶点处理、面处理、光栅化、像素处理。顶点处理:通过一系列坐标系转换将模型顶点在摄像机前位移,最终投影到摄像机屏幕上(本地 - 世界 - 观察 - 投影)。包括顶点坐标变化、逐顶点雾化、材质属性和光照属性处理。面处理:面的组装、截取、剔除。光栅化:消除遮挡面;Texture Operation,根据像素纹理坐标查询对应纹理值;Blending,根据已经画好颜色与正在计算的颜色alpha值混合形成新颜色;Filtering,将正在计算的颜色经过某种滤镜后输出,该阶段后像素的颜色值被写入帧缓存中。像素处理:对每个像素区域着色,对像素贴上贴图形成最终画面。

6、什么是material,什么是shader,二者有什么关系
答:材质系统定义了如何渲染物件表面信息。shader里面使用材质信息加自身操作,最终呈现物体渲染。shader是material一部分,是根据计算即时演算生成贴图的程序,叫着色器。常用处理无法用固定贴图表现的模型。material是模型的材质,包含贴图、shader、顶点、凹凸等信息。

7、简述单例模式和观察者模式,并用伪代码实现其中之一
答:单例模式:

public class Singleton{
	private static Singleton instance;
	private static readonly object locker = new object();
	private Singleton(){}
	public static Singleton GetInstance{
		get{
			if(instance == null){
				lock(locker){
					if(instance == null){
						instance = new Singleton();
					}
				}
			}
			return instance;
		}
	}
}

观察者模式:

public class Observer{
	public delegate void ObserverDelegate();
	public event Observer ObserverEvent;
	public void Function(){
		ObserverEvent();//调用所有注册对象
	}	
}

public class Test{
	public void Show(){
		Console.WriteLine("Test");
	}
}

public class Display{
	public static void ShowMsg(){
		Console.WriteLine("Display");
	}
}

static void Main(string[] args){
	Observer ob = new Observer();
	Test alarm = new Test();
	ob.ObserverEvent += Test.Show;//注册方法
	ob.ObserverEvent += (new Test()).Show;//注册匿名对象的方法
	ob.ObserverEvent += Display.ShowMsg;//注册静态方法
	ob.Function();//自动调用注册过的对象的方法
}

猜你喜欢

转载自blog.csdn.net/itsxwz/article/details/83378045