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"
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/182365.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【CCF-PTA】第03届Scratch第04题 -- 数字加密

数字加密 【题目描述】 "狼群战术"是第二次世界大战中德军对大西洋上盟军商船所使用的潜艇战术,一度遏制住英国的海上贸易。直到艾伦图灵成功破译了德国的英格尔码密码,成为二战的一个重要转折点。时至今日,图灵仍然是计算机的一…

JavaEE(SpringMVC)期末复习

文章目录 JavaEE期末复习一、单选题: JavaEE期末复习 一、单选题: 1.Spring的核⼼技术是( A )? A依赖注入 B.JdbcTmplate C.声明式事务 D.资源访问 Spring的核心技术包括依赖注入(Dependency Injection&am…

字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 输出: [[“bat”],[“nat”,“tan…

Python 基础【四】--数据类型-字符串【2023.11.23】

1 .定义 字符串是 Python 的一种数据类型,它可以通过单引号 ‘、双引号 "、三引号 ‘’’ 或 “”"来定义。 aabcd bacsdcd c"""accsfv""" print(a) print(b) print(c)2 .基本操作 访问单个字符 注意:从0开始…

Python 使用tkinter复刻Windows记事本UI和菜单功能(三)

上一篇:Python 使用tkinter复刻Windows记事本UI和菜单功能(二)-CSDN博客 下一篇:敬请耐心等待,如发现BUG以及建议,请在评论区发表,谢谢! 本文章完成了记事本的新建、保存、另存、打…

API自动化测试:如何构建高效的测试流程

一、引言 在当前的软件开发环境中,API(Application Programming Interface)扮演了极为重要的角色,连接着应用的各个部分。对API进行自动化测试能够提高测试效率,降低错误,确保软件产品的质量。本文将通过实…

Linux快速显示文件行号并跳转

有时候,想要在线上直接查看日志文件,搜索到关键词后,如果一直按n找下去,很麻烦,我们可以先显示出行号,确定好我们要找内容对应的行号,直接跳转过去。 esc进入命令模式,输入:set nu命…

【工具栏】热部署不生效

目录 配置热部署: 解决热部署不生效: 首先检查: 第一步: 第二步: 第三步: 第四步: 配置热部署: https://blog.csdn.net/m0_67930426/article/details/133690559 解决热部署不…

【Java并发】聊聊线程池原理以及实际应用

线程其实对于操作系统来说是宝贵的资源,java层面的线程其实本质还是依赖于操作系统内核的线程进行处理任务,如果频繁的创建、使用、销毁线程,那么势必会非常浪费资源以及性能不高,所以池化技术(数据库连接池、线程池&a…

【iOS】数据持久化(二)之归档和解档(iOS 13以后)

在之前介绍的数据存储方法中,不管是NSUserDefaults还是plist文件都不能对自定义对象进行存储,OC提供的解归档恰好解决了这个问题 本片文章对 iOS13 以后的版本 归档和解档 进行介绍。老版本的解归档见这篇文章:【iOS】文件(对象数…

【Java】认识String类

文章目录 一、String类的重要性二、String类中的常用方法1.字符串构造2.String对象的比较3.字符串查找4.转换5.字符串替换6.字符串拆分7.字符串截取8.其他操作方法9.字符串的不可变性10.字符串修改 三、StringBuilder和StringBuffer 一、String类的重要性 在C语言中已经涉及到…

微型计算机原理MOOC题

一、8254 1.掉坑了,AL传到端口不意味着一定传到的是低位,要看控制字D5和D4,10是只写高位,所以是0A00.。。 2. 3. 4.待解决:

leetCode 2925. 在树上执行操作以后得到的最大分数 + 正则难反 + 树形 DP

2925. 在树上执行操作以后得到的最大分数 - 力扣(LeetCode) 有一棵 n 个节点的无向树,节点编号为 0 到 n - 1 ,根节点编号为 0 。给你一个长度为 n - 1 的二维整数数组 edges 表示这棵树,其中 edges[i] [ai, bi] 表示…

【从零开始实现意图识别】中文对话意图识别详解

前言 意图识别(Intent Recognition)是自然语言处理(NLP)中的一个重要任务,它旨在确定用户输入的语句中所表达的意图或目的。简单来说,意图识别就是对用户的话语进行语义理解,以便更好地回答用户…

JS数组常用的20种方法详解(每一个方法都有例子,超全面,超好理解的教程,干货满满)

目录 1.会改变原数组的方法(7种) 1.push() 2.pop() 3.unshift() 4.shift() 5.reverse() 6.sort() 7.splice() 2.不改变原数组的方法(13种,返回的新数组是从原数组浅拷贝来的) 1.concat() 2.join() 3.slice…

九、ffmpeg命令转封装

开了几天小差,今天继续学习ffmpeg。 准备测试使用的视频,并查看其信息 # 查看视频信息。使用Mediainfo也可以 ffprobe test.mp4 视频格式的信息如下。 保持编码格式:ffmpeg -i test.mp4 -vcodec copy -acodec copy test_copy.tsffmpeg -i…

2015年2月4日 Go生态洞察:Go语言中的包命名艺术

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

王道p150 20.将给定的表达式树转化为等价的中缀表达式(通过括号反应操作符的计算次序)

本题代码如下 void btreetoexp(tree t, char deep) {if (t NULL)return;else if (t->lchild NULL && t->rchild NULL)printf("%c", t->data);//输出操作数,不加括号else {if (deep > 1)printf("(");btreetoexp(t->l…

231123 刷题日报-动态规划

今天主要看了DP,前几天频繁遇到DP打击有点大。。 1. 0-1背包问题 要点: a. 三部曲: 1. 状态和选择 状态:物品序号、背包容量 选择:放、不放 2. dp数组定义、base case dp[i][w] 对于前i个物品,当前背包…

UNETR:用于三维医学图像分割的Transformer

论文链接:https://arxiv.org/abs/2103.10504 代码链接: https://monai.io/research/unetr 机构:Vanderbilt University, NVIDIA 最近琢磨不出来怎么把3d体数据和文本在cnn中融合,因为确实存在在2d里面用的transformer用在3d里面…