关于shader:URP-Shader-FrameBuffer-Fetch-Mali-Crash

1)URP Shader FrameBuffer Fetch Mali Crash2)Unity模型Lightmap UV相干的疑难3)动画上下半身交融问题4)AnimatorControllerPlayable.PrepareFrame函数在什么状况下调用 这是第338篇UWA技术常识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地把握和学习。 UWA社区主页:community.uwa4d.comUWA QQ群:465082844 ShaderQ:应用FrameBuffer Fetch华为Mali设施编译Shader间接闪退,然而如果把纹理采样去掉就失常了,有遇到过这种问题的嘛?Unity 2021.3.23Custom SRPDevice : HUAWEI P40 --- Mali-G76设施自身反对GL_EXT_shader_framebuffer_fetch。 Shader "unlit/test"{ Properties { _Color ("Main Color", Color) = (1,1,1,1) [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" } Pass { Name "ForwardLit" Tags {"LightMode" = "UniversalForward"} HLSLPROGRAM #define ENABLE_FRAMEBUFFER_FETCH 1 #pragma vertex Vertex #pragma fragment Fragment #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float4 texcoord : TEXCOORD0; half4 color : TEXCOORD2; UNITY_VERTEX_OUTPUT_STEREO }; TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); CBUFFER_START(UnityPerMaterial) half4 _Color; CBUFFER_END Varyings Vertex(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.texcoord = input.texcoord.xyxy; output.color = input.color; return output; } half4 FragmentInner(Varyings input) { half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_LinearClamp, input.texcoord.xy).rgba; return color * input.color * _Color; } void Fragment(Varyings input, inout half4 output : CoLoR0) { half4 col = FragmentInner(input); output.rgb = lerp(output.rgb, col.rgb, col.a); output.a = col.a; } ENDHLSL } }}2023/04/20 19:54:29.555 13797 13846 Debug Unity GL_EXT_debug_marker GL_ARM_rgba8 GL_ARM_mali_shader_binary GL_OES_depth24 GL_OES_depth_texture GL_OES_depth_texture_cube_map GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_EXT_read_format_bgra GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture GL_OES_standard_derivatives GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_EGL_image_external_essl3 GL_OES_EGL_sync GL_OES_texture_npot GL_OES_vertex_half_float GL_OES_required_internalformat GL_OES_vertex_array_object GL_OES_mapbuffer GL_EXT_texture_format_BGRA8888 GL_EXT_texture_rg GL_EXT_texture_type_2_10_10_10_REV GL_OES_fbo_render_mipmap GL_OES_element_index_uint GL_EXT_shadow_samplers GL_OES_texture_compression_astc GL_KHR_texture_compression_astc_ldr GL_KHR_texture_compression_astc_hdr GL_KHR_texture_compression_astc_sliced_3d GL_EXT_texture_compression_astc_decode_mode GL_EXT_texture_compression_astc_decode_mode_rgb9e5 GL_KHR_debug GL_EXT_occlusion_query_boolean GL_EXT_disjoint_timer_query GL_EXT_blend_minmax GL_EXT_discard_framebuffer2023/04/20 19:54:29.555 13797 13846 Debug Unity GL_OES_get_program_binary GL_OES_texture_3D GL_EXT_texture_storage GL_EXT_multisampled_render_to_texture GL_EXT_multisampled_render_to_texture2 GL_OES_surfaceless_context GL_OES_texture_stencil8 GL_EXT_shader_pixel_local_storage GL_ARM_shader_framebuffer_fetch GL_ARM_shader_framebuffer_fetch_depth_stencil GL_ARM_mali_program_binary GL_EXT_sRGB GL_EXT_sRGB_write_control GL_EXT_texture_sRGB_decode GL_EXT_texture_sRGB_R8 GL_EXT_texture_sRGB_RG8 GL_KHR_blend_equation_advanced GL_KHR_blend_equation_advanced_coherent GL_OES_texture_storage_multisample_2d_array GL_OES_shader_image_atomic GL_EXT_robustness GL_EXT_draw_buffers_indexed GL_OES_draw_buffers_indexed GL_EXT_texture_border_clamp GL_OES_texture_border_clamp GL_EXT_texture_cube_map_array GL_OES_texture_cube_map_array GL_OES_sample_variables GL_OES_sample_shading GL_OES_shader_multisample_interpolation GL_EXT_shader_io_blocks GL_OES_shader_io_blocks GL_EXT_tessellation_shader GL_OES_tessellation_shader GL_EXT_primitive_bounding_box GL_OES_primitive_bounding_2023/04/20 19:54:29.555 13797 13846 Debug Unity box GL_EXT_geometry_shader GL_OES_geometry_shader GL_ANDROID_extension_pack_es31a GL_EXT_gpu_shader5 GL_OES_gpu_shader5 GL_EXT_texture_buffer GL_OES_texture_buffer GL_EXT_copy_image GL_OES_copy_image GL_EXT_shader_non_constant_global_initializers GL_EXT_color_buffer_half_float GL_EXT_unpack_subimage GL_EXT_color_buffer_float GL_EXT_YUV_target GL_OVR_multiview GL_OVR_multiview2 GL_OVR_multiview_multisampled_render_to_texture GL_KHR_robustness GL_KHR_robust_buffer_access_behavior GL_EXT_draw_elements_base_vertex GL_OES_draw_elements_base_vertex GL_EXT_protected_textures GL_EXT_buffer_storage GL_EXT_external_buffer GL_EXT_EGL_image_array GL_EXT_texture_filter_anisotropic GL_ARM_texture_unnormalized_coordinates GL_HUAWEI_smart_cache GL_EXT_shader_framebuffer_fetch GL_HUAWEI_framebuffer_partial_updateA1:Mali-G76就是不反对Fetch的,能够看一下上面这个博客:https://www.cnblogs.com/minggoddess/p/11471369.html感激QyoJWUqeW5Yj@UWA问答社区提供了答复 ...

June 2, 2023 · 2 min · jiezi

关于shader:主界面边框流动效果长时间挂机后会卡顿

1)主界面边框流动成果长时间挂机后会卡顿2)检测内存是否超过阈值问题3)堆内存会持续上升,如何用UWA报告来剖析4)对于AssetBundle加密这块,如何从新实现LoadFromFile接口 这是第323篇UWA技术常识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地把握和学习。 UWA社区主页:answer.uwa4d.comUWA QQ群:465082844 ShaderQ:咱们发现主界面上的边框流动成果,在进行较长游戏工夫之后,流动成果会变得比拟卡顿,请问有可能是什么起因? A:这个应该是因为Shader中传入的工夫太大,精度不够导致的,倡议对这个Shader中输出的工夫做一下相似于Clamp01或者Frac的操作,防止出现精度问题。感激qiling@UWA问答社区提供了答复 MemoryQ:请问有什么好的办法在Release包外面获取内存占用吗?想要用来检测内存是否超过阈值,PSS内存会有数值提早更新的问题。 A:倡议应用API:Profiler.GetTotalReservedMemoryLong,能够返回Unity为以后和将来调配预留的内存总量,能够定期调用这个API判断内存有没有超过阈值。感激龙粲@UWA问答社区提供了答复 MemoryQ:咱们我的项目的堆内存会持续上升到400多MB,这个值太高了,而UWA报告中无论是平均分配值乘以帧数还是泄露剖析中的驻留量尽管也很高,然而离400MB还有一些差值。到这里不晓得怎么持续剖析了,大家有什么好的倡议? A:我和题主私聊要了包测了下。收回来和大家分享一下: 应用Memory Profiler截帧后能够看到,我的项目的堆内存来到数百MB,但从图中能够看到其中有大量的碎片。 这里波及到UWA的GOT Online报告的一个特点,就是采集的是咱们函数在测试过程中理论调配的堆内存的相对值,而不包含碎片。所以在这样一个碎片十分多、比拟极其的状况下,报告统计的绝对驻留值和理论的Mono堆内存占用两者之间就会差的比拟大。 当然,到了这一步还是不够,接下来就要题主联合相干代码认真排查是否存在什么破绽,为什么会有如此大量的碎片和不能及时卸载的问题了。 感激Faust@UWA问答社区提供了答复 AssetBundleQ:对于AssetBundle加密这块,有人从新实现过LoadFromFile接口吗? A:倡议简略做下Offet Load,真的想解资源方法还是有很多的,越大的我的项目做AssetBundle资源加密越影响游戏性能,齐全得失相当。感激学无止境@UWA问答社区提供了答复 封面图来源于网络 明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。 官网:www.uwa4d.com官网技术博客:blog.uwa4d.com官网问答社区:answer.uwa4d.comUWA学堂:edu.uwa4d.com官网技术QQ群:465082844

