设置相机朝向对象,并设置最佳观察的视野

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);
    }

}

原文地址:https://www.cnblogs.com/kingBook/p/11345090.html

时间: 2024-10-14 16:15:10

设置相机朝向对象,并设置最佳观察的视野的相关文章

笔记01 登录、常用配置参数、Action访问Servlet API 和设置Action中对象的值、命名空间和乱码处理、Action中包含多个方法如何调用

Struts2登录 1. 需要注意:Struts2需要运行在JRE1.5及以上版本 2. 在web.xml配置文件中,配置StrutsPrepareAndExecuteFilter或FilterDispatcher 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <filter>     <filter-name>struts2</filter-name>     <filter-class>org.apache.struts2.di

.NET前后台-JS获取/设置iframe内对象元素并进行数据处理

转载请注明出处:果冻栋吖 这个主要是修改H3BPM一个批量审批的功能时候做的.先看下图: H3自带了批量审批的功能,也就是按钮1,有审批意见3,但是如果3里边不填写内容点击1之后,效果就是表单里边没有任何内容.其次可以依次点击每个表单的提交按钮进行提交.会提交对应的审批意见.现在的需求是:增加一个按钮,但是需要提交所有流程的审批内容,因为他们并不可能完全一样.也就是这里的2. 前台HTML代码: <asp:LinkButton ID="btnApproveone" runat=&

osg设置相机参数,包括初始位置

严重注意!!!以下设置必须在viewer.realize();之后,否则不起作用!!!! 设置相机的位置,可以通过CameraManipulator(一般是osgGA::TrackballManipulator)设置, 可以使用setTransformation设置 设置相机的其他参数,ViewMatrix,ProjectionMatrix,Viewport osg::Camera* c=viewer.getCamera(); c.setViewMatrix.... c.setProjectio

使用jquery同时设置两个对象的method为同一函数

$("#completeDate,#issuedDate").datebox({ formatter: function (date) { var y = date.getFullYear(); var m = date.getMonth() + 1; var d = date.getDate(); return y + '-' + (m < 10 ? ('0' + m) : m) + '-' + (d < 10 ? ('0' + d) : d); }, parser: f

Unity相机跟随-----根据速度设置偏移量

这里假设在水中的船,船有惯性,在不添加前进动力的情况下会继续移动,但是船身是可以360度自由旋转,当船的运动速度在船的前方的时候,相机会根据向前的速度的大小,设置相机的偏移量,从而提高游戏的动态带感. 但是由于惯性船的速度不一定在船的,因此可以获得当前船的速度方向在船的前方的投影分量,当分量与船的前方同向,那么设置偏移量为:速度分量的长度与船的最大比值t,乘以相机设定的最大偏移量 代码1 如下 using System.Collections; using System.Collections.

html5移动端页面分辨率设置及相应字体大小设置的靠谱使用方式

对于动端网页编写CSS网上有很多介绍的文章,但在实际使用过程中还是会纠结. 网上的资料太多,且大多都是技术介绍型,特别是针对android上,网上写的各种麻烦,各种复杂,各种不接地气儿... 我在做移动端网页时,总是和美工设计的页面有出入,主要还是由于双方对移动端HTML5实现页面还了解还不够. 今天就研究一下各大互联网公司对于移动端页面的处理方式. 主要研究对象:BAT(度娘,阿狸,企鹅)这几家的移动端网站或webapp 主要研究点:viewport的设置,字体的设置,图片原始宽高设置 汝甚吊

02---按钮的设置 控制器拥有导航栏包装一层导航控制器 添加子控制器 UIBarButtonItem导航按钮 设置导航栏UINavigationBar主题 设置状态栏样式

一.按钮的设置 1.设置背景图片 [btn setBackgroundImage:image forState:UIControlStateNormal]; 2.内部UIImageView 1> 设置内部UIImageView的图片 [btn setImage:image forState:UIControlStateNormal]; // 不能写成btn.imageView.image = image; 2> 调整内部图片的内容模式 self.imageView.contentMode =

[oldboy-django][2深入django]学生管理(Form)-- 编辑(设置input标签属性,设置input标签默认显示值,设置input的类型)

1 django 后台实现设置input标签属性,设置input标签默认显示值,设置input输入框类型 # Form生成html标签 a. 通过Form生成Input输入框,Form标签,以及submit标签还是要在前端写的, 但是Form标签内的Input标签可以在后台实现:只需要按以下步骤 - views定义StudentForm(Form)类 - views视图函数将Form实例化对象传递给前端 - 前端{{ obj.段 }}即可 b. 通过Form设置前端Input的type属性,即设

NXP 飞思卡尔 S12Z 系列单片机 SCI 设置(解决SCI已经设置完成,但却无法通信的问题)

近日在使用了飞思卡尔S12Z设置SCI后总是不出数据,明明按照前代单片机S12Z的方法设置好了,为什么又不能用了呢? 下面是我简单对SCI1的设置,仅仅这样设置是出不来数据的: 1 SCI1BD = GLOBAL_BUS_CLOCK / SCI1_BAUD_RATE; 2 SCI1CR2 = SCI1CR2_RE_MASK + SCI1CR2_TE_MASK + SCI1CR2_RIE_MASK; 在上面的设置中我仅仅设置了SCI1的设置,假设了S12Z与S12一样,不存在同一口多个功能复用的情