view source 
     print 
     ? 
    
    
      1. 
     void Update() 
     
     2. 
     { 
     
     3. 
     if(Input.GetMouseButtonDown(0)) 
     
     4. 
     { 
     
     5. 
     GetComponent<Renderer>().material.color = new Color(Random.value, Random.value, Random.value, 1.0f); 
     
     6. 
     } 
     
     7. 
     }
view source 
     print 
     ? 
    
    
      001. 
     public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList) 
     
     002. 
     { 
     
     003. 
     if (canvas == null) 
     
     004. 
     return; 
     
     005. 
       
     
     006. 
     // Convert to view space 
     
     007. 
     Vector2 pos; 
     
     008. 
     if (eventCamera == null) 
     
     009. 
     pos = new Vector2(eventData.position.x / Screen.width, eventData.position.y / Screen.height); 
     
     010. 
     else 
     
     011. 
     pos = eventCamera.ScreenToViewportPoint(eventData.position); 
     
     012. 
       
     
     013. 
     // If it's outside the camera's viewport, do nothing 
     
     014. 
     if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f) 
     
     015. 
     return; 
     
     016. 
       
     
     017. 
     float hitDistance = float.MaxValue; 
     
     018. 
       
     
     019. 
     Ray ray = new Ray(); 
     
     020. 
       
     
     021. 
     if (eventCamera != null) 
     
     022. 
     ray = eventCamera.ScreenPointToRay(eventData.position); 
     
     023. 
       
     
     024. 
     if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None) 
     
     025. 
     { 
     
     026. 
     float dist = eventCamera.farClipPlane - eventCamera.nearClipPlane; 
     
     027. 
       
     
     028. 
     if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All) 
     
     029. 
     { 
     
     030. 
     RaycastHit hit; 
     
     031. 
     if (Physics.Raycast(ray, out hit, dist, m_BlockingMask)) 
     
     032. 
     { 
     
     033. 
     hitDistance = hit.distance; 
     
     034. 
     } 
     
     035. 
     } 
     
     036. 
       
     
     037. 
     if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All) 
     
     038. 
     { 
     
     039. 
     RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, dist, m_BlockingMask); 
     
     040. 
       
     
     041. 
     if (hit.collider != null) 
     
     042. 
     { 
     
     043. 
     hitDistance = hit.fraction * dist; 
     
     044. 
     } 
     
     045. 
     } 
     
     046. 
     } 
     
     047. 
       
     
     048. 
     m_RaycastResults.Clear(); 
     
     049. 
     Raycast(canvas, eventCamera, eventData.position, m_RaycastResults); 
     
     050. 
       
     
     051. 
     for (var index = 0; index < m_RaycastResults.Count; index++) 
     
     052. 
     { 
     
     053. 
     var go = m_RaycastResults[index].gameObject; 
     
     054. 
     bool appendGraphic = true; 
     
     055. 
       
     
     056. 
     if (ignoreReversedGraphics) 
     
     057. 
     { 
     
     058. 
     if (eventCamera == null) 
     
     059. 
     { 
     
     060. 
     // If we dont have a camera we know that we should always be facing forward 
     
     061. 
     var dir = go.transform.rotation * Vector3.forward; 
     
     062. 
     appendGraphic = Vector3.Dot(Vector3.forward, dir) > 0; 
     
     063. 
     } 
     
     064. 
     else 
     
     065. 
     { 
     
     066. 
     // If we have a camera compare the direction against the cameras forward. 
     
     067. 
     var cameraFoward = eventCamera.transform.rotation * Vector3.forward; 
     
     068. 
     var dir = go.transform.rotation * Vector3.forward; 
     
     069. 
     appendGraphic = Vector3.Dot(cameraFoward, dir) > 0; 
     
     070. 
     } 
     
     071. 
     } 
     
     072. 
       
     
     073. 
     if (appendGraphic) 
     
     074. 
     { 
     
     075. 
     float distance = 0; 
     
     076. 
       
     
     077. 
     if (eventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay) 
     
     078. 
     distance = 0; 
     
     079. 
     else 
     
     080. 
     { 
     
     081. 
     // http://geomalgorithms.com/a06-_intersect-2.html 
     
     082. 
     distance = (Vector3.Dot(go.transform.forward, go.transform.position - ray.origin) / Vector3.Dot(go.transform.forward, ray.direction)); 
     
     083. 
       
     
     084. 
     // Check to see if the go is behind the camera. 
     
     085. 
     if (distance < 0) 
     
     086. 
     continue; 
     
     087. 
     } 
     
     088. 
       
     
     089. 
     if (distance >= hitDistance) 
     
     090. 
     continue; 
     
     091. 
       
     
     092. 
     var castResult = new RaycastResult 
     
     093. 
     { 
     
     094. 
     gameObject = go, 
     
     095. 
     module = this, 
     
     096. 
     distance = distance, 
     
     097. 
     index = resultAppendList.Count, 
     
     098. 
     depth = m_RaycastResults[index].depth, 
     
     099. 
     sortingLayer =  canvas.sortingLayerID, 
     
     100. 
     sortingOrder = canvas.sortingOrder 
     
     101. 
     }; 
     
     102. 
     resultAppendList.Add(castResult); 
     
     103. 
     } 
     
     104. 
     } 
     
     105. 
     }
