关于shader:编辑器在编译Shader时的报错疑问

29次阅读

共计 3298 个字符,预计需要花费 9 分钟才能阅读完成。

1)编辑器在编译 Shader 时的报错疑难
​2)对于图片大小和包体大小的疑难
3)对于合图和合批是否会升高带宽的疑难
4)URP 下,如何优化多相机渲染时的 Cull 耗时


这是第 312 篇 UWA 技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫 10 分钟,认真读完必有播种。

UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

Shader

Q:有时在 Shader 编写过程中,咱们可能会用到十分多纹理,如果每个纹理都采纳相似 uniform sampler2D \_Mask;的形式进行申明,编辑器在编译 Shader 的时候就会报错:

Shader error in‘CloudShaow/MaskBlend’: maximum ps_4_0 sampler register index (16) exceeded at line 69 (on d3d11)

A1:OpenGL ES2.0 中,单个 Shader 最多反对 8 个贴图;OpenGL ES3.0 中,单个 Shader 最多反对 16 个贴图。没方法,这是硬件限度,你只能缩小贴图数量。

比方,把几个 2D Texture 合成 2D Array Texture。或者,依据不同的 Keyword,拜访不同的贴图,然而要保障,贴图使用量最多的变体,合乎下面的要求。

感激王烁 @UWA 问答社区提供了答复

A2:以前的写法,参考这个:
https://blog.csdn.net/weixin_…

当初的写法,只定义一个 Sampler,传参数的时候共用这一个就行:

感激仇磊 @UWA 问答社区提供了答复

Resource

Q:对于图片大小和包体大小的疑难。

例如,一张图片,理论大小是 1KB,放到 Unity 里是 10KB(依据不同的压缩格局不一样),打包后查看 Editor Log 说图片占用了包体 10KB。查了很多文章都说 Unity 打包的时候,会把图片按设定的压缩格局转成 Unity 的图片格式,但理论打出的包不是增长 10KB,而是图片理论大小 1KB,这个 10KB 是内存大小。

到底这个包体大小与图片大小的关系是怎么的?如何查看理论的包体资源形成?

A1:jpg 和 png 领有良好的压缩率,也就是你所看到的 1KB 的图片。然而这 2 种格局不反对随机读取,所以引擎会帮你转换成反对随机读取的格局,会比原来的图片大一点,存储也是依照新格局来存储的。包体形成如果是 AssetBundle 或者全都放在 Resource 目录下,就能够通过 AssetStudio 进行解包查看。

感激萧小俊 @UWA 问答社区提供了答复

A2:你要了解内存大小和所占硬盘的容量大小,10KB 是理论加载这张图内存会占用的大小,1KB 是这个文件在你的操作系统中的文件所占的硬盘大小,然而不齐全等同于理论进包内的大小,毕竟 Resource 里或者打成 AssetBundle 之后会有肯定的压缩,能够在打下的 AssetBundle 中查看。

也就是说,要看下这个文件更改格局之后打进去的 AssetBundle 大小是否产生了本质的变动,因为 AssetBundle 的大小进到包内个别不会被压缩。

感激 [email protected] 问答社区提供了答复

A3:最终看打进去的 AssetBundle 包的大小即可,通常 AssetBundle 是不会 2 次压缩的,否则加载耗时会变高。纹理的压缩格局也会导致 AssetBundle 大小不一样,下图中是 1024×1024 的纹理测试失去的后果,仅供参考:

感激 [email protected] 问答社区提供了答复

Rendering

Q:对于合图和合批是否会升高带宽疑难。

有一张合图 1024×1024,200 个物体共用其中一张 100×100 纹理,总共 DrawCall 只有 1,请问下当初带宽是:
200 物体 x (1024 x 1024) or
200 物体 x (100 x 100) or
1 x (1024 x 1024) or
1 x (100 x 100)?

