博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在UGUI上显示3D模型,并限制范围的拖拽
阅读量:5306 次
发布时间:2019-06-14

本文共 14541 字,大约阅读时间需要 48 分钟。

  • 通过RenderTexture实现

显示图片

  • 记得在用NGUI的时候,就是用这种方式实现在UI上显示模型的。
  • 首先新建一张RenderTexture,右键点击Project窗口,Create->Render Texture;
  • 新建一个Shader ,将刚刚新建的RenderTexture 拖入Shader中。

  

  • 新建一个Cube 和一个相机名为ModelCamera,这个相机专门用来对准模型,并将刚刚新建的RenderTexture拖入相机的TargetTexture中。

  

  • 新建UI,将Canvas 的 RenderMode改为Camera,将Main Camera拖入Render Camera中。
  • 新建一个Image命名为MaskImg,并添加脚本Mask,用于遮罩,并设置Image的SourceImage为UIMask

  

  • 在MaskImg新建子物体Image,用于展示模型。然后将新建的 Shader拖入Image上。如下图,此时就已经看到模型的一面在Image上显示出来了。

  

  • 但是会发现,颜色不对,此时将Shader改为”UI/Default“就可以了。旋转模型会发现Image上的模型会同步旋转。

  

有限制的拖拽

   拖拽图片,通过UGUI的OnDrag函数来获取鼠标的世界坐标,赋值给图片即可。

  限制,要求Image必须在Mask中显示,拖出视野外后自动回到视野内。这就需要在Mask的上下左右设置限制位置,当图片超过限制并且松开拖拽后,计算位置自动返回到视野内。

  添加限制,在MaskImg上新建子物体 Limit ,并设置Anchor

  

  在Limit下新建四个子物体,作为上下左右的限制。Left的Anchor为Left-middle,POS为(0,0,0),其他同理,Right为Right-midle,Top为Center-Top,Bottom为center-Bottom

  

  缩放,通过获取滚轮的滑动实现缩放,添加上下限,(注意:1.移动限制里面需要将缩放的系数也计算其中;2.如果放大后显示的模型出现模糊,把RenderTexture的Size属性调大即可

  旋转,计算鼠标滑动的X轴和Y轴,给Cube赋值旋转。

  代码如下

  首先添加一个UIEventListener脚本,用于监听UI的OnDrag事件

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.Events;public class UIEventListener : UnityEngine.EventSystems.EventTrigger{    public delegate void VoidDelegate(GameObject go);    public delegate void VoidEventDelegate(PointerEventData eventData);    public VoidDelegate onClick;    public VoidEventDelegate onDrag;    public VoidEventDelegate onBeginDrag;    public VoidEventDelegate onEndDrag;      static public UIEventListener Get(GameObject go)    {        UIEventListener listener = go.GetComponent
(); if (listener == null) listener = go.AddComponent
(); return listener; } public override void OnPointerClick(PointerEventData eventData) { if (onClick != null) onClick(gameObject); } public override void OnDrag(PointerEventData eventData) { //if (eventData.button == PointerEventData.InputButton.Left) if (onDrag != null) onDrag(eventData); } public override void OnBeginDrag(PointerEventData eventData) { if (eventData.button == PointerEventData.InputButton.Left) if (onBeginDrag != null) onBeginDrag(eventData); } public override void OnEndDrag(PointerEventData eventData) { if (eventData.button == PointerEventData.InputButton.Left) if (onEndDrag != null) onEndDrag(eventData); } }
View Code

  然后新建一个MoveTest代码,挂在Canvas上

  

using UnityEngine;using System.Collections;using UnityEngine.EventSystems;public class MoveTest : MonoBehaviour{    public float ScaleMax = 4;    public float ScaleMin = 1;    public Transform Limit;    public GameObject Img;    public GameObject goModel;    public float RotSpeed = 10f;    Vector3 posOffset;    bool isDrag;    float fScale;    float LimitLeft;    float LimitRight;    float LimitTop;    float LimitBottom;    float fRotX;    float fRotY;    float fRotYMaxLimt = 360;    float fRotYMinLimt = -360;    // Use this for initialization    void Start()    {        UIEventListener.Get(Img).onBeginDrag = OnBeginDrag;        UIEventListener.Get(Img).onDrag = OnDrag;        UIEventListener.Get(Img).onEndDrag = OnEndDrag;        if (Limit != null)        {            LimitLeft = Limit.Find("Left").localPosition.x;            LimitRight = Limit.Find("Right").localPosition.x;            LimitTop = Limit.Find("Top").localPosition.y;            LimitBottom = Limit.Find("Bottom").localPosition.y;        }        //计算图片的宽度,因为模型的RenderTexture必须显示在Image上,所以Image的长宽必须相等,否则会拉伸模型的显示,此处计算取宽度和高度最大值作为图片的宽高。        float Width = (LimitRight - LimitLeft) > (LimitTop - LimitBottom) ? LimitRight - LimitLeft : LimitTop - LimitBottom;        Img.GetComponent
().sizeDelta = new Vector2(Width, Width); fScale = Img.transform.localScale.x; fRotX = goModel.transform.eulerAngles.x; fRotY = goModel.transform.eulerAngles.y; } // Update is called once per frame void Update() { float fMouseScale = Input.GetAxis("Mouse ScrollWheel"); if (!isDrag) { if (fMouseScale != 0) Scale(fMouseScale); MoveBack(Img); } } void OnBeginDrag(PointerEventData eventData) { Vector3 vPos = new Vector3(); if (RectTransformUtility.ScreenPointToWorldPointInRectangle(Img.GetComponent
(), eventData.position, Camera.main, out vPos)) { posOffset = Img.transform.position - vPos; } isDrag = true; } void OnDrag(PointerEventData eventData) { if (isDrag) { Vector3 pos; if (RectTransformUtility.ScreenPointToWorldPointInRectangle(Img.GetComponent
(), eventData.position, Camera.main, out pos)) { Img.transform.position = pos + posOffset; } } else if (eventData.button == PointerEventData.InputButton.Right) { Rotation(); } } void OnEndDrag(PointerEventData eventData) { posOffset = Vector3.zero; isDrag = false; } //回到视野内 void MoveBack(GameObject objImg) { float fOffsetX; float fOffsetY; { if (objImg.transform.localPosition.x < (LimitRight - objImg.GetComponent
().rect.width / 2 * fScale)) { fOffsetX = LimitRight - (objImg.transform.localPosition.x + objImg.GetComponent
().rect.width / 2 * fScale); } else if (objImg.transform.localPosition.x > (LimitLeft + objImg.GetComponent
().rect.width / 2 * fScale)) { fOffsetX = LimitLeft - (objImg.transform.localPosition.x - objImg.GetComponent
().rect.width / 2 * fScale); } else { fOffsetX = 0; } } { if (objImg.transform.localPosition.y > (LimitBottom + objImg.GetComponent
().rect.height / 2 * fScale)) { fOffsetY = LimitBottom - (objImg.transform.localPosition.y - objImg.GetComponent
().rect.height / 2 * fScale); } else if (objImg.transform.localPosition.y < (LimitTop - objImg.GetComponent
().rect.height / 2 * fScale)) { fOffsetY = LimitTop - (objImg.transform.localPosition.y + objImg.GetComponent
().rect.height / 2 * fScale); } else { fOffsetY = 0; } } objImg.transform.Translate(new Vector3(fOffsetX, fOffsetY, 0) * Time.deltaTime / 2, Space.Self); } //缩放 void Scale(float fDetla) { Debug.Log(fDetla); Img.transform.localScale = new Vector3(Img.transform.localScale.x + fDetla, Img.transform.localScale.y + fDetla, 1); if (Img.transform.localScale.x < ScaleMin) Img.transform.localScale = Vector3.one; else if (Img.transform.localScale.x > ScaleMax) Img.transform.localScale = new Vector3(ScaleMax, ScaleMax, 1); fScale = Img.transform.localScale.x; } void Rotation() { float fx = Input.GetAxis("Mouse X"); float fy = Input.GetAxis("Mouse Y"); #region//第一种方法,无法实现世界坐标的X轴旋转 //if (Mathf.Abs(fx) >= Mathf.Abs(fy)) //{ // fRotX -= fx * RotSpeed; //} //else if (Mathf.Abs(fy) > Mathf.Abs(fx)) //{ // fRotY += fy * RotSpeed; //} //fRotY = ClampAngle(fRotY, fRotYMinLimt, fRotYMaxLimt); //goModel.transform.rotation = Quaternion.Euler(fRotY, fRotX, 0); #endregion if (Mathf.Abs(fx) >= Mathf.Abs(fy)) { fRotX += fx * RotSpeed; fRotY = 0; } else if (Mathf.Abs(fy) > Mathf.Abs(fx)) { fRotY += fy * RotSpeed; fRotX = 0; } goModel.transform.Rotate(Vector3.up, -fx * Time.deltaTime * 500, Space.World); goModel.transform.Rotate(Vector3.right, fy * Time.deltaTime * 500, Space.World); } float ClampAngle(float angle, float min, float max) { if (angle < -360) angle += 360; if (angle > 360) angle -= 360; return Mathf.Clamp(angle, min, max); }}
View Code

 

 

  • 通过UI和模型的位置实现

  上述方法存在一个问题,就是无法直接和模型进行点击交互,因为你点击的是RenderTexture,那就需要 另外一种方法,调整UI和模型的位置,可以直接将模型放入主摄像机的视野中。

  为了方便计算,先将MainCamera坐标变为(0,0,0),将Canvas的PlaneDistance变成1,把Cube放到(0,0,2)的位置。现在在Game视图中就看到了对象Cube,并不是在RenderTexture上中显示的。

  

  其实原理就是等比,UI和Cube距离摄像机的距离等比于Img在UI上移动的距离和Cube在World上移动的距离。

  所以在移动的方法里把Img移动的距离X这个比例,就可以计算Cube的移动距离并赋值了。

  

  直接上修改后的代码。

  