view source 
     print 
     ? 
    
    
      01. 
     protected override void OnEnable() 
     
     02. 
     { 
     
     03. 
     base.OnEnable(); 
     
     04. 
     CacheCanvas(); 
     
     05. 
     GraphicRegistry.RegisterGraphicForCanvas(canvas, this); 
     
     06. 
       
     
     07. 
     #if UNITY_EDITOR 
     
     08. 
     GraphicRebuildTracker.TrackGraphic(this); 
     
     09. 
     #endif 
     
     10. 
     if (s_WhiteTexture == null) 
     
     11. 
     s_WhiteTexture = Texture2D.whiteTexture; 
     
     12. 
       
     
     13. 
     SetAllDirty(); 
     
     14. 
       
     
     15. 
     SendGraphicEnabledDisabled(); 
     
     16. 
     }
view source 
     print 
     ? 
    
    
      01. 
     public static void RegisterGraphicForCanvas(Canvas c, Graphic graphic) 
     
     02. 
     { 
     
     03. 
     if (c == null) 
     
     04. 
     return; 
     
     05. 
       
     
     06. 
     IndexedSet<Graphic> graphics; 
     
     07. 
     instance.m_Graphics.TryGetValue(c, out graphics); 
     
     08. 
       
     
     09. 
     if (graphics != null) 
     
     10. 
     { 
     
     11. 
     graphics.Add(graphic); 
     
     12. 
     return; 
     
     13. 
     } 
     
     14. 
       
     
     15. 
     graphics = new IndexedSet<Graphic>(); 
     
     16. 
     graphics.Add(graphic); 
     
     17. 
     instance.m_Graphics.Add(c, graphics); 
     
     18. 
     }
view source 
     print 
     ? 
    
    
      01. 
     bool CheckGuiRaycastObjects() 
     
     02. 
     { 
     
     03. 
     PointerEventData eventData = new PointerEventData(Main.Instance.<strong>eventSystem</strong>); 
     
     04. 
     eventData.pressPosition = Input.mousePosition; 
     
     05. 
     eventData.position = Input.mousePosition; 
     
     06. 
       
     
     07. 
     List<RaycastResult> list = new List<RaycastResult>(); 
     
     08. 
     Main.Instance.<strong>graphicRaycaster</strong>.Raycast(eventData, list); 
     
     09. 
     //Debug.Log(list.Count); 
     
     10. 
     return list.Count > 0; 
     
     11. 
     }
