【unity shader】水体渲染基础-基于texture distortion的流体流动材质

这篇具有很好参考价值的文章主要介绍了【unity shader】水体渲染基础-基于texture distortion的流体流动材质。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.基于uv的texture distortion

当液体静止时,它在视觉上与固体没有太大区别。 但大多数时候,我们的性能不一定支持去实现特别复杂的水物理模拟, 需要的只是在常规的静态材料的表面上让其运动起来。我们可以对网格的 UV 坐标实现动态变化,从而让表面的纹理效果实现变形的动态变化。

1.1. uv实时变化

我们直接生成一个默认unlit shader,然后赋予其对应的纹理图片,并且写入随时间变化的uv更新函数。

//in frag shader
i.uv += _Time.y;

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
为了实现随机方向的uv变化,我们这里引入一张指示流动方向的贴图。

float2 flowDir = tex2D(_FlowMap, i.uv);
i.uv += _Time.y * flowDir;

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
可以看到随着时间推移,出现了uv挤压过度的情况,我们这里可以直接用一个frac或者正弦函数来限制uv随时间的变化范围。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
tilling为4显得纹理太小了,我们把tilling调整回1。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
但是在进行实时变形的过程中,纹理会完全恢复到未变形的状态,还是有点过于奇怪,我们通过对三角函数进行缩放和位移,使纹理一直保持在变形的状态。

//即使得时间参数一直为正数
i.uv += (sin(_Time.y)/2.0 + 1.0) * flowDir;

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
当我们使用frac函数来对time进行限制的时候,就会出现突然抖动,一跳又变成了平整的未变形纹理的情况。这是由于frac本身会带来取值从1-0的非连续变化带来的。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

1.2. 实现循环衔接

既然frac函数存在不连续的问题,我们就得想办法掩盖一下(或者直接换成sin函数)。掩盖的办法就是通过黑色的淡入淡出,来掩盖住发生纹理颜色跳跃的瞬间。
即在frac的极大值和极小值时,都需要是黑色,且其需要在原有的周期内,实现从最小值到最大值的变化,再由最大值变为最小值,周期缩短一半(橙色线条)。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

///flowDir 命名时改为Float3,但其实这边单独设一个小数也可以的
flowDir.z = 1.0 - abs(1.0 - 2* time_fac);
fixed4 col = tex2D(_MainTex, i.uv) * flowDir.z;

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
为了让贴图的变形更多样化,增加信息量,我们引入相关的噪音,放入到flowmap中作为a通道。从a通道中采样noise信息,混入时间计算当中。

float3 flowDir;
flowDir.xy = tex2D(_FlowMap, i.uv).rg;
float noise = tex2D(_FlowMap, i.uv).a;

float time_fac = frac(_Time.y + noise);

flowDir.z = 1.0 - abs(1.0 - 2* time_fac);
i.uv += time_fac * flowDir;

fixed4 col = tex2D(_MainTex, i.uv) * flowDir.z;

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
由于噪音的混入,使得渐变的黑色也能像波纹一样扩散。且本身引入噪音后,即便是不适用黑色进行渐入,非连续跳跃的问题也得到了有效缓解。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

1.3. 混合纹理变形

当然通过黑色来进行淡入淡出,还是略显突兀一些,最好的方案肯定还是两种不同变形的纹理进行混合,通过权重进行区分。最好是当其中一个纹理的uv偏移为0时,另一个纹理的uv偏移为1,以确保能够全时刻都处在变形的状态。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

首先我们要将原本放在frag shader里面计算uv偏移的部分打包成一个函数:
输入是变形前的uv,变形方向(采样自flowmap),时间参数和用于判断是否为第二个混合纹理的布尔参数。
返回值是三位浮点数,uvw,对应偏移后的uv以及对应的可见度参数。

float3 flowUVW(float2 uv, float2 flowVec, float3 time, bool Btag)
{
	//period对应偏移周期
	float phaseOffset = Btag? _Period: 0 ;
	time += phaseOffset;
	float3 uvw;
	uvw.xy = uv + time * flowVec;
	uvw.z = 1.0 - abs(1.0 - 2* time);
	return uvw;
}

//in frag shader
float2 flowVec;
flowVec = tex2D(_FlowMap, i.uv).rg;
float noise = tex2D(_FlowMap, i.uv).a;
float time_fac = frac(_Time.y + noise);

float3 uvwA = flowUVW(i.uv, flowVec, time_fac, false);
float3 uvwB = flowUVW(i.uv, flowVec, time_fac, true);