February 8, 2023 · 1 min · jiezi

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

1)编辑器在编译Shader时的报错疑难2)对于图片大小和包体大小的疑难3)对于合图和合批是否会升高带宽的疑难4)URP下,如何优化多相机渲染时的Cull耗时 这是第312篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) ShaderQ:有时在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问答社区提供了答复 ResourceQ:对于图片大小和包体大小的疑难。 例如 ,一张图片,理论大小是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大小不一样,下图中是1024x1024的纹理测试失去的后果,仅供参考:感激[email protected]问答社区提供了答复 RenderingQ:对于合图和合批是否会升高带宽疑难。 有一张合图1024x1024,200个物体共用其中一张100x100纹理,总共DrawCall只有1,请问下当初带宽是:200物体 x (1024 x 1024) or200物体 x (100 x 100) or1 x (1024 x 1024) or1 x (100 x 100)? 如题目所说,合图的应该是被合成一个Batch,那是200物体 x (1024 x 1024)吗? ...

November 7, 2022 · 1 min · jiezi

关于shader:抓取手机端变体组合思路设想

1)抓取手机端变体组合思路构想2)如何革除File.ReadAllBytes产生的内存泄露3)atlas.GetSprite(name)内存泄露4)Unity版本更新后Odin插件序列化报错 这是第303篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) ShaderQ:对于变体收集的问题,PC端编辑器尽管自带收集,然而毕竟运行的时候是Editor环境,与实在挪动端环境相差甚远。Warmup只会预加载列表中的组合,非Shader打包的全副组合。这样如果收集的变体非实在环境, 只会白白浪费CPU及GPU显存,等实在渲染的时候发现之前提交的组合非挪动端所须要的,须要从新Warmup。 再者,如果做品质划分,比方粗劣画面开动静暗影,晦涩机型关。这样会产生两套组合。实践上应该分成两个SVC,而PC是只能保留所有的变体列表。 综上,我构想解决方案就是通过实在跑手机,抓取手机的应用数据,来划分到不同的列表中,这样应该是最实在牢靠的。 为了实现这个构想,须要能找到如何取得提交的变体数据,已知能够在profiler-CPU-Timeline模式下的Shader.CreateGPUProgram外面的meta_data外面能够拿到。 通过CS源码剖析到NativeProfilerTimeline这个控件是绘制Timeline的外围类。NativeProfilerTimeline.GetEntryInstanceInfo这个函数能够拿到对应的meta_data。 然而这个类是C++底层写的,C#只是Draw去提交绘制。GetEntryAtPosition去依据鼠标地位来取得Entry,代码无奈反射到EntryIndex。当初陷入了死胡同。 大家有解决办法或者新的思路吗?最好能获取手机上的变体列表。 A:能够在Graphics面板上勾选这个Log Shader Compilation: 编辑器下Console连贯真机,这样就能够在触发Shader.CreateGPUProgram时看到相应的Log:Autoconnected Player Compiled shader: Unlit/TestShader, pass: <unnamed>, stage: all, keywords FOG_EXP2 感激宗卉轩@UWA问答社区提供了答复 MemoryQ:最近我的项目玩的工夫长了,内存始终暴增。在查看过程中,发现游戏中用了一个File.ReadAllBytes办法来读取几个5~10MB不等的二进制数据,加载完数据曾经复制null,然而Mono还是始终增长,调用GC都开释不掉。 实践上来讲这个数组业务层曾经没有援用了。然而,用Memory Profiler查看,内存还始终在。求教一下,有没有人晓得革除的办法? Unity版本 2019.4.9 A1:缓冲区不必每次都new一个。感激jim@UWA问答社区提供了答复 A2:如果是Mono版本的APK,能够试试IL2CPP。如果IL2CPP版本没有这个问题,应该是遇到Mono的Bug了,一次性调配较多的堆内存,会概率呈现这些调配的堆内存无奈回收的问题。感激Xuan@UWA问答社区提供了答复 A3:Boehm GC自身的缺点导致的,能够搜搜BlackList,若有源码,能够有很多种防止或小修的改法;若没源码能够尝试: 缩小字典中Struct当Key;拆小文件,重写File的接口,复用内存。感激kent@UWA问答社区提供了答复 ScriptQ:Unity版本 2019.4.23,发现在频繁调用atlas.GetSprite(name) 时会内存泄露,只增不减,直至解体!有人遇到过这问题吗?请问有什么好的解决办法吗? A1:如果不思考引擎自身Bug的状况下,内存泄露大部分都是援用没有解决好。可能有些中央还在应用这些资源,只是没关联上,导致无奈回收这部分资源。所以能够着重先排查这部分性能。感激廖武兴@UWA问答社区提供了答复 A2://// 摘要:// Clone the first Sprite in this atlas that matches the name packed in this atlas// and return it.//// 参数:// name:// The name of the Sprite.public Sprite GetSprite(string name); ...

