ElectricityBusinessHall_Dig.../Assets/ArtRes/A_Ting/ModelViewer.cs

701 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
/// <summary>
/// Around center.
/// </summary>
public Vector3 AroundPos;
/// <summary>
/// 可操作范围
/// </summary>
public Rect rect = new Rect(0, 0, 1920, 1080);
/// <summary>
/// 中心点可移动区域 (限制围绕中心点和相机的 x z
/// </summary>
public Bounds aroundPosBounds = new Bounds();
/// <summary>
/// 相机可移动区域 (限制围绕中心点和相机的 x z
/// </summary>
public Bounds targetPosBounds = new Bounds();
/// <summary>
/// Settings of mouse button, pointer and scrollwheel.
/// </summary>
public MouseSettings mouseSettings = new MouseSettings(0, 1, 5, 0.1f, 2f);
public MouseSettings touchSettings = new MouseSettings(0, 1, 3, 0.1f, 4f);
/// <summary>
/// Range limit of angle.
/// </summary>
public Range angleRange = new Range(0, 90);
public bool isClampY = false;
/// <summary>
/// Range limit of angle.
/// </summary>
public Range yAngleRange = new Range(0, 360);
/// <summary>
/// Range limit of distance.
/// </summary>
public Range distanceRange = new Range(1, 1000);
/// <summary>
/// Damper for move and rotate.
/// </summary>
[Range(0, 10)]
public float damper = 7;
/// <summary>
/// Camera current TargetPos.
/// </summary>
public Vector3 CurrentAroundPos { private set; get; }
/// <summary>
/// Camera current angls.
/// </summary>
public Vector2 CurrentAngles { private set; get; }
/// <summary>
/// Current distance from camera to target.
/// </summary>
public float CurrentDistance { private set; get; }
/// <summary>
/// Camera target TargetPos.
/// </summary>
protected Vector3 targetAroundPos;
/// <summary>
/// Camera target angls.
/// </summary>
protected Vector2 targetAngles;
/// <summary>
/// Target distance from camera to target.
/// </summary>
protected float targetDistance;
/// <summary>
/// Target pos from camera to target.
/// </summary>
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;
}
/// <summary>
/// 重新计算中心点
/// </summary>
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;
/// <summary>
/// Camera around target by mouse input.
/// </summary>
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);
}
}
/// <summary>
/// 设置距离
/// </summary>
/// <param name="lerpValue">最近最远距离的 0-1 插值</param>
public void SetSize(float lerpValue)
{
targetDistance = Mathf.Lerp(distanceRange.min, distanceRange.max, lerpValue);
}
/// <summary>
/// 设置距离
/// </summary>
/// <param name="dis">距离 单位 m</param>
public void SetDistance(float dis)
{
targetDistance = dis;
}
/// <summary>
/// 对距离加减
/// </summary>
/// <param name="subtract">加减量</param>
public void SubtractDistance(float subtract)
{
targetDistance = targetDistance + subtract;
}
/// <summary>
/// 设置成其他的相机位置画面
/// </summary>
/// <param name="cameraTran">相机tranform</param>
/// <param name="distance">围绕点在相机前方的距离</param>
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;
}
/// <summary>
/// 设置相机位置和围绕点
/// </summary>
/// <param name="endPos">相机位置</param>
/// <param name="aroundPos">围绕点</param>
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;
}
}
/// <summary>
/// 计算直线与平面的交点
/// </summary>
/// <param name="point">直线上某一点</param>
/// <param name="direct">直线的方向</param>
/// <param name="planeNormal">垂直于平面的的向量</param>
/// <param name="planePoint">平面上的任意一点</param>
/// <returns></returns>
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;
}
/// <summary>
/// 判断鼠标的位置是否在UI上
/// </summary>
/// <returns>true:当前点击在UI上 false:当前不点击在UI上</returns>
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<RaycastResult> results = new List<RaycastResult>();
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
{
/// <summary>
/// ID of around mouse button.
/// </summary>
public int mouseID_around;
/// <summary>
/// ID of move mouse button.
/// </summary>
public int mouseID_move;
/// <summary>
/// Sensitivity of mouse pointer.
/// </summary>
public float pointerSensitivity;
/// <summary>
/// Sensitivity of mouse move.
/// </summary>
public float moveSensitivity;
/// <summary>
/// Sensitivity of mouse ScrollWheel.
/// </summary>
public float wheelSensitivity;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="mouseID_around">ID of around mouse button.</param>
/// <param name="mouseID_move">ID of move mouse button.</param>
/// <param name="pointerSensitivity">Sensitivity of mouse pointer.</param>
/// <param name="wheelSensitivity">Sensitivity of mouse ScrollWheel.</param>
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;
}
}
/// <summary>
/// Range form min to max.
/// </summary>
[Serializable]
public struct Range
{
/// <summary>
/// Min value of range.
/// </summary>
public float min;
/// <summary>
/// Max value of range.
/// </summary>
public float max;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min">Min value of range.</param>
/// <param name="max">Max value of range.</param>
public Range(float min, float max)
{
this.min = min;
this.max = max;
}
}
}