【博物纳新】Unity海洋场景构建

栏目: 后端 · 发布时间: 7年前

内容简介:【博物纳新】是UWA重磅推出的全新栏目,旨在为开发者推荐新颖、易用、有趣的开源项目,帮助大家在项目研发之余发现世界上的热门项目、前沿技术或者令人惊叹的视觉效果,并探索将其应用到自己项目的可行性。很多时候,我们并不知道自己想要什么,直到某一天我们遇到了它。更多精彩内容请关注:lab.uwa4d.com这个项目是基于Unity社区中一个经典Ocean shader多次改进后海洋场景,海平面实现了浮力、波浪、风、气泡、交互泡沫、焦散以及其他的一些光的反射折射效果。本文重点介绍海平面场景的构建,其他效果的实现不作

【博物纳新】是UWA重磅推出的全新栏目,旨在为开发者推荐新颖、易用、有趣的开源项目,帮助大家在项目研发之余发现世界上的热门项目、前沿技术或者令人惊叹的视觉效果,并探索将其应用到自己项目的可行性。很多时候,我们并不知道自己想要什么,直到某一天我们遇到了它。

更多精彩内容请关注:lab.uwa4d.com

导读

这个项目是基于Unity社区中一个经典Ocean shader多次改进后海洋场景,海平面实现了浮力、波浪、风、气泡、交互泡沫、焦散以及其他的一些光的反射折射效果。本文重点介绍海平面场景的构建,其他效果的实现不作重点介绍。

开源库地址:

https://lab.uwa4d.com/lab/5b442d9bd7f10a201faf74b5

Unity社区原版项目地址:

https://forum.unity.com/threads/wanted-ocean-shader.16540

效果展示:

【博物纳新】Unity海洋场景构建 普通效果
【博物纳新】Unity海洋场景构建 与岛屿交互
【博物纳新】Unity海洋场景构建 开启风效果,并设置较大风

使用方法

项目作者将重要参数可视化,在Inspector面板中进行修改。如果不太明白该参数的模拟的效果,可点击参数末尾的“?”按钮,会有详细的解释。

例如:Waves Settings 中的参数,由上而下依次可已设置波浪大小、波浪波动大小、流速、波浪密度。

【博物纳新】Unity海洋场景构建 Ocean Object属性面板

并在其中预置了一些参数集作为可选场景,大家也可以保存自己修改后的参数集,添加可选场景。

【博物纳新】Unity海洋场景构建
可选场景列表

实验原理/方法

  • 浮力效果在Buoyancy中实现;
  • 海平面的效果在Ocean.cs中实现,其中SetupOffscreenRendering、RenderReflectionAndRefraction等函数用于一些光影效果的实现,本文不做重点介绍,有兴趣的读者可以下载源代码研究。
【博物纳新】Unity海洋场景构建
开启折射反射效果
【博物纳新】Unity海洋场景构建 不开启折射反射效果

作者采用绘制Mesh作为海平面、采用LOD技术进行优化。

作者将海平面区域划分为如图所示的11*11块方形区域,采用5级LOD、最外层加载一个铜钱形状Mesh来填充最外围的场景。

【博物纳新】Unity海洋场景构建
海平面分割图

所有Mesh全部生成在名为Ocean的Object下,部分生成的Mesh列表如下:

【博物纳新】Unity海洋场景构建
Mesh列表

船体永远位于5*5Mesh区域内,LOD级别为LOD_0,绘制最为精细的细节与效果。其余部分采取较低级别LOD,如图所示:

【博物纳新】Unity海洋场景构建 普通场景
【博物纳新】Unity海洋场景构建 开启WireFrame

当船体移动,驶出该区域,Ocean 组件会计算偏移量,然后将Ocean Object整体移动一块Mesh的距离,例如,在场景开始后控制船体向X轴负方向前进,直至驶出该Mesh区域,此时Ocean Object通过计算,也平移了一段距离:

【博物纳新】Unity海洋场景构建
注意Mesh的移动
【博物纳新】Unity海洋场景构建 移动前
【博物纳新】Unity海洋场景构建 移动后

这样可以保证距离摄像机最近的地方显示效果最佳,距离摄像机较远的地方绘制的Mesh采用较低等级的LOD,以节省开销。

以下节选相应代码:

用于计算偏移量,来决定是否移动Ocean Object:

1    void calculateCenterOffset() {
 2        if (followMainCamera && player) {
 3            centerOffset.x = MyFloorInt(player.position.x * sizeInv.x) *  size.x;
 4            centerOffset.z = MyFloorInt(player.position.z * sizeInv.y) *  size.z;
 5            centerOffset.y = transform.position.y;
 6            if(transform.position != centerOffset) {
 7                 ticked = true;
 8                 transform.position = centerOffset; 
 9                //确保在偏移更改时立即更新LOD0
10                updateTiles(0, 1);
11                ticked2 = true;
12             }
13            //计算高度
14            if(player) {
15                if(farLodOffset!=0) {
16                    flodFact = 1f - Mathf.Clamp01((player.position.y)*0.0007f);
17                    //调整摄像机距离
18                    ffact = MyFloorInt(flodFact*10.5f);
19                    if(ffact != oldffact) {
20                        oldffact = ffact;
21                        ticked = true;
22                        updateTiles(1, max_LOD);
23                    }
24                 }
25             }
26        }
27    }

