Raycasting through UI Image with transparent part
Hi,
I use the new UI system (on unity 5.2.2) and I have an UI Image that contains a 2D sprite. This sprite have some transparent parts and looks like this :
(in gray transparent parts, in orange colored parts)
I use Physics.Raycast to select my gamesObjects in the scene and I check if my pointer isn't on a UI element (with EventSystem). But my problem is that EventSystem.IsPointerOverGameObject() return true on gray (transparent) parts of my sprite.How can I select 3D elements through transparent parts of my UI elements.
Thanks for help.
some code :
if (Input.GetButtonDown("Mouse1"))
{
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out selectionRay) &&
!eventSystem.IsPointerOverGameObject())
{
Debug.Log("Select game object "+ selectionRay.collider);
}
}
Answer by alpapan · Dec 24, 2019 at 11:00 PM
Resurrecting as this is a top google hit... use this:
GetComponent<Image>().alphaHitTestMinimumThreshold = 1f; // or anything > 0
Remember to set the image asset's read write enable checkbox to true
Answer by seguso · Apr 14, 2017 at 04:32 PM
Here is the solution: use RaycastAll to retrieve all the objects hit, then return the closest object such that the alpha value of the pixel is not 0.
private static RaycastHit? RaycastWithTransparency(Ray ray)
{
var res = Physics.RaycastAll(ray, float.MaxValue).ToList().OrderBy(h => h.distance);
foreach (var h in res)
{
var col = h.collider;
Renderer rend = h.transform.GetComponent<Renderer>();
Texture2D tex = rend.material.mainTexture as Texture2D;
var xInTex = (int) (h.textureCoord.x*tex.width);
var yInTex = (int) (h.textureCoord.y*tex.height);
var pix = tex.GetPixel(xInTex, yInTex);
if (pix.a > 0)
{
//Debug.Log("You hit: " + col.name + " position " + h.textureCoord.x + " , " + h.textureCoord.y);
return h;
}
}
return null;
}
This does not work with UI since they dont have colliders and EventSystem.current.RaycastAll(ray, res); is used
How can you deter$$anonymous$$e the transparency this way?
Thanks
if that is true using EventSystem.current.RacastAll(ray, res); with seguso's answer should work. You basically want to hit the UI object, grab the Texture2D, calculate the mouses position on the Texture2D, deter$$anonymous$$e if that part of the Texture2D is transparent or not.
But EventSystem.current.RacastAll returns a List of RaycastResult and from a RaycastResult it is not possible to access the Texture2D as far as I know
Sorry, I don't remember. It might be I was not using UI at all. (I might have missed the "ui" part.)
Answer by Hazneliel · Apr 27, 2018 at 07:34 PM
Using Physics.RaycastAll does not work with UI since they dont have colliders and EventSystem.current.RaycastAll is used
How can you determine the transparency this way?
Thanks
A technique used in other applications is to get the position of the raycast and then use getpixel to check the color of the pixels at that position. Not simple but probably possible...
Answer by w34edrtfg · Nov 08, 2021 at 08:59 AM
Script for RawImages that acts like alphaHitTestMinimumThreshold :
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/*
* RawImage doesn't have alphaHitTestMinimumThreshold, (which let's you avoid raycasting transparent pixels)
* This class act's as alphaHitTestMinimumThreshold replacement for RawImages by overriding raycast's default behaviour
* THE IMAGE TEXTURE MUST HAVE READ/WRITTING IN IT'S SETTINGS
* Stolen from https://github.com/Hengle/GrassWateringSimulator2019/blob/master/Grass%20Watering%20Simulator%202019/Assets/HTC.UnityPlugin/ViveInputUtility/Examples/4.Teleport/Scripts/ImageAlphaRaycastFilter.cs
*/
[RequireComponent(typeof(RawImage))]
public class ImageAlphaRaycastFilter : UIBehaviour, ICanvasRaycastFilter
{
[NonSerialized]
private RawImage m_rawImage;
public float alphaHitTestMinimumThreshold = 1;
protected RawImage rawImage {
get { return m_rawImage ?? (m_rawImage = GetComponent<RawImage>()); }
}
public virtual bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera) {
if (alphaHitTestMinimumThreshold <= 0) { return true; }
if (alphaHitTestMinimumThreshold > 1) { return false; }
var texture = rawImage.mainTexture as Texture2D;
Vector2 local;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rawImage.rectTransform, screenPoint, eventCamera, out local)) {
return false;
}
var rect = rawImage.GetPixelAdjustedRect();
// Convert to have lower left corner as reference point.
local.x += rawImage.rectTransform.pivot.x * rect.width;
local.y += rawImage.rectTransform.pivot.y * rect.height;
// normalize
local = new Vector2(local.x / rect.width, local.y / rect.height);
try {
return texture.GetPixelBilinear(local.x, local.y).a >= alphaHitTestMinimumThreshold;
} catch (UnityException e) {
Debug.LogError("Using alphaHitTestMinimumThreshold greater than 0 on Graphic whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);
return true;
}
}
}
Your answer
Follow this Question
Related Questions
Making A Model Transparent/Fade? Unity-chan etc... 3 days no results! 0 Answers
Rendering order shifts with transparent cubes (3D perspective camera, Standard shader) 0 Answers
How can I add alpha channel to this shader and how can I make the object to be transparent ? 1 Answer
Alpha transparency works but not in the whole tile 0 Answers