June 28, 2022 · 1 min · jiezi

关于shader:AB打包有的Shader没有触发IPreprocessShaders的回调

1)AB打包有的Shader没有触发IPreprocessShaders的回调2)场景中有多灯光导致粒子系统大量不合批3)获取Android和iOS的设施惟一标识符4)应用了Variant的AB包里的资源会判断为冗余 这是第302篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) ShaderQ:在Addressable外面打包AB,其中的Shader打包并没有触发IPreprocessShaders外面的回调,请问是什么起因? A:增量打包时曾经打包的Shader不会触发该回调,只有新打包的Shader才会。不论是Addressable打包或者是其余的打包形式都相似。如果须要通过IPreprocessShaders来进行Shader变体剔除,那么还是倡议从新全量打包一次,或者打包时设置ForceRebuild。感激宗卉轩@UWA问答社区提供了答复 RenderingQ:场景中有多灯光,导致了粒子系统大量的不合批,该如何优化? A:测试了一下,在2019.4.14版本中,如果多灯光“影响”到了粒子系统,的确会导致本该合批的ParticleSystem不能合批,尽管自身渲染的时候不会对ParticleSystem产生理论影响。在2020.3.17和2021.3.4版本中都没有这个问题。对于不是2020及以上版本的Unity,须要调整一下Light的CullingMask,不让其对ParticleSystem所在的Layer产生影响,就能够合批了。比方粒子特效在TransparentFX层,光源的CullingMask不包含这一个Layer即可。感激Xuan@UWA问答社区提供了答复 AndroidQ:求教获取Android和iOS的设施惟一标识符的形式。 A1:Android有获取IMEI的接口。如果iOS 15当前的设施设置不追踪,目前是无奈获取设施惟一ID的,得从其余相似热云插件的形式获取。感激Knight-132872@UWA问答社区提供了答复 A2:Android是应用OAID或者UUID。iOS应用IDFA。刷机或者复原出厂设置都会刷新ID,一些硬件档次的设施ID,在iOS 5.0以上不被容许获取,Android高版本中也不举荐应用。感激不小人@UWA问答社区提供了答复 A3:补充楼上的计划,有上面两种形式: 原生条件下,Android能够应用UUID的形式,iOS应用楼上说的IDFA,然而须要本人做兼容适配。能够借助SDK,获取SDK的OpenID。这个是牢靠和稳固的,长处是不须要兼容平台,然而须要接入SDK。感激廖武兴@UWA问答社区提供了答复 AssetBundleQ:应用UWA AssetBundle检测服务,发现一些应用了Variant的AB包里的资源会被断定为冗余,是Bug吗? A:应用Variant形式打包的AB中,资源名字完全相同的资源会生成完全一致的Guid,以实现它作为资源变体的性能,在加载的时候能够按需替换,而个别会认为Guid雷同的资源就是同一份资源,所以有可能是这个起因导致误判成冗余。能够改下资源名字或者不必Variant的形式打包试试。感激宗卉轩@UWA问答社区提供了答复 封面图来源于网络 明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。 官网:www.uwa4d.com官网技术博客:blog.uwa4d.com官网问答社区:answer.uwa4d.comUWA学堂:edu.uwa4d.com官网技术QQ群:793972859(原群已满员)

