700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Unity Shader - 实现类似镜面反射 水面扰动效果

Unity Shader - 实现类似镜面反射 水面扰动效果

时间:2018-09-20 07:58:29

相关推荐

Unity Shader - 实现类似镜面反射 水面扰动效果

前几天,家里出了一些问题,搞得心情很不好,面试我也取消了。

唉,反正那个伤心啊,不过,昨天处理好了。

所以说啊,家和万事兴。

加油加油!!!

所以心情好了,我又写博客了。

另外说一下:图形我今年.5才开始正式学习。

所以每个shader效果有些实现方法可能不是很好的,欢迎大神多多指点。

进入主题吧:

今天实现:Unity Shader - 实现类似镜面反射、水面扰动效果

Quad 效果

Cube 效果

思路

平面的过渡效果,可参考我之前写的一个,模型按平面渡效果:Unity Shader - 模型过滤效果

Noise 噪点实现类型水面可参考我之前写的:Unity Shader - Noise 噪点应用,实现类似流水的表面效果

模板缓存来只绘制镜面的内容:Unity Shader - 模板简单测试 - 实现镂空/遮罩、描边

上面两个效果组合,就差不多可以得到上面的效果了。

两个pass现实

第一个pass:绘制镜面模型

将模型的顶点按传进来的平面的法线、任一点,来对本体模型镜面顶点

这样再去绘制,就看起来又镜面的效果了

同时我们在镜像体绘制时,添加了纹理柏林噪点偏移UV,看起来有点像水流效果

但我们的镜面体的显示只能在那个地板模型中才绘制,所以我们给地板shader添加了Stencil处理(Stencil的功能实例看上面链接)

镜面详细讲解一下:

首先我们需要将镜面的法线、任意平面点传入shader(*.cs脚本:下面将法线、坐标传入shader我列出来)然后利用平面信息将顶点镜像处理,具体看下图

第二个pass:绘制本体模型

绘制模型本体

但需要处理,上面Unity Shader - 模型过滤效果 的过渡效果,因为超过镜面底下,我们就不显示了(可以按需求来处理)

然后再对纹理UV扰动想水流似的,基本就这样就完了

将法线、坐标传入shader

// jave.lin .08.15using System.Collections;using System.Collections.Generic;using UnityEngine;public class UpdateProps : MonoBehaviour{private static int nHash;private static int pHash;public GameObject obj;public GameObject plane;private Material objMat;// Start is called before the first frame updatevoid Start(){objMat = obj.GetComponent<MeshRenderer>().sharedMaterial;nHash = Shader.PropertyToID("n");pHash = Shader.PropertyToID("p");}// Update is called once per framevoid Update(){// n==normal of plane// p==position of planevar n = plane.transform.up;var p = plane.transform.position;objMat.SetVector(nHash, n);objMat.SetVector(pHash, p);}}

镜面的模板shader

// jave.lin .08.15Shader "Test/MirrorGroundStencil"{Properties{_MainTex ("Texture", 2D) = "white" {}_Color ("Color", Color) = (1,1,1,1)}SubShader{Tags {"Queue"="Geometry+1" "RenderType"="Opaque" }Stencil {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}}}

需要绘制镜面效果的完整Shader

注释我写的相当详细了