如题目所说,合图的应该是被合成一个 Batch,那是 200 物体 x (1024 x 1024)吗?

另外 NxN 的像素块有多大?比方想要渲染一张 1024×1024 背景图,个别会被读取几次?

若开启 Mipmap,我的了解是相当于弄了一个合图,合图里蕴含了更低级别的信息。如果是这个思路,那合图传的带宽应该是 100×100,而不是传整张合图 1024×1024?

A1:首先一点,Sprite 不是你想的 100X100 尺寸,传到 GPU 就是这块区域,最终传输到 GPU 还是纹理自身,GUI 只是通过 Sprite 信息设置了顶点 UV,能力正确渲染纹理的指标区域。Sprite 它不是任何显示资源或者物理资源,而就是一个纯数据结构,为了方便管理一个纹理的不同区域。

感激 1 9 7 [email protected]问答社区提供了答复

A2:纹理带宽次要指读纹理带宽:当 GPU 的 OnChip Memory 上没有,则会从 System Memory 外面读取,个别是会读取一个 NxN 的像素块的内容进 OnChip Memory。所以,当采样次数和采样点更多的时候,越容易 Cache Miss,这样就增多了到 System Memory 外面读取纹理到 OnChip 的次数,带宽就相应增大了。

因而,为了升高带宽,咱们常说纹理要开 Mipmap,要缩小采样次数(防止开启各项同性和三线性差值),从而尽量减少 Cache Miss 次数;也能够进一步压缩纹理格局,来缩小传输的数据量。

对于本问题,实质还是在 OnChip 上读取外面 NxN 的内容的,然而会受到采样次数的影响。其中如果有 200 个 DrawCall 但被合成一个了 Batch,依然会采样 200 次;但如果的确合成了一个 DrawCall,那就会只采一次。

之所以说 Mipmap 升高带宽,是因为传到 GPU 的是适合层级的纹理,当画下一个像素时很大概率就落在 OnChip 里的 NxN 个像素内,就不须要从新采从而减少 Cache Miss 概率;但如果没有开 Mipmap 而导致用了分辨率过大的层级,则画两个相邻的点也可能要跨纹理中的好几个像素,从而得从新采从而减少 Cache Miss 概率。

感激 [email protected] 问答社区提供了答复

A3:对于带宽来说,是 100×100 还是 1024×1024,区别不大,小图和大图的区别在于从 CPU 传到 GPU 的时候的操作,是一次性传图集到 GPU 外面还是分很屡次传小图到 GPU,到带宽层面,都是读取采样点四周的像素到 OnChip 上,应该没有太大区别。至于采样点读取的 NxN 有多大,这个应该是和硬件相干。

感激 [email protected] 问答社区提供了答复

Rendering

Q:依据 Profiler 来看,CPU 端相机的耗时有很大一部分在 Cull 阶段。有什么方法可能优化这部分的耗时吗?或者说跳过这部分?有尝试过通过 CommandBuffer 去绘制,然而 CommandBuffer 绘制的物体,SRPBatcher 仿佛没法失效。

请问在 URP 下,多相机渲染时的 Cull 耗时有方法优化吗?

A:Frustum Culling 曾经在 JobSytem 的子线程中。你相机可能反复渲染了,或者你场景的对象太多了,倡议先用些其余伎俩,比方 LOD、HLOD 或逻辑剔除等。

跳过不可能。如果跳过,全地图的顶点都会进入这一帧的 VBO(一样会卡),EBO 长度也大大增加,接着由驱动发送到 GPU,起初来到 Vertex Shader 阶段参加计算(压力),其次除法前裁剪[-w,w]之外的顶点(最初也裁剪了,然而节约了最大的计算过程资源)。

感激龙跃 @UWA 问答社区提供了答复

封面图来源于网络


明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在 UWA 问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官网技术博客:blog.uwa4d.com
官网问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官网技术 QQ 群:793972859(原群已满员)

正文完
 0