zoukankan      html  css  js  c++  java
  • 实现一个简单的Unity3D三皮卡——3D Picking (1)

    3D Picking 其原理是从摄像机位置到空间发射的射线。基于光线碰到物体回暖。

    这里我们使用了触摸屏拿起触摸,鼠标选择相同的原理,仅仅是可选API不同。


    unity3D官网Manual里找到下面Input内容:

    http://docs.unity3d.com/Documentation/Manual/Input.html

    当中有段样例程序:

    Following is an example script which will shoot a ray whenever the user taps on the screen:

    var particle : GameObject;
    function Update () {
        for (var touch : Touch in Input.touches) {
            if (touch.phase == TouchPhase.Began) {
                // Construct a ray from the current touch coordinates
                var ray = Camera.main.ScreenPointToRay (touch.position);
                if (Physics.Raycast (ray)) {
                    // Create a particle if hit
                    Instantiate (particle, transform.position, transform.rotation);
                }
            }
      }
    }

    var ray = Camera.main.ScreenPointToRay (touch.position);
                if (Physics.Raycast (ray))
    这两句代码是关键代码,我们从这里入手。

    查找ScreenPointToRay文档:

    http://docs.unity3d.com/Documentation/ScriptReference/Camera.ScreenPointToRay.html

    节选文档中主要描写叙述和一段样例

    Ray ScreenPointToRay(Vector3 position);

    Returns a ray going from camera through a screen point.

    using UnityEngine;
    using System.Collections;
    
    public class Example : MonoBehaviour {
        void Update() {
            Ray ray = camera.ScreenPointToRay(new Vector3(200, 200, 0));
            Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow);
        }
    }

    上面的Debug.DrawRay留着后面调试时使用,能够看到发射的射线。

    接下来Camera.main.ScreenPointToRay中的Camera.main是什么意思呢,查找Camera.main

    static Camera main; 

    The first enabled camera tagged "MainCamera" (Read Only).

     

    unity新建一个project后,默认的一个main Camera


    查找Physics.Raycast文档。

    http://docs.unity3d.com/Documentation/ScriptReference/Physics.Raycast.html

    文档内容非常多。当中有一个

    static bool Raycast(Vector3origin, Vector3direction, RaycastHithitInfo, float distance = Mathf.Infinity, int layerMask = DefaultRaycastLayers);

    红色的两个參数我们后面将会用到,在查看RaycastHithitInfo,

    http://docs.unity3d.com/Documentation/ScriptReference/RaycastHit.html

    至此。我们能够实现一个简单的Picking了,创建sphere, plane, Direction Light,和一个Empty GameObject取名GameController。并新建一个脚本与其绑定。

    打开GameController.cs。输入下面代码:

    using UnityEngine;
    using System.Collections;
    
    public class GameController : MonoBehaviour
    {
    	void Update () 
    	{
    		if(Input.touchCount == 1)
    		{
    			Ray ray = Camera.main.ScreenPointToRay (Input.GetTouch(0).position);
    
    			Debug.DrawRay (ray.origin, ray.direction * 10, Color.yellow);  // ray needs a origin, and a dir
    
    			if(Physics.Raycast(ray, 10))
    				Debug.Log("Hit something");
    		}
    	}
    }

    在移动设备上使用Unity remote,用手触摸屏幕,将会看到一道黄线,若触摸到小球Sphere或地面Plane后。可看到在Console中有Hit something信息,即射线击中了物体。



    以下我们想分别选中物体。即仅仅picking小球而忽略地面plane。查看Layer文档:

    http://docs.unity3d.com/Documentation/Components/Layers.html

    当中讲的非常仔细。关键就是要新建Tags和设定layerMask

    打开Edit,选择Project Settings->Tags and Layers

    Layer 8输入PlayerLayer 9输入Background


    将Sphere 和 PlaneLayer 设为对应的层

    改动GameController.cs

    using UnityEngine;
    using System.Collections;
    
    public class GameController : MonoBehaviour
    {
    	void Update () 
    	{
    		if(Input.touchCount == 1)
    		{
    
    			Ray ray = Camera.main.ScreenPointToRay (Input.GetTouch(0).position);
    			
    			int playersLayerMask = 1 << 8;
    			
    			RaycastHit hit;
    			if(Physics.Raycast(ray, out hit, Mathf.Infinity, playersLayerMask))
    			{
    				Debug.DrawLine(ray.origin, hit.point, Color.yellow);			// line needs two points
    			}
    		}
    	}
    }

    此时,仅仅有当我们触摸到Sphere时才绘制黄色射线提示,因为设置了LayerMask射线将忽略Plane

    以下我们尝试当射线击中Spheres时绘制黄色提示线,先击中Sphere后击中Plane时绘制红色提示线。

    改动GameController.cs

    using UnityEngine;
    using System.Collections;
    
    public class GameController : MonoBehaviour
    {
    	void Update () 
    	{
    		if(Input.touchCount == 1)
    		{
    			Ray ray = Camera.main.ScreenPointToRay (Input.GetTouch(0).position);
    			
    			int playersLayerMask = 1 << 8;
    			int backgroundLayerMask = 1 << 9;
    			
    			RaycastHit hit;
    			if(Physics.Raycast(ray, out hit, Mathf.Infinity, playersLayerMask))
    			{
    				Debug.DrawLine(ray.origin, hit.point, Color.yellow);			// line needs two points
    				
    				RaycastHit groundHit;
    				if(Physics.Raycast(ray, out groundHit, Mathf.Infinity, backgroundLayerMask))
    				{
    					Debug.DrawLine(ray.origin, groundHit.point, Color.red);
    					
    				}
    
    			}
    		}
    	}
    }

    点击Play,效果例如以下,




    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    apicloud 运费计算js+页面
    css让字体细长
    vue 请求完接口后执行方法
    js监听当前页面再次加载
    用apicloud+vue的VueLazyload实现缓存图片懒加载
    git merge和git rebase的区别(转)
    yuan先生博客链接
    django组件之contenttype(一)
    Django的orm中get和filter的不同
    python第三方库requests详解
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4717337.html
Copyright © 2011-2022 走看看