namespace HXSJFrameWork { using UnityEngine; using System; using System.Collections; using UnityEngine.Networking; using UnityEngine.EventSystems; using System.Collections.Generic; public enum ControlMode { ALL, PartArea, UIRect, } public class ModelViewer : MonoBehaviour { [SerializeField] public ControlMode _controlMode; [SerializeField] public bool _enabled = true; public bool isNear; // Text m_debugTip; public bool canRotation_X = true; public bool canRotation_Y = true; public bool canScale = true; public bool canMoveTargetPos = true; public bool isLimitAroundPos = false; public bool isLimitMoveArea = false; #region Field and Property /// /// Around center. /// public Vector3 AroundPos; /// /// 可操作范围 /// public Rect rect = new Rect(0, 0, 1920, 1080); /// /// 中心点可移动区域 (限制围绕中心点和相机的 x ,z) /// public Bounds aroundPosBounds = new Bounds(); /// /// 相机可移动区域 (限制围绕中心点和相机的 x ,z) /// public Bounds targetPosBounds = new Bounds(); /// /// Settings of mouse button, pointer and scrollwheel. /// public MouseSettings mouseSettings = new MouseSettings(0, 1, 5, 0.1f, 2f); public MouseSettings touchSettings = new MouseSettings(0, 1, 3, 0.1f, 4f); /// /// Range limit of angle. /// public Range angleRange = new Range(0, 90); public bool isClampY = false; /// /// Range limit of angle. /// public Range yAngleRange = new Range(0, 360); /// /// Range limit of distance. /// public Range distanceRange = new Range(1, 1000); /// /// Damper for move and rotate. /// [Range(0, 10)] public float damper = 7; /// /// Camera current TargetPos. /// public Vector3 CurrentAroundPos { private set; get; } /// /// Camera current angls. /// public Vector2 CurrentAngles { private set; get; } /// /// Current distance from camera to target. /// public float CurrentDistance { private set; get; } /// /// Camera target TargetPos. /// protected Vector3 targetAroundPos; /// /// Camera target angls. /// protected Vector2 targetAngles; /// /// Target distance from camera to target. /// protected float targetDistance; /// /// Target pos from camera to target. /// protected Vector3 targetPos; #endregion private void Awake() { } protected virtual void Start() { //StartCoroutine("ReadConfig"); //解决不好调整相机初始位置问题/* 2021-04-23 15:18:54 */ AroundPos = GetIntersectWithLineAndPlane(transform.position, transform.forward, Vector3.down, Vector3.up); Init(); } private void Update() { //判断相机是否进入房间内 if (transform.position.y > 3) { isNear = false; //显示空间Icon ModelManager.instance.CameraNear(false); } else { isNear = true; //隐藏空间Icon ModelManager.instance.CameraNear(true); } if (Input.GetKeyDown(KeyCode.A)) { Debug.Log(transform.position.x + "," + transform.position.y + "," + transform.position.z + "," + AroundPos.x + "," + AroundPos.y + "," + AroundPos.z); } } public void Init() { AroundPos = GetIntersectWithLineAndPlane(transform.position, transform.forward, Vector3.up, transform.up * 3); Debug.Log("围绕中心点"+AroundPos); CurrentDistance = targetDistance = Vector3.Distance(transform.position, AroundPos); CurrentAngles = targetAngles = transform.eulerAngles; CurrentAroundPos = targetAroundPos = AroundPos; } /// /// 重新计算中心点 /// public void InitTarget() { AroundPos = transform.position+ transform.forward*3; //Debug.Log("围绕中心点"+AroundPos); CurrentDistance = targetDistance = Vector3.Distance(transform.position, AroundPos); CurrentAngles = targetAngles = transform.eulerAngles; CurrentAroundPos = targetAroundPos = AroundPos; } bool uiDown = false; public void SetControlModeUIRect(RectTransform rect) { _controlMode = ControlMode.UIRect; } protected virtual void LateUpdate() { if (!_enabled) return; //Lerp. //CurrentAngles = Vector2.LerpUnclamped(CurrentAngles, targetAngles, damper * Time.deltaTime); CurrentAngles = targetAngles; CurrentDistance = Mathf.Lerp(CurrentDistance, targetDistance, damper * Time.deltaTime); CurrentAroundPos = Vector3.Lerp(CurrentAroundPos, targetAroundPos, damper * Time.deltaTime); AroundPos = CurrentAroundPos; //transform.rotation = Quaternion.Euler(CurrentAngles); transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(CurrentAngles), damper * Time.deltaTime); targetPos = AroundPos - transform.forward * CurrentDistance; if (isLimitMoveArea) { targetPos = ClampVector3(targetPos, targetPosBounds.min, targetPosBounds.max); } transform.position = targetPos; if (_controlMode == ControlMode.ALL) { if (IsPointerOverUIObject()) return; CheckInput(); } else if (_controlMode == ControlMode.PartArea) { if (!rect.Contains(Input.mousePosition)) return; CheckInput(); } else if (_controlMode == ControlMode.UIRect) { if (!uiDown) return; CheckInput(); } } public void CheckInput() { if (Input.touchCount > 0) { AroundByMobileInput(); } else { AroundByMouseInput(); } CheckKeyCodeInput(); } private void CheckKeyCodeInput() { if (Input.GetKey(KeyCode.W)) { Vector3 v = new Vector3(transform.forward.x, 0, transform.forward.z).normalized; targetAroundPos += v * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1) * 0.2f; } else if (Input.GetKey(KeyCode.S)) { Vector3 v = new Vector3(transform.forward.x, 0, transform.forward.z).normalized; targetAroundPos -= v * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1) * 0.2f; } if (Input.GetKey(KeyCode.A)) { targetAroundPos -= transform.right * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1) * 0.2f; } else if (Input.GetKey(KeyCode.D)) { targetAroundPos += transform.right * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1) * 0.2f; } if (Input.GetKey(KeyCode.Q)) { targetAroundPos -= Vector3.up * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1) * 0.2f; } else if (Input.GetKey(KeyCode.E)) { targetAroundPos += Vector3.up * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1) * 0.2f; } if (isLimitAroundPos) { targetAroundPos = ClampVector3(targetAroundPos, aroundPosBounds.min, aroundPosBounds.max); } } float lastTouchDistance = 0; protected void AroundByMobileInput() { if (Input.touchCount == 3 && canMoveTargetPos)//平移视角 { autoRotateValue = 0; lastTouchDistance = 0; //刚开始点击 if (Input.GetTouch(0).phase == TouchPhase.Moved) { targetAroundPos -= transform.right * Input.GetTouch(0).deltaPosition.x * touchSettings.moveSensitivity / 5 * (Mathf.Sqrt(CurrentDistance) + 1); targetAroundPos -= transform.up * Input.GetTouch(0).deltaPosition.y * touchSettings.moveSensitivity / 5 * (Mathf.Sqrt(CurrentDistance) + 1); } } else if (Input.touchCount == 2 && canScale)//缩放 { autoRotateValue = 0; if (lastTouchDistance == 0) { lastTouchDistance = Vector3.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position); } else if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved) { var tempPosition1 = Input.GetTouch(0).position; var tempPosition2 = Input.GetTouch(1).position; float currentTouchDistance = Vector3.Distance(tempPosition1, tempPosition2); //计算上次和这次双指触摸之间的距离差距 //然后去更改摄像机的距离 targetDistance -= (currentTouchDistance - lastTouchDistance) * Time.deltaTime * touchSettings.wheelSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1); //备份上一次触摸点的位置,用于对比 lastTouchDistance = currentTouchDistance; } } else if (Input.touchCount == 1)//旋转 { autoRotateValue = 0; lastTouchDistance = 0; if (Input.GetTouch(0).phase == TouchPhase.Moved) { if (canRotation_X) targetAngles.y += Input.GetTouch(0).deltaPosition.x * touchSettings.pointerSensitivity / 10; if (canRotation_Y) targetAngles.x -= Input.GetTouch(0).deltaPosition.y * touchSettings.pointerSensitivity / 10; //Range. targetAngles.x = Mathf.Clamp(ClampRotationX(targetAngles.x), angleRange.min, angleRange.max); if (isClampY) { targetAngles.y = Mathf.Clamp(targetAngles.y, yAngleRange.min, yAngleRange.max); } } } else { lastTouchDistance = 0; AutoRotate(); } if (targetDistance < distanceRange.min) { targetAroundPos += (distanceRange.min - targetDistance) * transform.forward; if (isLimitAroundPos) { targetAroundPos = ClampVector3(targetAroundPos, aroundPosBounds.min, aroundPosBounds.max); } targetDistance = distanceRange.min; } else { targetDistance = Mathf.Clamp(targetDistance, distanceRange.min, distanceRange.max); } } Vector3 offset; /// /// Camera around target by mouse input. /// protected void AroundByMouseInput() { if (Input.GetMouseButton(mouseSettings.mouseID_move)) { if (canMoveTargetPos) { targetAroundPos -= transform.right * Input.GetAxis("Mouse X") * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1); targetAroundPos -= transform.up * Input.GetAxis("Mouse Y") * mouseSettings.moveSensitivity * (Mathf.Sqrt(CurrentDistance * 10) + 1); } if (isLimitAroundPos) { //解决超出范围后,滚轮滚动时,值还在增加 if (!aroundPosBounds.Contains(targetAroundPos)) canScale = false; else canScale = true; targetAroundPos = ClampVector3(targetAroundPos, aroundPosBounds.min, aroundPosBounds.max); } autoRotateValue = 0; } else if (Input.GetMouseButton(mouseSettings.mouseID_around)) { //Mouse pointer. if (canRotation_X) targetAngles.y += Input.GetAxis("Mouse X") * mouseSettings.pointerSensitivity; if (canRotation_Y) targetAngles.x -= Input.GetAxis("Mouse Y") * mouseSettings.pointerSensitivity; //Range. targetAngles.x = Mathf.Clamp(ClampRotationX(targetAngles.x), angleRange.min, angleRange.max); if (isClampY) { targetAngles.y = Mathf.Clamp(targetAngles.y, yAngleRange.min, yAngleRange.max); } autoRotateValue = 0; } else if (Mathf.Abs(Input.GetAxis("Mouse ScrollWheel")) > 0) { autoRotateValue = 0; } else { AutoRotate(); } //Mouse scrollwheel. if (canScale) { targetDistance -= Input.GetAxis("Mouse ScrollWheel") * mouseSettings.wheelSensitivity * (Mathf.Sqrt(CurrentDistance) + 1); } if (targetDistance < distanceRange.min) { targetAroundPos += (distanceRange.min - targetDistance) * transform.forward; if (isLimitAroundPos) { targetAroundPos = ClampVector3(targetAroundPos, aroundPosBounds.min, aroundPosBounds.max); } targetDistance = distanceRange.min; } else { targetDistance = Mathf.Clamp(targetDistance, distanceRange.min, distanceRange.max); } } /// /// 设置距离 /// /// 最近最远距离的 0-1 插值 public void SetSize(float lerpValue) { targetDistance = Mathf.Lerp(distanceRange.min, distanceRange.max, lerpValue); } /// /// 设置距离 /// /// 距离 单位 m public void SetDistance(float dis) { targetDistance = dis; } /// /// 对距离加减 /// /// 加减量 public void SubtractDistance(float subtract) { targetDistance = targetDistance + subtract; } /// /// 设置成其他的相机位置画面 /// /// 相机tranform /// 围绕点在相机前方的距离 public void SetToCameraPos(Transform cameraTran, float distance = 5) { enabled = false; transform.position = cameraTran.position; transform.eulerAngles = cameraTran.eulerAngles; AroundPos = transform.position + transform.forward * distance; Init(); enabled = true; } /// /// 设置相机位置和围绕点 /// /// 相机位置 /// 围绕点 public void SetCameraPos(Vector3 endPos, Vector3 aroundPos) { enabled = false; transform.position = endPos; transform.LookAt(aroundPos); AroundPos = aroundPos; Init(); enabled = true; } #region 移动相机视角 author:wm #endregion public static bool isMobile = false; public void SetBool(string str) { isMobile = bool.Parse(str); } IEnumerator ReadConfig() { string path; switch (Application.platform) { case RuntimePlatform.WindowsPlayer: case RuntimePlatform.WindowsEditor: path = Application.streamingAssetsPath + "/ModelViewerConfig.txt"; break; default: path = Application.dataPath + "/StreamingAssets/ModelViewerConfig.txt"; break; } using (UnityWebRequest www = UnityWebRequest.Get(path)) { yield return www.SendWebRequest(); if (www.isHttpError || www.isNetworkError) { Debug.Log(www.error); } else { // Debug.Log(www.downloadHandler.text); string[] strs = www.downloadHandler.text.Split('\n');//读取文件的所有行,并将数据读取到定义好的字符数组strs中,一行存一个单元 mouseSettings.pointerSensitivity = float.Parse(strs[0]); mouseSettings.moveSensitivity = float.Parse(strs[1]); mouseSettings.wheelSensitivity = float.Parse(strs[2]); touchSettings.pointerSensitivity = float.Parse(strs[3]); touchSettings.moveSensitivity = float.Parse(strs[4]); touchSettings.wheelSensitivity = float.Parse(strs[5]); Debug.Log(Application.platform); if (Application.platform == RuntimePlatform.WebGLPlayer) { if (isMobile) { mouseSettings.pointerSensitivity = mouseSettings.pointerSensitivity * -1; mouseSettings.moveSensitivity = mouseSettings.moveSensitivity * -1; touchSettings.pointerSensitivity = touchSettings.pointerSensitivity * -1; touchSettings.moveSensitivity = touchSettings.moveSensitivity * -1; } } } }; } public Vector3 ClampVector3(Vector3 v, Vector3 min, Vector3 max) { v.x = Mathf.Clamp(v.x, min.x, max.x); v.y = Mathf.Clamp(v.y, min.y, max.y); v.z = Mathf.Clamp(v.z, min.z, max.z); return v; } private float autoRotateValue; public bool IsAutoRotate = false; public float autoRotateSpeed = 5; private void AutoRotate() { autoRotateValue += Time.deltaTime; if (IsAutoRotate && autoRotateValue >= 2) { //Range. targetAngles.y += Time.deltaTime * autoRotateSpeed; if (isClampY) { targetAngles.y = Mathf.Clamp(targetAngles.y, yAngleRange.min, yAngleRange.max); } autoRotateValue = 2; } } /// /// 计算直线与平面的交点 /// /// 直线上某一点 /// 直线的方向 /// 垂直于平面的的向量 /// 平面上的任意一点 /// public static Vector3 GetIntersectWithLineAndPlane(Vector3 point, Vector3 direct, Vector3 planeNormal, Vector3 planePoint) { float d = Vector3.Dot(planePoint - point, planeNormal) / Vector3.Dot(direct.normalized, planeNormal); if (Vector3.Dot(direct.normalized, planeNormal) == 0) d = 3; return d * direct.normalized + point; } /// /// 判断鼠标的位置是否在UI上 /// /// true:当前点击在UI上 false:当前不点击在UI上 public static bool IsPointerOverUIObject() { PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); #if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IPHONE) eventDataCurrentPosition.position = Input.GetTouch(0).position; #else eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y); #endif List results = new List(); if (EventSystem.current) { EventSystem.current.RaycastAll(eventDataCurrentPosition, results); } for (int i = 0; i < results.Count; i++) { if (results[i].gameObject.layer == LayerMask.NameToLayer("UI") ) return true; } return false; } private float ClampRotationX(float x) { if (x > 180) { //当前值应该为负数 return x - 360; } return x; } } [Serializable] public struct MouseSettings { /// /// ID of around mouse button. /// public int mouseID_around; /// /// ID of move mouse button. /// public int mouseID_move; /// /// Sensitivity of mouse pointer. /// public float pointerSensitivity; /// /// Sensitivity of mouse move. /// public float moveSensitivity; /// /// Sensitivity of mouse ScrollWheel. /// public float wheelSensitivity; /// /// Constructor. /// /// ID of around mouse button. /// ID of move mouse button. /// Sensitivity of mouse pointer. /// Sensitivity of mouse ScrollWheel. public MouseSettings(int mouseID_around, int mouseID_move, float pointerSensitivity, float moveSensitivity, float wheelSensitivity) { this.mouseID_around = mouseID_around; this.mouseID_move = mouseID_move; this.pointerSensitivity = pointerSensitivity; this.moveSensitivity = moveSensitivity; this.wheelSensitivity = wheelSensitivity; } } /// /// Range form min to max. /// [Serializable] public struct Range { /// /// Min value of range. /// public float min; /// /// Max value of range. /// public float max; /// /// Constructor. /// /// Min value of range. /// Max value of range. public Range(float min, float max) { this.min = min; this.max = max; } } }