June 21, 2022 · 1 min · jiezi

关于shader:Shader-Graph和Amplify-Shader-Editor有哪些区别

1)Shader Graph和Amplify Shader Editor有哪些区别2)Canvas AdditionalShaderChannels设置有效3)IL2CPP打包速率问题4)SRP是否还须要图集 这是第290篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) ShaderQ:求教各位,Unity自带的Shader Graph或Amplify Shader Editor,在应用和生成的Shader性能问题上,除了Amplify Shader Editor目前自带Node性能的丰盛度以及社区资源丰盛度应该更胜一筹外,两者还有多少区别? 我的项目背景:新我的项目(手游),基于Unity URP的二次元NPR+PBR,3D场景+3D角色。 A1:参考如下:体验:Amplify Shader Editor优应用:Amplify Shader Editor优通用水平:Amplify Shader Editor优兼容性:Shader Graph优将来倒退:Shader Graph优<br/>论断:两个都用并不抵触,然而我偏向于优先应用Shader Graph缓缓代替Amplify Shader Editor。感激大崔-287520@UWA问答社区提供了答复 A2:理论体验上Amplify Shader Editor会比Shader Graph好用很多。 Amplify Shader Editor生成的是明文Shader文件,能够自行批改调整局部不合理的生成;Shader Graph也能看到他生成的Shader,然而设计上Unity尽量心愿黑盒,不想让你看到。Amplify Shader Editor能够几条管线相互切,Shader Graph只能在URP下应用。Amplify Shader Editor兼容所有Shader Graph的节点和参数。Shader Graph界面比Amplify Shader Editor难看,品控比拟好,小bug没Amplify Shader Editor多。每一步计算的节点后果,Shader Graph能预览根本所有的,Amplify Shader Editor如果是本人定义的管线全局参数以及有些内置的,不太好预览。连连看这种生成的Shader品质都很差,根本须要效率的都得翻新一遍。常见的优化,比方c=tex2d(uv) 紧接着应用c,是须要期待GPU操作显存回来的工夫耗费。这种个别会插入其余计算,对消这个耗费。 比方: c = tex2d(uv)//do other thingc = c*c;目前两种都是按节点逻辑生成,一个uv节点就会生成tex2d(uv)和后续计算的逻辑。没有整体做语义剖析的优化。 感激uwa菜鸡奶泡泡.@UWA问答社区提供了答复 UGUIQ:在UI中应用到的Shader中用到了uv1和uv2通道,在Canvas AdditionalShaderChannels中抉择增加了对应通道后没有成果,雷同代码资源在2019.4.26f1c1正确显示,求教大家是否是版本问题还是须要非凡设置解决? Unity版本:2018.4.17f1 A:在2018.4.23f1版本上参考这个链接的Outline成果进行了测试,在小米9真机上没有发现问题。 能够参考一下《基于Shader实现的UGUI描边解决方案》。 PS:看了一下2018.4.18到2018.4.23之间的所有的Release Note,没有发现相干问题的修复。这个文章是应用Shader来实现Outline的,感觉成果挺不错的。 感激Xuan@UWA问答社区提供了答复 ...

March 28, 2022 · 1 min · jiezi

关于shader:纹理动画

Unity Shader 入门精要笔记 纹理动画纹理动画即管制纹理随着工夫的变动而变动。 序列帧动画首先须要一张蕴含了所有动画帧的主纹理,它有两点要求,它的每行和每列都应该是能够等分的,它是从左到右,从上到下顺次排列的。序列帧动画的关键在于,计算该时刻下应该播放的关键帧的地位,并对该关键帧进行纹理采样。 步骤如下: 除了申明序列帧图像的纹理_MainTex外,还须要申明序列帧图像纹理上每一行和每一列有多少个关键帧图像。序列帧图像通常都是通明纹理,蕴含了通明通道,所以须要设置Pass的状态,将其当做一个半透明对象,在SubShader中将Tags设置为:Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" },并且在Pass中敞开深度写入,应用Blend命令开启混合模式。在片元着色器中计算关键帧的地位,并对其采样。 float time = floor(_Time.y * _Speed); float row = floor(time/_HorizontalAmount); float column = time - row * _VerticalAmount; // half2 uv=float2(i.uv.x/_HorizontalAmount,i.uv.y/_VerticalAmount); // uv.x+=column/_HorizontalAmount; // uv.y-=row/_VerticalAmount; half2 uv = i.uv + half2(column,-row); uv.x /= _HorizontalAmount; uv.y /= _VerticalAmount;前三行计算了关键帧的地位,即对序列帧中第几个关键帧采样。_Time内置变量存储了该场景加载以来通过了多少工夫,其y重量上即是具体的工夫。用工夫time除以程度方向上关键帧的个数,并对后果向下取证,能够失去对应的行索引,而后用除法后果的余数作为列索引。这样咱们就晓得了须要对第几个关键帧进行采样。而后咱们要计算以后纹理坐标映射到子图像(须要采样的关键帧)中的纹理坐标是多少,这能够用以后的纹理坐标除以行数和列数来取得。最初,咱们须要计算最初理论要采样的纹理坐标是多少,这就是关键帧的左上角的坐标来加上坐标偏移量。那么关键帧左上角的坐标是多少?咱们晓得uv坐标的范畴是(0,1),并且在纹理属性中将其设置为了Repeat(值超过1的坐标会舍弃整数局部,取小数进行计算)。因而用行索引和列索引来除以行列上的关键帧个数,即失去了关键帧左上角的坐标。如下图: 滚动动画很多2D游戏应用了一直滚动的背景来模仿角色在场景中的穿梭,用多个层(layers)来模仿视差成果。 滚动动画的关键在于,应用多张纹理图,对这些纹理图进行采样的时候,uv坐标偏移量随工夫变动,并且每张纹理图的单位偏移量不同。比方,咱们要应用两张纹理图来模仿滚动背景。关键步骤如下: 申明两张纹理图属性和滚动速度属性。在顶点着色器中对uv坐标进行变换: o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX,0.0) * _Time.y); o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X,0.0) * _Time.y); 在片元着色器中,利用前景图像纹理的通明通道来混合两张纹理: ...

