Interfaz de usuario (7) - Optimización de la interfaz de usuario (2)

④ Separación alfa del atlas de UI.

¿Por qué separación alfa para UI Atlas?

Nuestra compresión del atlas de la interfaz de usuario es parte de la reducción del tamaño del paquete de la aplicación, que también es una forma más efectiva de reducir el uso de la memoria. Al reducir la memoria, también reducirá el consumo de la CPU. La compresión del atlas de la interfaz de usuario tiene muchos beneficios, pero también causa algunos problemas.Cuando comprimimos el atlas, el efecto que se muestra en la pantalla no es satisfactorio, como aparecen líneas borrosas, irregulares y otras imágenes de baja calidad. Esto se debe a que también comprimimos el canal transparente cuando usamos el modo de compresión ECT o PVRTC, lo que genera una distorsión de la representación, por lo que debemos separar el canal transparente alfa y comprimirlo por separado. De esta manera, el atlas se puede comprimir para lograr el propósito de reducir la memoria y la visualización de la imagen no se distorsionará demasiado.

¿Cómo separar el Alpha del UI Atlas?

Estamos aquí principalmente para la solución de NGUI, y dado que UGUI está integrado internamente, la separación alfa ya se ha realizado para usted en la UGUI de Unity3D, por lo que solo hablaremos sobre cómo separar alfa para NGUI.

En primer lugar, use TexturePacker para convertir el atlas original en dos atlas en un png RGB888 y un png Alpha8. La imagen PNG de RGB888 no tiene alfa y todos los canales alfa están en el PNG de Alpha8. También puede usar el método de separación de programas para extraer el color de la imagen original y colocarlo en una nueva imagen, y extraer la parte alfa y colocarla en otra imagen.

Luego, debemos modificar el sombreador original de NGUI y cambiar el sombreador original que solo vincula una imagen principal a un sombreador que necesita vincular una imagen principal y una imagen alfa.

Los siguientes 4 Shaders necesitan ser modificados

	Unlit – Transparent Colored.shader,

	Unlit – Transparent Colored 1.shader,

	Unlit – Transparent Colored 2.shader,

	Unlit – Transparent Colored 3.shader

El contenido modificado es para agregar

_AlphaTex ("Alpha (A)", 2D) = "black" {} 变量,用来可以绑定Alpha图

Luego, en la función frag, los contenidos de la operación en alfa y el alfa de la imagen principal se reemplazan con el valor alfa en la imagen alfa. Utilice el Alfa de la imagen Alfa para reemplazar la parte alfa de la imagen principal original, y la imagen principal seguirá teniendo el contenido de color principal. detalles de la siguiente manera:

	 //fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
	 //return col;
	 fixed4 texcol = tex2D(_MainTex, i.texcoord);   
	 fixed4 result = texcol;  
	 result.a = tex2D(_AlphaTex,i.texcoord).r*i.color.a;

En el código anterior, la parte comentada es que el original solo usa una imagen para mostrar los canales de color y transparencia, y el método recién agregado es usar las dos imágenes _MainTex y _AlphaTex para reemplazar los canales de color y transparencia respectivamente.

Finalmente, después de completar todo lo anterior, seleccione un prefabricado de atlas creado y encontrará que la ventana de vista previa debajo de la ventana Inspector y el sprite que se ve en la ventana de selección de Sprite no tienen visualización de canal alfa, porque se usa para el modo de visualización. bajo el editor La imagen original que todavía se usa usa dos canales, por lo que también necesitamos modificar las herramientas NGUI en estos editores.

Para solucionar este problema, nuestra solución es generar dinámicamente una textura rgba32 en el modo editor para reemplazarla.Los valores de los canales rgb y alfa se toman respectivamente de las dos imágenes que tenemos ahora.

Entre ellos, la clase de edición NGUI que necesita ser modificada tiene los siguientes archivos:

	UIAtlas.cs,

	UIAtlasInspector.cs,

	SpriteSelector.cs,

	NGUITools.cs,

	UISpriteInspector.cs

