Unity SpotLight光照事件的判断

15
回复
977
查看
打印 上一主题 下一主题
[ 复制链接 ]
7日久生情
1744/5000
排名
1366
昨日变化

7

主题

241

帖子

1744

积分

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

UID
162659
好友
3
蛮牛币
4431
威望
0
注册时间
2016-8-16
在线时间
602 小时
最后登录
2019-4-18

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

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

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, 下载次数: 11)

灯光射线

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

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

7日久生情
1623/5000
排名
4093
昨日变化

0

主题

977

帖子

1623

积分

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

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

0

主题

659

帖子

1052

积分

Rank: 6Rank: 6Rank: 6

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

0

主题

199

帖子

1010

积分

Rank: 6Rank: 6Rank: 6

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

3

主题

27

帖子

140

积分

Rank: 2Rank: 2

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

7

主题

241

帖子

1744

积分

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

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

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

6

主题

58

帖子

887

积分

Rank: 5Rank: 5

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

7

主题

241

帖子

1744

积分

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

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

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

0

主题

977

帖子

1623

积分

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

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

0

主题

414

帖子

2175

积分

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

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

1

主题

32

帖子

165

积分

Rank: 3Rank: 3Rank: 3

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

1

主题

233

帖子

742

积分

Rank: 5Rank: 5

UID
245227
好友
0
蛮牛币
956
威望
0
注册时间
2017-9-21
在线时间
148 小时
最后登录
2019-4-18
12#
2019-2-28 09:25:26 只看该作者
被光照到? 数学不就行了? 判断是否在一个椎体之内不就行了?
7日久生情
4885/5000
排名
1669
昨日变化

0

主题

3464

帖子

4885

积分

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

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

2

主题

154

帖子

1737

积分

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

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

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

1

主题

44

帖子

67

积分

Rank: 2Rank: 2

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

本版积分规则