September 12, 2021 · 1 min · jiezi

关于shader:高级纹理映射

立方体纹理立方体纹理是环境映射的一种实现办法。立方体纹理就是将沿着世界空间下察看失去的上下左右前后六个方向的图像存储在立方体的六个面上。它能够实现反射和折射的成果。能够通过3D方向矢量对立方体纹理进行采样,从立方体核心登程,沿着矢量方向延长就能够和立方体的六个纹理之一产生相交,交点就是须要采样的纹理。 天空盒子天空盒子用于模仿背景。它是一个盒子,应用skybox时,整个场景被突围在一个立方体内。立方体的每个面应用立方体纹理映射技术。 创立一个材质,并抉择skybox/6 sided,并将六张纹理图赋值给材质,将纹理的WrapMode设置为Clamp,避免在接缝处呈现不匹配。将材质赋给摄像机,或者在Lighting中将材质赋值给Skybox选项(这个办法会将所有摄像机的skybox设置为同一个).创立立方体纹理创立立方体纹理的办法有三种,第一种应用非凡纹理,官网举荐,参照第18章。第二种办法创立一个Cubemap(Create,Legacy,Cubmap),而后将6张纹理拖拽到它的面板中。第三种办法应用程序生成纹理,它能够依据物体在场景中的地位的不同,生成它们各自不同的立方体纹理,通过Unity提供的Camera.RenderToCubemap函数来实现。第三种办法创立立方体纹理的步骤如下: 筹备好程序脚本。创立一个空的GameObject,将以这个GameObject的地位信息来渲染立方体纹理。创立一个Cubemap用于存储立方体纹理,并将Readable勾选。应用脚本将以GameObject为核心察看到的世界空间下的6张图渲染到立方体纹理中。Cubemap的facesize越大,分辨率越大,成果越好,占用的内存也越大。 反射应用立方体纹理使得物体具备反射成果。如图,就像镀了一层金属。 步骤如下: 调整模型的地位,将其与生成立方体纹理的GameObject的地位一样。而后将立方体人纹理赋给模型。给Shader 的 properties增加属性_Cubemap(类型为Cube)在顶点着色器中用reflect函数取得物体的反射方向o.worldRefl = reflect(-o.worldViewDir,o.worldNormal);在片元着色器中利用反射方向对立方体纹理_Cubemap进行采样。fixed3 reflection = texCUBE(_Cubemap,i.worldRefl).rgb * _ReflectColor.rgb;最初将反射色彩和漫反射色彩线性混合并和环境光相加后返回。折射应用斯涅耳定律,n1sino1=n2sino2来计算折射方向。步骤如下: 调整模型的地位,并赋给材质。在Shader中申明透射比和立方体纹理在 顶点着色器中计算折射方向,须要将入射光线和外表法线归一化。o.worldRefl = refract(-normalize(o.worldViewDir),normalize(o.worldNormal),_RefractRatio);在片元着色器中利用折射方向对立方体纹理进行采样。fixed3 reflection = texCUBE(_Cubemap,i.worldRefl).rgb * _RefractColor.rgb;混合漫反射色彩和折射色彩并和环境光相加后返回。菲涅尔反射菲涅尔反射形容这样一种光学景象,即照射到物体外表的光线,一部分被折射一部分被反射,并且折射的光和反射的光存在比例关系。比方在湖边能够分明的看到脚边的水底,却看不到远处的水下情景。菲涅尔反射与视角方向无关,近似等式为:F(v,n)=F0+(1-F0)(1-v*n)^5。F0是反射系数。 步骤如下: 调整模型的地位,并赋给材质。在Shader中申明菲涅尔反射系数和立方体纹理。在顶点着色器中计算反射方向。o.worldRefl = reflect(-o.worldViewDir,o.worldNormal);在片元着色器中计算菲涅尔反射。fixed fresnel = _FresnelScale + (1 - _FresnelScale)*pow(1-dot(worldViewDir,worldNormal),5);利用菲涅尔反射混合漫反射和反射色彩。fixed3 color = ambient + (lerp(diffuse,reflection,saturate(fresnel))+specular)*atten;渲染纹理渲染纹理就是利用一个摄像机,将其看到的图像渲染到一个两头缓冲中 ,这个两头缓冲就是渲染指标纹理。利用渲染纹理,咱们能够实现镜子成果,和玻璃成果。 镜子成果步骤如下: 创立一个材质。创立一个立方体将其作为镜子,并调整其地位和大小,将第一步创立的材质赋值给它。创立一个渲染纹理(create,render texture)创立一个摄像机,调整其地位,裁剪立体,视角等,而后将摄像机看到的图像渲染到渲染纹理(将第三部创立的渲染纹理拖拽到摄像机的target texture上)。在shader的顶点着色器中翻转纹理坐标的程度坐标,对渲染纹理进行采样。总的来说渲染纹理,就是将摄像机看到的图渲染到一张两头图中,将其作为纹理贴图,而后将纹理贴图渲染到物体外表。 玻璃成果除了应用一个额定的摄像机获取屏幕图像,还能够在unity shader中定义一个GrabPass,而后unity会将以后屏幕的图像绘制在一张纹理中供咱们在后续的pass中拜访。GrabPass能够用来模仿通明材质,然而与简略的应用通明混合不同,其能够对物体前面的图像进行更简单的解决。然而要额定小心渲染队列设置,将其设置为Transparent,保障所有不通明物体先被渲染。 步骤如下: 在shader的properties中定义玻璃的材质纹理,法线纹理,立方体纹理等。在SubShader中定义GrabPass。GrabPass {"_RefractionTex"}。unity会将以后屏幕图像绘制在_RefractionTex中,供后续Pass拜访。在Pass中定义_RefractionTex和_RefractionTex_TexelSize变量,_RefractionTex_TexelSize是文素大小。在顶点着色器中获取顶点的屏幕坐标,o.scrPos = ComputeGrabScreenPos(o.pos);在片元着色器中利用法线等信息计算偏移量,而后用偏移量对屏幕图像_RefractionTex进行采样,以此来模仿折射成果。 fixed2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy; i.scrPos.xy = offset + i.scrPos.xy; fixed3 refrCol = tex2D(_RefractionTex,i.scrPos.xy/i.scrPos.w).rgb; 而后计算反射方向,用反射方向对Cubemap进行采样。最初将反射色彩和折射颜色混合返回。 ...

