Category - Unity3d

2024-07-31 16:14:15    86    0    0

Unity在很多需求下,不得不进行颜色的像素级填充,
诸如:实时贴花功能,绘图功能开发,乃至非Native的情况下视频播放(比如视频是CPU计算出来的,而不是文件流或直播流,提交颜色),各种游戏模拟器,等画面显示;

亦或者,必须要通过CPU逻辑运算,得到一个图形,并展示到UI中,或某个贴图上时,

采用类似Rendertexture的方式,都就需要处理Textture2d的填充。
尤其在高频填充的情况下(指60帧或者更高刷新率绘制),我们就需要考虑效率了。

以下是我做Unity下街机模拟器画面显示开发的心得
title
* 最终我还要上PSVita,使用unity(113M的极限内存可用,还要预留性能给我的网络联机网络库,害只能用77M的模式,主频非超频也只有333Mhz,所以能省则省了)

省流版,总结,几种:
Plan1. 使用SetPixelData< T > (T[] data, int mipLevel, int sourceDataStartIndex = 0)
Plan2. GetNativeTexturePtr纹理指针,对底层指针,进行绘制。如果你对DX11/DX9的绘制指针比较了解 ,可以使用Texture2d的GetNativeTexturePtr 获取指针,在C++扩展下进行操作。(跨平台不友好)
Plan3. 低版本Unity使用 LoadRawTextureData< T >(NativeArray data),LoadRawTextureData(byte[] data)
Plan4. 低版本Unity使用 LoadRawTextureData 的指针用法 (推荐) LoadRawTextureData(IntPtr data, int size)
Plan5. 交给shader

好好好,咱们从低到高,说说各种用法的演进

全局参数

  1. //这里是一个代码构建的Texture2D用于填充数据和提交
  2. private Texture2D m_rawBufferWarper;
  3. //这里是UI上一个RawImage组件作为显示
  4. private RawImage m_drawCanvas;
