Unity 3d 4.6 Raycast忽略Sprite上的Alpha [英] Unity 3d 4.6 Raycast ignore alpha on sprite

查看:142
本文介绍了Unity 3d 4.6 Raycast忽略Sprite上的Alpha的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有这个图像我正在使用脚本来检测拖动事件,以便用户可以从屏幕侧面拉动滚动条.问题是我有一个按钮位于黏土密封上方,并且被滚动图片的Rect阻塞.由于滚动移动了,因此我无法完全将按钮作为其父项.所以我想问是否有一种方法可以忽略滚动条上的Alpha,并使射线投射通过它.我已经有一个使用盒对撞机并实现ICanvasRaycastFilter的脚本,但是由于某种原因,它似乎无法与unity scroll rect一起使用.这是完整的脚本:

So i have this image I'm using a script on it to detect drag event so that the user can pull the scroll from the side of the screen. The problem is that I have a button that sits above the clay seal and it is being blocked by the Rect of the scroll picture. Since the scroll moves I cant exactly parent the button to it. So I'm asking if there is a way to ignore the alpha on the scroll and make ray casts pass trough it. I already have a script that uses a box collider and implements the ICanvasRaycastFilter but it doesnt seem to work with the unity scroll rect for some reason. Here is the full script :

using UnityEngine;
using System.Collections;

public class RaycastFilter : MonoBehaviour, ICanvasRaycastFilter
{
    private RectTransform rectTransform;
    private new BoxCollider2D collider2D;

    public void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
        collider2D = GetComponent<BoxCollider2D>();
    }

    public bool IsRaycastLocationValid(Vector2 screenPosition, Camera raycastEventCamera) //uGUI callback
    {
        // If we don't have a collider we will simply use the big button box. //TODO: make custom exception for this.
        if (collider2D == null)
            return true;

        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPosition, raycastEventCamera, out localPoint);

        Vector2 pivot = rectTransform.pivot - new Vector2(0.5f, 0.5f);

        Vector2 pivotScaled = Vector2.Scale(rectTransform.rect.size, pivot);

        Vector2 realPoint = localPoint + pivotScaled;

        Rect colliderRect = new Rect(
            collider2D.center.x - collider2D.size.x / 2,
            collider2D.center.y - collider2D.size.y / 2,
            collider2D.size.x,
            collider2D.size.y); // TODO: CACHE

        bool containsRect = colliderRect.Contains(realPoint);

        return containsRect;
    }
}

推荐答案

万一有人像我一样偶然发现这个问题,这是我在3D世界中通过alpha射线投射精灵的解决方案.

In case anyone stumbles upon this like I did, here's my solution for raycasting sprites through alpha in a 3D world.

首先,使用逆变换将击中点转换为精灵的局部空间.然后,添加精灵的枢轴点.由于它以像素表示,因此将其除以每单位像素可得到正确的偏移量. 要获得该局部点的UV值,请将其除以Sprite边界大小.这将为您提供0到1之间的值.由于我们的坐标系是Y向上,纹理是Y向下,所以我们必须反转我们的Y值. 现在,很容易读取正确的像素.将UV乘以纹理的宽度和高度.

First, transform your hit point to the local space of the sprite using an inverse transform. Then, add the pivot point of your sprite. Since it is expressed in pixels, dividing it by the pixels per unit gives you the correct offset. To get the UV values of that local point, divide it by the sprite bounds size. This will give you values between 0 and 1. Since our coordinate system is Y up and a texture is Y down, we'll have to invert our Y value. Now it's easy to read the correct pixel. Multiply the UV with the texture width and height.

    private GameObject Raycast(Vector2 screenPos)
    {
        Ray ray = new Ray(_camera.ScreenToWorldPoint(screenPos), _camera.transform.forward);

        var result = Physics.RaycastAll(ray, float.MaxValue).ToList().OrderByDescending(h => h.distance); //inverse raycast

        foreach (var hit in result)
        {
            var rend = hit.transform.GetComponent<SpriteRenderer>();
            if (rend == null)
                continue;

            Vector2 localPos = hit.transform.InverseTransformPoint(hit.point);
            localPos += rend.sprite.pivot / rend.sprite.pixelsPerUnit;

            Vector2 uv = localPos / rend.sprite.bounds.size;
            uv.y = 1f - uv.y;

            Texture2D tex = rend.sprite.texture as Texture2D;

            int x = (int)(uv.x * tex.width);
            int y = (int)(uv.y * tex.height);
            var pix = tex.GetPixel(x, y);

            if (pix.a > 0)
            {
                return hit.transform.gameObject;
            }
        }

        return null;
    }

这篇关于Unity 3d 4.6 Raycast忽略Sprite上的Alpha的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