Unity SpotLight光照事件的判断

16
回复
1352
查看
打印 上一主题 下一主题
[ 复制链接 ]
7日久生情
1770/5000
排名
1365
昨日变化

7

主题

244

帖子

1770

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
162659
好友
3
蛮牛币
4639
威望
0
注册时间
2016-8-16
在线时间
625 小时
最后登录
2019-6-26

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 十二点的BigBen 于 2019-2-19 09:10 编辑

场景中需要检测SpotLight灯光,判断这个物体是否被灯光照射到。在网上找了许多,然后发现是通过在灯光内发射许多射线,通过射线与物体碰撞进行检测。在这记录学习下。具体代码:

public enum LightEventType { Enter, Stay, Exit }


public class LightEventData
{
    public string name;
    public Action<RaycastHit>[] methods;
    public LightEventData(string na, Action<RaycastHit>[] meths)
    {
        name = na;
        methods = meths;
    }
}

public class RayData
{
    public Vector3 position;
    public Vector3 direction;
    public float distance;

    public RayData(Vector3 dir, Light light)
    {
        position = light.transform.position + direction * distance;
        direction = dir;
        distance = light.range;
    }

    public RayData(float x, float y, Light light)
    {
        float radius = Mathf.Tan(Mathf.Deg2Rad * (light.spotAngle) / 3) * light.range;
        position = light.transform.position + light.transform.forward * light.range + light.transform.rotation * new Vector3(x, y) * radius;
        direction = Vector3.Normalize(position - light.transform.position);
        distance = Vector3.Distance(position, light.transform.position);
    }
}

public class HitInfoList : List<RaycastHit>
{
    public HitInfoList() { }

    public HitInfoList(HitInfoList copy)
    {
        foreach (var elem in copy) this.Add(elem);
    }

    public bool AddElement(RaycastHit info)
    {
        RaycastHit result;
        if (!ExistElement(info, out result))
        {
            this.Add(info);
            return true;
        }
        return false;
    }

    public bool RemoveElement(RaycastHit info)
    {
        RaycastHit result;
        if (ExistElement(info, out result))
        {
            this.Remove(result);
            return true;
        }
        return false;
    }

    public HitInfoList GetSubList(HitInfoList another)
    {
        HitInfoList list = new HitInfoList(this);
        foreach (var elem in another)
        {
            RaycastHit result;
            if (ExistElement(elem, out result))
                list.Remove(result);
        }
        return list;
    }

    public bool ExistElement(RaycastHit info, out RaycastHit result)
    {
        foreach (var elem in this)
        {
            string iName = info.collider.name;
            string eName = elem.collider.name;
            if (iName.Equals(eName))
            {
                result = elem;
                return true;
            }
        }
        result = new RaycastHit();
        return false;
    }
}

public class FlashLight : MonoBehaviour
{
    public float dampSpeed = 0.5f;
    public float rangeOffset = 1f;
    public bool useMultipleRay = true;

    [Range(0.05f, 1f)]
    public float sectionOfMultipleRay = 0.05f;
    Light light; float dampTmp;
    float maxLightDistance;
    static HitInfoList InfoList = new HitInfoList();

    void Start()
    {
        light = GetComponent<Light>();
        maxLightDistance = light.range;
    }

    void Update()
    {
        ControlLightRange();
        DetectObject();
    }

    public void Switch(bool switchOn)
    {
        light.enabled = switchOn;
    }

    void ControlLightRange()
    {
        Ray ray = new Ray(transform.position, transform.forward);
        RaycastHit info;
        float distance;
        if (Physics.Raycast(ray, out info))
        {
            distance = Mathf.Clamp(info.distance + rangeOffset, 0, maxLightDistance);
            Debug.DrawLine(transform.position, info.point);
        }
        else
            distance = maxLightDistance;

        light.range = Mathf.SmoothDamp(light.range, distance, ref dampTmp, dampSpeed);
    }

    void DetectObject()
    {
        HitInfoList list = new HitInfoList();
        foreach (var data in GetRayData())
        {
            Ray ray = new Ray(transform.position, data.direction);
            RaycastHit info;
            if (Physics.Raycast(ray, out info, data.distance))
                list.AddElement(info);
            Debug.DrawLine(transform.position, data.position, Color.red);
        }
        int operate = (list.Count == InfoList.Count) ? 0 : ((list.Count > InfoList.Count) ? 1 : -1); HandleEvent(list, operate);
    }

