赞
踩
出于个人写作习惯,还是喜欢在开始之前加上一小段技术无关的叙述,通过这个方式我会更加容易进入到写作状态,当然也可以理解为序章一样的东西,会参杂一些生活上的事,废话会比较多,如果不看的话请直接通过目录跳转。
在完成了这个效果之后,我继续参考了Linden Reid女士的博客希望为我的水面增加上一层折射效果,显然我走的更远了一些,把反射也加上了,期间也复习了使用环境纹理这个知识点,多少算是有一点点在进步吧,当初看书时一知半解的东西随着要解决实际问题,也变得更加清晰了。
今天因为个人身体原因需要会去一趟医院,因此就不对原理进行过深描述。而是转而直接介绍代码的实现,当然了过程中如果有所提及,还是会尽量解释的。
至于涉及的原理,以及过程中必然会涉及到的知识点,其内容肯定是多于我在代码中使用到的,而为了帮助我自己记忆和学习,我也会找时间写下来的,主要参考还是冯乐乐的书,当然官网的文档也会使用。(大概率明天就会写)
接下来就开始吧。
为了更加明确思路,而不是愣在那里想“我要写个水面”,然后毫无头绪,我们还是把水面的效果拆解开来,并一个一个针对实现吧。
首先是水面在与其他物体接触的时候会产生的交界线,会与周围有些许不同的效果,这个效果已经在这篇博客里头具体实现过了,当时的效果如下:
但是可以看到这个水面现在空有交界线和边界的起伏,非常简单。
折射效果其实简单考虑起来,就是希望让水面下的画面能够进行一部分的扭动。
这里Unity提供了grabPass,通过简单的声明,能够获取当前摄像机渲染的屏幕画面纹理,而通过对这个纹理进行带变形的采样之后再显示出来,就能够实现折射效果。
为了达到这一点,需要对shader代码进行如下设置:
Shader "Custom/Water" { Properties{ //some properties here ... } SubShader { Tags{ "RenderType" = "Opaque" "Queue"="Transparent"}//将物体设置为不透明,渲染队列设置为透明队列 GrabPass{ "_GrabPass"}//紧接着就声明GrabPass,可以理解为就是一个Pass,将屏幕纹理输出到了指定名字的纹理中 Pass { CGPROGRAM ... sampler2D _GrabPass;;//在需要的地方声明变量,这里变量名要和GrabPass里的字符串一致 float4 _GrabPass_TexelSize;//通过后缀获取该图像的纹素大小,若屏幕纹理大小为800*600, //那么该变量的xy即为1/800,1/600 ... ENDCG } } }
这里解释一下渲染标签。实际上这里渲染的是不透明效果,我们要输出的颜色是grabpass获得的颜色与其他效果的叠加,并不会与背后的其他物体进行混合,因此选择RenderType为Opaque即可,当然也可以选择Transparent然后大概Blend选项,但是没有必要,因为我们已经能通过grabpass某种程度上获得屏幕上的像素了。
而渲染队列则必须设置为Transparent,因为这样保证我们当前绘制的物体是在Geometry中的物体之后绘制的,也就意味着在我们获取grabpass图像时,前提必须是其他不透明物体已经绘制完了,这样获得的grabpass才能够包含正确的我们需要的信息。
这部分所需代码与效果:
Shader "Custom/Water" { Properties{ //这部分会用到的变量,主要是后两个 _Color("Color",Color) = (1,1,1,1) _DepthFactor("DepthFactor",range(0,1)) =0.5 _Distortion("_Distortion",float) = 1.0 _NoiseTex("noiseSample",2D) = "white"{ } } SubShader { Tags{ "RenderType" = "Opaque" "Queue"="Transparent"} GrabPass{ "_GrabPass"}//使用GrabPass Pass { CGPROGRAM // required to use ComputeScreenPos() #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag sampler2D _CameraDepthTexture; fixed4 _Color; float _DepthFactor; fixed _Distortion; sampler2D _NoiseTex; float4 _NoiseTex_ST; sampler2D _GrabPass;//通过声明获取需要的Grabpass图像 float4 _GrabPass_TexelSize; struct vertexInput { float4 vertex : POSITION; float4 texcoord:TEXCOORD; float3 normal:NORMAL; float4 tangent:TANGENT; }; struct vertexOutput { float4 pos : SV_POSITION; float4 grabScreenPos:texcoord2; float4 UV:TEXCOORD3; float4 originalPos:TEXCOORD4; }; vertexOutput vert(vertexInput input) { vertexOutput output; output.originalPos= UnityObjectToClipPos(input.vertex); output.UV.xy = TRANSFORM_TEX(input.texcoord.xy, _NoiseTex); //Animating //tex2D(_NoiseTex,input.texcoord)is not available in vertex shader //for there are no UV derivatives in Vertex Shader float noise =tex2Dlod(_NoiseTex, float4(output.UV.xy, 0, 0)); input.vertex.y += cos(_Time.y*10 * noise)*0.2*noise; // convert obj-space position to camera clip space output.pos = UnityObjectToClipPos(input.vertex); //使用了变换前的坐标来获取屏幕坐标,确保纹理会跟着定点动画波动 output.grabScreenPos = ComputeGrabScreenPos(output.originalPos); return output; } float4 frag(vertexOutput input) : COLOR { //完成折射形变部分 //获取对GrabPass的采样坐标,坐标包含形变,形变从噪声获取 //使用噪声来进行偏移,包含了时间变量以让折射存在动感 float noise = tex2D(_NoiseTex, input.UV.xy + float2(_Time.x,_Time.x)); //bump参数乘以纹素大小以得到正确的UV偏移量 float2 bump
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。