zoukankan      html  css  js  c++  java
  • 设置相机朝向对象,并设置最佳观察的视野

    LookToObject.cs绑定到Camera上

    using UnityEngine;
    /// <summary>
    /// 设置相机朝向对象,并设置最佳观察的视野
    /// </summary>
    public class LookToObject:MonoBehaviour{
    	[Tooltip("相机所拍摄的对象")]
        public GameObject target;
        private MeshRenderer _targetMeshRenderer;
        private Camera _camera;
    
        private Vector3[] _points;
    	private Vector3 _planeCenter;
    
        private void Start(){
            _targetMeshRenderer=target.GetComponent<MeshRenderer>();
            _camera=GetComponent<Camera>();
        }
    
        private void Update(){
            //相机旋转朝向目标对象
            Bounds bounds=_targetMeshRenderer.bounds;
    		Vector3 boundsCenter=bounds.center;
            _camera.transform.LookAt(boundsCenter);
            //包围盒角点
            Vector3[] points=getBoundsCorners(boundsCenter,bounds.extents);
            //所有角点投射到平面
            Vector3 planeNormal=boundsCenter-_camera.transform.position;
            worldPointsToPlane(points,points.Length,planeNormal);
            _points=points;
            //平面中心
            Vector3 planeCenter=Vector3.ProjectOnPlane(boundsCenter,planeNormal);
    		_planeCenter=planeCenter;
            //取平面上各个点与平面中心的最大距离作为相机的视野矩形框大小
            float halfHeight=getMaxDistanceToPlaneCenter(points,points.Length,planeCenter);
            //相机与包围盒中心的距离(世界坐标为单位)
            float distance=Vector3.Distance(boundsCenter,_camera.transform.position);
            //得到视野大小
            _camera.fieldOfView=Mathf.Atan2(halfHeight,distance)*Mathf.Rad2Deg*2;  
        }
        
        /// <summary>
    	/// 返回包围盒的角点列表
    	/// </summary>
    	/// <param name="boundsCenter">包围盒的中心</param>
    	/// <param name="boundsExtents">Bounds.extents</param>
    	/// <returns></returns>
    	private Vector3[] getBoundsCorners(Vector3 boundsCenter,Vector3 boundsExtents){
    		Vector3[] vertices=new Vector3[8];
    		//左下后
    		vertices[0]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(-1,-1,-1));
    		//左上后
    		vertices[1]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(-1,1,-1));
    		//右上后
    		vertices[2]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(1,1,-1));
    		//右下后
    		vertices[3]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(1,-1,-1));
    
    		//左下前
    		vertices[4]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(-1,-1,1));
    		//左上前
    		vertices[5]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(-1,1,1));
    		//右上前
    		vertices[6]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(1,1,1));
    		//右下前
    		vertices[7]=boundsCenter+Vector3.Scale(boundsExtents,new Vector3(1,-1,1));
    		return vertices;
    	}
        
        /// <summary>
        /// 将世界坐标点数组投射到以原点为中心的平面
        /// </summary>
        /// <param name="points">世界坐标点数组</param>
        /// <param name="pointCount">坐标点数量</param>
        /// <param name="planeNormal">平面法线</param>
        /// <returns></returns>
        private Vector3[] worldPointsToPlane(Vector3[] points,int pointCount,Vector3 planeNormal){
            for(int i=0;i<pointCount;i++){
                var vertex=points[i];
                points[i]=Vector3.ProjectOnPlane(vertex,planeNormal);
            }
            return points;
        }
        
        /// <summary>
        /// 返回平面上各个点与平面中心的最大距离
        /// </summary>
        /// <param name="points">平面上的各个点</param>
        /// <param name="pointCount">点数量</param>
        /// <param name="planeCenter">平面中心</param>
        /// <returns></returns>
        private float getMaxDistanceToPlaneCenter(Vector3[] points,int pointCount,Vector3 planeCenter){
            float maxDistance=float.MinValue;
            for(int i=0;i<pointCount;i++){
                var vertex=points[i];
                float distance=Vector3.Distance(vertex,planeCenter);
                if(distance>maxDistance)maxDistance=distance;
            }
            return maxDistance;
        }
        
        private void OnDrawGizmos(){
            if(Application.isPlaying){
                if(_points!=null){
                   drawPath(_points);
                }
    			drawPoint(_planeCenter,0.02f);
            }
        }
        
        /// <summary>
    	/// 根据路径点数组画线
    	/// </summary>
    	/// <param name="vertices">路径点数组</param>
    	private void drawPath(Vector3[] vertices){
            int len=vertices.Length;
            for (int i=0;i<len;i++){
                int nexti=(i+1)%len;
                Gizmos.DrawLine(vertices[i],vertices[nexti]);
            }
        }
    
    	/// <summary>
    	/// 用一个球体线框画一个点
    	/// </summary>
    	/// <param name="point">点位置</param>
    	/// <param name="radius">球体线框半径</param>
    	private void drawPoint(Vector3 point,float radius=0.02f){
    		Gizmos.DrawWireSphere(point,radius);
    	}
    
        
    }
    
  • 相关阅读:
    ExtJs中ComboBox使用之技巧
    Ethernet帧结构
    Sqlite修改表
    Solr系列:Linux下部署Solr
    Ethernet帧的接收流程
    使用SQLite作为Quartz.Net的Job Store
    Quartz.Net的一个Bug
    获取程序集的Public key token
    SQLite数据类型
    shell取出多列文件中某一列重复的数据
  • 原文地址:https://www.cnblogs.com/kingBook/p/11345090.html
Copyright © 2011-2022 走看看