view source 
     print 
     ? 
    
    
      01. 
     void Update () 
     
     02. 
     { 
     
     03. 
     if (CheckGuiRaycastObjects()) return; 
     
     04. 
     //Debug.Log(EventSystem.current.gameObject.name); 
     
     05. 
     if (Input.GetMouseButtonDown(0)) 
     
     06. 
     { 
     
     07. 
     Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 
     
     08. 
     RaycastHit hit; 
     
     09. 
       
     
     10. 
     if (Physics.Raycast(ray, out hit)) 
     
     11. 
     { 
     
     12. 
     //do some thing 
     
     13. 
     } 
     
     14. 
     } 
     
     15. 
     }
  • 简述
    最近在用UGUI的时候遇到了鼠标穿透的问题,就是说在UGUI和3D场景混合的情况下,点击UI区域同时也会 触发3D中物体的鼠标事件。比如下图中
  • UNity实现在Image上颜色过渡 unity物体颜色怎么改_Graphic

  • 这里给Cube加了一个鼠标点击改变颜色的代码,如下




  • 运行一下,会发现只要有鼠标点击(任何位置点击),Cube的颜色就会改变,根据代码我们知道这也是必然的,但是问题是如果Cube是一个3D世界中的mesh或者terrain,而button是UI的话也同样会出现同样的问题。
    在游戏开发中我们的UI是始终出现在屏幕的,如果在一个战斗场景中用户点了UI战斗场景中的物体也会作出响应肯定是有问题的!
    其实关于这个问题网上有不少解决方法了,但是总感觉没有一个是适合我的需求,或者说没有一个最好的答案。
    其中提到最多的是利用EventSystem.current.IsPointerOverGameObject()来判断,这个方法的意义是判断鼠标是否点到了GameObject上面,这个GameObject包括UI也包括3D世界中的任何物体,所以他只能判断用户是都点到了东西。对于本文中的问题意义不是很大。那么这个问题到底该怎么解决呢?
    原理
    解决方法最终还是离不开射线检测,不过UGUI中已经封装了针对UI部分的射线碰撞的功能,那就是GraphicRaycaster类。里面有个Raycast方法如下,最终就是将射线碰撞到的点添加进resultAppendList数组。




  • 从这个方法开始深入查看Unity UGUI源码你会发现,其实每个组件在创建的时候已经被添加进了一个公共列表,UGUI 源码中的GraphicRegistry类就是专门干这件事的。再看下Graphic类中的OnEnable方法




  • 看这句GraphicRegistry.RegisterGraphicForCanvas(canvas, this);就是注册需要做射线检测的UI组件。再看他内部是如何工作的




  • 不过,问题又来了,为什么是添加进列表的对象都是Graphic类型呢?这跟ScrollRect,Button,Slider这些有关吗?其实,这就跟UGUI的类继承关系有关了,其实我们使用的UGUI中的每个组件都是继承自Graphic或者依赖一个继承自Graphic的组件
    看一下UGUI的类层次结构就会一目了然,如下

    UNity实现在Image上颜色过渡 unity物体颜色怎么改_Graphic_02

  • 看图就会更加清楚,在这我们可以把我们用到的UGUI的所有组件分为两类,1.是直接继承自Graphic的组件。2.是依赖于1的组件"[RequireComponent(typeof(Griphic))]",仔细想想会发现,所有组件都属于这两种中的某一种。
    所以对所有Graphic进行Raycast其实就相当于对所有UI组件进行Raycast。
    结合上面的知识所以,解决这个问题最好的方法是根据,UGUI的射线碰撞来做。这样会比较合理。
    解决方案
    这里我们直接在使用Input.GetMouseButtonDown(0)的地方加了一个检测函数,CheckGuiRaycastObjects,如下




  • 不过在使用时需要先获取两个加粗显示的变量,graphicRaycaster和eventSystem。
    这两个变量分别对应的是Canvas中的GraphicRaycaster组件,和创建UI时自动生成的“EventSystem”中的EventSystem组件,用的是自己制定以下就可以。
    然后在使用的时候可以这样:




  • 还有一个需要注意的地方就是,在做UI的时候一般会用一个Panel做跟目录,这个panel也会被添加到GraphicRegistry中的公共列表中,如果是这样的话记得把list.Count>0改成list.Count>1,或者直接删除Panel上的继承自Graphic的组件。
    这样在结合着EventSystem.current.IsPointerOverGameObject()来使用就比较好了。
    本文固定连接:
    ok了,现在舒服多啦!