赞
踩
一、流动河流
Shader "Unity Shaders Book/Chapter 11/Water" { Properties { _MainTex ("Main Tex", 2D) = "white" {} //主纹理 _Color ("Color Tint", Color) = (1, 1, 1, 1) //整体颜色 _Magnitude ("Distortion Magnitude", Float) = 1 //控制水流波动幅度 _Frequency ("Distortion Frequency", Float) = 1 //控制波动频率 _InvWaveLength ("Distortion Inverse Wave Length", Float) = 10 //控制波长的倒数 _Speed ("Speed", Float) = 0.5 //河流纹理的移动速度 } SubShader { // Need to disable batching because of the vertex animation Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"} //DisableBatching:批处理合并所有模型,会使各自的模型空间丢失,我们在进行顶点动画时,需要使用到模型空间的变换,所以需要关闭批处理。 Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off //关闭深度写入 Blend SrcAlpha OneMinusSrcAlpha //开启混合模式 Cull Off //关闭了剔除功能 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Color; float _Magnitude; float _Frequency; float _InvWaveLength; float _Speed; struct a2v { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(a2v v) { v2f o; float4 offset; //顶点的位移量 offset.yzw = float3(0.0, 0.0, 0.0); //yzw都为0, offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude; //书上说,用_Frequency乘时间来模拟频率,为了让不同位置有不同位移,我们对上述结果加上了模型空间的位置分量,×_InvWaveLength来控制波长。_Magnitude来控制幅度。 //可以看下物体模型的坐标系,上下运动对应着模型空间的x轴,所以我们才更改x轴。 o.pos = UnityObjectToClipPos(v.vertex + offset); //加上偏移 o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); //计算偏移和缩放 o.uv += float2(0.0, _Time.y * _Speed); //水平移动,如果不是河流只是飘动效果,那这个可以去掉 return o; } fixed4 frag(v2f i) : SV_Target { fixed4 c = tex2D(_MainTex, i.uv); c.rgb *= _Color.rgb; return c; } ENDCG } } FallBack "Transparent/VertexLit" }
二、广告牌技术
广告牌技术 : 会根据视角方向旋转一个被纹理着色的多边形(通常为简单的四边形,这个多边形就是广告牌),使得多边形看起来好像总是面对着摄像机。
应用:渲染一些烟雾、云朵、闪光效果等等。
广告牌技术的本质就是构造旋转矩阵,广告牌技术使用的三个基向量是表面法线、向上的方向、向右的方向,除此之外还需要一个锚点。锚点不变用来确定位置。
广告牌要按照需求来构建三个相互正交的基向量:
我们首先可以确定一个方向,比如草丛的上方向是不变的(0,1,0),法线方向不变,比如粒子效果,法线方向固定一直指向视角方向,指向上的方向是变化的。
我们假定法线方向固定,用法线方向和向上的方向叉乘计算right方向(此时法线和向上的方向并不垂直,但right方向和这两个其中之一肯定是垂直的),然后我们再用right和法线来计算up方向,这样确定的法线、right、up两两之间都垂直,就构建出了基向量。
感觉书作者的代码有些难理解的地方,研究了好久才懂,在代码中注释了。
Shader "Unity Shaders Book/Chapter 11/Billboard" { Properties { _MainTex ("Main Tex", 2D) = "white" {} //广告牌的透明纹理 _Color ("Color Tint", Color) = (1, 1, 1, 1) //整体颜色 _VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1 //调整是固定法线还是固定指向上方向,就是控制约束垂直方向的程度。 } SubShader { // Need to disable batching because of the vertex animation Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"} //一样还是取消批处理,因为我们需要模型空间来操作(需要得到模型空间的中心锚点)。 Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off //这三个没变化 Blend SrcAlpha OneMinusSrcAlpha Cull Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Color; fixed _VerticalBillboarding; struct a2v { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert (a2v v) { v2f o; float3 center = float3(0, 0, 0); //确定锚点 float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1)); //获得模型空间中的视角方向 float3 normalDir = viewer - center; //法线方向确定 normalDir.y =normalDir.y * _VerticalBillboarding; //使用_VerticalBillboarding控制垂直方向上的约束度, //当_VerticalBillboarding为1时,意味着法线方向固定为视角方向。 //当_VerticalBillboarding为0时,意味着法线y方向为0,也就是说广告牌的上方向为(0,1,0) normalDir = normalize(normalDir); //进行归一化 float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0); //用于防止法线的方向和向上方向平行, float3 rightDir = normalize(cross(upDir, normalDir)); //这里是粗略的upDir upDir = normalize(cross(normalDir, rightDir)); //重新计算精确的 float3 centerOffs = v.vertex.xyz - center; //获得原来的偏移 float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z; //也就是说进行一个坐标的转换,原来是普通的x、y、z轴, //现在呢,我们把原来的z轴当成了法线方向,y轴当成了upDir,x轴当成了 负的rightDir //这里我没有理解错的话,应该是: //float3 localPos = center - rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z; //因为我们构建的是右手坐标系,所以x轴进行翻转后,才能模拟出坐标轴变换的效果,这样才能根据顶点和锚点的偏移量进行转换。 //举个例子原来 坐标轴 顶点和锚点的偏移是(1,1,1),那么我们在新的坐标轴就也要有(1,1,1)的偏移, //所以就要求我们要使用相同类型的坐标系(指左手右手),计算就是在新的坐标轴方向上加上偏移。 //之所以书中作者在这里使用的是加法,因为项目中的纹理,x轴的正负并不能影响实际效果,是对称的。 //我觉得还是要使用减法更加严谨。 //或许我们可以直接建立左手坐标系的基向量,这样会更好理解。。 o.pos = UnityObjectToClipPos(float4(localPos, 1)); //转换到裁剪空间 o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //进行便宜缩放的计算 return o; } fixed4 frag (v2f i) : SV_Target { fixed4 c = tex2D (_MainTex, i.uv); //采样 c.rgb *= _Color.rgb; return c; } ENDCG } } FallBack "Transparent/VertexLit" }
我们使用的是(Quad),而不可以是(Plane),因为我们的代码是建立在数值摆放的多边形基础上,
我们使用的多边形的定点结构要满足在模型空间下竖直排列。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。