-
通过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事件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49using 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<UIEventListener>(); if (listener == null) listener = go.AddComponent<UIEventListener>(); 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); } }
然后新建一个MoveTest代码,挂在Canvas上


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179using 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<RectTransform>().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<RectTransform>(), 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<RectTransform>(), 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<RectTransform>().rect.width / 2 * fScale)) { fOffsetX = LimitRight - (objImg.transform.localPosition.x + objImg.GetComponent<RectTransform>().rect.width / 2 * fScale); } else if (objImg.transform.localPosition.x > (LimitLeft + objImg.GetComponent<RectTransform>().rect.width / 2 * fScale)) { fOffsetX = LimitLeft - (objImg.transform.localPosition.x - objImg.GetComponent<RectTransform>().rect.width / 2 * fScale); } else { fOffsetX = 0; } } { if (objImg.transform.localPosition.y > (LimitBottom + objImg.GetComponent<RectTransform>().rect.height / 2 * fScale)) { fOffsetY = LimitBottom - (objImg.transform.localPosition.y - objImg.GetComponent<RectTransform>().rect.height / 2 * fScale); } else if (objImg.transform.localPosition.y < (LimitTop - objImg.GetComponent<RectTransform>().rect.height / 2 * fScale)) { fOffsetY = LimitTop - (objImg.transform.localPosition.y + objImg.GetComponent<RectTransform>().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); } }
-
通过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的移动距离并赋值了。
直接上修改后的代码。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199using 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<RectTransform>().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<RectTransform>(), 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<RectTransform>(), 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<RectTransform>().rect.width / 2 * fScale)) { fOffsetX = LimitRight - (objImg.transform.localPosition.x + objImg.GetComponent<RectTransform>().rect.width / 2 * fScale); } else if (objImg.transform.localPosition.x > (LimitLeft + objImg.GetComponent<RectTransform>().rect.width / 2 * fScale)) { fOffsetX = LimitLeft - (objImg.transform.localPosition.x - objImg.GetComponent<RectTransform>().rect.width / 2 * fScale); } else { fOffsetX = 0; } } { if (objImg.transform.localPosition.y > (LimitBottom + objImg.GetComponent<RectTransform>().rect.height / 2 * fScale)) { fOffsetY = LimitBottom - (objImg.transform.localPosition.y - objImg.GetComponent<RectTransform>().rect.height / 2 * fScale); } else if (objImg.transform.localPosition.y < (LimitTop - objImg.GetComponent<RectTransform>().rect.height / 2 * fScale)) { fOffsetY = LimitTop - (objImg.transform.localPosition.y + objImg.GetComponent<RectTransform>().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); } }
这时候会发现一个问题,就是Cube不会被Mask遮挡住,因为Mask遮罩遮不住模型,其实只要在Mask周围添加上UI图片,挡住Cube就行了。
转载于:https://www.cnblogs.com/YDoubleC/p/9777411.html
最后
以上就是开放刺猬最近收集整理的关于在UGUI上显示3D模型,并限制范围的拖拽的全部内容,更多相关在UGUI上显示3D模型,并限制范围内容请搜索靠谱客的其他文章。
发表评论 取消回复