查看: 2011|回复: 6
打印 上一主题 下一主题

光线折射路径绘制

[复制链接]

3795

主题

2

听众

5万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
53202
精华
32

活跃会员 优秀版主 推广达人 突出贡献 荣誉管理 论坛元老

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


           非常不错的教程,有关unity3d中,ray类的使用,文章结尾有项目源文件下载!
           

           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 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 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 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 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
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

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

沙发
发表于 2012-2-17 23:20:25 |只看该作者
我无语!
回复

使用道具 举报

   

671

主题

1

听众

3247

积分

中级设计师

Rank: 5Rank: 5

纳金币
324742
精华
0

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

板凳
发表于 2012-3-28 23:24:10 |只看该作者
顶!学习了!阅!
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

地板
发表于 2012-4-8 23:25:51 |只看该作者
发了那么多,我都不知道该用哪个给你回帖了,呵呵
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

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

5#
发表于 2012-5-6 23:25:02 |只看该作者
再看一看,再顶楼主
回复

使用道具 举报

   

671

主题

1

听众

3247

积分

中级设计师

Rank: 5Rank: 5

纳金币
324742
精华
0

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

6#
发表于 2012-9-29 23:22:44 |只看该作者
非常感谢,管理员设置了需要对新回复进行审核,您的帖子通过审核后将被显示出来,现在将转入主题
回复

使用道具 举报

5969

主题

1

听众

39万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

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

7#
发表于 2012-10-15 23:24:38 |只看该作者
其实楼主所说的这些,俺支很少用!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2024-11-10 23:55 , Processed in 0.104069 second(s), 29 queries .

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

© 2008-2019 Narkii Inc.

回顶部