朝日

ZhaoriGame

出现’permission denied: 的解决办法

1
libs chmod 777 path

查看端口占用情况命令

1
2
sudo lsof -i tcp:port
//如: sudo lsof -i tcp:8082

看到进程的PID,可以将进程杀死。

1
2
sudo kill -9 PID
//如:sudo kill -9 3210

苹果打包隐藏Home键

1
2
3
4
5
(UIRectEdge)preferredScreenEdgesDeferringSystemGestures
{
return UIRectEdgeAll;
}

实现原理

  • 基于队列实现
  • 根据当前Content视口的大小计算出视口里最多存在的Item
  • 根据位置不断更新当前显示的数据
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 基于UGUI ScrollView组件的高性能列表组件。对性能有高要求的列表组件可以考虑使用该组件
/// </summary>
[RequireComponent(typeof(ScrollRect))]
public class ScrollViewList : MonoBehaviour
{
public enum ELayoutType
{
/// <summary>
/// 垂直列表
/// </summary>
VERTICAL,
/// <summary>
/// 横向列表
/// </summary>
HORIZONTAL,
}

/// <summary>
/// 布局方式
/// </summary>
public ELayoutType layoutType = ELayoutType.VERTICAL;

/// <summary>
/// 列表项的间隔
/// </summary>
public float itemGap = 0;

/// <summary>
/// 滚动组件
/// </summary>
ScrollRect _scrollRect;

/// <summary>
/// 存储位置
/// </summary>
RectTransform _content;

/// <summary>
/// 列表项的Prefab,默认Content第一个物体
/// </summary>
GameObject _itemPrefab;

/// <summary>
/// 列表项的大小
/// </summary>
Vector2 _itemSize;

/// <summary>
/// 生成的列表项示例列表
/// </summary>
List<GameObject> _items = new List<GameObject>();

/// <summary>
/// 列表视口
/// </summary>
Rect _viewport;

/// <summary>
/// 视口可见的最大列表项数量
/// </summary>
int _itemMaxCount;

/// <summary>
/// 列表的数据
/// </summary>
object[] _datas;

/// <summary>
/// 列表项更新的回调
/// </summary>
Action<int, object, GameObject> _onItemUpdate;

/// <summary>
/// 列表项占用的空间
/// </summary>
float _itemSpace = 0;

/// <summary>
/// Item 的缓存池
/// </summary>
Queue<GameObject> _itemPool = new Queue<GameObject>();

/// <summary>
/// 正在显示的列表项
/// </summary>
Dictionary<int, GameObject> _showedDic = new Dictionary<int, GameObject>();

private void Awake()
{
_scrollRect = GetComponent<ScrollRect>();
_viewport = _scrollRect.GetComponent<RectTransform>().rect;
_content = transform.Find("Viewport/Content").GetComponent<RectTransform>();
_itemPrefab = _content.GetChild(0).gameObject;
var rt = _itemPrefab.GetComponent<RectTransform>();
_itemSize = rt.sizeDelta;
var topLeft = new Vector2(0, 1);
rt.pivot = topLeft;
rt.anchorMin = topLeft;
rt.anchorMax = topLeft;
_itemPrefab.SetActive(false);
SetItemGap(itemGap);
}


#region 测试

//public void Update()
//{
// if (Input.GetKeyDown(KeyCode.A))
// {
// SetItemUpdata(OnItemUpDate);
// SetItemGap(10);
// List<string> ls = new List<string>();
// for (int i = 0; i < 1000000; i++)
// {
// ls.Add("current"+i);
// }
// SetData(ls.ToArray());
// }
//}
#endregion

/// <summary>
/// 设置列表项间隙
/// </summary>
/// <param name="gap"></param>
public void SetItemGap(float gap)
{
itemGap = gap;
SetData(_datas);
}



private void OnEnable()
{
_scrollRect.onValueChanged.AddListener(OnScroll);
}

public void SetData(object[] data)
{
Clear();

switch (layoutType)
{
case ELayoutType.VERTICAL:
_itemSpace = _itemSize.y + itemGap;
_itemMaxCount = Mathf.CeilToInt(_viewport.height / _itemSpace) + 1;
break;
case ELayoutType.HORIZONTAL:
_itemSpace = _itemSize.x + itemGap;
_itemMaxCount = Mathf.CeilToInt(_viewport.width / _itemSpace) + 1;
break;
}

_datas = data;
if (data != null)
{
_refreRate = 0.1f / data.Length;
}
Debug.LogError(_refreRate);

if (null == _datas || _datas.Length == 0)
{
return;
}
int count = _datas.Length;
SetContentSize((_itemSpace * count) - itemGap);
RefreshUI();
}

/// <summary>
/// 显示指定索引位置的列表项
/// </summary>
/// <param name="idx"></param>
public void ShowItem(int idx)
{
if(null == _datas)
{
return;
}
var pos = _itemSpace * idx;
SetContentPos(pos);
}

void SetContentSize(float size)
{
var contentSize = _content.sizeDelta;

switch (layoutType)
{
case ELayoutType.VERTICAL:
contentSize.y = size;
break;
case ELayoutType.HORIZONTAL:
contentSize.x = size;
break;
}

_content.sizeDelta = contentSize;
}

void SetContentPos(float pos)
{
var contentPos = _content.localPosition;

switch (layoutType)
{
case ELayoutType.VERTICAL:
contentPos.y = pos;
break;
case ELayoutType.HORIZONTAL:
contentPos.x = -1 * pos;
break;
}

_content.localPosition = contentPos;
}

public void Clear()
{
for(int i = 0; i < _items.Count; i++)
{
GameObject.Destroy(_items[i]);
}
_showedDic.Clear();
_items.Clear();
_itemPool.Clear();
_datas = null;
_scrollRect.velocity = Vector2.one;

SetContentPos(0);

switch (layoutType)
{
case ELayoutType.VERTICAL:
SetContentSize(_viewport.height);
break;
case ELayoutType.HORIZONTAL:
SetContentSize(_viewport.width);
break;
}
}

private void OnDisable()
{
_scrollRect.onValueChanged.RemoveListener(OnScroll);
}

/// <summary>
/// 当前位置
/// </summary>
private Vector2 _currentPos;

private float _refreRate;

private void OnScroll(Vector2 v)
{
if (CompareVector2(v, _currentPos ,_refreRate))
{
return;
}

_currentPos = v;
RefreshUI();
}

private bool CompareVector2(Vector2 v1,Vector2 v2,float dis)
{
return Mathf.Abs(v1.x - v2.x) < dis && Mathf.Abs(v1.y - v2.y) < dis;
}


HashSet<int> updateNeedlessSet = new HashSet<int>();
Dictionary<int, GameObject> showedDic = new Dictionary<int, GameObject>();

/// <summary>
/// 刷新界面
/// </summary>
private void RefreshUI()
{
if( _datas == null)
{
return;
}

float localPos;
if(layoutType == ELayoutType.VERTICAL)
{
localPos = _content.localPosition.y;
}
else
{
localPos = -1 * _content.localPosition.x ;
}

//显示开始的索引
int startIdx = Mathf.FloorToInt(localPos / _itemSpace);
if(startIdx < 0)
{
startIdx = 0;
}

//Item 显示开始的位置
Vector2 pos = new Vector2(0f, startIdx * _itemSpace);

int endIdx = startIdx + _itemMaxCount;
if (endIdx > _datas.Length)
{
endIdx = _datas.Length;
}

HashSet<int> updateNeedlessSet = new HashSet<int>();
Dictionary<int, GameObject> showedDic = new Dictionary<int, GameObject>();

//找出可以不用更新的Item
foreach (var entry in _showedDic)
{
if(entry.Key >= startIdx && entry.Key < endIdx)
{
//不用更新的
updateNeedlessSet.Add(entry.Key);
showedDic.Add(entry.Key, entry.Value);
}
else
{
//加入缓存池
_itemPool.Enqueue(entry.Value);
}
}

_showedDic = showedDic;

for (int i = startIdx; i < endIdx; i++)
{
if(updateNeedlessSet.Contains(i))
{
//已经显示的可以忽略不处理
continue;
}

if(layoutType == ELayoutType.VERTICAL)
{
pos.x = 0f;
pos.y = -1 * i * _itemSpace;
}
else
{
pos.x = i * _itemSpace;
pos.y = 0f;
}

CreateItem(i, pos, _datas[i], _itemPool);
}
}

private void OnItemUpDate(int num, object data, GameObject item)
{
item.transform.Find("Text").GetComponent<Text>().text = (string)data;
}

public void SetItemUpdata(Action<int ,object,GameObject> ItemUpdata)
{
_onItemUpdate = ItemUpdata;
}




public GameObject CreateItem(int idx, Vector2 pos, object data, Queue<GameObject> itemPool)
{
GameObject go = null;
if(itemPool.Count > 0)
{
go = itemPool.Dequeue();
}
else
{
go = GameObject.Instantiate(_itemPrefab, _content);
go.name = "item" + idx;
_items.Add(go);
}

_showedDic.Add(idx, go);
go.transform.localPosition = pos;
go.SetActive(true);
_onItemUpdate?.Invoke(idx, data, go);
return go;
}
}

