文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Unity3d 射线反射

2023-01-31 02:46

关注

As any person that has already used Unity’s Ray class knows, there’s no support for reflection, which could be useful for some specific cases. This post will try to offer a solution to that, explaining how to create a script which casts a ray that gets reflected when it hits a surface. Not only that, but the script also allows to set the number of times the cast ray should bounce. An example project with a scene and the code explained below is available for download at the end of the tutorial.

Before looking how the reflection script works, a scene must be set with some walls to reflect the ray. Additionally, a game object will be required to act as the source of the ray . To create the ray’s source, just select GameObject->Create Other->Cube:

Creating a new Cube.

Creating a new Cube game object.

The name of the game object doesn’t matter, so use any one you like. For this tutorial, I’ll be naming it as “Ray Emitter“. Since the cast ray isn’t visible, something must represent it, and that’s why we need to add a Line Renderer component, by clicking Component->Miscellaneous->Line Renderer:

Attaching the Line Renderer

Attaching the Line Renderer to the 'Ray Emitter' game object.

After it has been attached to the Ray Emitter, add a material to it and set both the Start Width andEnd Width attributes to 0.1 . Make sure that the Use World Space box is checked. Next, create various cube game objects and scale them so they look a more like walls. Position these created objects close to the Ray Emitter game object, to ensure that the ray bounces in one of these walls:

Adding some walls.

Rotate the walls so the emitted ray can reflect in all of them.

Finally, the following script must be attached to the Ray Emitter game object:

view plaincopy to clipboardprint?

  1. using UnityEngine;  

  2. using System.Collections;  

  3.   

  4. [RequireComponent (typeof (LineRenderer))]  

  5.   

  6. public class RaycastReflection : MonoBehaviour  

  7. {  

  8.     //this game object's Transform  

  9.     private Transform goTransform;  

  10.     //the attached line renderer  

  11.     private LineRenderer lineRenderer;  

  12.   

  13.     //a ray  

  14.     private Ray ray;  

  15.     //a RaycastHit variable, to gather informartion about the ray's collision  

  16.     private RaycastHit hit;  

  17.   

  18.     //reflection direction  

  19.     private Vector3 inDirection;  

  20.   

  21.     //the number of reflections  

  22.     public int nReflections = 2;  

  23.   

  24.     //the number of points at the line renderer  

  25.     private int nPoints;  

  26.   

  27.     void Awake ()  

  28.     {  

  29.         //get the attached Transform component  

  30.         goTransform = this.GetComponent<Transform>();  

  31.         //get the attached LineRenderer component  

  32.         lineRenderer = this.GetComponent<LineRenderer>();  

  33.     }  

  34.   

  35.     void Update ()  

  36.     {  

  37.         //clamp the number of reflections between 1 and int capacity  

  38.         nReflections = Mathf.Clamp(nReflections,1,nReflections);  

  39.         //cast a new ray forward, from the current attached game object position  

  40.         ray = new Ray(goTransform.position,goTransform.forward);  

  41.   

  42.         //represent the ray using a line that can only be viewed at the scene tab  

  43.         Debug.DrawRay(goTransform.position,goTransform.forward * 100, Color.magenta);  

  44.   

  45.         //set the number of points to be the same as the number of reflections  

  46.         nPoints = nReflections;  

  47.         //make the lineRenderer have nPoints  

  48.         lineRenderer.SetVertexCount(nPoints);  

  49.         //Set the first point of the line at the current attached game object position  

  50.         lineRenderer.SetPosition(0,goTransform.position);  

  51.   

  52.         for(int i=0;i<=nReflections;i++)  

  53.         {  

  54.             //If the ray hasn't reflected yet  

  55.             if(i==0)  

  56.             {  

  57.                 //Check if the ray has hit something  

  58.                 if(Physics.Raycast(ray.origin,ray.direction, out hit, 100))//cast the ray 100 units at the specified direction  

  59.                 {  

  60.                     //the reflection direction is the reflection of the current ray direction flipped at the hit normal  

  61.                     inDirection = Vector3.Reflect(ray.direction,hit.normal);  

  62.                     //cast the reflected ray, using the hit point as the origin and the reflected direction as the direction  

  63.                     ray = new Ray(hit.point,inDirection);  

  64.   

  65.                     //Draw the normal - can only be seen at the Scene tab, for debugging purposes  

  66.                     Debug.DrawRay(hit.point, hit.normal*3, Color.blue);  

  67.                     //represent the ray using a line that can only be viewed at the scene tab  

  68.                     Debug.DrawRay(hit.point, inDirection*100, Color.magenta);  

  69.   

  70.                     //Print the name of the object the cast ray has hit, at the console  

  71.                     Debug.Log("Object name: " + hit.transform.name);  

  72.   

  73.                     //if the number of reflections is set to 1  

  74.                     if(nReflections==1)  

  75.                     {  

  76.                         //add a new vertex to the line renderer  

  77.                         lineRenderer.SetVertexCount(++nPoints);  

  78.                     }  

  79.   

  80.                     //set the position of the next vertex at the line renderer to be the same as the hit point  

  81.                     lineRenderer.SetPosition(i+1,hit.point);  

  82.                 }  

  83.             }  

  84.             else // the ray has reflected at least once  

  85.             {  

  86.                 //Check if the ray has hit something  

  87.                 if(Physics.Raycast(ray.origin,ray.direction, out hit, 100))//cast the ray 100 units at the specified direction  

  88.                 {  

  89.                     //the refletion direction is the reflection of the ray's direction at the hit normal  

  90.                     inDirection = Vector3.Reflect(inDirection,hit.normal);  

  91.                     //cast the reflected ray, using the hit point as the origin and the reflected direction as the direction  

  92.                     ray = new Ray(hit.point,inDirection);  

  93.   

  94.                     //Draw the normal - can only be seen at the Scene tab, for debugging purposes  

  95.                     Debug.DrawRay(hit.point, hit.normal*3, Color.blue);  

  96.                     //represent the ray using a line that can only be viewed at the scene tab  

  97.                     Debug.DrawRay(hit.point, inDirection*100, Color.magenta);  

  98.   

  99.                     //Print the name of the object the cast ray has hit, at the console  

  100.                     Debug.Log("Object name: " + hit.transform.name);  

  101.   

  102.                     //add a new vertex to the line renderer  

  103.                     lineRenderer.SetVertexCount(++nPoints);  

  104.                     //set the position of the next vertex at the line renderer to be the same as the hit point  

  105.                     lineRenderer.SetPosition(i+1,hit.point);  

  106.                 }  

  107.             }  

  108.         }  

  109.     }  

  110. }  

