顶点程序经典案例——树木生长
树木生长Shader
一、介绍
大家好,我是阿赵。这次来做一个树木生长的Shader。
顶点程序作为整个渲染管线里面和片段程序并列的两大可控过程之一,一直存在感都比较低。我们平时制作的效果,很多都是在片段程序里面实现的计算,顶点程序一般只是用来计算一下坐标系转换。
这次介绍的树木生长shader,我个人感觉是顶点程序的一个比较经典的应用,通过控制模型的顶点,做出一棵树的生长动画,还是比较有意思的。
另外一个知识点,就是黑白遮罩的运用。在深入学习各种效果的Shader编写之后,会发现很多效果的计算基础,都是模型不同部位的黑白颜色分布的计算。比如说透明度的计算,黑透白不透,比如边缘光的计算,边缘计算出白色,内部计算出黑色,等。
这个例子里面,黑白色控制了顶点是否显示,控制了树木生长的边缘,控制了刚长出来的部分的颜色,诸如此类。如果明白了黑白关系,在编写Shader的道路上,可以说是跨进了一大步。
其实我知道我在一开始写这么多废话,一般也不会有人看的。所以还是快点说制作过程吧。完整Shader在最后面。
二、制作过程说明
1、准备工作:
看到上面的视频,可能有些朋友会说,是不是直接在3DsMax里面做一段动画,然后直接在Unity里面播放呢?
其实不是的。我这里只在3DsMax里面准备了一棵树的模型,它包括了树干和树叶2个部分。

把模型导出fbx然后导入Unity后,把贴图附上,会看到这个模型的效果如下,并没有任何的动画。

地面是为了好看我随便找了一张贴图赋予了一个地面,这个不重要,我们只要关系树干和树叶就行了。
2、展UV
先说一下,为什么树木能实现生长的效果。
为了让树木能从根部到顶部,再到树叶逐渐的出现,我必须找到一个信息,是从树木根部一直到叶子渐变的。为了看得比较清晰,我先把叶子隐藏了,单纯用树干来做说明。

这种信息可以有很多,举个例子:
1.顶点颜色
2.UV坐标
3.贴图颜色
4.顶点坐标
等
通过这些手段,理论上都能实现到这种渐变的效果。但顶点坐标只能是从上到下,或者从左到右之类线性的控制,这里的树枝有可能是横向纵向甚至是拐弯的,所以并不适合用顶点坐标来做。所以我们可以在顶点颜色、UV坐标、贴图颜色这些数据里面选择一种比较容易实现的来做,都无所谓。
我这里选择的是UV坐标。
由于模型已经有了UV1信息用于漫反射贴图的UV坐标计算了。所以我要展一个UV2。

展完之后的UV2大概是这个样子的,我使用了uv的u坐标,从左往右在0-1的区间渐变。
把展好UV后的模型导入到Unity,然后单独显示一下我们需要的坐标看看。
3、检查UV信息显示
这里插一个知识点,介绍一下怎么单独去看模型的某个数据。
比如我现在要看UV2的信息,我可以在顶点程序里面先读取了uv2信息传入到片段程序,然后在最后的输出时
return half4(i.uv2.xxx,1);
这样,就可以单独把我们需要的信息当做颜色显示出来。
我这里的UV2的u坐标信息,显示完是这样的:

可以看到,现在树干从根部到树枝,是有一个由黑到白的渐变。
如果我想把颜色反过来,根部是白色,树枝是黑色,可以这样:
float val = 1- i.uv2.x
return half4(val.xxx,1);
这样,就能得到了之前显示的那个渐变效果了:

4、控制黑白渐变的过程
上面的黑白渐变图,发现有一个问题,就是黑白渐变的区域太大了,我们想做树木生长,一般是需要有一个比较明显的黑白分割线过渡的。
为了实现过渡范围的控制,可以使用smoothstep方法来控制:
float v2Val = 1 - v.uv2.x;
float heightVal = saturate(v2Val + _height);
float growVal = smoothstep(_min, _max, heightVal);
还是那个规则,黑的地方不显示,白的地方显示,所以就可以得到下面这个效果,可以看看黑白范围和最后显示效果的对比:




5、根据法线方向做树枝大小缩放
树木的生长并不是圆柱形生长出来,而是生长出来的地方是尖的,长出一段距离之后才慢慢变粗。
这个效果实现起来不难,还是刚才的黑白图过渡部分,我们可以使用黑白关系,然后加上模型顶点法线的方向,来做一个顶点沿着法线方向的缩放。
由于模型显示的过渡范围和变尖的过渡范围可能不一致,所以虽然都是用smoothstep来控制范围,但min和max的值可以不一样。
float v2Val = 1 - v.uv2.x;
float heightVal = saturate(v2Val + _height);
float growVal = smoothstep(_min, _max, heightVal);
heightVal = smoothstep(_endMin, _endMax, heightVal);


