内容简介:【博物纳新】是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
效果展示:
使用方法
项目作者将重要参数可视化,在Inspector面板中进行修改。如果不太明白该参数的模拟的效果,可点击参数末尾的“?”按钮,会有详细的解释。
例如:Waves Settings 中的参数,由上而下依次可已设置波浪大小、波浪波动大小、流速、波浪密度。
并在其中预置了一些参数集作为可选场景,大家也可以保存自己修改后的参数集,添加可选场景。
可选场景列表
实验原理/方法
- 浮力效果在Buoyancy中实现;
- 海平面的效果在Ocean.cs中实现,其中SetupOffscreenRendering、RenderReflectionAndRefraction等函数用于一些光影效果的实现,本文不做重点介绍,有兴趣的读者可以下载源代码研究。
开启折射反射效果
作者采用绘制Mesh作为海平面、采用LOD技术进行优化。
作者将海平面区域划分为如图所示的11*11块方形区域,采用5级LOD、最外层加载一个铜钱形状Mesh来填充最外围的场景。
海平面分割图
所有Mesh全部生成在名为Ocean的Object下,部分生成的Mesh列表如下:
Mesh列表
船体永远位于5*5Mesh区域内,LOD级别为LOD_0,绘制最为精细的细节与效果。其余部分采取较低级别LOD,如图所示:
当船体移动,驶出该区域,Ocean 组件会计算偏移量,然后将Ocean Object整体移动一块Mesh的距离,例如,在场景开始后控制船体向X轴负方向前进,直至驶出该Mesh区域,此时Ocean Object通过计算,也平移了一段距离:
注意Mesh的移动
这样可以保证距离摄像机最近的地方显示效果最佳,距离摄像机较远的地方绘制的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;
不同LOD级别的材质
本次性能测试中,使用了开启多线程渲染的版本,分别在小米8、红米Note2两款设备上进行了测试,并使用UWA GOT Online获取性能数据。得到数据如下:
可以看到即使在红米Note2这样的低端机上,这个Demo也可以跑出平均46帧,在这样的效果来说属于性能非常不错的移动端海洋效果,推荐在移动设备上使用。
今天的推荐就到这儿啦,或者它可直接使用,或者它需要您的润色,或者它启发了您的思路~请不要吝啬您的点赞和转发,让我们知道我们在做对的事。当然如果您可以留言给出宝贵的意见,我们会越做越好。
快用UWA Lab合辑Mark好项目!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【博物纳新】Unreal 海洋场景构建
- 【博物纳新】2D破碎效果开源库测评
- 【博物纳新】Procedural开源库合辑
- 【博物纳新】Isaura—光环特效开源库评测
- 【博物纳新】水面涟漪反射效果开源库测评
- 【博物纳新】2D开源库合辑推荐
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。