This is a long script, but don’t worry: more than half of it is just for making the lineRendererfollow the ray; the part that makes the reflection work is actually quite small. Right at its start, there are some variables being declared, such as goTransform and the lineRenderer. Both will act as handles for the two components this script needs to read values from or modify (lines 9 and 11). Then, we have the Ray and the RaycastHit object – the first casts the ray, and the second queries information about the objects the ray is colliding with (lines 14 and 16).

The inDirection is a Vector3 that will store the direction of the reflected ray and the integersnReflections and nPoints are, respectively, the number of reflections and the number of vertices the line representing the ray must have (lines 19 and 22). On a side note, for this script, thenReflections is the number of times the ray is reflected, and not the number of times the ray has hit something. This means that nReflections with a value of 2 will make the ray “bounce” two times before “stopping” on the third collision.

Back to the code, inside the Awake() method, the goTransform and lineRenderer variables are initialized (lines 27 through 33). Finally, at the Update() method, line 38 defines that the number of reflections can’t be smaller than one (otherwise, there is no point of using this script over a simple raycast). Next, the ray is cast forwards using the attached game object as the origin (line 40). After that, the Debug.DrawRay() method is called, drawing a magenta colored line to represent the ray (line 43). This is just one of the many Debug.Draw() method calls in this script. The rays created by it can only be seen when the game is running, under the Scene tab. They won’t appear at the Game tab or when the game is compiled and exported, as the class name suggests, they are for debugging purposes only. More information can be found here.

Moving on, lines 46 through 50 ensures that the lineRender is going to be rendered to represent the path of the ray. Finally, we have reached the most critical part of the code: the for loop (line 52). This block of code runs nReflections+1 times for each frame, meaning that, for this example, it will execute three times for each game update. This loop has basically a if-else block that checks whether if it’s first iteration is being executed (line 55). Case that’s true and the ray is colliding with an object, line 61 initializes the inDirection variable, by calculating the reflection of the ray, using the Vector3.Reflect() method. It takes two parameters, the first is a Vector3 we want to reflect and the other is the axis to be used for the reflection. These parameters were filled, respectively, with the ray’s direction and the normal of the surface at the collision point.

With the inDirection variable calculated, the ray can be cast again, using the former as the new direction (line 63). The next two lines renders two ray representations for debugging purposes only, as explained above. The one being rendered with the magenta color will represent the reflected ray, and the blue one represents the collision normal (lines 66 and 68). Again, they can only be seen when the game is running, at the Scene tab. Then, the following lines check if the number of reflections is set to be only a single one. If it is, the script must add a new vertex to thelineRenderer (lines 74 through 78). Next, the position of the next vertex in the lineRenderer is set to be the same as the collision point (line 81).

The code inside the else block works the same way as the one inside the if part, except that we don’t need to check for the first iteration of the loop. The reflection is calculated in the same manner as before: the ray direction and hit normal are passed as parameters to theVector3.Reflect() method.

That’s it! Here’s how it look like:

Example project screenshot

Example project screenshot.

At the example project, the LineRenderer won’t draw the line if it isn’t going to hit anything. However, chances are, in a real game situation, there’s always going to be a surface for the ray to bounce. That said, this script could be improved by checking if the ray isn’t colliding with anything, assigning a position to the lineRenderer to draw. But this is a unusual situation, meaning this code will fit most purposes when a raycast reflection is required.


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