地形生成Lab

柏林噪音版

想在游戏中加一个沙漠场景,所以试试生成沙漠地形。

生成mesh

这一步不多说,借用catlike coding的Procedural Grid 代码,稍作修改。

PerlinNoise

修改mesh vertices的y轴坐标即可改变顶点高度。简易版使用PerlinNoise。

砂砾闪耀效果

使用一张Noise贴图——

通过控制一个灰度阈值决定像素是否显示(Cut off)。

//...
// 沙粒闪耀效果
float4 sparklesStatic = tex2D(_SparkleNoise, IN.uv_MainTex * _SparkleScale * 5);
float4 sparklesResult = tex2D(_SparkleNoise, (IN.uv_MainTex ) * _SparkleScale) * sparklesStatic;
//...
o.Albedo += step(_SparkCutoff, sparklesResult) * _SparkleColor;			
o.Emission += step(_SparkCutoff, sparklesResult) * _RimColor * pow(rim, _RimPower)

HeightMap版

HeightMap和Tessellation

HeightMap的shader实现很简单,依然是vertex displacement,根据heightmap修改vert部分就可以了。

但是shader只能改变视觉效果,无法生成mesh collider(目前未找到可行方法),还得直接修改mesh的顶点坐标。通过Mesh.GetPixel获取高度图灰度值,从而决定地图高度坐标。

emmm所以最后shader还是加上了tessellation和heightmap,调节细分程度可以稍微细化一下地图,但是效果不是很好,除了视觉效果和纯shader相比不明显外,细化过度还会出现未明原因多余连线。

Triplanar Mapping

此外地形贴图还用到了Triplanar Mapping,使陡峭面的贴图按正常比例显示,不会被拉伸。

Triplanar Mapping核心代码如下:

	float3 blendNormal = saturate(pow(worldNormalE * 1.4,4));

	// triplanar for top texture for x, y, z sides
	float3 xm = tex2D(_MainTex, IN.worldPos.zy * _Scale);
	float3 zm = tex2D(_MainTex, IN.worldPos.xy * _Scale);
	float3 ym = tex2D(_MainTex, IN.worldPos.zx * _Scale);

	// lerped together all sides for top texture
	float3 toptexture = zm;
	toptexture = lerp(toptexture, xm, blendNormal.x);
	toptexture = lerp(toptexture, ym, blendNormal.y);

表层贴图和侧边贴图

通过法线判断可以实现在表层覆盖其他贴图的效果,比较适用于植被、积雪等情景。

  float3 worldNormalE = WorldNormalVector(IN, o.Normal);
  float worldNormalDotNoise = dot(o.Normal, worldNormalE.y);

  float3 topTextureResult = step(_TopSpread, worldNormalDotNoise) * toptexture;
	float3 sideTextureResult = step(worldNormalDotNoise, _TopSpread) * sidetexture;
		
	o.Albedo = topTextureResul + sideTextureResult;

用于生成山崖和简单的迷宫都很有效。

洛 美 岛 梦 幻 联 动 (危)——

TODO

【待续…】Splatmesh,covermap,virtual texture…

还有mesh要保存成文件,不然每次都重新生成一波…晚点搞…

另外mesh collider有bug,大概是tess有问题。

链接

东西放在这里惹→AlfxTerrain