fixed4 colA = tex2D(_MainTex, uvwA.xy) * uvwA.z;
fixed4 colB = tex2D(_MainTex, uvwB.xy) * uvwB.z;

fixed4 col = colA + colB;

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
会出现黑色区域过多的问题,目测是因为uvw的z值没有处理好,并没有做好严格的偏移1/2个周期,导致累加的效果有问题。所以我们这里需要换成:

fixed4 colA = tex2D(_MainTex, uvwA.xy) * uvwA.z;
fixed4 colB = tex2D(_MainTex, uvwB.xy) * (1 - uvwA.z);

确保两个权重相加为1,调整后黑波纹的效果改善了。
当然这里也可以对time += phaseOffset做调整,传入前的时间参数不再进行取小数,而改用frac函数处理传入后的值,能够实现一样的效果。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
在计算uv时,为更好表现两个uv的偏移程度,最好在uv初始化时也加入偏移值。

//in flowUVW function
uvw.xy = uv + time * flowVec + phaseOffset ;

1.4.通过uv jumping调整循环的周期

目前来说,我们的uv动画的周期,完全取决于_Time.y的固定周期。若是我们想要自定义地去调整uv动画的周期,则需要人为地添加相应的变量。
这里我们引入了jump参数,一个二维浮点数变量。
我们可以分别定义jump参数在u方向,v方向上的数值,通过这两个数值来控制循环周期。

_UJump ("u direction jump para", Range(-0.25, 0.25)) = 0.25
_VJump ("v direction jump para", Range(-0.25, 0.25)) = 0.25

//in frag shader
float2 jump = float2(_UJump, _VJump);

在flowUVW,我们新传入入jump参数,在初始化uvw的xy值后,通过jump参数对uvw.xy做一个叠加。

float3 flowUVW_jump(float2 uv, float2 flowVec, float2 jump, float3 time, bool Btag){
    float phaseOffset = Btag? _Period: 0 ;
    float progress = frac(time + phaseOffset);
    
    float3 uvw;
    uvw.xy = uv + progress * flowVec + phaseOffset;
    uvw.xy +=  (time - progress) * jump ;
    uvw.z = 1.0 - abs(1.0 - 2* progress);
    return uvw;
}

//in frag shader
float time_fac = _Time.y + noise;
float2 jump = float2(_UJump, _VJump);

float3 uvwA = flowUVW_jump(i.uv, flowVec, jump, time_fac, false);
float3 uvwB = flowUVW_jump(i.uv, flowVec, jump, time_fac, true);

可知我们得uv值的初始值是固定的,随着时间的变化,time值(即_Time.y + noise的值)逐渐增大,uvw.xy的值最终会以(time - progress) * jump为周期稳定循环,最终实现uv动画的可控周期。

在使得flowVec 为(0,0)时,我们能够比较明显地比较jump参数带来的周期差异:
左边是使用了jump为(0.25, 0)时的uv动画,右边为仅使用flowUVW的uv动画。unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2. 为uv动画添加其他参数

2.1. Tilling

用于调整贴图缩放的参数,典中典操作。

//in flowUVW
uvw.xy = uv + progress * flowVec + phaseOffset;
uvw.xy *= _Tilling;
//.....

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.2. 动画速度

显然这个是放到跟_Time.y乘在一起的,影响uv动画的速度。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.3. 变形/流动强度

通过设置相关参数,放大/缩小从a通道采样到的变形方向。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.4. 通过变形偏移控制uv动画的清晰度

目前来看,uv动画的清晰度多少有点捉鸡,这是由uv偏移程度,和当前纹理的权重决定的。
显然,当uvw.z=1时,当前计算的颜色越清晰。(无论是a颜色还是b颜色,只要有其中一方的uvw.z为1时,另一方则一定为0)
当uvw.z=1时, progress值为1/2。即time + phaseoffset值为xxxxxx.5。
所以我们需要在uvw.z=1的前提下,添加一个_FlowOffset,通过和progress相互抵消,去抹平相应的uv偏移,使得uv不受flowVec引入的各向异性变形的影响。

//in flowUVW, 
uvw.xy = uv + (progress + _FlowOffset) * flowVec + phaseOffset;
uvw.xy *= _Tilling;

使用_FlowOffset(左)和不使用_FlowOffset(右)的对比。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
当变形强度增大时,清晰化的效果会更明显。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.5. 替换颜色贴图

接下来我们使用真正的液体颜色贴图,以及对应的法线贴图。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
同样的,我们需要各自用uvwA和uvwB对变换后的法线贴图进行采样,并对采样后的法线和进行标准化。