    void HandleEvent(HitInfoList current, int operate)
    {
        foreach (var elem in current)
        {
            if (operate != -1 && InfoList.AddElement(elem))
                LightEventListener.EventHandler(elem, LightEventType.Enter);
        }

        foreach (var elem in InfoList.GetSubList(current))
        {
            if (operate != 1 && InfoList.RemoveElement(elem))
                LightEventListener.EventHandler(elem, LightEventType.Exit);
        }
        foreach (var elem in InfoList)
            LightEventListener.EventHandler(elem, LightEventType.Stay);
    }

    List<RayData> GetRayData()
    {
        List<RayData> list = new List<RayData>();
        if (useMultipleRay)
            list.AddRange(GetFullCircleRay(new int[] { 1, -1 }, new int[] { 1, -1 }, sectionOfMultipleRay, light));
        else
            list.Add(new RayData(transform.forward, light));
        return list;
    }

    List<RayData> GetFullCircleRay(int[] xParams, int[] yParams, float section, Light light)
    {
        List<RayData> list = new List<RayData>();
        foreach (var x in xParams)
            foreach (var y in yParams)
                list.AddRange(GetQuarterCircleRay(x, y, section, light)); return list;
    }

    List<RayData> GetQuarterCircleRay(int xParam, int yParam, float section, Light light)
    {
        float x = 0, y = 0;
        List<RayData> list = new List<RayData>();
        while ((yParam > 0) ? y <= 1 : y >= -1)
        {
            while (x * x + y * y <= 1)
            {
                list.Add(new RayData(x, y, light));
                x += xParam * section;
            }
            x = 0;
            y += yParam * section;
        }
        return list;
    }
}

public abstract class LightEventListener : MonoBehaviour
{
    private static List<LightEventData> ListenerList = new List<LightEventData>();

    public static void EventHandler(RaycastHit info, LightEventType type)
    {
        foreach (var listener in ListenerList)
        {
            string lName = listener.name;
            string iName = info.collider.name;
            Action<RaycastHit> Method = listener.methods[(int)type];
            if (lName.Equals(iName) && Method != null)
            {
                Method(info);
            }
        }
    }

    protected abstract void OnLightEnter(RaycastHit info);
    protected abstract void OnLightStay(RaycastHit info);
    protected abstract void OnLightExit(RaycastHit info);

    void OnEnable()
    {
        LightEventData data = new LightEventData(name,
            new Action<RaycastHit>[] { OnLightEnter, OnLightStay, OnLightExit });

        ListenerList.Add(data);
    }
}

这是灯光发射射线,判断是否射线与物体碰撞到。碰撞到后

protected override void OnLightEnter(RaycastHit info)
    {
        Debug.Log(info.collider.name+ "Enter");
    }
    protected override void OnLightStay(RaycastHit info)
    {
        Debug.Log(info.collider.name + "Stay");
    }
    protected override void OnLightExit(RaycastHit info)
    {
        Debug.Log(info.collider.name + "Exit");
    }






0.png (1.25 MB, 下载次数: 27)

灯光射线

灯光射线
参与人数 1鲜花 -5 收起 理由
ceshi12580 -5 淡定

查看全部评分总评分 : 鲜花 -5

7日久生情
1868/5000
排名
4092
昨日变化

0

主题

1184

帖子

1868

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
254705
好友
1
蛮牛币
1725
威望
0
注册时间
2017-11-16
在线时间
322 小时
最后登录
2019-6-26
沙发
2019-2-19 08:21:35 只看该作者
66666666666666666666666666666666666666
6蛮牛粉丝
1050/1500
排名
5543
昨日变化

0

主题

657

帖子

1050

积分

Rank: 6Rank: 6Rank: 6

UID
300432
好友
1
蛮牛币
1450
威望
0
注册时间
2018-10-18
在线时间
133 小时
最后登录
2019-3-27
板凳
2019-2-19 09:29:32 只看该作者
666666666666
6蛮牛粉丝
1100/1500
排名
2066
昨日变化

0

主题

230

帖子

1100

积分

Rank: 6Rank: 6Rank: 6

UID
26073
好友
1
蛮牛币
4174
威望
0
注册时间
2014-5-21
在线时间
202 小时
最后登录
2019-6-26
地板
2019-2-19 09:45:25 只看该作者
牛逼,这绝对是高手
2初来乍到
142/150
排名
26983
昨日变化

3

主题

27

帖子

142

积分

Rank: 2Rank: 2