Al modificar la clase anterior, la imagen recién generada se habilita al dibujar la imagen, que es la imagen temporal sintetizada con RGB888 y Alpha mencionada anteriormente.

De hecho, no hay muchas partes para modificar, y la dirección y el principio de la modificación también son simples. Primero, se generan dos imágenes, una con solo color y otra con solo canal alfa, y luego la fuente alfa del Shader. se cambia a una nueva imagen alfa y, finalmente, el sombreador. La modificación causó el problema de visualización del editor, y es necesario generar un diagrama temporal en la parte del editor para reemplazar el diagrama original que se muestra.

⑤ División de fuente de interfaz de usuario.

¿Por qué dividir las fuentes de la interfaz de usuario?

Las fuentes en el proyecto en realidad ocupan mucho espacio, si varias fuentes diferentes se muestran juntas en la pantalla, consumirá mucha memoria. Las fuentes a menudo son inevitables, pero deben estandarizarse y organizarse, y también deben optimizarse. Necesitamos una eficiencia de rendimiento más rápida, dividir las fuentes hará que las fuentes se carguen más rápido y las escenas se cargarán más rápido.

¿Cómo dividir las fuentes de la interfaz de usuario?

Nuestra solución es eliminar los caracteres de uso común en la fuente y generar otro archivo de fuente para hacer que el archivo de fuente sea más pequeño y la memoria sea menor, y finalmente hacer que la carga sea más rápida.

Por ejemplo, en la escena de inicio de sesión, solo necesitamos unos pocos números y letras, por lo que podemos extraer los números y 26 letras de la fuente para crear una nueva fuente y aplicarla en la escena, lo que ahorra la carga de fuentes grandes.

Para otro ejemplo, en la escena de elegir un nombre después del registro e inicio de sesión, eliminamos algunas palabras que se usan con menos frecuencia y solo mantenemos 3000 palabras de uso común. Se eliminan los 3000 caracteres que se usan comúnmente en la fuente y se genera y usa una nueva fuente en la escena. Esto ahorra una gran cantidad de imágenes de glifos inútiles almacenadas en la fuente, lo que ahorra mucho espacio en la memoria.

⑥ Optimización de desplazamiento de vista de desplazamiento.

Scroll View 使用在类似背包的界面中非常常见,会有巨量的元素存在在窗口中进行渲染,所以在生成和滑动时,会消耗大量的CPU来重构Mesh,进而导致游戏运行缓慢,出现卡顿现象。这是由于我们前面在UGUI源码剖析中介绍过的元素属性上的改变将导致网格的重构,如果不断移动则每帧都需要重构,导致大量的CPU浪费。

要优化这种情况,就必须对滚屏菜单组件进行改造,将原来策略中所有元素都必须一次性实例化的问题,改为只实例化需要显示的实例数量。然后在拖动滑动的期间,实时判断是否有有UI元素被移出画面,这样的元素可以重复利用,将他们填补到需要显示的位置的上去,再对该单位元素的属性重新设置,我们需要的元素信息,让它展现为在该位置需要显示的元素的样子。

从表现上观察就如同下面所描述的那样:

	我们在窗口中实例化10排元素显示在那里滚动窗口中,其中5排是展示在中央的窗口上的,另外5排中的顶上2排因为超出了窗口被裁剪而无法看见,

	同样的下面3排也是因为超出了窗口被裁剪无法看见,在整个10排元素整体向上滑动期间,顶上2排变成了3排,底下3排变成了2排,

	其中最顶上的1排超过了重置的界线,就被移动到了底下去了,这样整体10排元素,变成了顶上2排,底下3排的局面,

	这样不断反复,不断在移动顶上或底下的1排元素,把他们移动到需要补充的位置上去。看起来像是,很顺畅地上下滚屏整个500个元素那样,实际上是对这5排元素在不断重复的利用而已。