//in frag shader
//前置步骤:计算TBN矩阵,传递TBN矩阵,获取worldPos,执行uvwA,uvwB的计算等
float4 packedBumpA = tex2D(_NormalTex, uvwA.xy);
float4 packedBumpB = tex2D(_NormalTex, uvwB.xy);

float3 tangentSpaceNormalA = UnpackNormalWithScale(packedBumpA, _BumpScale);
float3 tangentSpaceNormalB = UnpackNormalWithScale(packedBumpB, _BumpScale);

float3 worldNormalA = normalize(mul(tangent2World, tangentSpaceNormalA));
float3 worldNormalB = normalize(mul(tangent2World, tangentSpaceNormalB));
float3 worldNormal = normalize(worldNormalA + worldNormalB);
//后续步骤:bling-phong三部曲

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.6.尝试不同的噪音组合

我用SD也做了一点自制噪音贴图,主要是voronoi和bnw混合,以及voronoi和plasma混合,大家也可以自己做一些尝试。
如果是老版本的SD,没有voronoi节点的话,可以用tile generator加上distance来做一个简易的voronoi。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.7. 通过derivative map增加法线细节

由于图像压缩的机制,常规的法线贴图往往会有一定程度的细节丢失。derivative map主要是将法线的x,y方向的偏导数(即切线和副切线的部分值)存储在a,g通道,而不需要经过再次转换。
我们直接通过a,g通道的值组成两个切线,并通过叉乘的方式反求法线。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
同样的,我们写一个解包函数,把从图像中读取到的值恢复到(-1,1)的区间。

float3 UnpackDerivativeHeight(float4 textureData){
    float3 dh = textureData.agb;
    dh.xy = dh.xy * 2 - 1;
    return dh;
}

在片元着色器中,我们全部删掉切线空间转换相关的内容,但是需要保留worldPos来做光照计算。其余的换成综合两个采样的法线贴图求解worldNormal的部分。

注意这里和catlikecoding大佬的教程不同,由于derivative map展开的是沿z方向的法线在xy方向的偏导数,但是我们没有再去求TBN矩阵来做转换,而是直接使用相应的值。需要还原出来的法线是沿y方向的,所以需要调整下相应的组成分布来求解正确的法线方向。

//in frag shader
float3 dhA = UnpackDerivativeHeight(tex2D(_DerivHeightMap, uvwA.xy)) * uvwA.z;
float3 dhB = UnpackDerivativeHeight(tex2D(_DerivHeightMap, uvwB.xy)) * uvwB.z;

float2 worldNormalXY = -(dhA.xy + dhB.xy);
float3 worldNormal = normalize(float3(worldNormalXY.x, 1, worldNormalXY.y));
//正常计算bling-phong

右边为使用derivative map的uv流体动画。
unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图

2.8.控制浪高

通过增加可调的_HeightScale参数,影响采样后的权重计算。

float3 dhA = UnpackDerivativeHeight(tex2D(_DerivHeightMap, uvwA.xy)) * (uvwA.z * _HeightScale);
float3 dhB = UnpackDerivativeHeight(tex2D(_DerivHeightMap, uvwB.xy)) * (uvwB.z * _HeightScale);

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图
更近一步的,我们能够通过波流动速度来影响浪高。

float finalHeightScale = length(flowVec) * _Flow2HeightScale + _HeightScale;

float3 dhA = UnpackDerivativeHeight(tex2D(_DerivHeightMap, uvwA.xy)) * (uvwA.z * finalHeightScale);
float3 dhB = UnpackDerivativeHeight(tex2D(_DerivHeightMap, uvwB.xy)) * (uvwB.z * finalHeightScale);

unity流动渲染,unity之路,unity,游戏引擎,技术美术,着色器,材质,图形渲染,贴图文章来源地址https://www.toymoban.com/news/detail-779810.html