6、生长颜色的变化
最后,我还想实现一种效果,在树木刚长出来的时候,颜色是比较浅的,然后到了生长完成的时候,颜色会变深:


为了实现这种效果,我继续利用了刚才的黑白渐变过渡的信息,给他叠加一个颜色:
half3 diffuseCol = (1 - i.growVal)*_growCol + col.rgb;
这样在过渡的部分,就会乘以一个growCol,在生长完成之后,就纯是漫反射贴图的颜色。
7、树叶部分
其实刚才我们已经把整个shader做完了。树叶的部分,实际上不需要额外写shader去实现,因为展UV的时候,树叶也是根据出现的先后顺序,展UV在树枝的后面的。

这里我比较的偷懒,把相同形状的树叶的UV展在了一起了,所以实际出现的效果,就是同样形状的树叶会一起长出来。如果想效果更真实有点,可以根据整棵树的树枝生长先后顺序,来排列这些树叶的UV2.


三、完整shader
Shader "azhao/TreeGrow"
{Properties{_MainTex("Texture", 2D) = "white" {}_AlphaMap("AlphaMap", 2D) = "white" {}_height("height", Range(-1 , 1)) = 0_min("min", Range(0 , 1)) = 0_max("max", Range(0 , 1)) = 1_endMin("endMin", Range(0 , 1)) = 0_endMax("endMax", Range(0 , 1)) = 1_growCol("growCol", Color) = (0,1,0,0) }SubShader{cull offTags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float2 uv2 : TEXCOORD1;float3 normal:NORMAL;};struct v2f{float4 vertex : SV_POSITION;float2 uv : TEXCOORD0;float2 uv2 : TEXCOORD1;float growVal : TEXCOORD2;};uniform float _min;uniform float _max;uniform float _height;uniform float _endMin;uniform float _endMax;uniform sampler2D _MainTex;uniform float4 _MainTex_ST;uniform float4 _growCol;uniform sampler2D _AlphaMap;v2f vert (appdata v){v2f o; o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.uv2 = v.uv2;float v2Val = 1 - v.uv2.x;float heightVal = saturate(v2Val + _height);float growVal = smoothstep(_min, _max, heightVal);heightVal = smoothstep(_endMin, _endMax, heightVal);heightVal = max(heightVal, growVal);float3 offsetVal = v.normal*heightVal - v.normal;o.vertex = UnityObjectToClipPos(v.vertex+ float4(offsetVal,1));o.growVal = growVal;return o;}half4 frag (v2f i) : SV_Target{half4 col = tex2D(_MainTex, i.uv);half3 diffuseCol = (1 - i.growVal)*_growCol + col.rgb;half4 alphaCol = tex2D(_AlphaMap, i.uv);float alpha = alphaCol.r*i.growVal;clip(alpha - 0.5);return half4(diffuseCol,alpha);}ENDCG}}
}
相关文章:
顶点程序经典案例——树木生长
树木生长Shader一、介绍 大家好,我是阿赵。这次来做一个树木生长的Shader。 顶点程序作为整个渲染管线里面和片段程序并列的两大可控过程之一,一直存在感都比较低。我们平时制作的效果,很多都是在片段程序里面实现的计算,顶点程序…...
在云计算环境下保护Java应用程序的有效措施
云计算(Cloud)技术是近年来计算机科学的一个重要突破。大多数组织已经通过将自己的应用程序移入云平台而获益。不过,如何保证应用程序在第三方服务器上的安全性,是一项艰巨的挑战。 在本文中,我们将重点讨论Java&…...
vscode-markdown-代码片段及快捷键设置
代码片段及快捷键设置 主要为了插入表格和图片标签节约一点输入时间 代码片段设置 ctrlshiftp 打开面板输入 configure user snippets选择markdowncopy如下设置放入{}中 "tb4*4": {"prefix": "tb4*4","body": ["| $1 | $2 | $…...
ModelNet40数据集
跑PointNet,modelnet40数据集时; 有些人直接用.off文件;——【CAD模型】普林斯顿形状Banchmark中的.off文件遵循以下标准: OFF文件全是以OFF关键字开始的ASCII文件。下一行说明顶点的数量、面片的数量、边的数量。 边的数量可以安全地省略。对模型不会有影响(可以为…...
【都2023年了,还在问网络安全怎么入门】
前言 【都2023年了,还在问网络安全怎么入门】所以这一期就出一一个怎么学习网络安全的学习路线和方法,觉得有用的话点赞收藏下 首先咱们聊聊,学习网络安全方向通常会有哪些问题 1、打基础时间太长 学基础花费很长时间,光语言都有…...
Apple Xcode 14.3 (14E222b) 正式版发布下载
Command Line Tools for Xcode 14, tvOS 16 & watchOS 9 Simulator Runtime 请访问原文链接:https://sysin.org/blog/apple-xcode-14/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org Xcode 14 包含了在所有 Ap…...
【Linux】sar常用选项介绍
sar 使用 安装sysstat apt-get install sysstat -y #或 yum install sysstat -y选项 用法: sar [ 选项 ] [ <时间间隔> [ <次数> ] ] 选项: [ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F [ MOUNT ] ] [ -H ] [ -h ] [ -p ] [ -q ] [ -r [ ALL ] ]…...
PHP 单笔转账到支付宝账户,支付宝公钥证书实现版本
支付宝某些业务只能使用公钥证书方式来验签 如:即使转账 红包等 笔者就要实现这样一个功能,【单笔转账到支付宝账户】,采用支付宝公钥证书签名来实现。 话不多说,流程先走起 第一步:下载支付宝秘钥生成器 由于我们使…...
第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 E 题
颜色平衡树问题描述格式输入格式输出样例输入样例输出评测用例规模与约定解析参考程序问题描述 格式输入 输入的第一行包含一个整数 n ,表示树的结点数。 接下来 n 行,每行包含两个整数 Ci , Fi,用一个空格分隔,表示第 i 个结点 …...
Python 小型项目大全 21~25
二十一、DNA 可视化 原文:http://inventwithpython.com/bigbookpython/project21.html 脱氧核糖核酸是一种微小的分子,存在于我们身体的每个细胞中,包含着我们身体如何生长的蓝图。它看起来像一对核苷酸分子的双螺旋结构:鸟嘌呤、…...
MinIO从信息泄漏到RCE
文章目录信息泄露漏洞利用漏洞分析漏洞修复RCE漏洞分析参考文章信息泄露 漏洞利用 如果MinIO以集群方式部署,存在信息泄露漏洞,攻击者可以通过HTTP请求获取目标进程的所有环境变量,包括MINIO_SECRET_KEY和MINIO_ROOT_PASSWORD. vulhub有环…...
202.Spark(九):SparkStreaming案例实操
目录 一、启动zookeeper,kafka基础环境 二、项目导好jar包,并且创建源数据,并在kafka中测试能否消费到数据...
GlusterFS(GFS)分布式文件系统
目录 一.文件系统简介 1.文件系统的组成 2.文件系统的作用 3.文件系统的挂载使用 二.GlusterFS概述 1.GlusterFS是什么? 2.GlusterFS的特点 3.GlusterFS术语介绍 3.1 Brick(存储块) 3.2 Volume(逻辑卷) 3.3…...
ChatGPT文本框再次升级,打造出新型操作系统
在ChatGPT到来之前,没有谁能够预见。但是,它最终还是来了,并引起了不小的轰动,甚至有可能颠覆整个行业。 从某种程度上说,ChatGPT可能是历史上增长最快的应用程序,仅在两个多月就拥有了1亿多活跃用户&…...
DPU02国产USB转UART控制芯片替代CP2102
目录DPU02简介DPU02芯片特性应用DPU02简介 DPU02是高度集成的USB转UART的桥接控制芯片,该芯片为RS-232设计更新为USB设计,并简化PCB组件空间提供了一个简单的解决方案。 DPU02包括了一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带…...
Softing新版HART多路复用器软件支持西门子控制器
用于访问配置和诊断数据的HART多路复用器软件——Softing smartLink SW-HT,现在支持西门子的ET200远程IO和FDT/DTM接口。 smartLink SW-HT是一个基于Docker容器的软件应用。通过该软件,用户可以快速地访问以太网远程IO的HART设备,并且无需额外…...
〖Python网络爬虫实战⑫〗- XPATH语法介绍
订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 说明:本专栏持续更新中,目前专栏免费订阅,在转为付费专栏前订阅本专栏的,可以免费订阅付费…...
实例方法、类方法、静态方法、实例属性、类属性
背景:今天在复习类相关知识的时候,突然想到这几种类型的方法的区别和用法,感觉有点模棱两可,于是总结一下,加深记忆。 定义:想要区别和理解几种方法,首先要定义一个类,要在类中加深…...
数据结构---二叉树
专栏:数据结构 个人主页:HaiFan. 专栏简介:这里是HaiFan.的数据结构专栏,今天的内容是二叉树。 二叉树树的概念及结构二叉树概念及结构二叉树的概念二叉树的存储结构二叉树的顺序结构及实现大根堆和小根堆堆的实现及其各个接口堆的…...
CMake——从入门到百公里加速6.7s
目录 一、前言 二、HelloWorld 三、CMAKE 界面 3.1 gui正则表达式 3.2 GUI构建 四 关键字 4.1 add_library 4.2 add_subdirectory 4.3 add_executable 4.4 aux_source_directory 4.5 SET设置变量 4.6 INSTALL安装 4.7 ADD_LIBRARY 4.8 SET_TARGET_PROPERTIES 4.9…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
