当前位置: 首页 > news >正文

Unity实现在镜子间反射光柱

一、最终效果:

二、代码来源及思路

unity-raycast-reflection/Assets/RaycastReflection.cs at master · Loafwad/unity-raycast-reflection · GitHub

在GitHub找到了现成的,效果很好,稍微改了一点来满足我的需求,并加上了注释理解,代码如下

using System.Collections;
using System.Collections.Generic;
//using UnityEditor.EditorTools;
using UnityEngine;

public class MirrorReflection : MonoBehaviour
{
    //挂在发射光线的物体上
    [Tooltip("光线反射次数")]
    public int refelections;
    [Tooltip("光线最大长度")]
    public float maxLength;
    /// <summary>
    /// 通过这个transform旋转后的up来决定射线方向
    /// </summary>
    [Tooltip("光线射出的方向")]
    public Transform direction;
    
    LineRenderer lineRenderer;
    Ray ray;
    RaycastHit hit;
    

    void Awake()
    {
        lineRenderer =GetComponent<LineRenderer>();    
    }
    void Update()
    {
        //ray在这为初始光线的起点和方向
        ray = new Ray(transform.position,direction.up);
        
        //设定初始光线起点
        lineRenderer.positionCount=1;
        lineRenderer.SetPosition(0,transform.position);
        
        //定义剩余长度
        float remainingLength = maxLength;

        //反射
        for(int i=0;i<refelections;i++){
            //如果打到物体
            if(Physics.Raycast(ray.origin,ray.direction,out hit,remainingLength)){
                //光线击中物体
                lineRenderer.positionCount+=1;
                lineRenderer.SetPosition(lineRenderer.positionCount-1,hit.point);//设置末端点位置
                remainingLength-=Vector3.Distance(ray.origin,hit.point);//更新剩余光线长度
                

                //如果打到的物体不是镜子,则不继续发生折射
                if(hit.collider.tag!="Mirror"){
                    break;
                }

                //将Ray更新成折射后的射线
                ray=new Ray(hit.point,Vector3.Reflect(ray.direction,hit.normal));
            }
            //如果没打到任何东西
            else if(i==refelections-1){
                //则在设定长度的末端生成一个端点
                lineRenderer.positionCount+=1;
                lineRenderer.SetPosition(lineRenderer.positionCount-1,ray.origin+ray.direction*remainingLength);
            }
        }
    }
}

思路: 该脚本挂在光源物体上(发射光柱的物体,即光柱起点物体),给光源物体加上一个子物体法平面用于调节光柱方向。

围绕Vector3的reflect方法确定所需参数,利用unity提供的Ray类型在代码中确定光柱的起点和方向,LineRenderer渲染实际光柱

ray建立入射光线的起点以及入射方向,使用Raycast方法(它有很好的特性:能获取被射点的法线normal向量)得到入射点的法线向量,即可完成光线入射

而如果入射物体是镜子,则可以发生反射。更新ray的起点为入射点,方向为使用reflect方法计算得出的反射方向向量。

如果入射物体不是镜子,则不计算反射光线,也不更新ray,仅在最后一次循环时更新光柱末端点

写在update里起到每帧都会重新发射一次光线的作用

for循环决定了一帧内一共能反射多少次(通过refelections来控制数量)

三、场景搭建步骤

1、创建一个发射光线的物体,我这里创了一个球体来代表光源

2、给光源添加LineRenderer组件,size改成0,线的材质可以根据自己需求改,我这里用默认材质

3、再在光源物体下创建一个法平面子物体(作用是决定光源物体发射的光线的方向)

个人认为直接创建一个平面物体在下面好一些,调方向的时候很直观

调好方向后关掉MeshRenderer(自带的collider可以移除掉)

PS.为什么不直接转光源物体来决定方向?LineRenderer不会跟着物体转

5、给光源物体挂上MirrorRefelection脚本,设定好需要的反射次数,光柱总长度,以及挂上直接设置的法平面

4、创建一个带“mirror”tag的镜子,我这里创建了一个平面来当作镜子,并且设置了一个镜子材质

注意:ray要想成功打到物体要求那个物体必须有collider才能检测到,因此使用自定义模型时一定要记住添加碰撞体(并且meshcollider的话要求勾选convex)

5、运行,可以多复制几个镜子验证效果

这样看效果还比较差,需要调节LineRenderer的参数

这样就发现圆润多了

但是我们会发现悬空了,悬空的原因是平面的collider比较大,不贴合平面本身

所以自己建一个boxcollider调整一下位置就好啦

相关文章:

  • PySide(PyQT)的视图(QGraphicsView)范例(一) 基本框架
  • CSRF 攻击详解:原理、案例与防御
  • kubernetes介绍
  • 10.RabbitMQ集群
  • 【大数据项目】计算机行业招聘数据处理与分析系统
  • 2025.3.3总结
  • 面试基础---MySQL 事务隔离级别与 MVCC 深度解析
  • Mac安装配置使用nginx的一系列问题
  • git 学习笔记
  • 【消息队列】BrokerServer的核心概念
  • 在Electron中通过Node-API调用DLL导出函数的完整指南
  • 神经网络前向微分和后向微分区别
  • 面试题汇总(一)
  • 机器学习4-PCA降维
  • CMake学习笔记(一):工程的新建和如何将源文件生成二进制文件
  • conda 更换镜像究极方法
  • 新品速递 | 多通道可编程衰减器+矩阵系统,如何破解复杂通信测试难题?
  • YOLO11改进-模块-引入多域学习MDL(Multi-Domain Learning) 使用频域增强图像特征
  • jQuery UI 简介
  • IntelliJ IDEA集成MarsCode AI
  • 做网站过程/临沂seo推广
  • 高职思政主题网站建设作用/百度应用下载安装
  • 蚌埠网站制作哪家好/东莞seo建站哪家好
  • 信誉好的东莞网站设计/自己做网站需要什么条件
  • 没有经验可以做网站编辑吗/电商运营方案
  • 平面设计教程视频全集免费/网络优化的流程