Cg 标准函数库

– 来自《 GPU编程与CG语言GPU-Programming-AndCgLanguage-Primer》

  1. 数学函数(Mathematical Functions);

  2. 几何函数(Geometric Functions);

  3. 纹理映射函数(Texture Map Functions);

  4. 偏导数函数(Derivative Functions);

  5. 调试函数(Debugging Function);

数学函数(Mathematical Functions)

列举了 Cg 标准函数库中所有的数学函数,这些数学函数用于执行数学上常用计算,包括:三角函数、幂函数、园函数、向量和矩阵的操作函数。这些函数都被重载,以支持标量数据和不同长度的向量作为输入参数。

函数 功能
abs(x) 返回输入参数的绝对值
acos(x) 反余切函数,输入参数范围为[-1,1], 返回[0,p ]区间的角度值
all(x) 如果输入参数均不为 0,则返回 ture;否则返回 flase。&&运算
any(x) 输入参数只要有其中一个不为 0,则返回true。||运算
asin(x) 反正弦函数,输入参数取值区间为[-1,1] ,返回角度值范围为⎡⎢- p , p ⎤⎥⎣ 2 2 ⎦
atan(x) 反正切函数,返回角度值范围为⎡- p , p ⎤⎢⎣ 2 2 ⎥⎦
atan2(y,x) 计算 y/x 的反正切值。实际上和 atan(x)函数功能完全一样,至少输入参数不同。atan(x) =atan2(x, float(1))。
ceil(x) 对输入参数向上取整。例如:ceil(float(1.3)) ,其返回值为 2.0
clamp(x,a,b) 如果 x 值小于 a,则返回 a;如果 x 值大于 b,返回 b;否则,返回 x。
cos(x) 返回弧度 x 的余弦值。返回值范围为[-1,1]
cosh(x) 双曲余弦(hyperbolic cosine)函数,计算 x的双曲余弦值。
cross(A,B) 返回两个三元向量的叉积(cross product)。注意,输入参数必须是三元向量!
degrees(x) 输入参数为弧度值(radians),函数将其转换为角度值(degrees)
determinant(m) 计算矩阵的行列式因子。
dot(A,B) 返回A 和 B 的点积(dot product)。参数 A 和 B可以是标量,也可以是向量(输入参数方面, 点积和叉积函数有很大不同)。
exp(x) 计算e**x 的值,e= 2.71828182845904523536
exp2(x) 计算2x 的值
floor(x) 对输入参数向下取整。例如 floor(float(1.3))返回的值为 1.0;但是 floor(float(-1.3))返回的值为-2.0。该函数与 ceil(x)函数相对应。
fmod(x,y) 返回 x/y 的余数。如果 y 为 0,结果不可预料。
frac(x) Returns the fractional portion of a scalar oreach vector component
frexp(x, out exp) 将浮点数 x 分解为尾数和指数,即x = m* 2^exp,返回 m,并将指数存入 exp 中; 如果 x 为 0,则尾数和指数都返回 0
isfinite(x) 判断标量或者向量中的每个数据是否是有限数,如果是返回 true;否则返回 false;无限的或者非数据(not-a-number NaN),
isinf(x) 判断标量或者向量中的每个数据是否是无限,如果是返回 true;否则返回 false;
isnan(x) 判断标量或者向量中的每个数据是否是非数据(not-a-number NaN),如果是返回 true;否则返回 false;
ldexp(x, n) 计算 x * 2n 的值
lerp(a, b, f) 计算(1- f )* a + b * f 或者a + f *(b - a) 的值。即在下限 a 和上限 b 之间进行插值,f 表示权值。注意,如果 a 和 b 是向量,则权值 f 必须是标量或者等长的向量。
lit(NdotL, NdotH, m) N 表示法向量;L 表示入射光向量;H 表示半角向量;m 表示高光系数。函数计算环境光、散射光、镜面光的贡献, 返回的 4 元向量:X 位表示环境光的贡献,总是 1.0;Y 位代表散射光的贡献,如果 N · L < 0 ,则为 0;否则为 N · LZ 位代表镜面光的贡献,如果 N · L < 0 或者N · H < 0 ,则位 0;否则为(N · H )m ;W 位始终位 1.0
log(x) 计算ln ( x) 的值,x 必须大于 0
log2(x) 计算log(x) 的值,x 必须大于 02
log10(x) 计算log(x) 的值,x 必须大于 010
max(a, b) 比较两个标量或等长向量元素,返回最大值。
min(a,b) 比较两个标量或等长向量元素,返回最小值。
modf(x, out ip) 在 Cg Reference Manual 中没有查到
mul(M, N) 计算两个矩阵相乘,如果 M 为 AxB 阶矩阵,N 为 BxC 阶矩阵,则返回 AxC 阶矩阵。下面两个函数为其重载函数。
mul(M, v) 计算矩阵和向量相乘
mul(v, M) 计算向量和矩阵相乘
noise( x) 噪声函数,返回值始终在 0,1 之间;对于同样的输入,始终返回相同的值(也就是说, 并不是真正意义上的随机噪声)。
pow(x, y) x y
radians(x) 函数将角度值转换为弧度值
round(x) Round-to-nearest,或 closest integer to x 即四舍五入。
rsqrt(x) X 的反平方根,x 必须大于 0
saturate(x) 如果 x 小于 0,返回 0;如果 x 大于 1,返回1;否则,返回 x
sign(x) 如果 x 大于 0,返回 1;如果 x 小于 0,返回01;否则返回 0。
sin(x) 输入参数为弧度,计算正弦值,返回值范围为[-1,1]
sincos(float x, out s, out c) 该函数是同时计算 x 的 sin 值和 cos 值,其中s=sin(x),c=cos(x)。该函数用于“同时需要计算 sin 值和 cos 值的情况”,比分别运算要快很多!
sinh(x) 计算双曲正弦(hyperbolic sine)值。
smoothstep(min, max, x) 值 x 位于 min、max 区间中。如果 x=min,返回 0;如果 x=max,返回 1;如果 x 在两者之间,按照下列公式返回数据:-2*( x - min )3 + 3*( x - min )2max- min max- min
step(a, x) 如果 x<a,返回 0;否则,返回 1。
sqrt(x) 求 x 的平方根, x ,x 必须大于 0。
tan(x) 输入参数为弧度,计算正切值
tanh(x) 计算双曲正切值
transpose(M) M 为矩阵,计算其转置矩阵

