【shader】边缘自定角度高光,描边,闪烁

来源:互联网 发布:项目数据分析报告 编辑:程序博客网 时间:2024/05/01 09:42

最终效果


两个点我要讲

向量的旋转

事实上是初中知识,但我书读的不好,所以我要给自己讲下。
先弄清楚如何在一个二维空间旋转一个变量。

观察图中v和v`的关系是 v`=[Cosθ,Sinθ]v  (假设v是列向量)
但在二维空间中,每个物体都有2个轴且互相垂直,如果旋转一个物体,就相当于旋转这个物体的坐标系,需要同时旋转这个物体的2个轴向量,才能达到完全旋转一个物体的要求。
我们把上面的图扩展下。

这样,我们就成功的获得了一个二维旋转矩阵。
[cosθ,-sinθ]
[sinθ,cosθ]
用这个矩阵就可以任意旋转任何二维物体,如果矩阵乘以对应的物体的世界坐标那物体就会围绕世界原心旋转(因为物体的坐标在图形是以矩阵的形式存储的)
旋转的方向如图示,θ是弧度,可不是角度,弧度乘以180/π,才是角度。
现在会旋转二维物体了,其实也就会旋转三维物体了,因为二维旋转就是在绕三维空间的Z轴旋转,只不过Z轴与我们的坐标系垂直,看不到(这里我就不画图啦)。
把上面的矩阵扩展到三维就是
[cosθ,-sinθ,0]
[sinθ,cosθ, 0]
[     0,       0, 1]
我们在3行3列留1,保证相乘后Z轴不变。绕X轴,绕Y轴以此类推。

乒乓效果

其实这个很简单,只是我脑子笨。
shader中,_Time是unity通过cpu给gpu传的time值。我们可以取他的余弦实现乒乓效果。
float t = abs(cos(_Time.x*loopTime));
用时间取余你的间隔时间比较你的间隔中间时间来,判断到底是增还是减。

其他问题

关于描边,注释中有作者的博客地址。
sinθ和cosθ的正负只要成对改,依然能正常旋转,因为和你传入的角度依然是正确的函数关系。

Shader代码

Shader "QQ/RimLight" {Properties{_Color("Color", Color) = (1,1,1,1)_MainTex("纹理", 2D) = "white" {}<span style="white-space:pre"></span>_LightColor("灯颜色",Color) = (1,1,1,1)_LightDir("灯方向",Vector) = (0,1,0,1)_OutLine("描边颜色",Color) = (1,1,1,1)_EdgeChange("描边大小",Range(0,.1)) = .05_FlickerTime("闪烁时间,0为关闭",Range(0,2)) = 1}CGINCLUDE#include "UnityCG.cginc"#pragma vertex vert#pragma fragment frag#pragma target 3.0ENDCGSubShader{Tags{ "RenderType" = "Transparent""Queue" = "Transparent""LightMode" = "ForwardBase" }LOD 200Pass{Cull FrontZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAMfixed4 _OutLine;float _EdgeChange;float _FlickerTime;struct a2v{float4 vertex:POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : POSITION;};v2f vert(a2v v){v2f o;//参考博客 http://blog.csdn.net/candycat1992/article/details/45577749o.pos = mul(UNITY_MATRIX_MV,v.vertex);v.normal = mul((float3x3)UNITY_MATRIX_MV,v.normal);v.normal.z = -.5;o.pos.xyz += v.normal*_EdgeChange;o.pos = mul(UNITY_MATRIX_P,o.pos);//参考官方教程//v.vertex.xyz += v.normal*_EdgeChange;//o.pos = mul(UNITY_MATRIX_MVP, v.vertex);return o;}fixed4 frag(v2f i) :COLOR{//闪烁的乒乓的速度,如果脚本传值可以把这段删掉_OutLine.a = abs(cos(_Time.x*_FlickerTime));return _OutLine;}ENDCG}Pass{CGPROGRAMfixed4 _Color;sampler2D _MainTex;fixed4 _MainTex_ST;fixed4 _LightColor;fixed4 _LightDir;struct a2v{float4 vertex:POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : POSITION;float2 uv:TEXCOORD0;float3 normal:TEXCOORD1;float3 viewDir:TEXCOORD2;UNITY_FOG_COORDS(3)};v2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);float4 wPos = mul(_Object2World, v.vertex);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//不过分追求效果的情况下在这里normalize,如果追求效果,请在frag内normalize,否则插值会被归一。o.normal = normalize(mul(v.normal, _World2Object).xyz);//我们希望光是从摄像机对面过来的,所以就反减o.viewDir = normalize(wPos.xyz - _WorldSpaceCameraPos);//旋转矩阵float3x3 rotaX = { 1,0,0,0,cos(_LightDir.x),sin(_LightDir.x),0,-sin(_LightDir.x),cos(_LightDir.x) };float3x3 rotaY = { cos(_LightDir.y),0,sin(_LightDir.y),0,1,0,-sin(_LightDir.y),0,cos(_LightDir.y) };float3x3 rotaZ = { cos(_LightDir.z),sin(_LightDir.z),0,-sin(_LightDir.z),cos(_LightDir.z),0,0,0,1 };o.viewDir = mul(rotaX, o.viewDir);o.viewDir = mul(rotaY, o.viewDir);o.viewDir = mul(rotaZ, o.viewDir);//矩阵相乘后结果不太对,可能写错了。//float3x3 rota = { sin(_LightDir.y)*sin(_LightDir.z),sin(_LightDir.y)*cos(_LightDir.z),cos(_LightDir.y),// -sin(_LightDir.y)*cos(_LightDir.x)*sin(_LightDir.z) - sin(_LightDir.x)*sin(_LightDir.z),-sin(_LightDir.y)*cos(_LightDir.x)*cos(_LightDir.z) + sin(_LightDir.x)*cos(_LightDir.z),cos(_LightDir.x)*cos(_LightDir.y),// -sin(_LightDir.y)*cos(_LightDir.x)*sin(_LightDir.z) + sin(_LightDir.x)*sin(_LightDir.z),-sin(_LightDir.y)*cos(_LightDir.x)*cos(_LightDir.z) - sin(_LightDir.x)*cos(_LightDir.z),cos(_LightDir.x)*cos(_LightDir.y)//};//o.viewDir = mul(rota, o.viewDir);return o;}fixed4 frag(v2f i) :COLOR{fixed4 col;fixed4 tex = tex2D(_MainTex,i.uv);//点乘normal和视线,判断相似度float diff = max(0,dot(i.normal, i.viewDir));col = tex*_Color + _LightColor*diff*_LightDir.w;return col;}ENDCG}}FallBack "Diffuse"}


0 0
原创粉丝点击