12 第1页 | 共2 页下一页
返回列表 发新帖
查看: 2858|回复: 11
打印 上一主题 下一主题

光线折射路径绘制

[复制链接]

5552

主题

2

听众

8万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
11

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2011-11-2 17:32:00 |只看该作者 |倒序浏览

          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 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 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
           
            and
           
            End 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:
         


           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:
         

           using UnityEngine;
         

           using System.Collections;
           

            
         

           [RequireComponent (typeof (LineRenderer))]
         



            
         

           public class RaycastReflection : MonoBehaviour
         

           {
         

           //this game object's Transform
         

           private Transform goTransform;
         

           //the attached line renderer
         

           private LineRenderer lineRenderer;
         



            
         

           //a ray
         

           private Ray ray;
         

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

           private RaycastHit hit;
         



            
         

           //reflection direction
         

           private Vector3 inDirection;
         



            
         

           //the number of reflections
         

           public int nReflections = 2;
         



            
         

           //the number of points at the line renderer
         

           private int nPoints;
         



            
         

           void Awake ()
         

           {
         

           //get the attached Transform component
         

           goTransform = this.GetComponent<Transform>();
         

           //get the attached LineRenderer component
         

           lineRenderer = this.GetComponent<LineRenderer>();
         

           }
         



            
         

           void Update ()
         

           {
         

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

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

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

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



            
         

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

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



            
         

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

           nPoints = nReflections;
         

           //make the lineRenderer have nPoints
         

           lineRenderer.SetVertexCount(nPoints);
         

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

           lineRenderer.SetPosition(0,goTransform.position);
         



            
         

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

           {
         

           //If the ray hasn't reflected yet
         

           if(i==0)
         

           {
         

           //Check if the ray has hit something
         

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

           {
         

           //the refletion direction is the reflection of the current hit point flipped at the hit normal
         

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

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

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



            
         

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

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

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

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



            
         

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

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



            
         

           //if the number of reflections is set to 1
         

           if(nReflections==1)
         

           {
         

           //add a new vertex to the line renderer
         

           lineRenderer.SetVertexCount(++nPoints);
         

           }
         



            
         

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

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

           }
         

           }
         

           else // the ray has reflected at least once
         

           {
         

           //Check if the ray has hit something
         

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

           {
         

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

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

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

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



            
         

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

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

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

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



            
         

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

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



            
         

           //add a new vertex to the line renderer
         

           lineRenderer.SetVertexCount(++nPoints);
         

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

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

           }
         

           }
         

           }
         

           }
         

           }
         

           This is a long script, but don’t worry: more than half of it is just for making the
           
            lineRenderer
           
           follow 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
           
            integers
           

            nReflections
           
            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, the
           
            nReflections
           
            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***nning, 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***ns
           
            nReflections+1
           
            times for each frame, meaning that, for this example, it will***cute three times for each game update. This loop has basically a
           
            if-else
           
            block that checks whether if it’s first iteration is being***cuted (line 55). Case that’s ***e 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 hit position 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***nning, 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 the
           
            lineRenderer
           
            (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. On top of that, the reflection is calculated differently: instead of using the hit point as the first parameter for the
           
            Vector3.Reflect()
           
            method, the
           
            inDirection
           
            is used (line 90). This happens because the first reflected ray is being projected at in the same direction defined by
           
            inDirection
           
           . Trying to calculate the reflection using the
           
            hit.position
           
            again would result in the reflection of the reflection, which is not what we want.
         

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


           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.
         
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

沙发
发表于 2012-2-26 23:22:36 |只看该作者
水……生命之源……灌……
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2012-4-4 23:27:13 |只看该作者
加精、加亮滴铁子,尤其要多丁页丁页
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-4-25 23:25:29 |只看该作者
跑着去顶朋友滴铁
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

5#
发表于 2012-5-17 23:20:20 |只看该作者
呵呵,很漂亮啊
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

6#
发表于 2012-5-24 23:24:08 |只看该作者
呵呵,很好,方便罗。
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

7#
发表于 2012-6-3 23:18:16 |只看该作者
我看看就走,你们聊!
回复

使用道具 举报

5969

主题

1

听众

39万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

8#
发表于 2012-6-24 23:25:50 |只看该作者
不错 非常经典  实用
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

9#
发表于 2012-8-25 23:59:13 |只看该作者
既来之,则看之!
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

10#
发表于 2012-9-28 23:25:57 |只看该作者
“再次路过……”我造一个-----特别路过
回复

使用道具 举报

12 第1页 | 共2 页下一页
返回列表 发新帖
您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-19 05:46 , Processed in 0.121486 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部