找回密码
 立即注册
查看: 255|回复: 0

Unity 3D地图鼠标根据目标点缩放

[复制链接]
发表于 2022-12-17 17:26 | 显示全部楼层 |阅读模式
之前要做一个以鼠标目标点进行Zoom In/Zoom Out的功能,查了一些资料,没查到- 。-
所以自己动手写了一个,造福广大和我一样没有找到这种方法的同学,加快工作速度,好好享受生活与学习。
因最近在准备各种杂七杂八的东西,所以物理流体模拟一直没更新,也请谅解~趁着有空写篇小的,也算抒发下最近的一段时间的感慨了~


效果大致如下:


https://www.zhihu.com/video/1586344044770344960
其实,步骤很简单,如果要改变相机位置而鼠标定的远距离目标点不变的话,只需要将摄像机移动以后的目标点的移动的向量反向给相机就可以,简而言之,目标点移动,鼠标点不动,相机相对于反方向运动。




如图所示,分别画了侧视图和正视图,黑色1是远离鼠标的一步,粉色是移回来的那一步。这个方法可以在有俯仰角变换的时候通用。
第一步,在摄像机的高度和俯仰角都没变的时候,发出的一根射线,计算射线打到的物体,也就是图中的兔子的某个点的世界坐标,
  float sign = Input.GetAxis("Mouse ScrollWheel");
        //perform lowering down Camera
        //1.更新相机位置发出射线
        Camera.transform.position = temptransform.transform.position;
        RaycastHit hit0;
        Ray ray0 = Camera.ScreenPointToRay(Input.mousePosition);

        Vector3 point0=Vector3.zero;
        if (Physics.Raycast(ray0, out hit0, Mathf.Infinity))
        {
            point0 = hit0.point;
        }
  
目标点远离屏幕鼠标点发出射线检测到的点所在的世界坐标,
第二步,对摄像机做偏移动画,降低高度,俯仰角根据高度改变:
float DiveRatio = Camera.transform.position.y / CameraMaxHeight;
Vector3 temposition = temptransform.transform.position + new Vector3(0, -sign * SensityDive* DiveRatio, 0);
temposition = new Vector3(Mathf.Clamp(temposition.x, CameraXmin, CameraXMax),
             Mathf.Clamp(temposition.y, HeightMinimum+0.01f, CameraMaxHeight-0.01f),
             Mathf.Clamp(temposition.z, CameraBottomMin, CameraUpMax));
   
temptransform.transform.position = temposition;
pitchAngle = PitchRotateAnimation();
Camera.transform.rotation = Quaternion.Euler(pitchAngle, rotationY, 0);
Camera.transform.position = temposition;
第三步,再将鼠标的目标点发出射线,检测这个新的鼠标目标的位置。
RaycastHit hit1;
        Ray ray1 = Camera.ScreenPointToRay(Input.mousePosition);
     
        Vector3 point1 = Vector3.zero;
        if (Physics.Raycast(ray1, out hit1, Mathf.Infinity))
        {
            point1 = hit1.point;
        }

     
        Vector3 direction = point0 - point1;
  
        Vector3 offset = new Vector3(direction.x, 0, direction.z);
这个offset便是要将目标点移到原本的鼠标位置的点的反方向,也就是摄像机应该相对做出的位移
最后更新位置:
Camera.transform.position += offset;
Camera.transform.position = new Vector3(Mathf.Clamp(Camera.transform.position.x, CameraXmin, CameraXMax),
Mathf.Clamp(Camera.transform.position.y, HeightMinimum, CameraMaxHeight),
Mathf.Clamp(Camera.transform.position.z, CameraBottomMin, CameraUpMax));
temptransform.position = Camera.transform.position;
Bingo!
函数如下(大家可以放心忽略temptransform的值赋来赋去,可以直接CameraTransform)
void Zoom()
    {
        //Get Camera position beforeHeighchange
      
        //Get Camera pitch beforeHeighchange
        float pitchAngle1 = Camera.transform.rotation.eulerAngles.x;
        float sign = Input.GetAxis("Mouse ScrollWheel");
        //perform lowering down Camera
        //1.更新相机位置发出射线
        Camera.transform.position = temptransform.transform.position;
        RaycastHit hit0;
        Ray ray0 = Camera.ScreenPointToRay(Input.mousePosition);

        Vector3 point0=Vector3.zero;
        if (Physics.Raycast(ray0, out hit0, Mathf.Infinity))
        {
            point0 = hit0.point;
        }
        Debug.Log("sign" + sign);
        float DiveRatio = Camera.transform.position.y / CameraMaxHeight;
        Vector3 temposition = temptransform.transform.position + new Vector3(0, -sign * SensityDive* DiveRatio, 0);
        temposition = new Vector3(Mathf.Clamp(temposition.x, CameraXmin, CameraXMax),
             Mathf.Clamp(temposition.y, HeightMinimum+0.01f, CameraMaxHeight-0.01f),
             Mathf.Clamp(temposition.z, CameraBottomMin, CameraUpMax));
       // Debug.Log("point0" + point0);
        temptransform.transform.position = temposition;
      
         // Debug.Log(point0);

        //相机角度
        //Get Camera position after Height change
        //CameraHeight2 = Camera.transform.position.y;
       //2.更新相机位置再发出射线
        pitchAngle = PitchRotateAnimation();


        Camera.transform.rotation = Quaternion.Euler(pitchAngle, rotationY, 0);
        Camera.transform.position = temposition;

        //Get Object offsets position after Height change
        RaycastHit hit1;
        Ray ray1 = Camera.ScreenPointToRay(Input.mousePosition);
     
        Vector3 point1 = Vector3.zero;
        if (Physics.Raycast(ray1, out hit1, Mathf.Infinity))
        {
            point1 = hit1.point;
        }

     
        Vector3 direction = point0 - point1;
  
        Vector3 offset = new Vector3(direction.x, 0, direction.z);
       // Debug.Log(offset);
      //  pitchAngle = PitchRotateAnimation();
      //  Camera.transform.rotation = Quaternion.Euler(pitchAngle, rotationY, 0);
        //perform the opposite offset
        Camera.transform.position += offset;
        Camera.transform.position = new Vector3(Mathf.Clamp(Camera.transform.position.x, CameraXmin, CameraXMax),
             Mathf.Clamp(Camera.transform.position.y, HeightMinimum, CameraMaxHeight),
             Mathf.Clamp(Camera.transform.position.z, CameraBottomMin, CameraUpMax));
        temptransform.position = Camera.transform.position;


    }
好了,到此为止~祝大家工作学习愉快

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-15 23:00 , Processed in 0.091787 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表