Scroll View 自定义组件是大部分项目都必须的,大部分项目都会遇到这类问题也会去改善这个问题,有一个自己优化过的自定义组件,能很快很高效的解决这类问题。

⑦ UGUI图在改变颜色或Alpha后,导致对Mesh重构的优化。

这里再稍微解释下为什么在UGUI的图元素在改变颜色或Alpha后会导致Mesh的重构?UGUI的Mesh的合并机制是拥有相同的材质球的Mesh合并在一起才能达到最佳效果,一个材质球对应一个图集,只有相同图集内的图片才需要合并在一起。

UGUI中当元素需要对颜色进行改变时,UGUI是通过改变顶点的颜色来实现颜色的变化的。改变当前元素的顶点颜色,然后需要将它们重新合并到整块的Mesh里去,因为不能直接从原来合并好的Mesh上找到当前的顶点位置,所以需要一次整体的合并重构Mesh。

元素改变了 alpha 则会更糟糕,由于改变 alpha 的效果无法通过改变顶点的颜色来实现,于是就需要拆分出一个另外的材质球来进行渲染,通过对材质球的参数改变来实现 alpha 的效果。这样做不但重构了Mesh,还多出来个材质球,就相当于多一个Drawcall,效率消耗相当大。

倘若在动画里,每一帧都对UGUI的颜色和Alpha进行改变,那么UGUI每一帧都会对Mesh进行重构一次,并且每帧都生成新的材质球来实现 alpha 的透明效果。这样做消耗了大量的CPU运算,通常使得UI界面在运行动画时效率特别低下,即使拆分动静分离也无济于事。

如何对此做优化呢?我们不希望在UI颜色改变时,导致Mesh重构,这样动画中消耗掉太多CPU,那么我们就自己建一个材质球,提前告诉UGUI:我们使用自己的特殊的材质球进行渲染。当颜色动画对颜色和 alpha 更改时,我们直接对我们自定义的材质球进行颜色和 alpha 的改变。这样UGUI就不需要重构Mesh了,因为把渲染的工作交给了新的材质球,而不是通过 UGUI 设置顶点颜色和新材质球来达到效果。

如何操作?

	首先,我们需要把UGUI的Shader下载下来。

	然后,建立一个自己的材质球,并且材质球里使用下载下来的UGUI的Shader。

	再次,把这个材质球放入Image或RawImage的Material上去,与Image或RawImage绑定。

	接着,写个类比如class ImageColor继承MonoBehaviour,里面有个public 的颜色变量,比如public Color mColor,类里面只干一件事,在update里一直判断是否需要更改颜色,如果颜色被更改,就把颜色赋值给Material。

	最后,把动画文件中的颜色部分从更改Image或RawImage的颜色变为更改 ImageColor 的颜色变量。这样UGUI颜色动画在播放时,不会直接去改变 Image 或 RawImage 的颜色,改变的是我们创建的 ImageColor 的颜色。

通过 ImageColor 来改变材质球属性,最后达到不重构Mesh的效果。切换元素的贴图时也一样可以做到不重构的效果,由于贴图更换会导致重构,为了达到不重构的目的可以给一个自定义材质球的并且更换材质球中的贴图。

不过要注意下,因为启用了自定义的材质球,所以Drawcall就提高了,因为每个材质球都会单独增加一次Drawcall。并且当 alpha 不是1的时候,会与原有的UGUI产生的材质球的透贴形成不同的渲染排序,原因是当两张透贴放在一起渲染时,alpha混合会导致渲染排序混乱而前后不一致。所以使用时要小心谨慎,权衡利弊用在恰当的地方将发挥大的功效,用在不恰当的地方则事倍功半。

这个半透明物体的排序问题,归根结底是无法写入深度数据问题,是3D渲染中无法彻底解决的问题。我们会在后面的渲染管线与图形学章节中详细介绍。这里解决半透明排序问题,可以通过改变自定义的 Shader 中的渲染次序(RenderQueue)来解决。

Guess you like

Origin blog.csdn.net/s178435865/article/details/129535213