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