Unity地面交互效果——6、地形动态顶点置换和曲面细分

回到目录

Unity置换贴图局部距离曲面细分

  大家好,我是阿赵。
  这篇文章是我无聊的时候做了一个demo,觉得挺有趣,于是就发上来。这里面包含了4个内容:置换贴图、顶点偏移、局部曲面细分,曲面细分按距离调整强度。

一、考虑的思路

  一开始我是在考虑不同的技术手段实现物体的表面凹凸效果的。我能想到的方法大概是这些:
1、凹凸贴图
2、法线贴图
3、视差偏移
4、置换顶点
  这几个方法里面,凹凸贴图现在很少有人用了,因为效果不好。法线贴图效果比凹凸贴图好很多,不过他只能模拟光射到表面时,通过不同的法线方向来模拟凹凸感觉,并不会真正的产生凹凸变形。视差偏移的效果比法线贴图好很多,因为他是通过改变采样的位置来模拟遮挡物和被遮挡物之间的关系,所以产生的不止是光影的凹凸感,而是会真正的有遮挡关系。不过视差偏移真的要效果逼真,要采样多次,而且也不适合做太过明显的变形,比如地形大面积凹凸。
  最后,就把思考点停留在了置换顶点上面了。这个是一个比较真实的手段,靠一张置换贴图,就能生成出不同高度的模型。

二、实现手段

  我这里就简单的准备了一张高度图,黑色是凹陷,白色是凸出,灰色是平地。
在这里插入图片描述

  通过在顶点程序采样,根据黑白的值来偏移顶点的y轴,就可以做出凹凸的效果:
在这里插入图片描述

  很明显的问题,顶点数不够,所以凹凸的效果不好。
  这个时候,可以使用曲面细分,增加一些面数,就可以看到凹凸的感觉比较正常:
在这里插入图片描述

  不过这么多面数并不是我想希望看到的,所以最后,再加一个根据高度图决定是否需要细分,只有凹凸的部分做细分。这里需要读取高度图,然后把高度图的0到1范围转换成-1到1的范围,然后然后计算值的绝对值大于一个数值才需要细分。也可以不转换到-1到1,就那0到1的范围减去0.5,再去绝对值比较也想。最后,就能计算出一个范围内才需要细分的效果:
在这里插入图片描述

  这样在需要凹凸的地方增加一些面数,其他的地方还是保持正常。
  最后,我还想根据距离进行细分,如果离镜头远了,那么细分的程度就没那么大,所以把刚才的那个计算细分的值,再用UnityDistanceBasedTess方法,传入距离的最大最小值,就可以计算出根据距离的细分结果了:
在这里插入图片描述

  这个效果虽然只是我一时想起来做的一个小Demo,但我觉得似乎还是在某些地方挺好用的,你们是否想到在哪些地方用得上呢?

三、Shader代码:

