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

news2024/11/15 11:04:32

回到目录

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.coloradmin.cn/o/1244039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

经营现金流转正,宝尊电商解构内容电商3.0时代长期价值

在过去的“黄金十年”里,货架电商、直播电商鱼贯而出,接力式地推动品牌增长。彼时,价格换市场、“以快打快”的打法足以满足品牌发展所需。 然而,随着流量红利消退,消费者愈发理性,品牌增长集体“失速”。…

前端开发学习 (二) 事件修饰符、系统命令

其实,我们上一章的时候就已经说过了一些系统指令,这里详细介绍一下 一、v-on的事件修饰符 事件作用click点击时触发submit表单被提交时触发input输入框发生改变时触发keyup按键松开时触发keydown按键按下时触发mouseover鼠标悬停触发mouseout当鼠标移开…

【附代码】判断线段是否相交算法(Python,C++)

【附代码】判断线段是否相交算法(Python,C) 文章目录 【附代码】判断线段是否相交算法(Python,C)相关文献测试电脑配置基础向量旋转向量缩放向量投影推导 点乘定义推导几何意义 叉乘定义推导几何意义 判断线…

批量将本地N个英文Html文档进行中文翻译-操作篇

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分…

MeterSphere | 接口测试请求体中,int类型的入参实现动态化变量

项目场景: 在接口自动化的时候,要把上一个接口的 Int 变量传入到 下一个接口中进行使用,但编译器会出现 红色的 X 符号 问题描述 如何实现 int 类型的入参实现动态化变量? 解决方案: 忽视掉这个红色 X 号&#xff0…

latex通过bib添加参考文献作者名字有特殊符号如字母上有两点乱码解决办法

一、背景 在使用latex写英文论文时,一般是通过bib的方式添加参考文献。但有的参考文献作者是法国人或其他国家的,名字会有特殊符号,如某个字母上有两个点,或者声调符号等等,如下图所示: 如果不进行特殊操作…

广告机/商业显示屏_基于MT8788安卓主板方案

安卓主板在广告机领域扮演着重要的角色。无论是在商场、车站、酒店、电梯、机场还是高铁站,LED广告机广泛应用,并通过不同方式进行播放和管理。 广告机/商业显示屏_基于MT8788安卓主板方案 基于MT8788安卓主板方案的广告机采用了联发科MT8788八核芯片方案…

车辆管控大数据可视化平台案例源码分析【可视化项目案例-10】

🎉🎊🎉 你的技术旅程将在这里启航! 🚀🚀 本专栏包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章底部可下载对应案例源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你是初学者还是资深开发者,这里都有适合你的内容。…

【LeetCode刷题-回溯】-- 47.全排列II

47.全排列II 主要需要解决全排列不重复的问题,设定一个规则,保证在填第i个数的时候重复数字只会被填入一次即可,而在本题中,我们选择对原数组排序,保证相同的数字都相邻,然后每次填入的数一定是这个数所在重…

[点云分割] Clustering of Pointclouds into Supervoxels

介绍 “Clustering of Pointclouds into Supervoxels” 是一种点云数据聚类的方法,用于将点云数据分割成具有相似特征的超体素(supervoxel)。 超体素是一种在点云数据中表示连续区域的方法,类似于像素在图像中表示连续区域。超体…

SPASS-信度分析

信度分析概述 效度 效度指的是量表是否真正反映了我们希望测量的东西。一般来说,有4种类型的效度:内容效度、标准效度、结构效度和区分效度。内容效度是一种基于概念的评价指标,其他三种效度是基于经验的评价指标。如果一个量表实际上是有效…

练习七-在Verilog中使用任务task

在Verilog中使用任务task 1,任务目的2,RTL代码,交换3,测试代码4,波形显示 1,任务目的 (1)掌握任务在verilog模块设计中的应用; (2)学会在电平敏感…

使用pt-query-digest分析慢查询日志

介绍 pt-query-digest 属于 Percona Toolkit 工具集中较为常用的工具,用于分析 slow log,可以分析 MySQL 数据库的 binary log 、 general log 日志,同时也可以使用 show processlist 或从 tcpdump 抓取的 MySQL 协议数据来进行分析。 安装…

人工智能教程(一):基础知识

目录 前言 什么是人工智能? 教学环境搭建 向量和矩阵 前言 如果你是关注计算机领域最新趋势的学生或从业者,你应该听说过人工智能、数据科学、机器学习、深度学习等术语。作为人工智能系列文章的第一篇,本文将解释这些术语,并搭…

Python实现交易策略评价指标-收益率

1.收益率的定义 收益率几乎是所有投资者都会关注的一个指标,收益率的高低决定了投资策略的赚钱能力,常见关于收益率的指标如下: 持有期收益率 持有期收益率 期末投资权益 − 期初投资权益 期初投资权益 持有期收益率 \frac {期末投资权益…

王道p149 9.设树B是一棵采用链式结构存储的二叉树,编写一个把树 B中所有结点的左、右子树进行交换的函数。(c语言代码实现)

本题代码如下 void swap(tree* t) {if (*t){treenode* temp (*t)->lchild;(*t)->lchild (*t)->rchild;(*t)->rchild temp;swap(&(*t)->lchild);swap(&(*t)->rchild);} } 完整测试代码 #include<stdio.h> #include<stdlib.h> typed…

C++每日选择题—Day1

第一题 以下C代码会输出什么? #include <iostream> using namespace std; class A { public:A() {}~A() {} private:static int a; }; int main() {cout << sizeof(A) << endl;return 0; } A&#xff1a;0 B&#xff1a;1 C&#xff1a;4 D&#xff1a;8 答…

视频网关简介

在数字化时代&#xff0c;视频通信已经成为了人们日常生活和工作中的重要部分。为了满足不同设备和平台之间的视频通信需求&#xff0c;各种视频协议应运而生。然而&#xff0c;这些协议之间的差异使得相互通信变得复杂。因此&#xff0c;视频网关作为一种重要的网络设备&#…

初识Java 18-3 泛型

目录 边界 通配符 编译器的能力范畴 逆变性 无界通配符 捕获转换 本笔记参考自&#xff1a; 《On Java 中文版》 边界 在泛型中&#xff0c;边界的作用是&#xff1a;在参数类型上增加限制。这么做可以强制执行应用泛型的类型规则&#xff0c;但还有一个更重要的潜在效果…

IntelliJ IDEA 16创建Web项目

首先要理解一个概念&#xff1a;在IntelliJ IDEA中“new Project”相当于eclipse中的工作空间&#xff08;Workspace&#xff09;&#xff0c;而“new Module”相当于eclipse中的工程&#xff08;Project&#xff09;。以下均采用Intellij的说法&#xff0c;请自行对照转换理解…