在UI上显示模型无非就是2种。
1.在两个UI摄像机中夹一层3d摄像机,利用摄像机的Viewport Rect属性对模型进行裁切。
2.使用RenderTexture渲染在RawImage后显示在UI上。
我上一个项目就是采取第一种方法,用起来很不舒服。因为有很多效果都做不了,比如就是UI上盖模型,在盖UI,再盖模型这种,还有就是在滑动列表中显示模型,滑动裁切的话都很麻烦。
今天我想说的就是第二种,使用RenderTexture的方式来渲染模型。
先说缺点:
1.为了保证显示上的效果RenderTexture的文件区域必须大于RawImage的区域,我们目前用的是乘2倍。比如RawImage的区域是512X512,那么就得创建一个1024X1024大小的RenderTexture才能保证渲染效果。
2.如果人物身上有一些特殊的效果,比如outline描边这样的,放在RenderTexture上就是达不到效果。
3.如果模型身上带有AlphaBlend这样的特效,因为AlphaBlend要和背景做混合,而RenderTexture不像Camera那样有背景,显示上就会有问题。(下面我会说我目前是怎么解决的)
优点的话,就很爽了。完全和UI一样,层级顺序,列表中显示模型、裁切、等等都很方便了。
RenderTexture显示AlphaBlend特效的方法
因为AlphaBlend特效需要和背景做混合,所以我们可以给它后面垫一个底图。这样就能解决在RenderTexture上显示带AlphaBlend的特效的模型。
创建一个Sprite 可以直接把UI的Sprite放上去。如果模型带特效就用Sprite2d,如果模型不带特效,完全可以用之前UI的制作方式,很方便灵活的切换它。
如下图所示,Game视图中显示的效果,这个翅膀的火焰特效就是alphablend
如下图所示,因为底图不止一张,大家看到下面还有好几张花纹了吗?都可以用Sprite2d叠在下面。
渲染RenderTexture的摄像机,这里已经能看出来渲染的是正确的,下面被水印挡住了 图片尺寸是1401*540 ARGB32 4.3M。为什么尺寸这么大呢?上面我也提过,因为RenderTexture尺寸和RawImage一样的话,效果会比较差,所以这里乘了2倍。
这样问题来了,摄像机的大小或者fov变了,那岂不是每次都要手动去把sprite的size对齐,手动设置localScale。这样就太麻烦了。
下面我再给大家分享一个脚本,正交或者非正交摄像机都支持的。自动根据摄像机的区域来自动自适应计算sprite的size 。(这个脚本挂在Sprite上即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SpriteFull : MonoBehaviour { //设置SpriteRender和摄像机的距离 public float distance = 1.0f; private SpriteRenderer spriteRenderer = null; void Start() { spriteRenderer = GetComponent<SpriteRenderer> (); spriteRenderer.material.renderQueue =2980; //这段代码非常重要!!!大家务必要加上,不然透明的渲染层级会出错 } void Update() { Camera camera = Camera.main; camera.transform.rotation = Quaternion.Euler (Vector3.zero); float width = spriteRenderer.sprite.bounds.size.x; float height = spriteRenderer.sprite.bounds.size.y; float worldScreenHeight,worldScreenWidth; //这里分别处理正交和非正交摄像机 if (camera.orthographic) { worldScreenHeight = Camera.main.orthographicSize * 2.0f; worldScreenWidth = worldScreenHeight / Screen.height * Screen.width; } else { worldScreenHeight = 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad); worldScreenWidth = worldScreenHeight * camera.aspect; } transform.localPosition = new Vector3 (camera.transform.position.x, camera.transform.position.y, distance); transform.localScale = new Vector3 (worldScreenWidth / width, worldScreenHeight / height, 0f); } } |
上面有段代码非常重要,切记一定要设置sprite的renderQueue ,因为ui是3000这里和UI不一样就行,不然透明会显示错误。
最后,垫在模型下面可能一张图是不够的,可能还有一些花纹,可能还有花纹需要镜像等,这样的图片就得需要手动设置一下缩放和位置了。
OK 大家如果有疑问欢迎再下面给我留言,继续干活了~
- 本文固定链接: https://www.xuanyusong.com/archives/4318
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
RenderTexture方式渲染模型,感觉在低端机效率不行呢?特别是开了抗锯齿,掉帧严重。请问有什么办法优化吗?
你好,我想请教下,如果用了rendertexture的方法,又想点了模型的不同位置(比如头部,手臂等)有不同的响应,应该怎么处理不叫合适呢?
可以发送射线, 用看模型的 3D摄像机发射线 就可以 判断点在不同的位置上了
好的,谢谢
momo大神,对于一个UI上有多个模型的情况,我要创建多个相机吗? 就像你说的那样 ui上放模型 在盖一个ui 上面还有模型 就是游戏那种查看其它玩家装备 和自己装备的对比 2个UI都显示模型的
可以用一个摄像机看多个模型, 站了一排 模型 角色
背后放一张图片确实行,但是策划需求背景是透明的…
momo大神,是不是可以用UGUI的canvas的第三种渲染方式,让模型在物理方位上在UI的前面,这样也可以让模型和UI混合显示。但是有个问题,比如模型要求必须用透视摄像机,这样还得有个透视摄像机,并
momo大神,对于一个UI上有多个模型的情况,我要创建多个相机吗?
使用RenderTexture碰到一个问题,如果模型要超出背景图的区域,这种情况下怎么处理呢?
刚接触U3D 最近在做粒子特效与UI层级的关系的问题时也遇到了这个问题,上面的那个脚本23行会报错, NullReferenceException:Object reference not set to an instance of an object.有可能是哪里使用有错误吗
最近在做这块需求,可以直接通过shader去实现混合效果,也很方便。。。
1.修改 Sprites-Default shader,去掉 c.rgb *= c.a;
2.将渲染模型摄像机的颜色置为黑色,alpha值设为0
这样就可以了。
因为默认摄像机的alpha值为5,遇到alpha混合特效的时候基本就看不见了,而调整渲染摄像机确保背景是透明的。。
我测试的效果,并不能解决问题,使用AlphaBend的特效和背景叠加的时候仍然会有显示问题
哈哈哈,测试可用
亲测可用,另外混合模式改为Blend One One,相机颜色改为黑色透明很重要,要不然会叠加成白色
应该是 Blend One OneMinusSrcAlpha 才对.
推算下:
理论上的 Dest = Alpha(特效)*Color(特效) + (1-Alpha(特效))*Color(背景)
但实际上:
Dest(RT) = Alpha(特效)*Color(特效) + 0
Dest = Alpha(特效)*Dest(RT) + (1-Alpha(特效))*Color(背景),
因为乘了两次 Alpha(特效),所以导致特效表现很弱.
momo你好,请问通过RenderTexture显示的3D模型,能不能在3D模型上添加点击事件,我有尝试过在模型上添加EventTrigger事件,可能是因为RenderTexture的原因点击事件不管用,有没有什么很好的实现方式呢?
点在UI上就可以了吧。 如果策划比较矫情,那就只能用模型摄像机发射线了。
你好,我想对界面进行一个优化,当弹出一个界面的时候,把后面的静态界面渲染成一个Texture,但是我们canvas的模式是camera,所以只能选定一个相机,不能多出一个相机去渲染静态界面,有什么办法来解决这个问题吗?
可以创建多个摄像机。 我印象剑侠手机, 就是这个效果,打开UI后 背景变成一张图不动。。
不过后来我用了另外一种方式, 打开UI后 把主界面 以及所有失去焦点的(不可点击操作不需要的UI) 放在另外的一个层上,不让camera渲染。 并且关闭他们的点击事件,效率也还可以 而且也有很多手游都是这样做的。。
放到另一个层要变量界面所有子物体吗