表 4 Cg 标准函数库中的数学函数

几何函数(Geometric Functions)

几何函数,如表 5 所示,用于执行和解析几何相关的计算,例如根据入射光向量和顶点法向量,求取反射光和折射光方向向量。Cg 语言标准函数库中有3 个几何函数会经常被使用到,分别是:normalize 函数,对向量进行归一化;reflect函数,计算反射光方向向量;refract 函数,计算折射光方向向量。大声呐喊,并要求强烈注意:

  1. 着色程序中的向量最好进行归一化之后再使用,否则会出现难以预料的错误;

  2. reflect 函数和 refract 函数都存在以“入射光方向向量”作为输入参数, 注意这两个函数中使用的入射光方向向量,是从外指向几何顶点的;平时我们在着色程序中或者在课本上都是将入射光方向向量作为从顶点出发。

函数 功能
distance( pt1, pt2) 两点之间的欧几里德距离(Euclideandistance)
faceforward(N,I,Ng) 如果 Ng · I < 0 ,返回 N;否则返回-N。
length(v) 返回一个向量的模,即 sqrt(dot(v,v))
normalize( v) 归一化向量
reflect(I, N) 根据入射光方向向量 I,和顶点法向量N,计算反射光方向向量。其中 I 和 N 必须被归一化,需要非常注意的是,这个 I 是指向顶点的;函数只对三元向量有效。
refract(I,N,eta) 计算折射向量,I 为入射光线,N 为法向量,eta 为折射系数;其中 I 和 N 必须被归一化,如果 I 和 N 之间的夹角太大,则返回(0,0,0),也就是没有折射光线;I 是指向顶点的;函数只对三元向量有效。