// jave.lin .08.15Shader "Test/PerlinNoiseMirror" {Properties {[NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {}// 主纹理[NoScaleOffset] _NoiseTex ("NoiseTex", 2D) = "white" {} // 噪点图_NoiseScaleX ("NoiseScaleX", Range(0, 1)) = 0.1 // 水平噪点放大系数_NoiseScaleY ("NoiseScaleY", Range(0, 1)) = 0.1 // 垂直放大系数_NoiseSpeedX ("NoiseSpeedX", Range(0, 10)) = 1 // 水平扰动速度_NoiseSpeedY ("NoiseSpeedY", Range(0, 10)) = 1 // 垂直扰动速度_NoiseBrightOffset ("NoiseBrightOffset", Range(0, 0.9)) = 0.25// 噪点图整体的数值偏移_NoiseFalloff ("NoiseFalloff", Range(0, 1)) = 1 // 扰动衰减_MirrorRange ("MirrorRange", Range(0, 3)) = 1 // 镜面范围(最大范围,超出该范围就不反射)_MirrorAlpha ("MirrorAlpha", Range(0, 1)) = 1 // 镜面图像不透明度_MirrorFadeAlpha ("_MirrorFadeAlpha", Range(0,1)) = 0.5 // 镜面范围值边缘位置的不透明度,如果调整为0,意思越接近该最大范围的透明就越接近该值:0}CGINCLUDE#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata {float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;};struct v2f {float4 vertex : SV_POSITION;float2 uv : TEXCOORD0;float3 wPos : TEXCOORD1;};struct v2f_m {float4 vertex : SV_POSITION;float2 uv : TEXCOORD0;float4 normal : TEXCOORD1;float4 wPos : TEXCOORD2;};sampler2D _MainTex;sampler2D _NoiseTex;fixed _NoiseScaleX, _NoiseScaleY;fixed _NoiseSpeedX, _NoiseSpeedY;fixed _NoiseBrightOffset;fixed _NoiseFalloff;float _MirrorRange, _MirrorAlpha, _MirrorFadeAlpha;float3 n, p; // 镜面法线,镜面任意点v2f vert_normal (appdata v) {v2f o;o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag_normal (v2f i) : SV_Target {float3 dir = i.wPos.xyz - p;// 平面与插值点的指向half d = dot(dir, n); // 与反向镜面的距离if (d < 0) discard;// 如果平面背面,那就丢弃return tex2D(_MainTex, i.uv);}v2f_m vert_mirror (appdata v) {v2f_m o;o.wPos = mul(unity_ObjectToWorld, v.vertex);float3 nn = -n; // 法线反向float3 dp = o.wPos.xyz - p;// 平面点与世界空间的点的向量(即:从平面的点指向世界空间点的方向)half nd = dot(n, dp); // 计算出点与平面的垂直距离o.wPos.xyz += nn * (nd * 2); // 将垂直距离反向2倍的距离,就是镜像的位置o.vertex = mul(unity_MatrixVP, o.wPos);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;return o;}fixed4 frag_mirror (v2f_m i) : SV_Target {if (i.wPos.w > _MirrorRange) discard; // 超过镜像范围也丢弃if (i.normal.w <= 0) discard;// 透明度为0丢弃float3 dir = i.wPos.xyz - p;// 平面与插值点的指向half d = dot(dir, n); // 与反向镜面的距离if (d > 0) discard;// 如果超过了平面,那就丢弃fixed2 ouvxy = fixed2( // 噪点图采样,用于主纹理的UV偏移的tex2D(_NoiseTex, i.uv + fixed2(_Time.x * _NoiseSpeedX, 0)).r,tex2D(_NoiseTex, i.uv + fixed2(0, _Time.x * _NoiseSpeedY)).r);ouvxy -= _NoiseBrightOffset; // 0~1 to ==> -_NoiseBrightOffset~ 1 - _NoiseBrightOffsetouvxy *= fixed2(_NoiseScaleX, _NoiseScaleY); // 扰动放大系数float scale = i.wPos.w / _MirrorRange;// 用距离来作为扰动衰减scale = lerp(scale, 1, (1 - _NoiseFalloff)); // 距离越近扰动越是衰减(即:与镜面距离越近,基本是不扰动的,所以我们可以看到边缘与镜面的像素是吻合的)ouvxy *= scale;fixed4 col = tex2D(_MainTex, i.uv + ouvxy);// 加上扰动UV后再采样主纹理return fixed4(col.rgb, i.normal.w);}ENDCGSubShader {Tags {"Queue"="Geometry+2" "RenderType"="Opaque" }Pass {Cull frontZTest AlwaysZWrite OffBlend SrcAlpha OneMinusSrcAlphaStencil {Ref 1Comp Equal}CGPROGRAM#pragma vertex vert_mirror#pragma fragment frag_mirrorENDCG}Pass {CGPROGRAM#pragma vertex vert_normal#pragma fragment frag_normalENDCG}}}

Source Project

TestShaderToy_NoiseAndMirror 提取码: j1kh 复制这段内容后打开百度网盘手机App,操作更方便哦

打开:PerlinNoiseMirror.unity场景即可

(今天要去探亲,我就过几天再回来学习shader,然后再博客)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。