pc8888888 发表于 2023-3-14 09:28

【Unity3D】卷轴特效

1 原理


当一个圆在地面上沿直线匀速滚动时,圆上固定点的运动轨迹称为旋轮线(或摆线、圆滚线)。本文实现的卷轴特效使用了旋轮线相关理论。

以下是卷轴特效原理及公式推导,将屏幕坐标 (x) 映射到纹理坐标 (u)。

注意:屏幕坐标 x 值域为 ,这里已归一化到 。

本文代码资源见→Unity3D Shader卷轴滚动特效。
2 代码实现


RollEffect.cs
using UnityEngine; // 屏幕后处理特效一般都需要绑定在像机上public class RollEffect : MonoBehaviour {    public float radius = 0.05f; // 圆半径    public float rollSpeed = 0.8f; // 圆滚动角速度    private Texture rollTex; // 滚动轴纹理    private Texture backTex; // 底部背景纹理    private float rollTime = 0; // 滚动时间    private float maxRollTime; // 最长滚动时间    private float rollDirection = 1; // 滚动方向(1: 向右, -1: 向左)    private Material rollMaterial; // 滚动特效材质    private bool enableRoll = false; // 滚动特效开关   private void Awake() {      rollMaterial = new Material(Shader.Find("Custom/Curl/Roll"));      rollMaterial.hideFlags = HideFlags.DontSave;      rollTex = Resources.Load<Texture>("RollTex");      backTex = Resources.Load<Texture>("BackTex");    }   private void Update() {      if (Input.GetMouseButton(0)) {            rollTime = 0;            maxRollTime = 1 / rollSpeed / radius;            enableRoll = true;      }    }   private void OnRenderImage (RenderTexture source, RenderTexture destination) {      if (enableRoll) {            rollMaterial.SetTexture("_RollTex", rollTex);            rollMaterial.SetTexture("_BackTex", backTex);            rollMaterial.SetFloat("_theta", rollSpeed);            rollMaterial.SetFloat("_r", radius);            rollMaterial.SetFloat("_t", rollTime);            IncreaseTime();            Graphics.Blit (source, destination, rollMaterial);      }else {            Graphics.Blit (source, destination);      }    }   private void IncreaseTime() { // 时间自增      rollTime += rollDirection * Time.deltaTime;      if (rollTime > maxRollTime) {            rollTime = maxRollTime;            rollDirection = -rollDirection; // 反向卷轴      } else if (rollTime < 0) {            rollTime = 0;            rollDirection = -rollDirection;      }    }}
说明: RollEffect 脚本组件需要挂在相机上。

Roll.shader
Shader "Custom/Curl/Roll" // 小凸镜变换{    Properties   {      _MainTex ("mainTex", 2D) = "white" {}      _RollTex ("rollTex", 2D) = "white" {}      _BackTex ("backTex", 2D) = "white" {}    }   SubShader   {      Pass      {            ZTest Always            Cull Off            ZWrite Off            Fog { Mode off }             CGPROGRAM             #pragma vertex vert_img // UnityCG.cginc中定义了vert_img方法, 对vertex和texcoord进行了处理, 输出v2f_img中的pos和uv            #pragma fragment frag            #pragma fragmentoption ARB_precision_hint_fastest             #include "UnityCG.cginc"             sampler2D _MainTex;            sampler2D _RollTex; // 滚动轴纹理            sampler2D _BackTex; // 底部背景纹理            float _theta; // 圆滚动角速度            float _r; // 圆半径            float _t; // 滚动时间            float4 roll(float rho, float v)            { // 滚动变换, 将屏幕坐标映射到纹理坐标                float trt = _theta * _r * _t;                if (rho < trt - _r)                {                  return tex2D(_BackTex, float2(rho, v));                }                else if (rho < trt)                {                  float a = trt - rho;                  float phi = acos(a / _r);                  float u = trt - (UNITY_HALF_PI + phi) * _r;                  if (u > 0)                  {                        return tex2D(_RollTex, float2(u, v)) * pow(sin(phi), 2);                  }                  u = trt - (UNITY_HALF_PI - phi) * _r;                  return tex2D(_MainTex, float2(u, v)); // 刚开始卷动时会触发                }                else if (rho < trt + _r)                {                  float a = rho - trt;                  float phi = acos(a / _r);                  float u = trt - (3 * UNITY_HALF_PI - phi) * _r;                  if (u > 0)                  {                        return tex2D(_RollTex, float2(u, v)) * pow(sin(phi), 2);                  }                  return tex2D(_MainTex, float2(rho, v)); // 刚开始卷动时会触发                }                else                {                  return tex2D(_MainTex, float2(rho, v));                }            }             fixed4 frag(v2f_img i) : SV_Target // uv坐标的计算不能在顶点着色器中进行, 因为屏后处理的顶点只有屏幕的4个角顶点            {                return roll(i.pos.x / _ScreenParams.x, i.uv.y);            }             ENDCG      }    }   Fallback off}3 运行效果


4 推荐阅读

渲染管线固定管线着色器一固定管线着色器二表面着色器顶点和片元着色器选中物体描边特效基于模板测试和顶点膨胀的描边方法水波特效半球卷屏特效激光灯、碰撞特效

声明:本文转自【Unity3D】卷轴特效
页: [1]
查看完整版本: 【Unity3D】卷轴特效