表 5 Cg 标准函数库几何函数

纹理映射函数(Texture Map Functions)

下表提供 Cg 标准函数库中的纹理映射函数。这些函数被 ps_2_0、ps_2_x、arbfp1、fp30 和 fp40 等 profiles 完全支持(fully supported)。所有的这些函数返回四元向量值。

函数
tex1D(sampler1D tex, float s)一维纹理查询
tex1D(sampler1D tex, float s, float dsdx, float dsdy)使用导数值(derivatives)查询一维纹理
Tex1D(sampler1D tex, float2 sz)一维纹理查询,并进行深度值比较
Tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy)使用导数值(derivatives)查询一维纹理, 并进行深度值比较
Tex1Dproj(sampler1D tex, float2 sq)一维投影纹理查询
Tex1Dproj(sampler1D tex, float3 szq)一维投影纹理查询,并比较深度值
Tex2D(sampler2D tex, float2 s)二维纹理查询
Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy)使用导数值(derivatives)查询二维纹理
Tex2D(sampler2D tex, float3 sz)二维纹理查询,并进行深度值比较
Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy)使用导数值(derivatives)查询二维纹理,并进行深度值比较
Tex2Dproj(sampler2D tex, float3 sq)二维投影纹理查询
Tex2Dproj(sampler2D tex, float4 szq)二维投影纹理查询,并进行深度值比较
texRECT(samplerRECT tex, float2 s)
texRECT (samplerRECT tex, float2 s, float2 dsdx, float2 dsdy)
texRECT (samplerRECT tex, float3 sz)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy)
texRECT proj(samplerRECT tex, float3 sq) texRECT proj(samplerRECT tex, float3 szq)
Tex3D(sampler3D tex, float s) 三维纹理查询
Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询三维纹理
Tex3Dproj(sampler3D tex, float4 szq) 查询三维投影纹理,并进行深度值比较
texCUBE(samplerCUBE tex, float3 s) 查询立方体纹理
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询立方体纹理
texCUBEproj (samplerCUBE tex, float4 sq) 查询投影立方体纹理

​ 标准函数库纹理映射函数

偏导函数(Derivative Functions)

函数 功能
ddx(a) 参数 a 对应一个像素位置,返回该像素 值在 X 轴上的偏导数
ddy(a) 参数 a 对应一个像素位置,返回该像素 值在 X 轴上的偏导数 表 7 Cg 标准函数库偏导函数

调试函数(Debugging Function)

函数 功能
void debug(float4 x) 如果在编译时设置了 DEBUG,片段着 色程序中调用该函数可以将值 x 作为 COLOR 语义的终输出;否则该函数 什么也不做。

1
2
3
//只允许一个同样的Component
[DisallowMultipleComponent]
public class Sample:MonoBehaviour{}
1
2
[Header("头标题")]
[RequireComponent(Type of("必须加上的组件"))]
0%