Unity 框选多个3D物体

今天研究了一下框选功能,这是个很老旧的功能了 ,网上有很多资料,不过看了几个发现都是旧版本的,新版本有些东西要改动一下才好使,就改了改,写个博客纪录一下,

还是大概说一下思路吧,

1.鼠标按下时记录鼠标点下的屏幕坐标,通过unity提供的Camera的方法 WorldToScreenPoint,将待选物体由世界坐标转屏幕坐标.当然反过来也是一样的

2.第二就是比较一个点是否在一个范围内 这个很好理解,比xy轴就行了

3.屏幕上要画线 刷出来拖动的范围,用的是GL划线,需要一个特定的shader 这个也是之前老版本的代码不支持的地方

先上效果图

然后上代码 

这个因为有OnPostRender方法,脚本需要挂相机上才框选范围可以生效;

这个因为有OnPostRender方法,脚本需要挂相机上才框选范围可以生效;

这个因为有OnPostRender方法,脚本需要挂相机上才框选范围可以生效

using UnityEngine;
 
public class DrawRect : MonoBehaviour {
 
    private bool drawing;
    private Material rectMat;
    private Color rectColor = Color.green;
    private Vector2 startPosition = Vector2.zero;
    private Vector2 endPosition = Vector2.zero;
 
    void Start()
    {
        rectMat = new Material(Shader.Find("Lines/Colored Blended"));
    }
 
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            drawing = true;
            // 设置开始位置
            startPosition = Input.mousePosition;   
            CubeManager.Instance.BeginDraw();
        }
        if (Input.GetMouseButtonUp(0))
        {
            drawing = false;
        }
      
    }
    
    // 该方法为系统函数,需将此脚本挂载到Camera下才能执行。
    void OnPostRender()
    {
        if (drawing)
        {
            GL.PushMatrix();
 
            if (!rectMat)
                return;
            endPosition = Input.mousePosition;      // 设置结束位置
            CubeManager.Instance.Drawing(startPosition, endPosition);
            rectMat.SetPass(0);
            GL.LoadPixelMatrix();
            GL.Begin(GL.QUADS);
            GL.Color(new Color(rectColor.r, rectColor.g, rectColor.b, 0.1f ));
            GL.Vertex3(startPosition.x, startPosition.y, 0);
            GL.Vertex3(endPosition.x, startPosition.y, 0);
            GL.Vertex3(endPosition.x, endPosition.y, 0);
            GL.Vertex3(startPosition.x, endPosition.y, 0);
            GL.End();
            GL.Begin(GL.LINES );
            GL.Color(rectColor );
            GL.Vertex3(startPosition.x, startPosition.y, 0);
            GL.Vertex3(endPosition.x, startPosition.y, 0);
            GL.Vertex3(endPosition.x, startPosition.y, 0);
            GL.Vertex3(endPosition.x, endPosition.y, 0);
            GL.Vertex3(endPosition.x, endPosition.y, 0);
            GL.Vertex3(startPosition.x, endPosition.y, 0);
            GL.Vertex3(startPosition.x, endPosition.y, 0);
            GL.Vertex3(startPosition.x, startPosition.y, 0);
            GL.End();
            GL.PopMatrix();
        }
    }
}

这个脚本随便挂一个地方 拖个盒子和两个材质球就好了

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class CubeManager : MonoBehaviour {
    private static CubeManager instance;
    public static CubeManager Instance
    {
        get
        {
            return instance;
        }
    }
 
    public GameObject prefab;
    public int count = 10;
 
    public Material originMat;
    public Material outlineMat;
 
    private List<MeshRenderer> meshRendererList;
 
    void Awake()
    {
        instance = this;
    }
 
	// Use this for initialization
    void Start () {
        meshRendererList = new List<MeshRenderer>();
 
        // 创建物体
        for ( int i = 0; i < count; i++ )
	    {
            GameObject go = GameObject.Instantiate( prefab ) as GameObject;
            go.name = (i + 1).ToString();
            go.transform.parent = transform;
            go.transform.position = new Vector3( Random.Range( -10, 10 ), 0, Random.Range( -10, 10 ) );
            meshRendererList.Add( go.GetComponent<MeshRenderer>() );
	    }
        originMat = meshRendererList[0].material;
    }
 
    public void BeginDraw()
    {
        var item = meshRendererList.GetEnumerator();
        while (item.MoveNext())
        {
            item.Current.material = originMat;
        }
    }
    
    public void Drawing(Vector2 point1, Vector2 point2)
    {
        Vector3 p1 = Vector3.zero;
        Vector3 p2 = Vector3.zero;
 
        if (point1.x > point2.x)
        {
            p1.x = point2.x;
            p2.x = point1.x;
        }
        else
        {
            p1.x = point1.x;
            p2.x = point2.x;
        }
        if (point1.y > point2.y)
        {
            p1.y = point2.y;
            p2.y = point1.y;
        }
        else
        {
            p1.y = point1.y;
            p2.y = point2.y;
        }
 
        var item = meshRendererList.GetEnumerator();
        while (item.MoveNext())
        {
            Vector3 position = Camera.main.WorldToScreenPoint(item.Current.transform.position);
            if (position.x > p1.x && position.y > p1.y 
                && position.x < p2.x && position.y < p2.y )
            {
                item.Current.material = outlineMat;
            }
            else
            {
                item.Current.material = originMat;
            }
        }
    }
}

场景中截图

下边是GL的材质shader

Shader "Lines/Colored Blended"
{
    SubShader 
    {
        Pass 
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off Cull Off Fog { Mode Off }
            BindChannels
            {
              Bind "vertex", vertex Bind "color", color
            }
        }
    }
}

最后也把原来的博客连接发一下,不能那么无耻的就偷别人的代码哈哈修改前的原文


版权声明:本文为qq_35080168原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。