Unity Shader - Curved World - 类似 地铁跑酷,动物森友会 的世界扭曲效果 - 球形透视


我发现莉莉丝的《神觉者》在战斗中也有使用到这个效果,视觉效果提升还是很大的


比如,球形投影前的效果
在这里插入图片描述

球形投影后的效果
在这里插入图片描述

GIF:
请添加图片描述


ShaderLab cginc


固定 Vector.forward 方向的球形透视

参考: Shader in Unity & Curved world shader & Change material color 实现的效果

实现的只能是 Vector.forward 方向的球形投影

#ifndef __CURVE_WORLD_LIB_H__
#define __CURVE_WORLD_LIB_H__

// jave.lin 2023/02/01 curve world library

    #ifdef _CURVE_WORLD_ON

        uniform float _Curve_Depth;
        uniform float _Depth_Divider;

        void CurveWorldApply(inout float3 positionWS, out float3 positionOS)
        {
    
    
            float3 deltaVec = positionWS - _WorldSpaceCameraPos.xyz;
            float  E = -_Curve_Depth * _Depth_Divider;
            float  detlaVecZ2 = deltaVec.z * deltaVec.z;
            detlaVecZ2 *= E;
            float3 offset = float3(0.0, detlaVecZ2, 0.0);
            positionWS += offset;
            positionOS = mul(unity_WorldToObject, float4(positionWS, 1.0)).xyz;
        }

        #define CURVE_WORLD_APPLY(positionWS, positionOS) CurveWorldApply(positionWS, positionOS);

    #else

        #define CURVE_WORLD_APPLY(positionWS, positionOS)

    #endif

#endif

根据镜头任意视角方向的球形透视

#ifndef __CURVE_WORLD_LIB_H__
#define __CURVE_WORLD_LIB_H__

// jave.lin 2023/02/01 curve world library

    #ifdef _CURVE_WORLD_ON

        uniform float _Curve_Depth;
        uniform float _Depth_Divider;
        //uniform int _CW_Enabled;
        uniform float4 _Cam_Forward;

        void CurveWorldApply(inout float3 positionWS, out float3 positionOS)
        {
    
    
            //float3 srcPosWS = positionWS;
            //float3 srcPosOS = positionOS;

            // jave.lin : zDist ref to : AutoLight.cginc

            float3 deltaVec = _WorldSpaceCameraPos - positionWS;
            //float zDist = dot(deltaVec, UNITY_MATRIX_V[2].xyz);
            float zDist = dot(deltaVec, _Cam_Forward.xyz);
            float  E = -_Curve_Depth * _Depth_Divider;
            float  zDist2 = zDist * zDist;
            zDist2 *= E;
            float3 offset = float3(0.0, zDist2, 0.0);
            positionWS += offset;
            positionOS = mul(unity_WorldToObject, float4(positionWS, 1.0)).xyz;

            //positionWS = lerp(srcPosWS, positionWS, _CW_Enabled);
            //positionOS = lerp(srcPosOS, positionOS, _CW_Enabled);
        }

        #define CURVE_WORLD_APPLY(positionWS, positionOS) CurveWorldApply(positionWS, positionOS);

    #else

        #define CURVE_WORLD_APPLY(positionWS, positionOS)

    #endif

#endif

添加开始弯曲透视的 z 距离偏移

留意: uniform float _Z_Dist_Offset;

#ifndef __CURVE_WORLD_LIB_H__
#define __CURVE_WORLD_LIB_H__

// jave.lin 2023/02/01 curve world library

    #ifdef _CURVE_WORLD_ON

        uniform float _Curve_Depth;
        uniform float _Depth_Divider;
        //uniform int _CW_Enabled;
        uniform float4 _Cam_Forward;
        uniform float _Z_Dist_Offset;

        void CurveWorldApply(inout float3 positionWS, out float3 positionOS)
        {
    
    
            //float3 srcPosWS = positionWS;
            //float3 srcPosOS = positionOS;

            // jave.lin : zDist ref to : AutoLight.cginc

            float3 deltaVec = _WorldSpaceCameraPos - positionWS;
            //float zDist = dot(deltaVec, UNITY_MATRIX_V[2].xyz);
            float zDist = max(0, dot(deltaVec, _Cam_Forward.xyz) - _Z_Dist_Offset);
            float E = -_Curve_Depth * _Depth_Divider;
            float zDist2 = zDist * zDist;
            zDist2 *= E;
            float3 offset = float3(0.0, zDist2, 0.0);
            positionWS += offset;
            positionOS = mul(unity_WorldToObject, float4(positionWS, 1.0)).xyz;

            //positionWS = lerp(srcPosWS, positionWS, _CW_Enabled);
            //positionOS = lerp(srcPosOS, positionOS, _CW_Enabled);
        }

        #define CURVE_WORLD_APPLY(positionWS, positionOS) CurveWorldApply(positionWS, positionOS);

    #else

        #define CURVE_WORLD_APPLY(positionWS, positionOS)

    #endif

#endif

CurveWorldControl.cs

// jave.lin : curve world control

using UnityEngine;

[ExecuteInEditMode]
public class CurveWorldControl : MonoBehaviour
{
    
    
    private bool _last_on = false;
    public bool on = true;
    [Range(0.005f, 1.0f)]
    public float curveDepth = 0.015f;
    public float depthDivider = 0.0f;

    public Camera cam;

    private static int _Curve_Depth = Shader.PropertyToID("_Curve_Depth");
    private static int _Depth_Divider = Shader.PropertyToID("_Depth_Divider");
    private static int _Cam_Forward = Shader.PropertyToID("_Cam_Forward");
    private void Update()
    {
    
    
        if (cam == null)
        {
    
    
            Shader.DisableKeyword("_CURVE_WORLD_ON");
            return;
        }

        if (_last_on != on)
        {
    
    
            if (on)
            {
    
    
                Shader.EnableKeyword("_CURVE_WORLD_ON");
            }
            else
            {
    
    
                Shader.DisableKeyword("_CURVE_WORLD_ON");
            }
            _last_on = on;
        }

        if (_last_on)
        {
    
    
            Shader.SetGlobalFloat(_Curve_Depth, curveDepth);
            Shader.SetGlobalFloat(_Depth_Divider, depthDivider);
            var view_forward = cam.worldToCameraMatrix.GetColumn(2);
            Shader.SetGlobalVector(_Cam_Forward, view_forward);
        }
    }
}

需要修改的代码

修改所有 3D shader 即可

  1. pass添加代码:
  • #pragma multi_compile _ _CURVE_WORLD_ON
  • #include “CurveWorldLib.cginc”
  • CURVE_WORLD_APPLY(posWorld.xyz, v.vertex.xyz)
  1. 要添加的pass
  • ForwardBase
  • ForwardAdd
  • ShadowCaster
  1. CurveWorldControl.cs 的 DontDestryOnLoad
  2. 对应场景才开启 CurveWorldControl

Project

TestingSphereProjectionEffect - 参考: Shader in Unity & Curved world shader & Change material color 实现的效果


References

全部看完,相信你可以做一款很有意思的游戏,或是游戏中很有特色的效果

猜你喜欢

转载自blog.csdn.net/linjf520/article/details/126528523