UGUI ScrollView中显示模型和特效
游戏开发中有时候会遇到在UI上显示模型和特效的需求,这次需要在ScrollView上显示。我们使用UGUI的Screen Space - Camera模式,修改模型和特效的layer使之显示在UI上面,但是会遇到ScrollView的mask无法剔除模型和特效的问题。
解决思路:计算出ScrollView的显示矩形框的世界坐标和尺寸,传给模型和特效的shader,在shader里判断这个像素的世界坐标是否超过矩形框,来判断是否显示图像。
C#代码部分:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ScrollViewModelAndEffectClip : MonoBehaviour { public RectTransform scrollViewArea; float mWidth, mHeight, m_canvasScale; Canvas mCanvas; public Vector4 area; List<Material> modelMaterials = new List<Material>(); // Start is called before the first frame update void Start() { var renderers=GetComponentsInChildren<Renderer>(); for(int i = 0; i < renderers.Length; i++) { //Debug.LogError(renderers[i]); modelMaterials.AddRange(renderers[i].GetMaterials()); } for(int i = 0; i < modelMaterials.Count; i++) { modelMaterials[i].shader = Shader.Find(modelMaterials[i].shader.name + "ScrollViewClip"); //Debug.LogError(modelMaterials[i].shader.name + "ScrollViewClip"); } mCanvas = GetComponentInParent<Canvas>(); GetArea(); } // Update is called once per frame void Update() { } public void GetArea() { m_canvasScale = mCanvas.transform.localScale.x; mWidth = scrollViewArea.rect.width * m_canvasScale; mHeight = scrollViewArea.rect.height * m_canvasScale; area = CalculateArea(scrollViewArea.position, scrollViewArea.pivot); for (int i = 0; i < modelMaterials.Count; i++) { //Debug.LogError(area); modelMaterials[i].SetVector("_Area", area); } } Vector4 CalculateArea(Vector3 position,Vector2 pivot) { return new Vector4() { x = position.x - mWidth*pivot.x, y = position.y - mHeight * pivot.y, z = position.x + mWidth *(1- pivot.x), w = position.y + mHeight * (1 - pivot.y) }; } }
接下来是Shader:
Shader "SonicDance/AddtiveScrollViewClip" { Properties { _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5) _MainTex ("Particle Texture", 2D) = "white" {} _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0 //Clip新增 _Area("Area", Vector) = (0,0,1,1) // } Category { SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Off Lighting Off ZWrite Off Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; fixed4 color : COLOR; float4 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float4 texcoord : TEXCOORD0; float4 worldPos:TEXCOORD3; UNITY_FOG_COORDS(1) #ifdef SOFTPARTICLES_ON float4 projPos : TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO }; uniform sampler2D _MainTex; uniform fixed4 _TintColor; uniform float4 _MainTex_ST; uniform sampler2D_float _CameraDepthTexture; uniform float _InvFade; //Clip新增 float4 _Area; // v2f vert ( appdata_t v ) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); v.vertex.xyz += float3( 0, 0, 0 ) ; o.vertex = UnityObjectToClipPos(v.vertex); o.worldPos= mul(unity_ObjectToWorld, v.vertex); #ifdef SOFTPARTICLES_ON o.projPos = ComputeScreenPos (o.vertex); COMPUTE_EYEDEPTH(o.projPos.z); #endif o.color = v.color; o.texcoord = v.texcoord; UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag ( v2f i ) : SV_Target { //新增,判断顶点坐标是否在裁剪框内 bool inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w; if (!inArea) discard; //----end---- #ifdef SOFTPARTICLES_ON float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))); float partZ = i.projPos.z; float fade = saturate (_InvFade * (sceneZ-partZ)); i.color.a *= fade; #endif fixed4 col = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord.xy*_MainTex_ST.xy + _MainTex_ST.zw ); UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } } CustomEditor "ASEMaterialInspector" }
这个方法有一个问题就是,需要复制一份显示的模型和特效的shader,并且增加上面shader中注释的部分,如果模型和特效的shader多种多样的话,那工作量就比较大,需要其他的方法。