2015-01-25 22:22:47 book_longssl 阅读数 4175


2.制做一张灰度图:

需求:Photoshop 
          GIMP

先Google 搜 WorldMap-A_non-Frame.png  这个地图下载一张到你pc

然后gimp打开它, 右键图片,弹出菜单——选择——按颜色

这张图的好处在于海洋就是几种蓝色,按照颜色分别  左键 选取这几个蓝色,按下delete键删除颜色,清理干净后如图


然后 菜单栏 图像——模式——灰度
然后 菜单栏  颜色——反向
保存,用ps打开它,,,,用 滤镜——模糊——高斯模糊

有个问题需要注意!图像必须是边长相等的正方形!

做完,这个地图的灰度图一定要  点菜单栏 的编辑——变换——水平变换  (你肯定问为啥要这样!地图反了?对,反了,因为导入raw后会水平翻转,所以你要翻转高度图进引擎才是正的。)
保存为.raw

3.地形

运行,前面怎么可以找找教程,创建完工程后,新的场景里,我们开始地图工作, 左上角找到Create ,菜单里面选 Terrain.



于是我们得到了一个地形,如下图,找到那个齿轮图标

我们叫这个图标设置,其他我们不管,找下面的Resolution

然后Wides 宽度 Length长度 都设置为高度图的边长像素,也就是图片的长宽

Height可以随时调节,是地图的最大高度。

然后下面的Import raw...导入咱的高度图,然后弹出小窗口,其他别动,把默认的mac设置为windows.然后import,然后我们的地形就进去了。




调整到你认为合适吧,然后我们说下如何导出为 obj格式的。。。
这个我们需要导出脚本了:http://wiki.unity3d.com/index.php?title=TerrainObjExporter

