激光笔与玻璃砖的折射

教研室接了一个物理实验模拟的项目。我的第一个实验是“测定玻璃的折射率”。由于是刚刚学习unity和C#。实现过程终于到了很多问题,想记下来。这是第一个博客。

我用LineRenerer模拟的光线。

实验过程:

  1. 射线照射在玻璃砖上;
  2. 射线与玻璃砖碰撞,发生折射。该折射是光疏介质到光密介质;(暂不考虑反射)
  3. 折射光线与玻璃砖内侧碰撞,发射折射。该折射是光密介质到光疏介质;(暂不考虑全反射,不考虑和侧面碰撞)
  4. 光线出射玻璃砖。

如下图:其中矩形为玻璃砖,AB为入射光线,BC为折射光线,CD为出射光线。

 

其中折射部分,unity没有现有的方法可用,自己写了一个。确定C点着实花了一阵功夫。最后用bc射线的反向延长线确定一条线与玻璃砖碰撞确定C点。


代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Vectrosity;

public class LaserPen : MonoBehaviour {
    //游戏对象,这里是线段对象
    private GameObject LineRenderGameObject;

    //线段渲染器
    private LineRenderer lineRenderer;
    //设置线段的个数,标示一个曲线由几条线段组成
    private int lineCount = 2;

    //分别记录4个点,通过这4个三维世界中的点去连接一条线段
    private Vector3 v0 = new Vector3();
    private Vector3 v1 = new Vector3();
    private Vector3 v2 = new Vector3();
    private Vector3 v3 = new Vector3();
    //射线与激光笔的端点绑定
    private GameObject OriginPoint;
    private GameObject DirectionPoint;
    //用于碰撞检测
    Ray ray;
    RaycastHit HitPoint;
    Ray RefractRay;
    RaycastHit HitPoint_chushe;


    void Start()
    {
        lineRenderer= GetComponent<LineRenderer>();
        //获取激光笔模型的坐标
        OriginPoint = GameObject.Find("origin");
        DirectionPoint = GameObject.Find("direcfion");      
        
    }   
    void Update()
    {
        ray = new Ray(transform.position,-transform.right);
        v0 = new Vector3(OriginPoint.transform.position.x, OriginPoint.transform.position.y, OriginPoint.transform.position.z);
        v1 = new Vector3(DirectionPoint.transform.position.x, DirectionPoint.transform.position.y, DirectionPoint.transform.position.z);
        if (Physics.Raycast(ray,out HitPoint, Mathf.Infinity))
        {
            Debug.Log("碰撞对象是"+HitPoint.collider.name);            
            v3 = HitPoint.point;
            v2 = Refract((v1-v0),HitPoint.normal,0.6f);//返回值是折线向量
            lineRenderer.positionCount = 3;
            lineRenderer.SetPosition(0, v0);
            lineRenderer.SetPosition(1, v3);
            lineRenderer.SetPosition(2, v3+v2.normalized*100);
            RefractRay = new Ray(PointQ(HitPoint.point, v2.normalized ,100),-v2*50);//折线的碰撞检测ray
            碰撞检测射线RefractRay可视化
            //VectorLine.SetLine3D(Color.green,RefractRay.origin, RefractRay.GetPoint(100));
            if (Physics.Raycast(RefractRay, out HitPoint_chushe, Mathf.Infinity))
            {
                Debug.Log("二次碰撞对象是:" + HitPoint_chushe.collider.name);
                Debug.Log("出射点的坐标是:" + HitPoint_chushe.ToString());
                lineRenderer.positionCount = 4;
                lineRenderer.SetPosition(0, v0);
                lineRenderer.SetPosition(1, v3);
                lineRenderer.SetPosition(2, HitPoint_chushe.point);
                lineRenderer.SetPosition(3,HitPoint_chushe.point+ray.direction.normalized*100);

            }
            else
                Debug.Log("sorry,二次碰撞失败");

        }
        else
        {
            Debug.Log("没碰上");
            lineRenderer.positionCount = 2;            
            lineRenderer.SetPosition(0, v0 );
            lineRenderer.SetPosition(1, (v1-v0)*500 );
        }     
            
    }

    //I为入射光线,N为折射光线,h为透射比,玻璃的h=0.8
    public Vector3 Refract(Vector3 I,Vector3 N,float h)
    {
        I = I.normalized;
        N = N.normalized;//单位化

        float cosI = Vector3.Dot(I, N);
        float cosT2 = 1.0f - h * h * (1.0f - cosI * cosI);
        Vector3 T = h * I - (h * cosI + Mathf.Sqrt(cosT2)) * N;
        if (cosT2 > 0)
            return T;
        else
            return Vector3.zero;
    }
    //已知,空间点P(x,y,z)和一个方向向量n(x0,y0,z0).如何求得另一个离P点距离d的点Q(x',y',z')的坐标
    public Vector3 PointQ(Vector3 p,Vector3 n,float d)
    {
        float x, y, z;
        x = p.x + d * n.x / n.magnitude;
        y = p.y + d * n.y / n.magnitude;
        z = p.z + d * n.z / n.magnitude;
        Vector3 Q = new Vector3(x,y,z);
        return (Q);
    }
}


代码写得很烂。

学下的东西真的要记下来,不然过阵子就忘了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值