产生Mesh并选择对应的LOD级别(变量christ):

1   void GenerateTiles() {
 2
 3        int chDist, nmaxLod=0; // Chebychev distance
 4
 5        //设置LOD级别
 6  for (int y=0; y<tiles; y++) {
 7            for (int x=0; x<tiles; x++) {
 8                chDist = System.Math.Max (System.Math.Abs (tiles / 2 - y), System.Math.Abs (tiles / 2 - x));
 9                chDist = chDist > 0 ? chDist - 1 : 0;
10                if(nmaxLod<chDist) nmaxLod = chDist;
11            }
12        }
13        max_LOD = nmaxLod+1;
14
15        flodoffset = new float[max_LOD+1];
16        float ffact = farLodOffset/max_LOD;
17        for(int i=0; i<max_LOD+1; i++) {
18            flodoffset[i] = i*ffact;
19        }
20
21        btiles_LOD = new List<Mesh>();
22        tiles_LOD = new List<List<Mesh>>();
23//添加Mesh
24        for (int L0D=0; L0D<max_LOD; L0D++) {
25            btiles_LOD.Add(new Mesh());
26            tiles_LOD.Add (new List<Mesh>());
27        }
28
29        GameObject tile;
30
31        int ntl = LayerMask.NameToLayer ("Water");
32
33        for (int y=0; y<tiles; y++) {
34            for (int x=0; x<tiles; x++) {
35                chDist = System.Math.Max (System.Math.Abs (tiles / 2 - y), System.Math.Abs (tiles / 2 - x));
36                chDist = chDist > 0 ? chDist - 1 : 0;
37                if(nmaxLod<chDist) nmaxLod = chDist;
38                float cy = y - Mathf.Floor(tiles * 0.5f);
39                float cx = x - Mathf.Floor(tiles * 0.5f);
40                tile = new GameObject ("Lod_"+chDist.ToString()+":"+y.ToString()+"x"+x.ToString());
41
42                Vector3 pos=tile.transform.position;
43                pos.x = cx * size.x;
44                pos.y = transform.position.y;
45                pos.z = cy * size.z;
46
47                tile.transform.position=pos;
48                tile.AddComponent <MeshFilter>();
49                tile.AddComponent <MeshRenderer>();
50                Renderer renderer = tile.GetComponent<Renderer>();
51
52                tile.GetComponent<MeshFilter>().mesh = btiles_LOD[chDist];
53                //tile.isStatic = true;
54
55    //选择Material
56                    if(numberLods==2) {
57                        if(chDist <= sTilesLod) { if(material) renderer.material = material; }
58                        if(chDist > sTilesLod) { if(material1) renderer.material = material1; }
59                    }else if(numberLods==3){
60                        if(chDist <= sTilesLod ) { if(material) renderer.material = material; }
61                        if(chDist == sTilesLod+1) { if(material1) renderer.material = material1; }
62                        if(chDist > sTilesLod+1) { if(material2) renderer.material = material2; }
63                    }
64                } else {
65                    renderer.material = material;
66                }
67
68//设置为子节点               
69                tile.transform.parent = transform;
70
71//也不希望在进行折射/反射传递时绘制这些,
72//所以将添加到水层以便于过滤。
73
74                tile.layer = ntl;
75
76                tiles_LOD[chDist].Add( tile.GetComponent<MeshFilter>().mesh);
77            } 
78        }
79
80        //是否开启最外层铜钱状Mesh
81        initDisc();
82    }

不同的LOD级别也对应不同的Material

1mat[0] = material;
2        mat[1] = material1;
3        mat[2] = material2;
【博物纳新】Unity海洋场景构建
不同LOD级别的材质
性能测试

本次性能测试中,使用了开启多线程渲染的版本,分别在小米8、红米Note2两款设备上进行了测试,并使用UWA GOT Online获取性能数据。得到数据如下:

【博物纳新】Unity海洋场景构建

可以看到即使在红米Note2这样的低端机上,这个Demo也可以跑出平均46帧,在这样的效果来说属于性能非常不错的移动端海洋效果,推荐在移动设备上使用。

今天的推荐就到这儿啦,或者它可直接使用,或者它需要您的润色,或者它启发了您的思路~请不要吝啬您的点赞和转发,让我们知道我们在做对的事。当然如果您可以留言给出宝贵的意见,我们会越做越好。

快用UWA Lab合辑Mark好项目!

【博物纳新】Unity海洋场景构建


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Two Scoops of Django

Two Scoops of Django

Daniel Greenfeld、Audrey M. Roy / CreateSpace Independent Publishing Platform / 2013-4-16 / USD 29.95

Two Scoops of Django: Best Practices For Django 1.5 is chock-full of material that will help you with your Django projects. We'll introduce you to various tips, tricks, patterns, code snippets, and......一起来看看 《Two Scoops of Django》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具