September 11, 2021 · 1 min · jiezi

关于shader:后处理深入相机变形特效

后处理(Post-processing),是针对原有的游戏画面进行算法加工,达到晋升画面质量或加强画面成果的技术,可通过着色器Shader程序实现。 概述变形特效是解决和加强画面成果的一类后处理技术,常常被利用在各类相机短视频app特效中,如美颜瘦身、哈哈镜特效。 本文次要从各类美颜相机中梳理了以下几种罕用的变形特效: 部分扭曲 (twirl effect)部分收缩 (inflate effect)任意方向挤压 (pinch effect)其中,扭曲可用在眼睛的部分旋转,收缩能够用于大眼,挤压/拉伸可用于脸部塑性和瘦脸等。如何通过着色器Shader实现这些变形,是本文探讨的重点。(ps:焦急预览代码的童鞋见文末) 变形技原理尽管变形的成果千奇百怪,但它们往往离不开这三个因素:变形地位、影响范畴和变形水平。 因而它在Shader中的实现,就是通过结构一个变形函数,将传入原始uv坐标,变形的地位、范畴range和水平strength,通过计算后生成变形后的采样坐标,代码如下: #iChannel0 "src/assets/texture/joker.png"vec2 deform(vec2 uv, vec2 center, float range, float strength) { // TODO: 变形解决 return uv;}void mainImage(out vec4 fragColor, vec2 coord) { vec2 uv = coord / iResolution.xy; vec2 mouse = iMouse.xy / iResolution.xy; uv = deform(uv, mouse, .5, .5); vec3 color = texture(iChannel0, uv).rgb; fragColor.rgb = color;}本文着色器代码采纳GLSL标准,遵循Shader-Toy的写法,不便大家预览。变形小技巧:采样间隔场变换咱们设置定点坐标O,任意点到点O间隔为dist,以不同dist值为半径,以点O为核心可造成无数个等距的采样圈,它们被称为点O的间隔场。 咱们能够通过扭转采样圈的大小、地位,进而扭转纹理采样地位,以实现收缩/膨胀、挤压/拉伸的变形成果。 vec2 deform(vec2 uv, vec2 center, float range, float strength) { float dist = distance(uv, center); vec2 direction = normalize(uv - center); dist = transform(dist, range, strength); // 扭转采样圈半径 center = transform(center, dist, range, strength); // 扭转采样圈核心地位 return center + dist * direction;}这个技巧的利用先不急着说,当初咱们还是从简略的扭曲变形开始讲。 ...

May 24, 2021 · 3 min · jiezi

关于shader:在URP中的BRDF计算公式问题

