unity5是不是支持unity 多线程渲染访问游戏对象了

扫一扫,访问微社区
后使用快捷导航没有帐号?
签到成功!您今天第{todayrank}个签到,签到排名竞争激烈,记得每天都来签到哦!已连续签到:{constant}天,累计签到:{days}天
当前位置: &
查看: 2774|回复: 5
了解Unity中的多线程及使用多线程
本帖为抢楼帖,欢迎抢楼!&
89859/10000排名<font color="#FF昨日变化1主题帖子积分
常驻蛮牛, 积分 9859, 距离下一级还需 141 积分
常驻蛮牛, 积分 9859, 距离下一级还需 141 积分
蛮牛币182904
在线时间432 小时
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
才可以下载或查看,没有帐号?
  如果你想在游戏中使用多线程,你应该看看这篇文章,线程是一个相当复杂的,但如果你掌握了它,你就可以从容的使用多个硬件处理器或处理很难划分管理数据块.
  如在场景中用A*算法进行大量的数据计算.
  变形网格中操作大量的顶点.
  持续的要运行上传数据到服务器.
  二维码识别等图像处理.
  如果同时你要处理很多事情或者与Unity的对象互动小可以用thread,否则使用coroutine.
  线程是在你程序中与其他线程同时运行的进行.在多处理器的计算机上可以做到多个线程的真正的同步.更多的线程取决于有多个处理核心.
  Unity编程时,总有个主线程执行你的代码,也可以创建额外的线程和主线程同时运行.
QQ截图03.png (66.05 KB, 下载次数: 1)
14:06 上传
  而Unity中,你仅能从主线程中访问Unity的组件,对象和Unity系统调用.任何企图访问这些项目的第二个线程都将失败并引发错误.这是一个要重视的一个限制.
  所以当你写代码时,你认为一个函数开始并达到它执行的点后返回,同样你做的东西又在另外一个函数中执行,但又没有发生相应的变化.操作系统决定你代码的执行,任何时候,你的代码只能暂时“休眠”掉,然后让另外的代码开始运行,
  在这个例子中,在第一个线程将A的值加载到CPU寄存器中准备+1后被中断,第二个线程来读取A的值,并减去1000,这时A应该是-950.现在第一个线程重新开始,它在寄存器中的50+1的结果存储于A,A变成了51,而-950已经丢掉了.
  从根本上说,要在用多个线程在同时对变量或内存访问时,要采取很多预防措施来确保不会发生这样的事.
  所以Unity决定从另外线程访问这些变量或者内存是无效的,只是为了避免所有系统和框架对象出现.
  所以要确保一次只有一个线程来修改变量,这不意味着你不能用多线程工作,你可以用“排序”来解决这个问题.
  C#中有lock这个关键字,以确保只有一个线程可以在特定时间内访问特定的对象.这里说对象是因为无法锁定一个类型值(value type)或原型(primitive).
[AppleScript] 纯文本查看 复制代码  int a = 50;
  object guard = new object();
  void ThreadOneCode()
  //一些代码在这
  lock(guard)
  a = a + 1;
  //其余一些代码在这
  void ThreadTwoCode()
  //一些代码在这
  lock(guard)
  a = a - 1000;
  //其余一些代码在这
  所有都锁定在guard内,保证同一个时间只有一个线程通过guard访问它.你可以使用任何合适的对象.
  现在你可能会有各种各样的问题,比如你要锁定的不止一件事,可能是互相嵌套的.那我们该怎么办呢?
  我们这个类叫Loom,让你可以轻松在另一个线程运行代码,
  这里有两个要注意的功能:
  RunAsync(Action)-在另一个线程上运行的一组代码.
  QueueOnMainThread(Action,[可选]float time)-运行在主线程的语句(可选延迟).
  用Loom.Current访问Loom-创建一个看不见的GameObject用来处理游戏主线程的互动.
  下面这个例子用Loom来更新一个网格所有的顶点乘的结果.