到了这里,关于【unity shader】水体渲染基础-基于texture distortion的流体流动材质的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity Shader】Unity前向渲染

    ForwardBase Pass(优先渲染),渲染一个逐像素平行光和所有的顶点/球面调和光,阴影只和平行光有关系,那阴影应该是这个Pass中实现的 ForwardAdd Pass(需要和Base配合使用,否则不生效),渲染剩余全部逐像素灯光 Unity会根据场景中各个光源的设置以及这些光源对物体的影响程

    2024年02月08日
    浏览(58)
  • Unity中Shader编译目标渲染器

    Unity中Shader编译到目标渲染器 #pragma only_renderers 仅编译指定平台的Shader d3d11 - Direct3D 11/12 glcore - OpenGL 3.x/4.x gles - OpenGL ES 2.0 gles3 - OpenGL ES 3.x metal - iOS/Mac Metal vulkan - Vulkan d3d11_9x - Direct3D 11 9.x功能级别,通常在WSA平台上使用 xboxone - Xbox One ps4 - PlayStation 4 psp2 - PlayStation Vita n3ds -

    2024年02月05日
    浏览(52)
  • Unity shader 入门之渲染管线一、总览

     如下示意图 应用阶段(ApplicationStage):准备场景信息(视景体,摄像机参数)、粗粒度剔除、定义每个模型的渲染命令(材质,shader)——由开发者定义,不做讨论。 几何阶段(GemetryStage):顶点着色器、曲面细分着色器、几何着色器、裁剪、屏幕映射; 光栅化阶段(Rasterizer

    2024年02月11日
    浏览(48)
  • 【Unity大气渲染】Unity Shader中实现大气散射(半成品)

    写在前面 这是之前在做天空盒的时候同步写的分析博客,结果后面写到一半就忘了继续了,这里先贴出当时写的半成品,有小伙伴问我怎么做的,这里只能尽力把之前的半成品先放出来了(写得很乱,勿怪orz),,后面有机会会完善好的!希望能帮到大家~ 前置知识学习 【

    2024年02月08日
    浏览(49)
  • unity build-in 渲染管线升级urp渲染 shader篇

            由于工作原因需要对项目进行升级,从build-in渲染管线升级到urp渲染管线,我自己对应的unity版本是2018.版本升级到2021.3.2版本,由于最近几年unity版本升级比较快,个体版本差异有所不同,如遇与版本不一致问题敬请谅解。以下是根据官网等系列网站整理的内容

    2023年04月16日
    浏览(59)
  • Unity大面积草地渲染——1、Shader控制一棵草的渲染

    目录 1、Shader控制一棵草的渲染 2、草地的动态交互 3、使用GPUInstancing渲染大面积的草 4、对大面积草地进行区域剔除和显示等级设置 大家好,我是阿赵。 这里开始讲大面积草地渲染的第一个部分,一棵草的渲染。按照惯例,完整shader在最后。前面是原理的介绍。 这里我自己

    2024年02月12日
    浏览(46)
  • Unity Shader从内置渲染管线迁移到URP

    Unity 在URP中将shader更新为了HLSL语言,使用build-in shader 无法直接在URP中使用 这里讲一下关于shader的更新方法 参考 From Built-in to URP Tags 添加 \\\"RenderPipeline\\\" = \\\"UniversalPipeline\\\" CGPROGRAM ENDCG 改变为 HLSLPROGRAM ENDHLSL #include \\\"UnityCG.cginc\\\" 更改为 #include \\\"Packages/com.unity.render-pipelines.universal/Sh

    2024年02月05日
    浏览(46)
  • Unity中的渲染优化技术 -- Shader入门精要学习(15)

    本章中,我们将阐述一些 Unity 中常见的优化技术。这些优化技术都是和渲染相关的,例如,使用批处理、LOD 技术等。 游戏优化不仅是程序员的工作,更需要美工人员在游戏的美术上进行一定的权衡。例如,避免使用全屏的屏幕特效,避免使用计算复杂的 Shader,减少透明混合

    2024年01月18日
    浏览(42)
  • Unity-Chan Toon Shader卡通渲染学习

    (本文记录一下从0-1复刻UTS2,持续更新中) Unity-Chan Toon Shader  2.0 (UTS2)  是一款用于图像和视频的卡通着色器,旨在满足从事卡通着色 3DCG 动画的创作者的需求。 UTS2开源项目地址: GitHub - unity3d-jp/UnityChanToonShaderVer2_Project: UnityChanToonShaderVer2 Project / v.2.0.9 Release (1)3 Bas

    2024年02月04日
    浏览(50)
  • Unity Shader 学习笔记(4)URP渲染管线带阴影PBR-Shader模板 -- 新增可自定义阴影颜色

    材质面板截图 功能实现(URP渲染管线下): 1、进一步优化Shader结构和算法; 2、包含PBR材质; 3、投射和接收阴影,并升级 支持自定义阴影颜色 ; 4、支持点光源照射(但不支持点光源阴影)。 通用渲染截图 自定义阴影颜色截图 完整代码: 写在最后: 1、在我的上一篇文

    2024年02月12日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包