UID
279186
好友
0
蛮牛币
613
威望
0
注册时间
2018-4-28
在线时间
98 小时
最后登录
2019-5-3
5#
2019-2-19 09:46:56 只看该作者
看到过这个方法,觉得蠢得不行。。。
7日久生情
1770/5000
排名
1365
昨日变化

7

主题

244

帖子

1770

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
162659
好友
3
蛮牛币
4639
威望
0
注册时间
2016-8-16
在线时间
625 小时
最后登录
2019-6-26
6#
楼主 2019-2-19 11:22:52 只看该作者
uuuniity 发表于 2019-2-19 09:46
看到过这个方法,觉得蠢得不行。。。

那您有什么好的办法吗??求大大,
5熟悉之中
890/1000
排名
2867
昨日变化

6

主题

58

帖子

890

积分

Rank: 5Rank: 5

UID
257803
好友
0
蛮牛币
4616
威望
0
注册时间
2017-12-4
在线时间
310 小时
最后登录
2019-6-21
7#
2019-2-19 16:48:52 只看该作者
楼主可以参考一下文章,你这个方法太耗资源了,百度搜一下,蛮牛屏蔽链接
Unity3D学习(五):实现一个简单的视觉感知 - 0kk470 - 博客园
7日久生情
1770/5000
排名
1365
昨日变化

7

主题

244

帖子

1770

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
162659
好友
3
蛮牛币
4639
威望
0
注册时间
2016-8-16
在线时间
625 小时
最后登录
2019-6-26
8#
楼主 2019-2-19 17:42:34 只看该作者
无敌了咋办 发表于 2019-2-19 16:48
楼主可以参考一下文章,你这个方法太耗资源了,百度搜一下,蛮牛屏蔽链接
Unity3D学习(五):实现一个简单 ...

好的,万分感谢,
7日久生情
1868/5000
排名
4092
昨日变化

0

主题

1184

帖子

1868

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
254705
好友
1
蛮牛币
1725
威望
0
注册时间
2017-11-16
在线时间
322 小时
最后登录
2019-6-26
9#
2019-2-20 08:32:09 只看该作者
66666666666666666666666666666666666
7日久生情
2201/5000
排名
944
昨日变化

0

主题

416

帖子

2201

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
78535
好友
6
蛮牛币
2186
威望
0
注册时间
2015-3-10
在线时间
679 小时
最后登录
2019-6-26
10#
2019-2-21 10:13:24 只看该作者
好的,了解
3偶尔光临
166/300
排名
11086
昨日变化

1

主题

32

帖子

166

积分

Rank: 3Rank: 3Rank: 3

UID
312044
好友
0
蛮牛币
793
威望
0
注册时间
2019-1-17
在线时间
41 小时
最后登录
2019-5-8
11#
2019-2-22 16:11:09 只看该作者
{:89:}{:89:}{:89:}
5熟悉之中
754/1000
排名
4110
昨日变化

1

主题

240

帖子

754

积分

Rank: 5Rank: 5

UID
245227
好友
0
蛮牛币
953
威望
0
注册时间
2017-9-21
在线时间
153 小时
最后登录
2019-6-11
12#
2019-2-28 09:25:26 只看该作者
被光照到? 数学不就行了? 判断是否在一个椎体之内不就行了?
8常驻蛮牛
5306/10000
排名
1669
昨日变化

0

主题

3794

帖子

5306

积分

Rank: 8Rank: 8

UID
185339
好友
1
蛮牛币
3629
威望
0
注册时间
2016-11-20
在线时间
734 小时
最后登录
2019-6-26
13#
2019-2-28 09:38:41 只看该作者
{:107:}
7日久生情
1775/5000
排名
1365
昨日变化

2

主题

155

帖子

1775

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
148089
好友
0
蛮牛币
2674
威望
0
注册时间
2016-5-10
在线时间
710 小时
最后登录
2019-6-23
14#
2019-2-28 16:17:34 只看该作者
tiancaiwlk 发表于 2019-2-28 09:25
被光照到? 数学不就行了? 判断是否在一个椎体之内不就行了?

锥体内可能在障碍物
排名
26983
昨日变化

1

主题

44

帖子

67

积分

Rank: 2Rank: 2

UID
314291
好友
0
蛮牛币
124
威望
0
注册时间
2019-2-19
在线时间
8 小时
最后登录
2019-3-6
15#
2019-3-5 21:20:23 只看该作者
66666666666666666666666
您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则