using UnityEngine;using System.Collections;using UnityEngine.EventSystems;public class MoveTest : MonoBehaviour{    public float ScaleMax = 4;    public float ScaleMin = 1;    public Transform Limit;    public GameObject Img;    public GameObject goModel;    public float RotSpeed = 10f;    public Canvas canvas;    Vector3 posOffset;    bool isDrag;    float fScale;    float LimitLeft;    float LimitRight;    float LimitTop;    float LimitBottom;    float fRotX;    float fRotY;    float fRotYMaxLimt = 360;    float fRotYMinLimt = -360;    float fDistance;    Vector3 StartPos;    // Use this for initialization    void Start()    {        UIEventListener.Get(Img).onBeginDrag = OnBeginDrag;        UIEventListener.Get(Img).onDrag = OnDrag;        UIEventListener.Get(Img).onEndDrag = OnEndDrag;        if (Limit != null)        {            LimitLeft = Limit.Find("Left").localPosition.x;            LimitRight = Limit.Find("Right").localPosition.x;            LimitTop = Limit.Find("Top").localPosition.y;            LimitBottom = Limit.Find("Bottom").localPosition.y;        }        //计算图片的宽度,因为模型的RenderTexture必须显示在Image上,所以Image的长宽必须相等,否则会拉伸模型的显示,此处计算取宽度和高度最大值作为图片的宽高。        float Width = (LimitRight - LimitLeft) > (LimitTop - LimitBottom) ? LimitRight - LimitLeft : LimitTop - LimitBottom;        Img.GetComponent
().sizeDelta = new Vector2(Width, Width); fScale = Img.transform.localScale.x; fRotX = goModel.transform.eulerAngles.x; fRotY = goModel.transform.eulerAngles.y; StartPos = goModel.transform.localPosition; } // Update is called once per frame void Update() { float fMouseScale = Input.GetAxis("Mouse ScrollWheel"); if (!isDrag) { if (fMouseScale != 0) Scale(fMouseScale); MoveBack(Img); } } void OnBeginDrag(PointerEventData eventData) { Vector3 vPos = new Vector3(); if (RectTransformUtility.ScreenPointToWorldPointInRectangle(Img.GetComponent
(), eventData.position, Camera.main, out vPos)) { posOffset = Img.transform.position - vPos; } isDrag = true; } void OnDrag(PointerEventData eventData) { if (isDrag) { Vector3 pos; if (RectTransformUtility.ScreenPointToWorldPointInRectangle(Img.GetComponent
(), eventData.position, Camera.main, out pos)) { Img.transform.position = pos + posOffset; //计算比例,然后再Img移动的基础上乘以比例系数,就算出模型移动的距离了。 fDistance = goModel.transform.position.z / canvas.planeDistance; Debug.Log(fDistance); float fx = Img.transform.position.x * fDistance; float fy = Img.transform.position.y * fDistance; goModel.transform.localPosition = StartPos + new Vector3(fx, fy, 0); } } else if (eventData.button == PointerEventData.InputButton.Right) { Rotation(); } } void OnEndDrag(PointerEventData eventData) { posOffset = Vector3.zero; isDrag = false; } //回到视野内 void MoveBack(GameObject objImg) { float fOffsetX; float fOffsetY; { if (objImg.transform.localPosition.x < (LimitRight - objImg.GetComponent
().rect.width / 2 * fScale)) { fOffsetX = LimitRight - (objImg.transform.localPosition.x + objImg.GetComponent
().rect.width / 2 * fScale); } else if (objImg.transform.localPosition.x > (LimitLeft + objImg.GetComponent
().rect.width / 2 * fScale)) { fOffsetX = LimitLeft - (objImg.transform.localPosition.x - objImg.GetComponent
().rect.width / 2 * fScale); } else { fOffsetX = 0; } } { if (objImg.transform.localPosition.y > (LimitBottom + objImg.GetComponent
().rect.height / 2 * fScale)) { fOffsetY = LimitBottom - (objImg.transform.localPosition.y - objImg.GetComponent
().rect.height / 2 * fScale); } else if (objImg.transform.localPosition.y < (LimitTop - objImg.GetComponent
().rect.height / 2 * fScale)) { fOffsetY = LimitTop - (objImg.transform.localPosition.y + objImg.GetComponent
().rect.height / 2 * fScale); } else { fOffsetY = 0; } } //注意此处,(60/canvas.planeDistance)必须加上,否则会因为移动过,导致Postion的值过大而报错,因为一开始Canvas的值是60,现在改成1,所以需要60/1 objImg.transform.Translate(new Vector3(fOffsetX, fOffsetY, 0) * Time.deltaTime / (60 / canvas.planeDistance), Space.Self); goModel.transform.localPosition=StartPos+ new Vector3(objImg.transform.position.x * fDistance, objImg.transform.position.y * fDistance, 0); } //缩放 void Scale(float fDetla) { Img.transform.localScale = new Vector3(Img.transform.localScale.x + fDetla, Img.transform.localScale.y + fDetla, 1); if (Img.transform.localScale.x < ScaleMin) Img.transform.localScale = Vector3.one; else if (Img.transform.localScale.x > ScaleMax) Img.transform.localScale = new Vector3(ScaleMax, ScaleMax, 1); //fScale = Img.transform.localScale.x; //同样的代码,Cube再来一遍 goModel.transform.localScale = new Vector3(goModel.transform.localScale.x + fDetla, goModel.transform.localScale.y + fDetla, 1); if (goModel.transform.localScale.x < ScaleMin) goModel.transform.localScale = Vector3.one; else if (goModel.transform.localScale.x > ScaleMax) goModel.transform.localScale = new Vector3(ScaleMax, ScaleMax, 1); fScale = goModel.transform.localScale.x; } void Rotation() { float fx = Input.GetAxis("Mouse X"); float fy = Input.GetAxis("Mouse Y"); #region//第一种方法,无法实现世界坐标的X轴旋转 //if (Mathf.Abs(fx) >= Mathf.Abs(fy)) //{ // fRotX -= fx * RotSpeed; //} //else if (Mathf.Abs(fy) > Mathf.Abs(fx)) //{ // fRotY += fy * RotSpeed; //} //fRotY = ClampAngle(fRotY, fRotYMinLimt, fRotYMaxLimt); //goModel.transform.rotation = Quaternion.Euler(fRotY, fRotX, 0); #endregion if (Mathf.Abs(fx) >= Mathf.Abs(fy)) { fRotX += fx * RotSpeed; fRotY = 0; } else if (Mathf.Abs(fy) > Mathf.Abs(fx)) { fRotY += fy * RotSpeed; fRotX = 0; } goModel.transform.Rotate(Vector3.up, -fx * Time.deltaTime * 500, Space.World); goModel.transform.Rotate(Vector3.right, fy * Time.deltaTime * 500, Space.World); } float ClampAngle(float angle, float min, float max) { if (angle < -360) angle += 360; if (angle > 360) angle -= 360; return Mathf.Clamp(angle, min, max); }}
View Code

  这时候会发现一个问题,就是Cube不会被Mask遮挡住,因为Mask遮罩遮不住模型,其实只要在Mask周围添加上UI图片,挡住Cube就行了。

 

转载于:https://www.cnblogs.com/YDoubleC/p/9777411.html

你可能感兴趣的文章
04_web基础(七)之jsp
查看>>
BugTracker.NET安装指南
查看>>
openoj的一个小比赛(J题解题报告)poj1703(并查集)
查看>>
pku 1125 Stockbroker Grapevine 第一周训练——最短路
查看>>
【转】OO无双的blocking/non-blocking执行时刻
查看>>
eclipse,python
查看>>
深入理解java集合框架(jdk1.6源码)
查看>>
php截取后台登陆密码的代码
查看>>
选假球的故事
查看>>
ul li剧中对齐
查看>>
关于 linux 的 limit 的设置
查看>>
模块搜索路径
查看>>
localstorage - HTML 5 Web 存储总结---【巷子】
查看>>
蚂蚁的难题(二)首尾相连数组的最大子数组和(DP)
查看>>
Java内存模型简析
查看>>
线性基学习
查看>>
序列内第k小查询(线段树)
查看>>
Compile Groovy/Spock with GMavenPlus
查看>>
[Cocoa]深入浅出Cocoa系列
查看>>
GNU flex unistd.h在VC下的编译问题
查看>>