UnityShader 从入门到盖棺(四)

矫情吗;* 2023-02-19 15:28 144阅读 0赞

img

广告版

今天讲一下广告板的实现。来来来,先砸效果图。

final

广告版的意思是,虽然我只是一块板(一个平面),但是我始终对着观察者(打广告)。这个对着也有两种方式。

  1. 整个平面垂直于观察者的视线向量。常用于一些闪光特效。
  2. y向量始终垂直于地面。常用于像草这一类需要扎根在地面上的。

所以,理一下思路。我们要做的,其实就是把平面所有点基于平面的一个锚点做一个旋转变换。使得旋转后的平面符合我们预期的朝向。

介绍完概念,直接开始制作。

首先我们把我们的星星资源拖拽到场景中。然后将它的位置放在屋顶,并且进行一定的缩放。

trans

创建一个Unlit着色器,删除全部内容。然后实现一个简单的显示一个2D精灵的Shader,没什么特别的。命名为4_BillBorad。

  1. Shader "Unity Shader/C4/4_BillBoard"
  2. {
  3. Properties {
  4. _MainTex ("Main Tex", 2D) = "white" {}
  5. _Color ("Main Color", COLOR) = (1, 1, 1, 1)
  6. }
  7. SubShader
  8. {
  9. Tags {
  10. "Queue" = "Transparent"
  11. "RenderType" = "Transparent"
  12. "DisableBatching" = "True"
  13. }
  14. Blend SrcAlpha OneMinusSrcAlpha
  15. ZWrite Off
  16. Cull Off
  17. Pass {
  18. Tags {
  19. "LightMode" = "ForwardBase"
  20. }
  21. CGPROGRAM
  22. #pragma vertex vert
  23. #pragma fragment frag
  24. struct a2v {
  25. float4 vertex : POSITION;
  26. float2 uv : TEXCOORD0;
  27. };
  28. struct v2f {
  29. float4 pos : SV_POSITION;
  30. float2 uv : TEXCOORD0;
  31. };
  32. sampler2D _MainTex;
  33. float4 _Color;
  34. v2f vert(a2v i) {
  35. v2f o;
  36. o.pos = UnityObjectToClipPos(i.vertex);
  37. o.uv = i.uv;
  38. return o;
  39. }
  40. fixed4 frag(v2f i) : SV_Target {
  41. fixed4 c = tex2D(_MainTex, i.uv);
  42. c.rgb *= _Color.rgb;
  43. return c;
  44. }
  45. ENDCG
  46. }
  47. }
  48. }

创建一个材质4_Billboard_up, 并且应用上对应shader。再把这个材质拖到我们的屋顶星星上。现在的效果图如下。

init

因为我们需要所以顶点做一个相同变换,使得最终朝向满足我们的要求。

所以第一步,构造变换矩阵的向量基。

我们能得到的第一个向量是摄像机指向物体的向量。在顶点着色器中,定义一个物体的中心点,然后把摄像机位置转换到物体空间坐标系,利用坐标相减得到forward向量(顶点的朝向向量)。

  1. v2f o;
  2. float3 centerPos = float3(0, 0, 0);
  3. float3 objectSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));;
  4. float3 forward = objectSpaceCameraPos - centerPos;

接着我们先定义头顶向量为(0, 1, 0), 然后根据叉乘得到右向量,再根据叉乘重新计算头顶向量。读者一定要自己搞清楚这里面的原理,很简单的。

  1. forward = normalize(forward);
  2. float3 upDir = float3(0, 1, 0);
  3. float3 rightDir = normalize(cross(upDir, forward));
  4. upDir = normalize(cross(forward, rightDir));

有了这个变换矩阵,我们就可以用它去左乘当前每个顶点与中心点的偏移向量。然后根据结果重新对当前顶点计算经过变换后的偏移位置。

  1. float3 centerOffset = i.vertex.xyz - centerPos;
  2. float3 localPos = centerPos + rightDir * centerOffset.x + upDir * centerOffset.y + forward * centerOffset.z;
  3. o.pos = UnityObjectToClipPos(float4(localPos, 1.0));
  4. // o.pos = UnityObjectToClipPos(i.vertex);
  5. o.uv = i.uv;
  6. return o;

然后现在再看下结果,就会发现我们屋顶的星星能朝着我们摄像机动了。

middle

上面的实现属于我们说到的,头顶向量永远垂直于地面。广告版还有一种就是forward向量永远平行于实现向量。读者应该已经发现,如果我们把normalize.y = 0这一段代码删掉,那么星星就会永远朝向摄像机。

我们先在天空上在摆上几个星星。

然后添加一个开关变量控制是否永远朝向摄像机。

  1. _MainTex ("Main Tex", 2D) = "white" {}
  2. _Color ("Main Color", COLOR) = (1, 1, 1, 1)
  3. [MaterialToggle] _FaceCamera ("Face Camera", FLOAT) = 0

如果朝向摄像机,那么我们就保持forward向量的y分量。这里我们再加个保险设置,避免forward向量和upDir向量重合。

  1. float3 forward = objectSpaceCameraPos - centerPos;
  2. forward.y *= _FaceCamera;
  3. forward = normalize(forward);
  4. // float3 upDir = float3(0, 1, 0);
  5. float3 upDir = abs(forward.y) < 0.999 ? float3(0, 1, 0) : float3(0, 0, 1);
  6. float3 rightDir = normalize(cross(upDir, forward));
  7. upDir = normalize(cross(forward, rightDir));

然后我们再创建一个材质”4_Billboard_forward”, 把勾选框勾选上,再把材质拖到天空中的星星上。然后我们就会发现天上的星星也在一直对着我们的摄像机拉!

final

结语

在本次笔者自己动手的时候遇到了几个坑,总结一下几个问题,大家一起去试一下吧!

  • 试下用下面的代码去求摄像机物体空间位置,会有什么不同。

    float3 objectSpaceCameraPos = mul(unity_WorldToObject, _WorldSpaceCameraPos);

  • 试下把星星的缩放改成 5,5,1这种非均匀缩放,尝试一下去解释现象吧!

  • 删掉”Queue” = “Transparent”看看。

好啦,这次分享就到这了。支持作者专属二维码走起来。

vxpay

链接

github地址:https://github.com/gjbian/Unity-Shader-Study

上一篇:UnityShader 从入门到盖棺(三)

发表评论

表情:
评论列表 (有 0 条评论,144人围观)

还没有评论,来说两句吧...

相关阅读

    相关 UnityShader 入门(二)

    ![gamebighouse][] 前言  这是我入门学习笔记的第二篇。这篇开始,我们会逐渐做一些更贴近实际的效果。而不是和上周那个球体球体,随便输出点莫名其妙,妙不可