[AppleScript] 纯文本查看 复制代码
  //缩放一个网格在第二个线程
  void ScaleMesh(Mesh mesh, float scale)
  //Get the vertices of a mesh
  var vertices = mesh.
  //运行一个Action在新的线程
  Loom.RunAsync(()=&{
  //遍历所有的顶点
  for(var i = 0; i & vertices.L i++)
  //缩放顶点
  vertices[i] = vertices[i] *
  //在主线程上运行一些代码
  //更新网格
  Loom.QueueOnMainThread(()=&{
  //设置顶点
  mesh.vertices =
  //重新计算边界
  mesh.RecalculateBounds();
  上面这个是个很好的例子,使用lambda函数在第二个线程上做一个没有参数,不需要返回任何内容的操作. closures都是在你自己的类和函数的参数和局部变量的访问.
  你可以用 ()=&{ … } 定义一个lambda函数来在新的线程上运行函数内所有的代码.
  在主线程上我们需要将修改的网格顶点更新,所以我们使用QueueOnMainThread在接下来的时间更新周期运行处理(此帧或下一帧被称为接下来的更新周期). QueueOnMainThread也需要一个Action来将更新的顶点更新到原来的网格.
  如果是UnityScript,你可以这样使用Loom:
[AppleScript] 纯文本查看 复制代码  //缩放一个网格在第二个线程
  function ScaleMesh(mesh : Mesh, scale : float)
  //Get the vertices of a mesh
  var vertices = mesh.
  //运行一个Action在新的线程
  Loom.RunAsync(function() {
  //遍历所有的顶点
  for(var i = 0; i & vertices.L i++)
  //缩放顶点
  vertices[i] = vertices[i] *
  //在主线程上运行一些代码
  //更新网格
  Loom.QueueOnMainThread(function() {
  //设置顶点
  mesh.vertices =
  //重新计算边界
  mesh.RecalculateBounds();
unity多线程有问题;unity 锁定帧数;unity线程;unity 多线程 问题;unity是多线程的吗;unity线程安全;unity 锁定帧率
每日推荐:
我是一朵内心长满小碎花的女汉子!
5679/1000排名<font color="#FF昨日变化2主题帖子积分
熟悉之中, 积分 679, 距离下一级还需 321 积分
熟悉之中, 积分 679, 距离下一级还需 321 积分
在线时间252 小时
不错,谢谢分享& && && && && && && & 。
每日推荐:
4407/500排名<font color="#FF昨日变化3主题帖子积分
四处流浪, 积分 407, 距离下一级还需 93 积分
四处流浪, 积分 407, 距离下一级还需 93 积分
在线时间69 小时
这是极好的文章。。。。。。。。
每日推荐:
3243/300排名<font color="#FF昨日变化3主题帖子积分
偶尔光临, 积分 243, 距离下一级还需 57 积分
偶尔光临, 积分 243, 距离下一级还需 57 积分
在线时间31 小时
太好了, 正是很少了解这方面的东东, 现在学习了
每日推荐:
61172/1500排名<font color="#FF昨日变化3主题帖子积分
蛮牛粉丝, 积分 1172, 距离下一级还需 328 积分
蛮牛粉丝, 积分 1172, 距离下一级还需 328 积分
蛮牛币1413
在线时间358 小时
把源码公布一下,或者loom类公布一下,可以吗
每日推荐:
3205/300排名<font color="#FF昨日变化17主题帖子积分
偶尔光临, 积分 205, 距离下一级还需 95 积分
偶尔光临, 积分 205, 距离下一级还需 95 积分
在线时间5 小时
每日推荐:
社区QQ达人
使用QQ帐号登录论坛的用户
游戏蛮牛QQ群会员
加入游戏蛮牛官方QQ群
在“新人报到 ”版块发过自己的照片4452人阅读
Unity(112)
今天刚刚写完异步Socket客户端的数据收发,在进行测试的时候,Unity报出错误:
CompareBaseObjectsInternal can only be called from the main thread.
详情如下:
ERROR : CompareBaseObjectsInternal can only be called from the main thread. Constructors and field initializers will be executed from the loading thread when loading a scene. Don&#39;t use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
在Unity3d官方论坛有网友请教了这个问题
/questions/704284/comparebaseobjectsinternal-can-only-be-called-from-1.html
答案如下:
Seems like you must be calling Unity specific functions from another thread, compare gameobjects means you are checking if one gameobject equals another, apparently this is not threadsafe, so you would need to make sure your separate thread does NOT interract with Unity functions at all.
翻译过来就是说:
在Unity中需要遵循C#的线程安全,不能在另外的线程对Unity的GameObject进行相等比较操作。
在我的工程中,当Socket BeginConnect的时候就会 调用WindowManager来显示一个等待界面
当Connect Success或者failed的时候,就会关闭。
显示界面是在Unity线程中执行
关闭界面是在Socket的异步回调中执行
从Mono的断点来看这两个不是同一个线程。
因为在Wait.GetSingleton().Close() 中有用到WindowManager.GetSingleton()
public static CCWindowManager GetSingleton()
if(m_sInstance==null)
//Helper.LogError(&CCWindowManager m_sInstance==nul&);
GameObject obj = new GameObject(&CCWindowManager&);
m_sInstance=obj.AddComponent&CCWindowManager&();
return m_sI
所以在判断 m_sInstance == null 的时候出现了错误。
解决方法:
将关闭等待界面的代码移到了Update中。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1068045次
积分:14062
积分:14062
排名:第875名
原创:326篇
转载:108篇
评论:251条
文章:32篇
阅读:104050
(1)(2)(1)(1)(5)(1)(3)(3)(3)(5)(6)(4)(7)(1)(18)(18)(17)(13)(9)(24)(25)(2)(7)(5)(9)(17)(11)(7)(25)(8)(9)(1)(4)(12)(6)(2)(3)(16)(21)(10)(14)(1)(7)(25)(11)(6)(13)(4)(8)(7)(2)4029人阅读
unity3d(154)
如果你想在游戏中使用多线程,你应该看看这篇文章,线程是一个相当复杂的话题,但如果你掌握了它,你就可以从容的使用多个硬件处理器或处理很难划分管理数据块.
如在场景中用A*算法进行大量的数据计算.
变形网&#26684;中操作大量的顶点.
持续的要运行上传数据到服务器.
二维码识别等图像处理.
如果同时你要处理很多事情或者与Unity的对象互动小可以用thread,否则使用coroutine.
线程是在你程序中与其他线程同时运行的进行.在多处理器的计算机上可以做到多个线程的真正的同步.更多的线程取决于有多个处理核心.
Unity编程时,总有个主线程执行你的代码,也可以创建额外的线程和主线程同时运行.
而Unity中,你仅能从主线程中访问Unity的组件,对象和Unity系统调用.任何企图访问这些项目的第二个线程都将失败并引发错误.这是一个要重视的一个限制.
所以当你写代码时,你认为一个函数开始并达到它执行的点后返回,同样你做的东西又在另外一个函数中执行,但又没有发生相应的变化.操作系统决定你代码的执行,任何时候,你的代码只能暂时”休眠”掉,然后让另外的代码开始运行,
在这个例子中,在第一个线程将A的&#20540;加载到CPU寄存器中准备&#43;1后被中断,第二个线程来读取A的&#20540;,并减去1000,这时A应该是-950.现在第一个线程重新开始,它在寄存器中的50&#43;1的结果存储于A,A变成了51,而-950已经丢掉了.
从根本上说,要在用多个线程在同时对变量或内存访问时,要采取很多预防措施来确保不会发生这样的事.
所以Unity决定从另外线程访问这些变量或者内存是无效的,只是为了避免所有系统和框架对象出现问题.
所以要确保一次只有一个线程来修改变量,这不意味着你不能用多线程工作,你可以用”排序”来解决这个问题.
C#中有lock这个关键字,以确保只有一个线程可以在特定时间内访问特定的对象.这里说对象是因为无法锁定一个类型&#20540;(value type)或原型(primitive).
int a = 50;
object guard = new object();
void ThreadOneCode()
//一些代码在这
lock(guard)
a = a &#43; 1;
//其余一些代码在这
void ThreadTwoCode()
//一些代码在这
lock(guard)
a = a - 1000;
//其余一些代码在这
所有都锁定在guard内,保证同一个时间只有一个线程通过guard访问它.你可以使用任何合适的对象.
现在你可能会有各种各样的问题,比如你要锁定的不止一件事,可能是互相嵌套的.那我们该怎么办呢?
我们这个类叫Loom,让你可以轻松在另一个线程运行代码,
这里有两个要注意的功能:
RunAsync(Action)-在另一个线程上运行的一组代码.
QueueOnMainThread(Action,[可选]float time)-运行在主线程的语句(可选延迟).
用Loom.Current访问Loom-创建一个看不见的GameObject用来处理游戏主线程的互动.
下面这个例子用Loom来更新一个网&#26684;所有的顶点乘的结果.
//缩放一个网&#26684;在第二个线程
void ScaleMesh(Mesh mesh, float scale)
//Get the vertices of a mesh
var vertices = mesh.
//运行一个Action在新的线程
Loom.RunAsync(()=&{
//遍历所有的顶点
for(var i = 0; i & vertices.L i&#43;&#43;)
//缩放顶点
vertices[i] = vertices[i] *
//在主线程上运行一些代码
//更新网&#26684;
Loom.QueueOnMainThread(()=&{
//设置顶点
mesh.vertices =
//重新计算边界
mesh.RecalculateBounds();
上面这个是个很好的例子,使用lambda函数在第二个线程上做一个没有参数,不需要返回任何内容的操作. closures都是在你自己的类和函数的参数和局部变量的访问.
你可以用 ()=&{ … } 定义一个lambda函数来在新的线程上运行函数内所有的代码.
在主线程上我们需要将修改的网&#26684;顶点更新,所以我们使用QueueOnMainThread在接下来的时间更新周期运行处理(此帧或下一帧被称为接下来的更新周期). QueueOnMainThread也需要一个Action来将更新的顶点更新到原来的网&#26684;.
如果是UnityScript,你可以这样使用Loom:
//缩放一个网&#26684;在第二个线程
function ScaleMesh(mesh : Mesh, scale : float)
//Get the vertices of a mesh
var vertices = mesh.
//运行一个Action在新的线程
Loom.RunAsync(function() {
//遍历所有的顶点
for(var i = 0; i & vertices.L i&#43;&#43;)
//缩放顶点
vertices[i] = vertices[i] *
//在主线程上运行一些代码
//更新网&#26684;
Loom.QueueOnMainThread(function() {
//设置顶点
mesh.vertices =
//重新计算边界
mesh.RecalculateBounds();
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:335389次
积分:3978
积分:3978
排名:第7879名
转载:311篇
评论:38条
(3)(1)(1)(2)(6)(2)(2)(10)(13)(1)(6)(2)(1)(1)(6)(14)(41)(5)(5)(2)(5)(6)(14)(9)(4)(9)(5)(13)(1)(7)(6)(16)(17)(47)(8)(6)(8)(15)(2)1808人阅读
Graphic Tips(50)
Unity3D(148)
Shader(115)
DirectX~n(7)
西瓜的演讲
ppt翻译&#43;解释&#43;其他: wolf96
在最基本的层面上,这些新api是为了改进CPU性能和效率,通过:
减少CPU渲染瓶颈的情况,
提供更多可预测和稳定的驱动的行为,
给应用程序更多控制,就像在控制台开发一样
在传统的api,通常只有单个CPU线程提交GPU的工作。当试图渲染一个极其复杂的场景时,可能成为一个瓶颈。
因此,大多数应用程序尝试在“渲染线程”做尽可能少的事情,和驱动多线程也可以分担一点,但可伸缩性当然是有限的。
相比之下,我们会发现这些新的api,而不是处理这个问题而是更直接通过支持GPU创建很多线程来解决问题。
在谈到一个驱动的可预见性和稳定性,当你的应用程序提交一个draw call,或者映射一个缓冲区来写入,你的驱动可能通过即时编译着色器代码来应对,插入栅栏或刷新缓存来避免冲突,甚至可能去分配内存。所有这些意味着两次调用相同API函数可能会在非常不同的时间里(甚至跨帧),这使得它很难获得一致的帧时间。
与在PC上的这种驱动行为相比,现代控制台图形api给应用程序更大控制,在这些操作中:当发生编译时,当发生同步时,当分配内存时。
命令缓冲区
CPU创建线程调用对GPU发出命令,驱动交给了GPU的前端进行处理
更好的模型就是认为cpu线程把这些命令写入内存。这段内存就是我们说的“命令缓冲区”。
命令缓冲区的&#26684;式通常是GPU特定的,所以只有驱动知道的确切&#26684;式。
当命令缓冲区的命令已满,或者当应用程序请求刷新,缓冲就会被提交到GPU上执行
驱动将添加完整的缓冲队列到GPU前端进行处理。
通过这种方式,CPU和GPU可以异步运行。
前一代图形API的用户如D3D11或OpenGL通常不知道这些命令缓冲区的存在,因此,更简单的模型是可行的。
但是,GPU处理命令的速度比CPU产生的要快。如果我们要提高渲染性能,就需要扩展多个CPU线程。
但是当这样的命令缓冲区是隐藏的,并不可能扩展多个CPU线程来创建GPU命令。
所以为了解决这些问题,所有新的API包括一个更明确的具体的概念关于命令缓冲区或“命令列表”。
像图示:4个CPU线程都在写命令到另一个命令缓冲区…
当其中一个线程完成命令,它将提交执行的缓冲队列。
如果想要产生更多的GPU命令,线程将要开始填写一个新命令缓冲区。
所有这些api还支持多个队列,所以GPU可以使用多个异步流的命令。
大多数这些api使用方法,常常被称为“free threading
可以调用任何API函数在任何线程上,并不需要渲染线程,但应用程序的任何操作必须确保正确地同步读写相同的对象
命令缓冲区的内容是不透明的,不能像在控制台一样预建立缓冲传输。
Metal只有一次命令缓冲,一旦提交,就会隐式删除
Vulkan, D3D12允许更多缓冲区重用,可以重提交相同的缓冲通过帧/框架
Unity5中的情况
Unity5.2是使用双线程渲染,一个主线程负责高级逻辑渲染。一个渲染线程负责调用API和其他工作。
Unity有自己的命令缓冲区和环形缓冲。
可以在任何平台中使用,除了webGL,因为webGL没有线程&& &
环形缓冲是一个环形缓冲区,是首尾相连的队列数据结构,在一个线程上下文与另一个线程上下文之间传递数据
Ring Buffer 比链表要快,因为它是数组,而且有一个容易预测的访问模式。
详细请看/shanyou/archive//2891300.html和http://my.oschina.net/alphajay/blog/36602 我觉得讲得很明白
管线状态对象PSO
OpenGL是一个状态机,通过启用/禁用来改变状态,D3D9也有类&#20284;的“SetRenderState”来改变状态。但随着10和11,转向较粗粒度的状态对象。所以单个对象表现blend-related状态。&&
这些新的API,有一个状态对象,该对象封装了几乎全部GPU状态向量。
所以改变个体的状态,要切换到管道状态,绘制,然后切换到状态B,绘制,等等。
这些非常粗粒度,整体状态对象允许驱动程序在可预见的时期编译和验证状态,。当你刚开始在新的状态下渲染时,避免驱动暂停。
什么进入了PSO?最重要的部分是不同编程阶段的shader。所以你需要一个独特的PSO把每一个你将会用到的着色器组合起来。一些引擎的工作方式,但是如果你依赖于混搭的能力,这可能是棘手的。
同时,PSO也包含大部分的固定功能状态,如混合相关的、光栅化等。
它还包含所有顶点属性的&#26684;式信息和颜色/深度targets。
什么不能进入PSO?最重要的是你的资源绑定:实际的顶点/索引/持续的缓冲,纹理,取样器等等。
此外,每个APIs的一些固定功能状态也是与PSO分开的。每个API都有点不同,但就是一个例子,但是都允许动态设置常量的混合颜色。
内存和资源
分配,代表一些大块物理或虚拟地址空间
资源,一个内存和其特定布局的结合
一个视图,为了特殊的用途准备一个资源(比如一个颜色target)
进行分配时,你可能会选择不同的缓存行为,并决定是否需要CPU可视、GPU可视,或两者兼而有。
在创建一个资源时,你会选择是否是线性缓冲区,或一些纹理模型。你可能决定一块内存存放一个2 d 多采样纹理。
创建一个视图时,你可能决定层结构数组作为用一个特定的&#26684;式的深度-模板目标。
我们有完整的GPU状态向量,看看PSO状态与无PSO状态。
此外,我们有一些概念上的“绑定表”,我们填入绑定纹理,采样器,并缓冲到GPU状态。
描述符是一块数据,可以编写、复制和移动描述符,并不需要分配或释放内存。
例如,一个纹理描述符可能包括一个纹理数据指针,并随着宽度/高度,&#26684;式,等等。
根据描述符所代表的不同,你可以有不同的类型的描述符。
不同的gpu将存储的信息不同,&#26684;式不透明。
画一个新的资源绑定模型。现在应用程序管理的描述符表指向我们的纹理,取样器,和缓冲区,GPU状态只是指向这些表。
一环扣一环的,PSO包含所有GPU状态,GPU状态指向描述符表,描述符表是这些数据的指针,全部指向这些数据。
每个材质都要强加一些限制表的布局来得到约束。有人可能会说“描述符2 在表0 最好是一个贴图,“否则结果将是未定义的。
为了捕捉到这些信息,新API有“管道布局”的概念,这是一个明确的API,描述什么类型的描述符应该出现在每个绑定表的哪个槽中。这实际上形成了PSO的shader之间的接口,和描述符表。
多个shader(或者更确切地说,多个PSO)可以使用相同的布局,所以你可以很容易地绑定一组表并且通过多个draw call
使用它们。
D3D12和Vulkan 有描述符表分配的堆或池。
Vulkan称描述符表为”“ descriptor sets“。“D3D12称之为“descriptor tables”,但仅仅是一个堆的子区间。
这两种api对象来代表一个完整的绑定布局。D3D称之为“root layout”因为它是根表的布局,而 vulkan称之为“pipeline layout。”
Unity5.2现在已经实现了资源绑定
但是最主要的功能还没有实现,有点可惜
而且unity使用DX12变得运行很慢
Unity还没有做vulkan
Vulkan(TM)是Khronos Group研发的新一代高性能图像处理和计算API,它要比OpenGL ES更高效。
上图来自/article/5245展示了Vulkan和OpenGL ES 3.0 CPU占用差异
Vulkan实现了应用对GPU加速的直接控制,从而最大化性能和可预测性,同时,使用Khronos的新标准SPIR-V(TM)中间语言规范可以带来更高的渲染语言灵活性。Vulkan在移动、桌面、控制台和嵌入式平台上实现最小化驱动过载并提高了多线程性能。http://cn.khronos.org/news/press/khronos-to-create-new-open-standard-for-computer-vision
这些数据是来自两个不同基准的场景(一个是静态的;另一个很多材料动画参数)。在测3个人电脑上进行不同的硬件配置试。
也就是说unity现在并没有完全发挥DX12的作用
着色语言方面
Unity认为HLSL不是理想的着色/计算语言,但是有巨大的,大量的已经编好了的着色器。 unity希望继续使用HLSL,但最终会走向MetalSL
D3D9/11/12: 使用 d3dcompiler_xx.dll&& GL2, GLES2: HLSL -& (hlsl2glslfork) -& GLSL -& (glsl-optimizer) -& GLSL&& GL3/4, GLES3: HLSL -& (hlslcc) -& GLSL&& Metal: HLSL -& (hlsl2glslfork) -& GLSL -& (glsl-optimizer) -& MetalSL&& Vulkan: 目前没有
总之希望unity尽快发展渲染技术,充分发挥DX12强大特性
博主之后可能会发几篇unity现在渲染方面的情况。。。。
&&&&&&&&&&&& -----------&&by&wolf96& http://blog.csdn.net/wolf96
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:536637次
积分:8064
积分:8064
排名:第2514名
原创:201篇
转载:155篇
评论:171条
阅读:3110
阅读:12994
阅读:14507
文章:66篇
阅读:204139
(13)(10)(2)(1)(8)(6)(1)(1)(1)(4)(8)(5)(56)(18)(8)(13)(17)(26)(15)(7)(4)(11)(8)(17)(12)(6)(11)(14)(13)(19)(20)(9)鏌ョ湅: 5145|鍥炲?: 4
璇烽棶unity5鏄?笉鏄?敮鎸佸?绾跨▼璁块棶娓告垙瀵硅薄浜嗭紵
褰撳墠绂荤嚎
涓婚?甯栧瓙璐$尞
鍒濈骇UU鏃忊

我要回帖

更多关于 unity3d 多线程 的文章

 

随机推荐