1)在URP中的BRDF计算公式问题2)Job System占用主线程工夫问题3)在Profiler中定位TempBuffer问题4)Unity 2019应用HDRP的摄像机的GL画线问题5)Unity WebCamTexture获取到的相机图片被旋转 这是第248篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) ShaderQ:最近在看URP Shader的时候发现个问题,不晓得是不是我了解的不对。首先贴代码: 先是URP的Lighting.hlsl里初始化BRDF的局部: inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData){#ifdef _SPECULAR_SETUP half reflectivity = ReflectivitySpecular(specular); half oneMinusReflectivity = 1.0 - reflectivity; outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular); outBRDFData.specular = specular;#else half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic); half reflectivity = 1.0 - oneMinusReflectivity; outBRDFData.diffuse = albedo * oneMinusReflectivity; outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);#endif outBRDFData.grazingTerm = saturate(smoothness + reflectivity); outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness); outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN); outBRDFData.roughness2 = outBRDFData.roughness * outBRDFData.roughness; outBRDFData.normalizationTerm = outBRDFData.roughness * 4.0h + 2.0h; outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - 1.0h;#ifdef _ALPHAPREMULTIPLY_ON outBRDFData.diffuse *= alpha; alpha = alpha * oneMinusReflectivity + reflectivity;#endif}依照我的了解: ...

April 28, 2021 · 3 min · jiezi

关于editor:Addressable编辑器相关开发问题

1)Addressable编辑器相干开发问题2)Addressable动静设置更新地址3)Addressable在网络差的环境中下载资源4)Android ETC2 Fallback的疑难5)内置Shader中“Dependency”的定义 这是第245篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) AddressableQ:我想通过编辑器脚本来做主动导入下图这个选项并打钩,能本人设置相干的Key。有没有参考的工程或代码示例?谢谢! A:用AssetDatabase.AssetPathToGUID和AddressableAssetSettings.CreateOrMoveEntry。感激老王@UWA问答社区提供了答复 AddressableQ:Addressable动静配置的热更新地址,应用了文档外面的动态变量 (放大括号里),Addressable启动后获取到的Catalogs.Count始终为零,狐疑是地址的问题,有没有要求这个类也是动态的? 如果我配死地址,是能更新下来的,比方这样: 这种更新曾经测试通过,目前是想在生成首包后动静去改这个RemoteLoadPath。 A:咱们是这样子的,RemoteLoadPath指向一个static的property,这个property从配置表里返回资源更新的地址。 感激jim@UWA问答社区提供了答复 AddressableQ:咱们应用Addressable来做资源的热更新。当初模仿了一个较差网络环境下的下载资源状况,应用Windows上模仿丢包的软件模仿了网络环境,丢包率设置为30%。 Addressable的下载会卡死在某个百分比,DownloadDependenciesAsync的Completed事件不会被触发,所以无奈通过AsyncOperationHandle的status判断是失败还是胜利。 Log显示的报错是: 请问这种状况有什么好的解决办法吗? A:起初发现是有几个资源的Time Out值设置得太大了,导致始终在期待,所以进度条卡死。解决办法是将Time Out值设置的小一点,并减少retry次数。 我Time Out设置的是20。感觉不宜太长,否则超时的时候下载进度感觉会长工夫卡死;太短的话,挪动网络太差,也常常会超时导致超时下载失败。 感激题主jim@UWA问答社区提供了答复 EditorQ:咱们的游戏在模拟器上运行一会儿就会解体,狐疑是图片被解压成RGBA32导致内存过大产生的解体。Android ETC2 Fallback设置为16 bit是不是可能大幅升高在低端手机的内存占用呢? 另外我在Build Setting抉择ETC2 Fallback后,Project Setting没有任何变动,这个值是保留在哪里的?应该怎么上传?(版本:Unity 2018.4.31) A:模拟器个别内存都够的,如果怕是内存问题能够调整一下调配给模拟器的内存。最好还是连上Logcat看一下Log,是因为内存问题,还是32位或者64位利用的问题,又或者是64位LuaJit之类的问题。这个值存在LibraryEditorUserBuildSettings.asset文件中。感激郑骁@UWA问答社区提供了答复 ShaderQ:正在尝试自定义Terrain的Shader,发现内置Shader的开端有这样两行,想问问其中的“Dependency”是做什么用的,前面指定的Shader起什么作用? Dependency “AddPassShader” = "Hidden/TerrainEngine/Splatmap/Diffuse-AddPass"Dependency “BaseMapShader” = “Diffuse” A:Dependency是一个未文档的关键词,其用于指定Shader依赖关系,理论作用有两个: 打包的时候依赖不会脱漏,能够通过AssetBundle Browser验证。Unity 2019之后能够通过C#接口Shader.GetDependency(等号左侧依赖名) 获取等号右侧Shader名。地形零碎那么做,是因为有三种光照模型,通过GetDependency(依赖名) 能够缩小一些Shader名的硬编码,依赖名充当了接口的作用。 感激庄沁@UWA问答社区提供了答复 封面图来源于网络 明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。 官网:www.uwa4d.com官网技术博客:blog.uwa4d.com官网问答社区:answer.uwa4d.comUWA学堂:edu.uwa4d.com官网技术QQ群:793972859(原群已满员)

April 7, 2021 · 1 min · jiezi

关于shader:UE4-Shader编译以及变种实现