Shader "azhao/DisplacementTest"
{
	Properties
	{
		_heightTex("heightTex", 2D) = "white" {}
		_heightTexVal("heightTexVal",float) = 0.01
		_TessValue("Max Tessellation", Range(1, 32)) = 15
		_normalTex("normalTex", 2D) = "white" {}
		_height("height", Float) = 0
		_displacement("displacement",float) = 1
		_minDist("minDist",float) = 10
		_maxDist("maxDist",float) = 25
		[HideInInspector] _texcoord( "", 2D ) = "white" {}
		[HideInInspector] __dirty( "", Int ) = 1
	}

	SubShader
	{
		Tags{ "RenderType" = "Opaque"  "Queue" = "Geometry+0" }
		Cull Back
		CGPROGRAM
		#include "Tessellation.cginc"
		#pragma target 4.6
		#pragma surface surf Standard keepalpha addshadow fullforwardshadows vertex:vertexDataFunc tessellate:tessFunction 
		struct Input
		{
			half filler;
			float2 uv_texcoord;
		};

		uniform sampler2D _heightTex;
		uniform float4 _heightTex_ST;
		uniform float _height;
		uniform float _TessValue;
		uniform sampler2D _normalTex;
		uniform float4 _normalTex_ST;
		float _displacement;
		float _heightTexVal;
		float _minDist;
		float _maxDist;
		float4 tessFunction(appdata_full v0, appdata_full v1, appdata_full v2)
		{
			//这里要说明一下,传进来三个点,不能直接求平均值,而要逐个点去采样
			//因为只要有一个点在需要细分的范围内,这整个网格就需要细分,不然凹凸的边缘会和不需要细分的网格裂开
			float2 uv0 = v0.texcoord * _heightTex_ST.xy + _heightTex_ST.zw;
			float col0 = (tex2Dlod(_heightTex, float4(uv0, 0, 0.0)).r - 0.5);
			float2 uv1 = v1.texcoord * _heightTex_ST.xy + _heightTex_ST.zw;
			float col1 = (tex2Dlod(_heightTex, float4(uv1, 0, 0.0)).r - 0.5);
			float2 uv2 = v2.texcoord * _heightTex_ST.xy + _heightTex_ST.zw;
			float col2 = (tex2Dlod(_heightTex, float4(uv2, 0, 0.0)).r - 0.5);
			float col = max(abs(col0), abs(col1));
			col = max(col, abs(col2));
			col = step( _heightTexVal, col);
			col = col * _displacement;
			col = max(col, 0.01f);
			return UnityDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, _minDist, _maxDist, col);
		}

		void vertexDataFunc( inout appdata_full v )
		{
			float2 uv_heightTex = v.texcoord * _heightTex_ST.xy + _heightTex_ST.zw;
			float temp_output_4_0 = ( tex2Dlod( _heightTex, float4( uv_heightTex, 0, 0.0) ).r - 0.5 );
			float3 appendResult13 = (float3(0.0 , ( temp_output_4_0 * _height ) , 0.0));
			v.vertex.xyz += appendResult13;
			v.vertex.w = 1;
		}

		void surf( Input i , inout SurfaceOutputStandard o )
		{
			float4 color16 = IsGammaSpace() ? float4(0.5660378,0.5660378,0.5660378,0) : float4(0.280335,0.280335,0.280335,0);
			float2 uv_normalTex = i.uv_texcoord * _normalTex_ST.xy + _normalTex_ST.zw;
			o.Normal = UnpackNormal(tex2D(_normalTex, uv_normalTex));
			o.Albedo = color16.rgb;
			o.Alpha = 1;
		}

		ENDCG
	}
	Fallback "Diffuse"
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
几个星期前,我在想,能否使用Unity来进行地形的实时变化?比如说,如果发生爆炸,它能否在地形中显示一个气泡?我认为学习更多高级的Unity中的地形特征将会是一个好的项目。 这要比我预想的更具挑战性,因为很难在执行这些操作时获得帧率来保持稳定。使用一些技巧,最终实现了我预想的效果。 示例是这样工作的。脚本随机产生“shell”并很快掉落到地面。每一个shell都依附着一个onTrigger对撞机。如果它和拥有 TerrainDeformer组件的地形相冲突的话,shell将告诉组件它的位置和爆炸的作用力。shell然后实例化一个爆炸(explosion)(由Ben Throop great Detonator framework提供),然后移除它自身。 TerrainDeformer脚本然后将那个位置翻译成相对地形的正确位置,并修改heightmap(地形高度)和alphamap(地形纹理)。一点儿数学知识用来在影响圆周内部查找所有的heightmap和alphamap位置。 被用于在影响范围重绘质地的纹理,是从基于传递到脚本(Terrain Deformation Texture Num)中的数字顺序索引值的地形纹理列表中选择的。在这个例子中,它被设置为1,因此它将使用列表中的第二个纹理来重绘质地。 在创建你自己的地形时,有必要将地形的高度设置为大于0米,从而形成弹坑。我建议深度至少为3米。这可以通过将地形高度设为大于3米的任何值,然后点击Terrain->Flatten Heightmap并输入3米。 出于执行的原因,保持你的Terrain Size为small是非常重要的,以及更重要的是保持Heightmap Resolution为low。在这个例子中,设置为33。 目前版本没有想缺乏地形边缘检测的局限性,并提供多个地形。这个例子表明它不仅能够工作,而且不会有大的性能损失。 感谢Calin创建一个泥土纹理。 为检测示例,<http://blog.almostlogical.com/workingExamples/RealTimeTerrainDeformation/index.html> 为获得源码(unitypackage), 源码要求:Unity 2.6 以及 Detonator Framework。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值