2024-03-12 17:39:56    53    0    0
  1. public enum AnchorPresets
  2. {
  3. TopLeft,
  4. TopCenter,
  5. TopRight,
  6. MiddleLeft,
  7. MiddleCenter,
  8. MiddleRight,
  9. BottomLeft,
  10. BottonCenter,
  11. BottomRight,
  12. BottomStretch,
  13. VertStretchLeft,
  14. VertStretchRight,
  15. VertStretchCenter,
  16. HorStretchTop,
  17. HorStretchMiddle,
  18. HorStretchBottom,
  19. StretchAll
  20. }
  21. /// <summary>
  22. /// 安全的设置锚点,并保证位置不变
  23. /// </summary>
  24. /// <param name="source"></param>
  25. /// <param name="allign"></param>
  26. public static void SetAnchor(this RectTransform source, AnchorPresets allign)
  27. {
  28. //计算原锚点中心和组件大小
  29. Vector2 oldAnchorCenter = (source.anchorMin + source.anchorMax) / 2;
  30. Vector2 oldAnchoredPos = source.anchoredPosition;
  31. Vector2 objSize = new Vector2(source.rect.width, source.rect.height);
  32. switch (allign)
  33. {
  34. case (AnchorPresets.TopLeft):
  35. {
  36. source.anchorMin = new Vector2(0, 1);
2022-10-14 17:52:46    192    0    0
  1. public class ctrl : MonoBehaviour
  2. {
  3. [SerializeField]
  4. PostProcessVolume m_postpVol;
  5. [SerializeField]
  6. Camera m_Cam;
  7. DepthOfField m_Df;
  8. void Awake()
  9. {
  10. m_postpVol.profile.TryGetSettings(out m_Df);
  11. }
  12. //焦距设置为摄像机和玩家的位置
  13. void Update()
  14. {
  15. m_Df.focusDistance.value = Vector3.Distance(Player.position, m_Cam.transform.position);
  16. }
  17. }
2022-05-26 10:36:31    457    0    0

将unity缓存三个文件夹

C:\Users\你用户名\AppData\Local\Unity
C:\Users\你用户名\AppData\LocalLow\Unity
C:\Users\你用户名\AppData\Roaming\Unity

分别拷贝到 别的盘符,如

F:\UnityCache\LocalUnity
F:\UnityCache\LocalLowUnity
F:\UnityCache\RoaMingUnity

 

删除源文件夹,添加软链接

mklink /j C:\Users\你用户名\AppData\Local\Unity F:\UnityCache\LocalUnity
mklink /j C:\Users\你用户名\AppData\LocalLow\Unity F:\UnityCache\LocalLowUnity
mklink /j C:\Users\你用户名\AppData\Roaming\Unity F:\UnityCache\RoaMingUnity

 

管理员身份运行CMD,并执行, 结果:

Microsoft Windows [版本 10.0.19044.1706]
(c) Microsoft Corporation。保留所有权利。

C:\Users\Admin>mklink /j C:\Users\Admin\AppData\Local\Unity F:\UnityCache\LocalUnity
为 C:\Users\Admin\AppData\Local\Unity <<===>> F:\UnityCache\LocalUnity 创建的联接

C:\Users\Admin>mklink /j C:\Users\Admin\AppData\LocalLow\Unity F:\UnityCache\LocalLowUnity
为 C:\Users\Admin\AppData\LocalLow\Unity <<===>> F:\UnityCache\LocalLowUnity 创建的联接

C:\Users\Admin>mklink /j C:\Users\Admin\AppData\Roaming\Unity F:\UnityCache\RoaMingUnity
为 C:\Users\Admin\AppData\Roaming\Unity <<===>> F:\UnityCac

2022-05-19 11:32:19    1024    0    0

我写一个简单明了的范例
比如我们要同步一个V3类型的数据,
数据来源:客户端操作
目标:同步所有客户端的 Vector3 V3FromNetwork 变量值

流程为

本地客户端客户端(isLocalPlayer为true)进行操作
↓↓↓
调用[Command]修饰的方法SetTestV3,(SetTestV3就具备了往服务器上报的特性)
↓↓↓
服务器执行SetTestV3函数内容
↓↓↓
服务器修改TestV3值时,由于具备标识[SyncVar(hook = nameof(ChangeTestV3))],通知所有客户端的该对象脚本中调用ChangeTestV3
↓↓↓
客户端调用ChangeTestV3,最终成功修改到值。

代码如下

  1. using UnityEngine;
  2. using Mirror;
  3. public class Player : NetworkBehaviour
  4. {
  5. void Update()
  6. {
  7. if (!isLocalPlayer) return;//只操作本地客户端
  8. Vector3 V3SendData = new Vector3(Input.GetAxis("Vertical") * Time.deltaTime, 0, Input.GetAxis("Horizontal") * Time.deltaTime);
  9. SetTestV3(V3SendData);
  10. }
  11. [Command]//客户端上行标识
  12. public void SetTestV3(Vector3 v)
  13. {
  14. //服务端执行内容
  15. TestV3 = v;
  16. }
  17. [SyncVar(hook = nameof(ChangeTestV3))]//服务端修改触发客户端调用hook函数
  18. public Vector3 TestV3 = Vector3.zero;
  19. public void ChangeTestV3(Vector3 oldv, Vector3 newc)
  20. {
  21. //客户端执行内容
2022-05-17 17:13:05    1571    0    0

标签: Command 从客户端发送到服务器,服务器执行

  1. [Command]
  2. void ABC(){}

注意点
1,方法可以带参数,但需要序列化
2,客户端只能发送属于自己的对象的方法
如果都允许,则设置为不验证:

  1. [Command(requiresAuthority = false)]

标签: ClientRpc 从服务器发送到,客户端执行

  1. [ClientRpc]
  2. void ABC(){}

标签: TargetRpc 从服务器发送到,指定的客户端执行

  1. [TargetRpc]
  2. void TargetRemoteDamaged(NetworkConnection target, int damage){}

PS:第一个参数可忽略,默认发给自己,也就是调用此方法的客户端实体
PS:如果第一个参数有,则发给指定,目标

总结

[Command] 由客户端调用,内容服务器执行;
[ClientRpc]和[TargetRpc]由服务器调用,内容客户端执行;
但[TargetRpc]是指定目标发送,[ClientRpc]是都发送。

2022-05-17 16:05:14    805    0    0

一,用SyncVar进行同步

函数标签[SyncVar]
用标签来标记变量,被改变时时,同步给其他客户端;
可指定Hook指定回调函数,并返回旧值和新值

如:

  1. [SyncVar(hook = nameof(ChangeColor))]
  2. Color pcolor = Color.white;
  3. void ChangeColor(Color oldc, Color newc)
  4. {
  5. }

即pcolor发生变化时,客户端都调用ChangeColor

PS:使用此特性标注的变量,只应该在服务器上对此变量进行更改,而通过hook在客户端作用此更改
然后hook,仅会再客户端调用,如果服务器是OnlyServer模式则不会调用

使用脚本让服务器控制所有客户端颜色变化的代码

  1. using UnityEngine;
  2. using Mirror;
  3. public class PlayerController : NetworkBehaviour
  4. {
  5. [SyncVar(hook = nameof(ChangeColor))]
  6. Color pcolor = Color.white;
  7. Rigidbody rb;
  8. MaterialPropertyBlock prop;
  9. /// <summary>
  10. /// 客户端收到同步时调用
  11. /// </summary>
  12. /// <param name="oldc"></param>
  13. /// <param name="newc"></param>
  14. void ChangeColor(Color oldc, Color newc)
  15. {
  16. Debug.Log("更新为新颜色");
  17. prop.SetColor("_Color", newc);
  18. GetComponent<Renderer>().SetPropertyBlock(prop);
  19. }
  20. private void Awake()
  21. {
  22. rb = GetComponent<Rigidbody>();
  23. prop = new MaterialPropert
2022-05-17 14:39:49    161    0    0

个人理解的两种方式

方式一 房间模式:(自带一个需要准备等待功能的模式)

创建场景

Offline,Room,GamePlay
作用:区分Online和非Online模式

准备脚本

通过create->mirror 创建如下脚本

[NetworkRoomManager]
作用:房间管理,有房间创建,连接,等房间相关的回调
基于房间补充相关逻辑

[NetworkRoomPlayer]
作用:包含房间里的玩家状态和回调

[NetworkBehaviour]

创建多个NetworkBehaviour :
如,NetworkBehaviour 改为 myPlayer
NetworkBehaviour 改为 myItem
作用: 有了本脚本,才会标记告知服务器需要同步本对象
继承了MonoBehaviour的Network脚本,
可以衔接Update等函数书写自己的逻辑,
取到玩家网络状态,如

  1. isServer
  2. 如果是此对象是在服务器上运行的(包括服务器+客户端一体的主机),则返回true
  3. isServerOnly
  4. 如果是此对象仅在服务器运行的(而非包含客户端的主机),则返回true
  5. isClient
  6. 如果此对象已经存在,且处于客户端上(包括主机的客户端),则返回true
  7. 等等

准备预制体

创建空物体,命名为RoomPlayer,挂MyNetworkRoomPlayer
创建胶囊,命名为Player,挂MyPlayer
创建Cube, 命名为Item 挂myItem

客户端操作权限:
Player预制体上的挂NetworkTransform脚本的ClientAuthority 一定要勾选上,否则没有客户端操作其状态的权限。

在玩家或者我物体预制体上挂载,NetworkIdentity 脚本
(往往挂载其他Mirror脚本时,NetworkIdentity脚本会自动挂载)

创建管理组件

1.在Offline场景空物体,挂MyNetworkRoomManager脚本
挂载好在线和离线对应的场景,Player预制体,以及房间相关的预制体和场景
title

2.同时

2021-04-10 15:31:04    118    1    0

比起 Unity集成的Navigation中的OffMeshLink,扩展的NavMeshComponents中NavMeshLink,会强大好用许多,

2021-04-10 14:49:37    375    1    0

·比起 Unity集成的Navigation ,扩展的NavMeshComponents,扩展了不少方便的功能

比如同一个场景,更方便的创建不同的烘培网格

拷贝Github克隆的Asset中NavMeshComponents目录到你的项目Asset
title

title

创建一个场景,
然后在场景根节点下 挂载脚本提供的NavMeshSurface.cs

title

而且可以挂载多个

打开Agent 设置
title

设置不同体型的宽高配置
title

title

然后回到地形对象的Inspector面板,选择不同的配置
title
分别点击Bake,进行烘培得到两个不同的结果
title

此外还可以选择渲染的layer层级,
title
或者你也可以选择渲染范围:
title

然后就是移动了
创建两个玩家胶囊提
分别创建寻路导航代理组件
title

挂载移动脚本到两个player胶囊提上

  1. public class Player : MonoBehaviour
  2. {
  3. // Start is called before the first frame update
  4. void Start()
  5. {
  6. agent = GetComponent<NavMeshAgent>();
  7. }
  8. private NavMeshAgent agent;
  9. // Update is called once per frame
  10. void Update()
  11. {
  12. if (Input.GetMouseButtonDown(0))
  13. {
  14. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  15. RaycastHit hit;
  16. if (Physics.Raycast(ray, out hit))
  17. {
  18. agent.SetDestination(hit.point);
  19. }
  20. }
  21. }
  22. }

鼠标控制移动,两个角色则会走对应体型配置的烘培寻路

1/2