feat(dream): 添加梦境数据溢出与虚焦表现
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65a0de17c7fc4cc39ae305f6bb18ac77
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: DreamDataOverflow
|
||||
m_Shader: {fileID: 4800000, guid: 6c30d8e44b1b4b4ab9414a90e069f290, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _OverflowChromatic: 0.006
|
||||
- _OverflowExposure: 1.45
|
||||
- _OverflowGlow: 0.65
|
||||
- _OverflowIntensity: 0
|
||||
- _OverflowNoise: 0.08
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db54ed6c97bf4f05a79f53b268f0c52a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,154 @@
|
||||
Shader "AibisDream/DreamDataOverflow"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
|
||||
_Color("Tint", Color) = (1,1,1,1)
|
||||
_OverflowIntensity("Overflow Intensity", Range(0, 1)) = 0
|
||||
_OverflowExposure("Overflow Exposure", Range(0, 3)) = 1.45
|
||||
_OverflowGlow("Overflow Glow", Range(0, 2)) = 0.65
|
||||
_OverflowChromatic("Overflow Chromatic", Range(0, 0.04)) = 0.006
|
||||
_OverflowNoise("Overflow Noise", Range(0, 0.5)) = 0.08
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"Queue" = "Transparent"
|
||||
"RenderType" = "Transparent"
|
||||
"RenderPipeline" = "UniversalPipeline"
|
||||
"IgnoreProjector" = "True"
|
||||
"CanUseSpriteAtlas" = "True"
|
||||
}
|
||||
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
HLSLINCLUDE
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionHCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
float4 screenPosition : TEXCOORD1;
|
||||
};
|
||||
|
||||
TEXTURE2D(_MainTex);
|
||||
SAMPLER(sampler_MainTex);
|
||||
float4 _MainTex_ST;
|
||||
float4 _MainTex_TexelSize;
|
||||
float4 _Color;
|
||||
float _OverflowIntensity;
|
||||
float _OverflowExposure;
|
||||
float _OverflowGlow;
|
||||
float _OverflowChromatic;
|
||||
float _OverflowNoise;
|
||||
|
||||
float hash21(float2 value)
|
||||
{
|
||||
value = frac(value * float2(123.34, 456.21));
|
||||
value += dot(value, value + 45.32);
|
||||
return frac(value.x * value.y);
|
||||
}
|
||||
|
||||
Varyings vert(Attributes input)
|
||||
{
|
||||
Varyings output;
|
||||
output.positionHCS = TransformObjectToHClip(input.positionOS.xyz);
|
||||
output.uv = TRANSFORM_TEX(input.uv, _MainTex);
|
||||
output.color = input.color * _Color;
|
||||
output.screenPosition = ComputeScreenPos(output.positionHCS);
|
||||
return output;
|
||||
}
|
||||
|
||||
half4 SampleSprite(float2 uv)
|
||||
{
|
||||
return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
|
||||
}
|
||||
|
||||
half4 frag(Varyings input) : SV_Target
|
||||
{
|
||||
float intensity = saturate(_OverflowIntensity);
|
||||
float pulse = 0.92 + sin(_Time.y * 17.0 + input.uv.y * 23.0) * 0.08;
|
||||
float activeIntensity = saturate(intensity * pulse);
|
||||
|
||||
float2 radial = input.uv - 0.5;
|
||||
float radialLength = max(length(radial), 0.001);
|
||||
float2 chromaticDirection = radial / radialLength;
|
||||
float chromaticOffset = _OverflowChromatic * activeIntensity;
|
||||
|
||||
half4 center = SampleSprite(input.uv);
|
||||
half red = SampleSprite(input.uv + chromaticDirection * chromaticOffset).r;
|
||||
half blue = SampleSprite(input.uv - chromaticDirection * chromaticOffset).b;
|
||||
half3 chromatic = half3(red, center.g, blue);
|
||||
|
||||
float2 texel = _MainTex_TexelSize.xy * lerp(1.5, 7.0, activeIntensity);
|
||||
half4 blur = center * 0.2;
|
||||
blur += SampleSprite(input.uv + float2(texel.x, 0)) * 0.1;
|
||||
blur += SampleSprite(input.uv - float2(texel.x, 0)) * 0.1;
|
||||
blur += SampleSprite(input.uv + float2(0, texel.y)) * 0.1;
|
||||
blur += SampleSprite(input.uv - float2(0, texel.y)) * 0.1;
|
||||
blur += SampleSprite(input.uv + texel) * 0.1;
|
||||
blur += SampleSprite(input.uv - texel) * 0.1;
|
||||
blur += SampleSprite(input.uv + float2(texel.x, -texel.y)) * 0.1;
|
||||
blur += SampleSprite(input.uv + float2(-texel.x, texel.y)) * 0.1;
|
||||
|
||||
half luminance = dot(chromatic, half3(0.2126, 0.7152, 0.0722));
|
||||
half glowLuminance = dot(blur.rgb, half3(0.2126, 0.7152, 0.0722));
|
||||
half whiteAmount = saturate(activeIntensity * (_OverflowExposure * 0.38 + luminance * 0.8));
|
||||
half3 exposed = lerp(chromatic, half3(1, 1, 1), whiteAmount);
|
||||
exposed += blur.rgb * glowLuminance * _OverflowGlow * activeIntensity;
|
||||
|
||||
float2 screenUv = input.screenPosition.xy / max(input.screenPosition.w, 0.0001);
|
||||
float noiseSeed = floor(_Time.y * 24.0);
|
||||
float noise = hash21(floor(screenUv * _ScreenParams.xy * 0.32) + noiseSeed);
|
||||
float speck = smoothstep(0.82, 1.0, noise) * _OverflowNoise * activeIntensity;
|
||||
float scan = sin((screenUv.y * _ScreenParams.y + _Time.y * 90.0) * 0.12) * 0.5 + 0.5;
|
||||
exposed += speck * lerp(0.55, 1.0, scan);
|
||||
|
||||
half4 result;
|
||||
result.rgb = exposed * input.color.rgb;
|
||||
result.a = max(center.a, blur.a * activeIntensity * _OverflowGlow * 0.45) * input.color.a;
|
||||
clip(result.a - 0.001);
|
||||
return result;
|
||||
}
|
||||
ENDHLSL
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "DreamDataOverflow2D"
|
||||
Tags { "LightMode" = "Universal2D" }
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma target 3.0
|
||||
ENDHLSL
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "DreamDataOverflowUnlit"
|
||||
Tags { "LightMode" = "SRPDefaultUnlit" }
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma target 3.0
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
Fallback "Sprites/Default"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c30d8e44b1b4b4ab9414a90e069f290
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+33
-2
@@ -325,6 +325,7 @@ GameObject:
|
||||
- component: {fileID: 132823524}
|
||||
- component: {fileID: 132823525}
|
||||
- component: {fileID: 132823526}
|
||||
- component: {fileID: 132823527}
|
||||
m_Layer: 0
|
||||
m_Name: "\u573A\u666F\u52A8\u753B"
|
||||
m_TagString: Untagged
|
||||
@@ -406,6 +407,36 @@ MonoBehaviour:
|
||||
autoBindCinemachineBrain: 0
|
||||
resetToStartWhenFinished: 0
|
||||
resetToStartDelay: 0
|
||||
--- !u!114 &132823527
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 132823522}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c0c737b07db74d53bd47f7b140346ad4, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
director: {fileID: 132823524}
|
||||
starfieldRenderer: {fileID: 1420961919}
|
||||
initialBlur: 0.78
|
||||
blurSize: 0.009
|
||||
firstAttemptStart: 0.45
|
||||
firstFocusDuration: 0.48
|
||||
firstNearFocusBlur: 0.38
|
||||
firstHoldDuration: 0.14
|
||||
firstSlipDuration: 0.38
|
||||
firstSlipBlur: 0.72
|
||||
secondAttemptStart: 1.72
|
||||
secondFocusDuration: 0.55
|
||||
secondNearFocusBlur: 0.28
|
||||
secondHoldDuration: 0.18
|
||||
secondSlipDuration: 0.46
|
||||
unresolvedBlur: 0.62
|
||||
blurFadeStart: 4
|
||||
blurFadeDuration: 3.2
|
||||
--- !u!1 &218986882
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -458,7 +489,7 @@ SpriteRenderer:
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
|
||||
- {fileID: 2100000, guid: db54ed6c97bf4f05a79f53b268f0c52a, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
@@ -1036,7 +1067,7 @@ SpriteRenderer:
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
|
||||
- {fileID: 2100000, guid: db54ed6c97bf4f05a79f53b268f0c52a, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
|
||||
@@ -92,6 +92,22 @@ namespace AibisDream
|
||||
yield return SpriteShowcase.Instance.ShowObj(picName, duration);
|
||||
}
|
||||
|
||||
[YarnCommand("dream_overflow_on")]
|
||||
public static IEnumerator DreamOverflowOn(string preset = "entry", float duration = 0.35f)
|
||||
{
|
||||
var showcase = SpriteShowcase.Instance;
|
||||
if (showcase == null) yield break;
|
||||
yield return showcase.SetDreamOverflow(preset, 1f, duration);
|
||||
}
|
||||
|
||||
[YarnCommand("dream_overflow_off")]
|
||||
public static IEnumerator DreamOverflowOff(float duration = 0.8f)
|
||||
{
|
||||
var showcase = SpriteShowcase.Instance;
|
||||
if (showcase == null) yield break;
|
||||
yield return showcase.SetDreamOverflow(null, 0f, duration);
|
||||
}
|
||||
|
||||
[YarnCommand("show_sprite_motion")]
|
||||
public static IEnumerator ShowSpriteMotion(string picName, string motionProfile, float duration = 0.35f)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,33 @@ namespace AibisDream
|
||||
[SerializeField] private SpriteRenderer _backgroundSpriteRenderer;
|
||||
[SerializeField] private SpriteRenderer _largeSpriteRenderer;
|
||||
|
||||
private struct DreamOverflowSettings
|
||||
{
|
||||
public float exposure;
|
||||
public float glow;
|
||||
public float chromatic;
|
||||
public float noise;
|
||||
|
||||
public DreamOverflowSettings(float exposure, float glow, float chromatic, float noise)
|
||||
{
|
||||
this.exposure = exposure;
|
||||
this.glow = glow;
|
||||
this.chromatic = chromatic;
|
||||
this.noise = noise;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly int OverflowIntensityId = Shader.PropertyToID("_OverflowIntensity");
|
||||
private static readonly int OverflowExposureId = Shader.PropertyToID("_OverflowExposure");
|
||||
private static readonly int OverflowGlowId = Shader.PropertyToID("_OverflowGlow");
|
||||
private static readonly int OverflowChromaticId = Shader.PropertyToID("_OverflowChromatic");
|
||||
private static readonly int OverflowNoiseId = Shader.PropertyToID("_OverflowNoise");
|
||||
|
||||
private MaterialPropertyBlock _dreamOverflowBlock;
|
||||
private DreamOverflowSettings _dreamOverflowSettings;
|
||||
private float _dreamOverflowIntensity;
|
||||
private int _dreamOverflowTransitionVersion;
|
||||
|
||||
private SpriteRenderer _smallMotionRenderer;
|
||||
private SpriteMask _smallMotionMask;
|
||||
private DG.Tweening.Sequence _smallMotionSequence;
|
||||
@@ -35,6 +62,8 @@ namespace AibisDream
|
||||
|
||||
public override void OnSingletonInit()
|
||||
{
|
||||
_dreamOverflowSettings = EntryOverflowSettings();
|
||||
ResetDreamOverflow();
|
||||
CaptureSmallBaseTransform();
|
||||
|
||||
// 初始状态:隐藏
|
||||
@@ -49,6 +78,131 @@ namespace AibisDream
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
ResetDreamOverflow();
|
||||
}
|
||||
|
||||
public override void OnSingletonDestroy()
|
||||
{
|
||||
ResetDreamOverflow();
|
||||
}
|
||||
|
||||
private static DreamOverflowSettings EntryOverflowSettings()
|
||||
{
|
||||
return new DreamOverflowSettings(
|
||||
exposure: 1.45f,
|
||||
glow: 0.65f,
|
||||
chromatic: 0.006f,
|
||||
noise: 0.08f);
|
||||
}
|
||||
|
||||
private static DreamOverflowSettings RuptureOverflowSettings()
|
||||
{
|
||||
return new DreamOverflowSettings(
|
||||
exposure: 2.4f,
|
||||
glow: 1.15f,
|
||||
chromatic: 0.018f,
|
||||
noise: 0.2f);
|
||||
}
|
||||
|
||||
private static DreamOverflowSettings ResolveDreamOverflowSettings(string preset)
|
||||
{
|
||||
var normalized = string.IsNullOrWhiteSpace(preset)
|
||||
? "entry"
|
||||
: preset.Trim().ToLowerInvariant();
|
||||
|
||||
switch (normalized)
|
||||
{
|
||||
case "entry":
|
||||
return EntryOverflowSettings();
|
||||
case "rupture":
|
||||
return RuptureOverflowSettings();
|
||||
default:
|
||||
Debug.LogWarning($"[SpriteShowcase] Unknown dream overflow preset '{preset}', using 'entry'.");
|
||||
return EntryOverflowSettings();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drives the local overexposure/glow effect used by dream sprites.
|
||||
/// The effect is applied through MaterialPropertyBlock so no material instances are created.
|
||||
/// </summary>
|
||||
public IEnumerator SetDreamOverflow(string preset, float target, float duration)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(preset))
|
||||
{
|
||||
_dreamOverflowSettings = ResolveDreamOverflowSettings(preset);
|
||||
}
|
||||
|
||||
target = Mathf.Clamp01(target);
|
||||
duration = Mathf.Max(0f, duration);
|
||||
|
||||
var version = ++_dreamOverflowTransitionVersion;
|
||||
var start = _dreamOverflowIntensity;
|
||||
|
||||
if (duration <= 0f || !gameObject.activeInHierarchy)
|
||||
{
|
||||
_dreamOverflowIntensity = target;
|
||||
ApplyDreamOverflow();
|
||||
yield break;
|
||||
}
|
||||
|
||||
var elapsed = 0f;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
if (version != _dreamOverflowTransitionVersion)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
var progress = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(elapsed / duration));
|
||||
_dreamOverflowIntensity = Mathf.Lerp(start, target, progress);
|
||||
ApplyDreamOverflow();
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (version == _dreamOverflowTransitionVersion)
|
||||
{
|
||||
_dreamOverflowIntensity = target;
|
||||
ApplyDreamOverflow();
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetDreamOverflow()
|
||||
{
|
||||
_dreamOverflowTransitionVersion++;
|
||||
_dreamOverflowIntensity = 0f;
|
||||
ApplyDreamOverflow();
|
||||
}
|
||||
|
||||
private void ApplyDreamOverflow()
|
||||
{
|
||||
ApplyDreamOverflow(_spriteRenderer);
|
||||
ApplyDreamOverflow(_largeSpriteRenderer);
|
||||
ApplyDreamOverflow(_smallMotionRenderer);
|
||||
}
|
||||
|
||||
private void ApplyDreamOverflow(SpriteRenderer target)
|
||||
{
|
||||
if (target == null) return;
|
||||
|
||||
if (_dreamOverflowBlock == null)
|
||||
{
|
||||
_dreamOverflowBlock = new MaterialPropertyBlock();
|
||||
}
|
||||
|
||||
target.GetPropertyBlock(_dreamOverflowBlock);
|
||||
_dreamOverflowBlock.SetFloat(OverflowIntensityId, _dreamOverflowIntensity);
|
||||
_dreamOverflowBlock.SetFloat(OverflowExposureId, _dreamOverflowSettings.exposure);
|
||||
_dreamOverflowBlock.SetFloat(OverflowGlowId, _dreamOverflowSettings.glow);
|
||||
_dreamOverflowBlock.SetFloat(OverflowChromaticId, _dreamOverflowSettings.chromatic);
|
||||
_dreamOverflowBlock.SetFloat(OverflowNoiseId, _dreamOverflowSettings.noise);
|
||||
target.SetPropertyBlock(_dreamOverflowBlock);
|
||||
_dreamOverflowBlock.Clear();
|
||||
}
|
||||
|
||||
private void CaptureSmallBaseTransform()
|
||||
{
|
||||
if (_spriteRenderer == null) return;
|
||||
@@ -88,6 +242,7 @@ namespace AibisDream
|
||||
CopySmallRendererSettings(_smallMotionRenderer, 1, SpriteMaskInteraction.VisibleInsideMask);
|
||||
_smallMotionRenderer.gameObject.SetActive(false);
|
||||
_smallMotionRenderer.SetAlpha(0);
|
||||
ApplyDreamOverflow(_smallMotionRenderer);
|
||||
}
|
||||
|
||||
private void CopySmallRendererSettings(SpriteRenderer target, int sortingOrderOffset, SpriteMaskInteraction maskInteraction)
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
/// <summary>
|
||||
/// Drives the deliberately unsuccessful focus pulls at the start of the
|
||||
/// starfield-to-sea Timeline. The effect is evaluated from Timeline time so
|
||||
/// pausing, frame drops and repeated playback remain deterministic.
|
||||
/// </summary>
|
||||
public sealed class StarfieldDefocusController : MonoBehaviour
|
||||
{
|
||||
private static readonly int BlurAmountId = Shader.PropertyToID("_BlurAmount");
|
||||
private static readonly int BlurSizeId = Shader.PropertyToID("_BlurSize");
|
||||
|
||||
[Header("References")]
|
||||
[SerializeField] private PlayableDirector director;
|
||||
[SerializeField] private SpriteRenderer starfieldRenderer;
|
||||
|
||||
[Header("Defocus Look")]
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float initialBlur = 0.78f;
|
||||
[Range(0f, 0.05f)]
|
||||
[SerializeField] private float blurSize = 0.009f;
|
||||
|
||||
[Header("Focus Attempt 1")]
|
||||
[Min(0f)]
|
||||
[SerializeField] private float firstAttemptStart = 0.45f;
|
||||
[Min(0.01f)]
|
||||
[SerializeField] private float firstFocusDuration = 0.48f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float firstNearFocusBlur = 0.38f;
|
||||
[Min(0f)]
|
||||
[SerializeField] private float firstHoldDuration = 0.14f;
|
||||
[Min(0.01f)]
|
||||
[SerializeField] private float firstSlipDuration = 0.38f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float firstSlipBlur = 0.72f;
|
||||
|
||||
[Header("Focus Attempt 2")]
|
||||
[Min(0f)]
|
||||
[SerializeField] private float secondAttemptStart = 1.72f;
|
||||
[Min(0.01f)]
|
||||
[SerializeField] private float secondFocusDuration = 0.55f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float secondNearFocusBlur = 0.28f;
|
||||
[Min(0f)]
|
||||
[SerializeField] private float secondHoldDuration = 0.18f;
|
||||
[Min(0.01f)]
|
||||
[SerializeField] private float secondSlipDuration = 0.46f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float unresolvedBlur = 0.62f;
|
||||
|
||||
[Header("Downward Pan")]
|
||||
[Tooltip("Timeline time at which the starfield starts moving down toward the sea.")]
|
||||
[Min(0f)]
|
||||
[SerializeField] private float blurFadeStart = 4f;
|
||||
[Min(0.01f)]
|
||||
[SerializeField] private float blurFadeDuration = 3.2f;
|
||||
|
||||
private MaterialPropertyBlock propertyBlock;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
director = GetComponent<PlayableDirector>();
|
||||
starfieldRenderer = GetComponentInChildren<SpriteRenderer>(true);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
propertyBlock = new MaterialPropertyBlock();
|
||||
ApplyAtTime(director != null ? (float)director.time : 0f);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ApplyAtTime(director != null ? (float)director.time : 0f);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (director == null || starfieldRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyAtTime((float)director.time);
|
||||
}
|
||||
|
||||
private void ApplyAtTime(float time)
|
||||
{
|
||||
if (starfieldRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
propertyBlock ??= new MaterialPropertyBlock();
|
||||
starfieldRenderer.GetPropertyBlock(propertyBlock);
|
||||
propertyBlock.SetFloat(BlurAmountId, EvaluateBlur(time));
|
||||
propertyBlock.SetFloat(BlurSizeId, blurSize);
|
||||
starfieldRenderer.SetPropertyBlock(propertyBlock);
|
||||
}
|
||||
|
||||
private float EvaluateBlur(float time)
|
||||
{
|
||||
float firstFocusEnd = firstAttemptStart + firstFocusDuration;
|
||||
float firstHoldEnd = firstFocusEnd + firstHoldDuration;
|
||||
float firstSlipEnd = firstHoldEnd + firstSlipDuration;
|
||||
|
||||
float secondFocusEnd = secondAttemptStart + secondFocusDuration;
|
||||
float secondHoldEnd = secondFocusEnd + secondHoldDuration;
|
||||
float secondSlipEnd = secondHoldEnd + secondSlipDuration;
|
||||
|
||||
if (time < firstAttemptStart)
|
||||
{
|
||||
return initialBlur;
|
||||
}
|
||||
|
||||
if (time < firstFocusEnd)
|
||||
{
|
||||
return SmoothLerp(initialBlur, firstNearFocusBlur, InverseLerp(firstAttemptStart, firstFocusEnd, time));
|
||||
}
|
||||
|
||||
if (time < firstHoldEnd)
|
||||
{
|
||||
return firstNearFocusBlur;
|
||||
}
|
||||
|
||||
if (time < firstSlipEnd)
|
||||
{
|
||||
return SmoothLerp(firstNearFocusBlur, firstSlipBlur, InverseLerp(firstHoldEnd, firstSlipEnd, time));
|
||||
}
|
||||
|
||||
if (time < secondAttemptStart)
|
||||
{
|
||||
return firstSlipBlur;
|
||||
}
|
||||
|
||||
if (time < secondFocusEnd)
|
||||
{
|
||||
return SmoothLerp(firstSlipBlur, secondNearFocusBlur, InverseLerp(secondAttemptStart, secondFocusEnd, time));
|
||||
}
|
||||
|
||||
if (time < secondHoldEnd)
|
||||
{
|
||||
return secondNearFocusBlur;
|
||||
}
|
||||
|
||||
if (time < secondSlipEnd)
|
||||
{
|
||||
return SmoothLerp(secondNearFocusBlur, unresolvedBlur, InverseLerp(secondHoldEnd, secondSlipEnd, time));
|
||||
}
|
||||
|
||||
if (time < blurFadeStart)
|
||||
{
|
||||
return unresolvedBlur;
|
||||
}
|
||||
|
||||
return SmoothLerp(unresolvedBlur, 0f, InverseLerp(blurFadeStart, blurFadeStart + blurFadeDuration, time));
|
||||
}
|
||||
|
||||
private static float InverseLerp(float from, float to, float value)
|
||||
{
|
||||
return Mathf.Clamp01((value - from) / Mathf.Max(0.0001f, to - from));
|
||||
}
|
||||
|
||||
private static float SmoothLerp(float from, float to, float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
t = t * t * (3f - 2f * t);
|
||||
return Mathf.LerpUnclamped(from, to, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0c737b07db74d53bd47f7b140346ad4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -20,11 +20,13 @@ position: 2,-331
|
||||
<<declare $gameStage = 1>>
|
||||
|
||||
|
||||
<<show_sprite whiteboard 0.01>>
|
||||
<<dream_overflow_on "entry" 0>>
|
||||
jg: 数据溢出:未知来源的记忆… #line:09952c6
|
||||
jg: VERYFYING…bool seaExists = false; waiting for imput… #auto_next #line:05a8257
|
||||
<<fade_out 1>>
|
||||
<<dream_overflow_off 1>>
|
||||
// <<jump Test>>
|
||||
<<show_sprite whiteboard>>
|
||||
???: …下来… #line:0c8c60b
|
||||
???: 下来…下来。 #line:07bfa4b
|
||||
<<show_sprite "D2S枯树特写">>
|
||||
@@ -43,8 +45,10 @@ me: 这到底是… #line:0ef08ad
|
||||
jg: 数据溢出:未知来源的记忆… #line:007d96c
|
||||
me: 啊…又来了… #line:0b0acd0
|
||||
jg: VERYFYING…bool seaExists = waiting f 【WARNING: UNEXP #auto_next #line:07f7aba
|
||||
<<show_sprite whiteboard 1>>
|
||||
<<fade_in 1>>
|
||||
<<dream_overflow_on "rupture" 0.45>>
|
||||
<<show_sprite whiteboard 0.05>>
|
||||
<<fade_in 0.35>>
|
||||
<<dream_overflow_off 0>>
|
||||
// <i>场景闪白</i> #line:0d8d75a
|
||||
// <<hide_sprite>>
|
||||
你感到一阵眩晕。 #line:0ebd65e
|
||||
|
||||
Reference in New Issue
Block a user