关于我这几天去哪了,在写一个水面的shader,再加上最近公司事情多,就耽搁了。在网上分析了好几种水面的shader,最后发现大体上就两种,下面就来分析这两种shader。

镜面shader一,利用两个Pass渲染出物体本身及倒影

这类型的shader包括两部分:
1、需要被倒影的物体本身,我命名为MirrorShader
2、被投射的水面shader,我命名为waterShader

Shader "ShaderPath/MirrorShader"//shader的选择路径
{Properties//该Shader可控的属性{_PlaneNormal("地面旋转角度",Vector) = (0,0,0,0) //地面法线_PlanePosition("地面位置",Vector) = (0,0,0,0)  //地面位置_GradientTex("GradientTex", 2D) = "white" {}//渐变贴图_DiffuseColor("DiffuseColor",Color) = (1,1,1,1)//漫反射的主色调_SpecularColor("SpecularColor",Color) = (1,1,1,1)//高光反射的主色调_Gloss("Gloss",Range(1,100)) = 2 //光泽度(反光度) 控制高光区域的大小 _MirrorRange("MirrorRange", Range(0, 1)) = 1  // 镜面范围(最大范围,超出该范围就不反射)_MirrorAlpha("MirrorAlpha", Range(0, 1)) = 1  // 镜面图像不透明度_MirrorFadeAlpha("_MirrorFadeAlpha", Range(0,1)) = 0.5  // 镜面范围值边缘位置的不透明度,如果调整为0,意思越接近该最大范围的透明就越接近该值:0}//先用CGINCLUDE  ENDCG包裹起来片元顶点着色器,后面看比较直观CGINCLUDE#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata {float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;};//镜像片元结构体struct v2f_m {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float4 normal : TEXCOORD1;float4 wPos : TEXCOORD2;float3 lightDir : TEXCOORD3;float3 viewDir : TEXCOORD4;};//主体片元结构体struct v2f{float3 lightDir : TEXCOORD0;float3 viewDir : TEXCOORD1;float3 normal : TEXCOORD2;float2 uv : TEXCOORD3;//用于存储纹理信息float4 pos : SV_POSITION;//每个片元结构体必须有的};float4 _PlaneNormal;float4 _PlanePosition;sampler2D _GradientTex;float4 _GradientTex_ST;//图片的(平铺和偏移系数)如果要使图片的Tilling和Offset生效就必须定义fixed4 _DiffuseColor;fixed4 _SpecularColor;float _Gloss;float _MirrorRange;float _MirrorAlpha;float _MirrorFadeAlpha;v2f vert(appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//把顶点从模型空间转换到剪裁空间o.uv = TRANSFORM_TEX(v.uv, _GradientTex);//使图片对应的_ST生效,这里就是_GradientTex_ST//要区分UnityWorldSpaceLightDir()传入一个float3的世界坐标 和 WorldSpaceLightDir()传入一个float4的模型的顶点坐标//UnityWorldSpaceViewDir()传入一个float3的世界坐标 WorldSpaceViewDir()传入一个float4的模型的顶点坐标o.lightDir = WorldSpaceLightDir(v.vertex);//获取世界坐标下的光线方向o.viewDir = WorldSpaceViewDir(v.vertex);//获取世界坐标下的观察方向o.normal = normalize(UnityObjectToWorldNormal(v.normal));//将模型的法线转到世界坐标return o;}fixed4 frag(v2f i) : SV_Target//返回一个RGBA到模型上{fixed3 lightDir = normalize(i.lightDir);//归一化fixed3 viewDir = normalize(i.viewDir);//归一化//半罗伯特反射fixed halfLambert = (1 + dot(lightDir,i.normal)) / 2;fixed3 gradient = tex2D(_GradientTex,fixed2(halfLambert + i.uv.x,0)).rgb * _DiffuseColor;//采样_GradientTex里的颜色信息fixed3 diffuse = _LightColor0 * gradient;//Blinn-Phong模型高光 fixed3 halfView = normalize(lightDir + viewDir);fixed3 specular = _LightColor0.rgb * _SpecularColor * pow(saturate(dot(i.normal,halfView)),_Gloss);return fixed4(diffuse + specular,1);}//镜像定点着色器v2f_m Mirrorvert(appdata v){v2f_m o;o.wPos = mul(unity_ObjectToWorld, v.vertex);float3 nn = -_PlaneNormal.xyz;                 // 地面法线反向,镜像的物体要用float3 dp = o.wPos.xyz - _PlanePosition.xyz;     // 平面点与世界空间的点的向量(即:从平面的点指向世界空间点的方向)half nd = dot(_PlaneNormal.xyz, dp);           // 计算出点与平面的垂直距离o.wPos.xyz += nn * (nd * 2);    // 将垂直距离反向2倍的距离,就是镜像的位置o.pos = mul(unity_MatrixVP, o.wPos); //计算模型当前视图的投影点,更多表查看下面的“UnityShader部分常用内置矩阵表”o.normal.xyz = UnityObjectToWorldNormal(v.normal);fixed t = nd / _MirrorRange;       // 将位置与镜面最大范围比利作为fade alpha的插值系数fixed a = lerp(_MirrorAlpha, _MirrorAlpha * _MirrorFadeAlpha, t);o.normal.w = a;     // 透明度我们存于o.normal.wo.wPos.w = nd;      // 距离存于o.wPos.wo.uv = v.uv;o.lightDir = WorldSpaceLightDir(v.vertex);//获取世界坐标下的光线方向o.viewDir = WorldSpaceViewDir(v.vertex);//获取世界坐标下的观察方向return o;}fixed4 Mirrorfrag(v2f_m i) : SV_Target//返回一个RGBA到模型上{if (i.wPos.w > _MirrorRange) discard;       // 超过镜像范围也丢弃if (i.normal.w <= 0) discard;               // 透明度为0丢弃float3 dir = i.wPos.xyz - _PlaneNormal.xyz; // 平面与插值点的指向half d = dot(dir, _PlaneNormal.xyz);        // 与反向镜面的距离if (d > 0) discard;                         // 如果超过了平面,那就丢弃fixed3 lightDir = normalize(i.lightDir);//归一化fixed3 viewDir = normalize(i.viewDir);//归一化//半罗伯特反射fixed halfLambert = (1 + dot(lightDir,i.normal)) / 2;//fixed2(halfLambert+i.uv.x,0) x的值必须如上,具体解释看下面,y的值任意,因为图片的颜色值不随y的变化而变化fixed3 gradient = tex2D(_GradientTex,fixed2(halfLambert + i.uv.x,0)).rgb * _DiffuseColor;//采样_GradientTex里的颜色信息fixed3 diffuse = _LightColor0 * gradient;fixed3 halfView = normalize(lightDir + viewDir);fixed3 specular = _LightColor0.rgb * _SpecularColor * pow(saturate(dot(i.normal,halfView)),_Gloss);return fixed4(diffuse + specular , i.normal.w);}ENDCGSubShader//子着色器{Pass{Tags {"LightMode" = "ForwardBase"} //定义该Pass在Unity光照流水线中的角色CGPROGRAM#pragma vertex vert#pragma fragment fragENDCG}Pass{Tags { "Queue" = "Geometry" "RenderType" = "Opaque" }Cull Front //镜像里正反颠倒,此时应该剪裁掉正面ZTest Always //这里必须保持深度测试通过,否则会被水面挡住Blend SrcAlpha OneMinusSrcAlpha //渲染的叠加方式Stencil {Ref 1Comp Equal}Tags {"LightMode" = "ForwardBase"} //与ENDCG相照应,将CG代码包裹CGPROGRAM//顶点函数定义#pragma vertex Mirrorvert  //片元函数定义#pragma fragment MirrorfragENDCG}}
}
// jave.lin 2019.08.15
Shader "ShaderPath/WaterShader"
{Properties{_MainTex ("Texture", 2D) = "white" {}_Color ("Color", Color) = (1,1,1,1)}SubShader{Tags { "Queue"="Geometry" "RenderType"="Opaque" }ZWrite OnStencil {Ref 1Comp AlwaysPass Replace}Pass {CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata {float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f {float4 vertex : SV_POSITION;float2 uv : TEXCOORD0;};sampler2D _MainTex;float4 _MainTex_ST;fixed4 _Color;v2f vert (appdata v) {v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target {fixed4 col = tex2D(_MainTex, i.uv);return col * _Color;}ENDCG}}
}

效果如下如

UnityShader部分常用内置矩阵表

核心代码详解
1、下面这段代码是镜像呈现的核心代码

     float3 nn = -normal;                 // 法线反向float3 dp = o.wPos.xyz - _PlanePosition.xyz;     // 平面点与世界空间的点的向量(即:从平面的点指向世界空间点的方向)half nd = dot(normal, dp);           // 计算出点与平面的垂直距离o.wPos.xyz += nn * (nd * 2);    // 将垂直距离反向2倍的距离,就是镜像的位置

如下图所示,
平面过点O的法线为normal,
P为模型上的点,P’为镜像点,
dp为向量OP,
|nd| = normal·dp = |normal|·|dp| cosθ = |dp|cosθ
PS:normal为单位向量,θ为normal、dp的夹角
P’ = -normal * (2 * nd )

2、关于模板测试
在MirrorShader和WaterShader里面都有关于模板测试的东西

MirrorShader中
Stencil
{Ref 1Comp Equal
}
WaterShader中
Stencil
{Ref 1Comp AlwaysPass Replace
}

上面两个模板合起来解释就是:
1、在物体上渲染出来的投影设置模板参照值(Ref)为1,并且只要模板参考值相同的就通过模板测试;
2、水面的模板参照值为1,模板测试一律通过,并且只要通过了模板测试和深度测试的像素就直接显示出来
3、总结就是物体倒影和水面的模板参照值相同,并且物体倒影的深度测试也通过,所以物体的倒影能在水面显示

关于模板测试更多的知识查看该链接

PS,注意文中的深度写入,另一个水面在下一篇文章中叙述,不然篇幅太长。

UnityShader_倒影,水波倒影(1)相关推荐

  1. UnityShader_倒影,水波倒影(代码已更新)(2)

    相较于上一个水波倒影,这个水波倒影要更为复杂,但也更为真实,大体思路如下 利用脚本抓取水面的镜像,并在Shader中进行处理 先上个Gif解解馋,代码后面整理好再上传,最近实在事情多,早上优化到晚上的 ...

  2. 教你使用MATLAB制作水波倒影特效

    注: 本文算法参考大佬 grafx 的这篇博客: 图像处理算法之水面倒影特效 由于本文使用MATLAB复现,因此很多语法上会显得比较简洁,同时本博文对原大佬文章部分内容进行了改写,详见本文: 0效果展 ...

  3. HTML里面设置文本倒影,文字倒影怎么做

    现在的文字如果仅仅是在一个平面上,不加任何效果,那就真的是太死板.太单调了,尤其追求艺术的小伙伴们啊,细心的话你就会发现那些神马广告之类的文字都讲究有个性,让人过目不忘的效果,有木有!那么接下来就教大 ...

  4. android textview 文字倒影,textview 倒影

    场景:制造TextView的倒影 制作TextView的倒影 package com.javaeye.graphics; import android.app.Activity; import and ...

  5. CSS3蒙版/遮罩、倒影

    蒙版/遮罩mask 很简单的一个属性,并不是PS里面的那个蒙版 蒙版目前只有-webkit-内核的浏览器支持(谷歌.Safari.新欧朋opera),其他不支持 需要png的透明度遮罩 -webkit ...

  6. html 字体显示倒影,用CSS3的box-reflect设置文字倒影效果的方法讲解

    语法: CSS Code复制内容到剪贴板 box-reflect:none|  ? ? =above|below|left|rightright =  | =none|  |  |  |  | 默认值 ...

  7. css原地颠倒 h5_H5案例分享:CSS3 reflect倒影

    CSS3 reflect倒影 说起倒影效果,在传统网页中,我们只能使用photoshop事先将倒影设计好,然后导入到网页中,这样不但耗费资源,也阻碍了开发的效率.而现在CSS3有一个属性box-ref ...

  8. Qt 渐变(二): 线性渐变与合成模式实现倒影

    文章目录 1.Qt 渐变(二): 线性渐变与合成模式一起,实现倒影 ReflectionPanel.h ReflectionPanel.cpp 1.Qt 渐变(二): 线性渐变与合成模式一起,实现倒影 ...

  9. UnityShader_泳池实现

    实现思路: 1.实现水面抖动: ①利用顶点偏移实现水面的上下波动: ②对Unity自带的CustomRenderTextureUpdateZone生成波纹贴图,并采样实现水纹 2.水面的实现: ①水面 ...

最新文章

  1. Nginx 虚拟主机配置及负载均衡
  2. 【错误记录】MAC 存储空间 “其它“ 内容清理
  3. bash 脚本中激活conda环境_ubuntu18.10目标检测算法环境部署+开机自启动脚本创建screen下的web服务...
  4. php基础不好,基础不好,问个php类调用的初级问题
  5. 我们处理了10亿个Java记录的错误-这是导致97%的错误的原因
  6. mysql group by null_MySQL无GROUP BY直接HAVING返回空的问题分析
  7. 三七互娱李逸飞:未来将关注元宇宙等新业态 创新构建核心优势
  8. 安全测试===sqlmap(壹)转载
  9. ipv6详解_modbus之libmodbus库详解
  10. efs解密-Advanced EFS Data Recovery2.1-含注册KEY
  11. 忘记 Apple Watch PIN 码,如何解锁 Apple Watch?
  12. Jlink 下安装JLINK驱动
  13. 机器学习导论(五)-神经元网络
  14. 服务器进pe iso安装系统教程,iso系统怎么安装( pe怎么安装iso原版镜像)
  15. Golang 标准库 tips之waitgroup详解
  16. 【JY】STKO助力OpenSEES系列:结构模态分析以及动力特性(MDOF与等效SDOF验证)
  17. Confusing Problem
  18. NYOJ-234-DP(吃土豆)
  19. 【ASP.NET MVC系列】浅谈Google Chrome浏览器(操作篇)(上)
  20. VMware虚拟机无网络

热门文章

  1. 当前的最好的伪原创工具技术
  2. html5鼠标事件监听,HTML5 Canvas鼠标与键盘事件
  3. kettle 作业中javascript输出
  4. nacos配置mysql8
  5. 纯css3 svg 波浪底纹
  6. 【已解决】Appium+Java控制真机(小米12X),运行Appium Inspector或Java测试脚本时报错Error executing adbExec
  7. 以太坊solidity迁移flow cadence指南11 ---NFT盲盒应用
  8. python-回文数判断
  9. 基于AI的5G技术-研究方向与范例-学习笔记
  10. ubuntu系统安装MATLAB2020a