一、动机这篇文章次要是我对UE4中Shader编译过程以及变种的了解,理解这一块还是挺有必要的,毕竟动辄几千上万个Shader的编译在UE里几乎是粗茶淡饭。理解它底层的实现机制后心田虚浮一点,如果要去批改,大方向也不会错。 这部分工作是我之前就做好的,文章里波及外部批改的中央都被我阉割掉了。所以这篇文章次要用于常识遍及,分享给宽广被UE4中的Shader编译折磨的码农们,凑活着看,看完其实应该就理解了。 二、UE4中Shader的组织和获取在讲具体的Shader编译过程时,先讲UE4的渲染过程,渲染过程中是怎么拿Shader的,最初再讲这些Shader是怎么生成的。 空幻引擎中讲到线程次要有三个:游戏线程、渲染线程和RHI线程。 其中咱们平时关怀的比拟多的就是游戏线程和渲染线程了,至于RHI线程偏差于底层硬件接口,是甚少关怀的,个别状况下也很少有须要改变到RHI线程的货色。 1. 渲染线程 空幻引擎在FEngineLoop::PreInit中对渲染线程进行初始化。 具体的地位是在StartRenderingThread函数外面,此时空幻引擎主窗口是尚未被绘制进去的,渲染线程的启动位于StartRenderingThread函数外面,这个函数大略做了以下几件事: 1)通过FRunnableThread::Create函数创立渲染线程 2)期待渲染线程筹备好从本人的TaskGraph取出工作并执行 3)注册渲染线程 4)创立渲染线程心跳更新线程 2. 渲染线程的运行 在UE4的体系中,渲染线程的次要执行内容在全局函数RenderingThreadMain(RenderingThread.cpp)中。 从实质上来讲他更像是一个员工,等着老板给他派工作,老板塞给他的工作都会放在TaskMap中,他则负责一直地提取这些工作去执行。 老板能够通过ENQUEUE_RENDER_COMMAND系列宏,给员工派发工作(增加到TaskMap中),下图阐明了这个过程: 具体代码调用实例如下,这个宏是在游戏线程中调用的,有时候游戏线程中有一些资源产生了变动,或者增加了一些新的资源,抑或是因为一些逻辑而要去改到渲染线程的一些操作,都须要有一种办法去告诉到渲染线程,就像是两艘并行飞驰的船,各自走本人的路,另一艘船上产生了什么是齐全不晓得的,而UE4就通过设置一系列宏为两艘船之间的通信提供了办法。 员工执行工作时也不是间接向GPU发送指令,而是将渲染命令增加到RHICommandList,也就是RHI命令列表中,由RHI线程一直取出指令,向GPU发送,并阻塞期待后果。 此时RHI线程尽管阻塞,然而渲染线程仍然失常工作,能够持续解决向RHI命令列表填充指令。 3. 渲染过程中Shader的起源及抉择 明确了上述那些概念咱们晓得,屏幕后果就像是咱们最终要做进去的产品,老板就像是产品经理,通知员工这个产品要怎么做,并交给员工对应的资源,员工依据这些资源,和老板的命令去实现最终的产品(绘制到屏幕上)。 首先讲这些资源在UE4中对应的是什么,以及员工在实现不同的工作阶段(绘制Pass)时是如何从这么多资源中拿到本人想要的资源的,再去讲这些资源的生成。 3.1 资源的组织:ShaderMap 那么屏幕上的画面到底是如何出现的呢?员工是怎么样去用这些资源的呢,换句话说就是老板给员工的资源,员工是怎么解决成最终能用的资源的?这些资源是怎么组织的?这里就波及到一个名词:ShaderMap。 用过空幻4的渲染的都晓得,空幻引擎中的着色器数量是十分宏大的,如果改变一个材质,常常就须要编几千个甚至上万个Shader,其实也就是说单个材质会编译出多个Shader,这一点是十分重要的。 用一个简略点的概念来了解ShaderMap,能够把它了解成一个三维矩阵,长度为每个材质类型,宽度为每个渲染阶段,高度为每个顶点工厂类型,矩阵的每一个方格都对应了一组着色器组合(顶点着色器,像素着色器),材质也不肯定参加全副阶段,所以这个三维矩阵中是存在有很多空缺的。 顶点工厂在UE4中的含意是负责形象顶点数据以供前面的着色器获取,从而让着色器可能疏忽因为顶点类型造成的差别,比如说一般的动态网格物体和应用GPU进行蒙皮的物体,二者的顶点数据不同,然而通过顶点工厂进行形象后,提供对立的数据获取接口,供前面的着色器应用。 3.2 资源的抉择:怎么从ShaderMap中拿到想要的Shader 当初是第二个问题,如何依据以后阶段,以后的材质类型,以后顶点工厂类型,从这个三维矩阵中取得须要的着色器组合。 以一个StaticMesh物体的渲染为例(动静物体不同),对着色器数据抉择的过程如下: 1)渲染线程把这个物体增加进场景AddToScene。 2)更新场景的动态物体绘制列表AddStaticMeshes。 3)调用CacheMeshDrawCommands,开始生成以后物体的绘制命令MeshDrawCommands并缓存住。 4)遍历所有的Rendering Pass类型,获取以后场景的CachedDrawLists生成Drawlistcontext。 5)调用不同Pass(以BasePass为例)的AddMeshBatch函数,并将Drawlistcontext作为参数传入(不便之后把生成的绘制命令缓存住)。 6)通过一系列参数判断该Mesh应不应该在以后Pass(BasePass为例)生成绘制命令,如果验证通过,那么调用以后Pass的Process函数。 7)获取该Mesh在以后Pass绘制须要的Shaders,绘制状态,光栅化状态,并最终生成该Mesh的绘制命令。 所以到这一步就讲清楚了渲染时怎么去拿Shader的流程,须要去看不同Pass的GetShaders函数,联合之前对ShaderMap的剖析来看它的传入参数,MaterialResource对应它应用的材质资源,VertexFactory的type对应所用到的顶点工厂类型,最初还有用到的顶点和像素着色器。 最终失去顶点着色器和像素着色器的调用如下(此时材质类型和渲染Pass曾经确定): 材质的GetShader函数首先以以后顶点工厂类型的ID为索引,通过GetMeshShaderMap函数从OrderedMeshShaderMaps成员变量中查问到对应顶点工厂类型的MeshShaderMap,随后调用以后MeshShaderMap的GetShader函数,以以后着色器类型为参数查问,查问到理论对应的着色器。 总结如下:本质上获取一组着色器组合须要的三个变量:渲染Pass、顶点工厂类型和材质类型,这也就不难理解UE4中对资源的组织模式了。 ...

August 7, 2020 · 1 min · jiezi