用法我简单说下吧,懂英语的可以看懂上面网址里面说的用法。
如下图那是个管理资源的窗口,右侧那个大窗口的空白部分右键一下,菜单里点show in explorer  你发现资源管理器能打开一个文件夹,没错这是在你电脑文件夹里都有的(这一行文字只是让你了解构造。。。
so。。右键右侧空白部分,菜单里点 create....然后选 c# script 或  java script

然后如果你用c#了,刚才那个地址里的你就复制c的代码,往里面粘贴(新脚本都有几行代码,全删掉然后再粘贴。) JS 就粘贴JS的。




然后的菜单栏的就会多一个Terrain选项,点一下选 Export to obj....

然后没什么了。。。。
    export format  为Triangles    三角形默认的不用碰

    resolution 很重要: 
                           Full  当前地形网格的完整面数
                           Half 当前地形网格面数的一半
                           Quarter  四分之一
                           Eighth    八分之一
                           Sixteenth 十六分之一


注意: obj地图模型要先导入max,再往max导入一个native的地图的obj(别问我怎么把骑砍地图弄obj导出),对比着骑砍的地图obj旋转 移动 ,校准网格坐标。然后往编辑器导入才能正确。 

矫正坐标后导出obj到你的编辑器的map data里,然后编辑器就能导入了。。。。

一般导出后进max看看有几十万面以上的就不要导入编辑器了。。。。

细节大家自己摸索摸索吧

还有如果对手绘地图比较偏好的同学,你们可以结合着地图编辑器和unity用,具体你们看看。
但是纯属手绘的虽然细节你很爽,但是面数你会不爽。。。。


有些基础的东西我没说那么详细,不过摸索下就会了



补俩截图: 



2015-02-01 20:12:15 book_longssl 阅读数 3373


Unity3D中的多线程。线程是一个相当复杂的话题,但如果掌握了它,就可以从容的使用多个硬件处理器或处理很难划分管理数据块。

 

如在场景中用A*算法进行大量的数据计算,变形网格中操作大量的顶点,持续的要运行上传数据到服务器,二维码识别等图像处理,如果同时你要处理很多事情或者与Unity的对象互动小可以用thread,否则使用coroutine。

 

线程是在程序中与其他线程同时运行的进行。在多处理器的计算机上可以做到多个线程的真正的同步,更多的线程取决于有多个处理核心。

 

编程时,总有个主线程执行你的代码,也可以创建额外的线程和主线程同时运行。而Unity中,你仅能从主线程中访问的组件,对象和Unity3D系统调用。任何企图访问这些项目的第二个线程都将失败并引发错误,这是一个要重视的一个限制。

 

所以当你写代码时,你认为一个函数开始并达到它执行的点后返回,同样你做的东西又在另外一个函数中执行,但又没有发生相应的变化。操作系统决定你代码的执行,任何时候,你的代码只能暂时”休眠”掉,然后让另外的代码开始运行。

 

 

 

多线程及使用多线程

 

在这个例子中,在第一个线程将A的值加载到CPU寄存器中准备+1后被中断,第二个线程来读取A的值,并减去1000,这时A应该是-950,现在第一个线程重新开始,它在寄存器中的50+1的结果存储于A,A变成了51,而-950已经丢掉了。

 

从根本上说,要在用多个线程在同时对变量或内存访问时,要采取很多预防措施来确保不会发生这样的事。所以Unity决定从另外线程访问这些变量或者内存是无效的,只是为了避免所有系统和框架对象出现问题。所以要确保一次只有一个线程来修改变量,这不意味着你不能用多线程工作,你可以用”排序”来解决这个问题。

 

C#中有lock这个关键字,以确保只有一个线程可以在特定时间内访问特定的对象,这里说对象是因为法锁定一个类型值(value type)或原型(primitive)。

 

1. int a = 50;

2. 

3. object guard = new object();

4. 

5. void ThreadOneCode()

6. {

7. //一些代码在这

8. 

9. lock(guard)

10. {

11. a = a + 1;

12. }

13. 

14. //其余一些代码在这

15. 

16. }

17. 

18. void ThreadTwoCode()

19. {

20. //一些代码在这

21. 

22. lock(guard)

23. {

24. a = a - 1000;

25. }

复制代码

 

所有都锁定在guard内,保证同一个时间只有一个线程通过guard访问它,你可以使用任何合适的对象。现在你可能会有各种各样的问题,比如你要锁定的不止一件事,可能是互相嵌套的。那我们该怎么办呢?

 

我们这个类叫Loom,让你可以轻松在另一个线程运行代码,这里有两个要注意的功能:

 

RunAsync(Action)-在另一个线程上运行的一组代码.

 

QueueOnMainThread(Action,[可选]float time)-运行在主线程的语句(可选延迟).

 

用Loom.Current访问Loom-创建一个看不见的GameObject用来处理游戏主线程的互动,下面这个例子用Loom来更新一个网格所有的顶点乘的结果。

 

 

2017-11-04 15:10:54 atgczcl 阅读数 2709

unity3d报这个错误 get_isPlaying can only be called from the main thread.
原因就是多线程服务中,非主线程操作,ui界面等的一些操作,就会报这个错误,解决方案就是:
写在Update()中监听进行修改,这样就没有错误了

2016-02-17 12:31:40 WLDRSWGZMB 阅读数 538

线程(Thread)和协程(Coroutine)
使用协程的作用一共有两点:1,延迟等待一定时间执行代码;2,等待某个操作完成后执行下面的代码。总结一句话:控制代码在一定的时间执行。
协程不是线程也不是异步执行的。协程和MonoBehaviour的Update函数一样也是在MainThread中执行。使用协程不用考虑同步和锁的问题。
Unity中协程的执行原理
协程是一个分部执行,遇到条件(yield return 语句)会挂起,直到条件满足才会被唤醒继续执行后面的代码。如果yield return 后面是null(yiled return null)那么会直接执行下面的程序。
Unity在每一帧(Frame)都会去处理对象上的协程。Unity主要是在Update后去处理协程(检查协程的条件是否满足)。

using UnityEngine;
using System.Collections;
/// <summary>
/// unity协程
/// </summary>
public class Tests : MonoBehaviour {
    // Update is called once per frame
    void Update () {
        if(Input.GetKeyDown(KeyCode.J))
        {
            StartCoroutine(IETestNull());
        }
        if (Input.GetKeyDown(KeyCode.K))
        {
            StartCoroutine(IETestFrame());
        }
        if (Input.GetKeyDown(KeyCode.L))
        {
            StartCoroutine(IETestTime());
        }
    }
    /// <summary>
    /// 直接执行IEnumerator里面的所有代码无需等待
    /// </summary>
    /// <returns></returns>
    IEnumerator IETestNull()
    {
        Debug.Log("开启一道协程,先执行这段代码");
        yield return null;      //无需等待直接执行下面的代码
        Debug.Log("如果return后面是null,那么直接执行这段代码");
    }
    /// <summary>
    /// 帧等待
    /// </summary>
    /// <returns></returns>
    IEnumerator IETestFrame()
    {
        Debug.Log("开启一道携程时,先执行这段代码");
        yield return 2;         //等待2帧后执行下面的代码
        Debug.Log("等待2帧后,执行这段代码");
    }
    /// <summary>
    /// 时间等待
    /// </summary>
    /// <returns></returns>
    IEnumerator IETestTime()
    {
        Debug.Log("开启一道携程时,先执行这段代码");
        yield return new WaitForSeconds(2f);    //等待2秒后执行下面的代码
        Debug.Log("等待2秒后,执行这段代码");
    }
}

查看 YieldInstruction , WaitForSeconds , WaitForFixedUpdate , Coroutine and MonoBehaviour.StartCoroutine 可以获得更多使用yield的信息.

没有更多推荐了,返回首页