![c16525a390afdbaa98cf07b87f9a77c2.png](https://i-blog.csdnimg.cn/blog_migrate/8bf3d14deaea15554d316f4147676415.jpeg)
承接上一篇
saku一只松鼠:[unity]通过高度图制作一个真实世界的地形zhuanlan.zhihu.com![9d2489d2fde9e887b768e995cf591653.png](https://i-blog.csdnimg.cn/blog_migrate/12008a1bcc0980e037a9e35db86e2190.jpeg)
由于历史的车轮不断前进,松鼠为了不固步自封,在地形插件中更新了可以在SRP下使用的模式。从此使用Lightweight和High Definition Render Pipeline的用户再也不用面对生成的地块一片粉色的局面了。
![a754223336f1966937d92891b4b98ca0.png](https://i-blog.csdnimg.cn/blog_migrate/3dfb9e71d260694c4304a2b13a720c62.jpeg)
![d0e3d4957aa7f60aeb73a111a3f061f0.png](https://i-blog.csdnimg.cn/blog_migrate/5a9edcef6f07f03002e7701d6f6ae0b9.png)
不过通过这次更新,一个问题也浮出水面:
Unity的这一个新渲染管线目前还处于preview阶段,自带的转换工具只能处理built-in的shader,于是RTM中专门为地图应用而制作的材质全部阵亡了。
![534dccce54d285409a68788dd44a92e7.png](https://i-blog.csdnimg.cn/blog_migrate/d5fd27e7c0cb8b2ac6739090f28eb33a.jpeg)
不过好消息是,这样的效果借助新推出的图形化shader编辑工具可以轻松愉快地完成。于是,在这一章中,我们使用shaderGraph制作材质,并将它作为模板直接赋予到新生成的地形上。
首先,使用shadergraph需要做几个前置任务:
1.打开package manager,安装Lightweight RP。新建工程的时候使用LWRP模板也可以达到差不多的效果,不过建议之后还是在package manager中将其升级到最新版本。
2. Create > Render Pipeline > Lightweight > Pipeline Asset,之后把新建的asset拖到Project Settings > Graphics中的scriptable render pipeline setting一栏中。(如果是使用模板新建的工程则可以省略这一步。如果遇到报错的话,顺手把player setting中的color space从gamma改为linear)
3.在package manager中,安装shader graph。之后就可以新建shadergraph的文件了。
![59640cb688c52ffb79b78de6d54a9c24.png](https://i-blog.csdnimg.cn/blog_migrate/77519d244b522bae04934bfe57099556.png)
随意从这三项里选一个最简单的,建立unlit graph。之后随便create一个texture 2d的节点,连线到输出节点的color上,就可以显示这张贴图了。
![a4dd3ebd46316654329605de25618163.png](https://i-blog.csdnimg.cn/blog_migrate/79feb13275174bb7c37fe0864ef94b9b.jpeg)
接下来正文开始。
在使用传统的shaderlab制作依据高度着色的效果,需要两个property来设定高度最高点和最低点的高度。
_heightMax("pos Max",Float) = 10
_heightMin("pos Min",Float) = 0
_colorA ("Color Up",Color) = (0,0,0,1)
_colorB ("Color Down ",Color) = (0,0,0,1)
之后用vertrex.y来计算当前高度在最高点最低点之间的位置,并以此计算两个颜色的插值。
void
为了完成以上工作,我们设置一些节点,并按照公式连线。
首先是第一步
![2a4681a0752a90d6437c55f5cce7b6fe.png](https://i-blog.csdnimg.cn/blog_migrate/27f24ac6319bb474b886be9e53ddd952.jpeg)
接着第二步,使用上面计算的结果做两个颜色之间的插值。
![39cfd0a52407b426af3bae27f09189f9.png](https://i-blog.csdnimg.cn/blog_migrate/3bacbed0a779b0b3f32004220f8157ed.jpeg)
在这里,其实unity给提供了一个更方便的节点,remap。
根据非官方文档中提供的资料:
//The following example code represents one possible outcome of this node.
void Unity_Remap_float4(float4 In, float2 InMinMax, float2 OutMinMax, out float4 Out)
{
Out = OutMinMax.x + (In - InMinMax.x) * (OutMinMax.y - OutMinMax.x) / (InMinMax.y - InMinMax.x);
}
可以将连线简化,并且不用再受到除0的困扰。
![e52ae370ae379bab3622290942a41990.png](https://i-blog.csdnimg.cn/blog_migrate/d5f807e6442f7451da233f57d68ea1c0.jpeg)
![17f11dc44a6fb8e35c31c1552eabd92d.png](https://i-blog.csdnimg.cn/blog_migrate/308d93f5667469e2d4ecfdab938b859c.png)
虽然达到了效果,但是在inspector中都没有可调节的选项,这无疑会让人比较厌烦,这时就需要将一部分input的节点convert to property。
找到两个height节点和两个color节点,右键选择转换,它们就会出现在旁边的properties中
![1bfe3d9c99940dc289879b0f4d337e4b.png](https://i-blog.csdnimg.cn/blog_migrate/10f90ecca3cf9605734e42482455d26d.png)
![bd70b0326307ed17b5eb345b9bf87167.gif](https://i-blog.csdnimg.cn/blog_migrate/64286cb5cacb09e6b70a7a877c3bf75e.gif)
除了基于高度着色外,一个不带卫星图的地形显然是没有灵魂的,接下来我们做贴图的部分。
首先在新建一个property,并改名为_MainTex,接着将它拖到工作区。
![d50c09d6217419a625af6e466369d8f1.png](https://i-blog.csdnimg.cn/blog_migrate/66d1559996bd53424baf8d8ed1b72672.png)
根据文档中的解释Samples a Texture 2D and returns a Vector 4 color value for use in the shader.要使用texture2D就需要为它配备一个采样器,来将图片转换为RGBA的颜色数据。
![742320b7c593ff57d2ef264725c9610f.png](https://i-blog.csdnimg.cn/blog_migrate/5c3dac9cd90e67e84f5cbf7f1ab0f00e.jpeg)
接着,用加法或乘法的方式将贴图和颜色融合起来。
![3f12899e943892d3dea6070a164bb273.png](https://i-blog.csdnimg.cn/blog_migrate/fb7025742c986be64836a5f6255f95f5.jpeg)
就实现了这样的效果
![bae15c24db34a87542c4d164a6261e4c.png](https://i-blog.csdnimg.cn/blog_migrate/e5fee4a22699eecdf10ef32dddebdcc9.png)
接下来,要让生成一个地形的时候直接附上我们刚刚制作的材质。在前一章使用高度图生成地形的脚本基础上,增加材质模板和贴图的变量。
[SerializeField]
Texture2D Tex;
[SerializeField]
Material Mat;
string propertyname = "_MainTex";
propertyname就使用之前给贴图起的名字。
在生成texture的部分做一点修改:
void DrawTexture(){
if (gameObject.GetComponent <MeshRenderer> ()==null ) {
gameObject.AddComponent<MeshRenderer> ();
}
Material diffuseMap = new Material (Shader.Find (Mat.shader.name));
diffuseMap.CopyPropertiesFromMaterial(Mat);
diffuseMap.SetTexture(propertyname,Tex);
gameObject.GetComponent<Renderer> ().material = diffuseMap;
}
这样就以我们选用的材质的shader生成一个新材质,并复制了原材质的属性,接着将贴图赋给相应的property。
![169b035db7efe2bb36c13f0f6ca6ea7c.png](https://i-blog.csdnimg.cn/blog_migrate/50851514aad890d4f77c8d604c579672.jpeg)
接着,还有一件之前忘记做的事情,为mesh的每个顶点设定一个uv,不然所有uv都是默认值(0,0)的话,是没办法正确显示贴图的。
void setUV()
{
_uvs = new Vector2[(sx+1)*(sy+1)];
float u = 1.0F / sx;
float v = 1.0F / sy;
for (int yy = 0; yy <= sy; yy++)
{
for (int xx = 0; xx <= sx; xx++)
{
int self = xx + yy *(sx+1);
_uvs[self] = new Vector2(xx * u, yy * v);
}
}
}
接着,赋值给mesh。
mesh.uv = _uvs;
以上操作的作用是将所有顶点的uv按顺序均匀分配到0和1之间,即简单的让贴图均匀铺满整个mesh,并将计算结果存入数组。这个0到1的范围就对应了贴图从左下到右上的全部,而如果把范围修改为0~2的话,
float u = 1.0F / sx;
float v = 1.0F / sy;
根据贴图的wrap mode设置,就会得到不同的效果了。
![371e34636fe753f9eb492706621dd130.png](https://i-blog.csdnimg.cn/blog_migrate/acb07c2e4ab26a4c0ea01ad0c644b939.jpeg)
新建一个空物体,挂上脚本并配置好材质和图,然后try一下,就会有带有卫星图的彩色地形生成出来了。
这一章同样出自地形生成插件:
Real Terrain Maker - Asset Storeassetstore.unity.com![cc3388fd35366944505ffd1b41a3dfc1.png](https://i-blog.csdnimg.cn/blog_migrate/e3a499d1c28580684f0f026eec69fd59.jpeg)
好惨啊小本生意被打差评真的闹不住,而且还是问都没问直接打。希望有兴趣的客官在阅读使用说明或者看过demo之后理性购买,能打个5星真的感激不尽,作者哭超凶的。
作者活着,随时可在客(没)服(人)群里提问
这章所用到的资源在这里获取:
sakuraplus/make-terrain-with-google-elevationgithub.com由于使用了shadergraph,这次的需求是unity2019.1.7及以上。
脚本挂在任意物体上即可使用,当然建议使用空物体,不然会造成好玩的影响。
如果出现Texture 'Trr00downloadHeightmap_143' is not readable这样的提示,将图片的import setting设为Read/Write Enabled,同时不要忘记将Power of 2设置为none,filter mode为point,不然在逐像素采样的时候会受到影响。