feat(fix-system): 迁移记忆调频到精灵材质
This commit is contained in:
@@ -23,10 +23,12 @@ namespace AibisDream.FixSystem
|
||||
private const float MaxFrequencyBlur = 0.6f;
|
||||
private const float MinPixelDensity = 18f;
|
||||
private const float MaxPixelDensity = 96f;
|
||||
private const string DirectionalDistortionFadeProperty = "_DirectionalDistortionFade";
|
||||
|
||||
private static readonly int EnablePixelateId = Shader.PropertyToID("_EnablePixelate");
|
||||
private static readonly int FrequencyTuningId = Shader.PropertyToID("_FrequencyTuning");
|
||||
private static readonly int ClarityTuningId = Shader.PropertyToID("_ClarityTuning");
|
||||
private static readonly int DirectionalDistortionFadeId = Shader.PropertyToID(DirectionalDistortionFadeProperty);
|
||||
private static readonly int PixelateFadeId = Shader.PropertyToID("_PixelateFade");
|
||||
private static readonly int PixelatePixelDensityId = Shader.PropertyToID("_PixelatePixelDensity");
|
||||
private static readonly int EnableGaussianBlurId = Shader.PropertyToID("_EnableGaussianBlur");
|
||||
@@ -34,8 +36,8 @@ namespace AibisDream.FixSystem
|
||||
private static readonly int GaussianBlurOffsetId = Shader.PropertyToID("_GaussianBlurOffset");
|
||||
private static readonly int EnableUvDistortId = Shader.PropertyToID("_EnableUVDistort");
|
||||
private static readonly int UvDistortFadeId = Shader.PropertyToID("_UVDistortFade");
|
||||
private static readonly int EnableSaturationId = Shader.PropertyToID("_EnableSaturation");
|
||||
private static readonly int SaturationId = Shader.PropertyToID("_Saturation");
|
||||
private static readonly int MemoryGrayscaleId = Shader.PropertyToID("_MemoryGrayscale");
|
||||
private static readonly int MemoryContrastId = Shader.PropertyToID("_MemoryContrast");
|
||||
|
||||
[SerializeField] private GameObject memoryView;
|
||||
[SerializeField] private GameObject projector;
|
||||
@@ -63,6 +65,7 @@ namespace AibisDream.FixSystem
|
||||
|
||||
[SerializeField] private Material fadeMaterial;
|
||||
private Material runtimeMemoryMaterial;
|
||||
private Material runtimeNoColorMemoryMaterial;
|
||||
private readonly List<RenderTexture> runtimeRenderTextures = new();
|
||||
|
||||
public void OpenMemoryView()
|
||||
@@ -175,6 +178,8 @@ namespace AibisDream.FixSystem
|
||||
{
|
||||
if (runtimeMemoryMaterial != null)
|
||||
Destroy(runtimeMemoryMaterial);
|
||||
if (runtimeNoColorMemoryMaterial != null)
|
||||
Destroy(runtimeNoColorMemoryMaterial);
|
||||
|
||||
foreach (var renderTexture in runtimeRenderTextures)
|
||||
{
|
||||
@@ -323,6 +328,9 @@ namespace AibisDream.FixSystem
|
||||
|
||||
public void TweenWeight(Volume postProcessingVolume, float targetWeight, float duration)
|
||||
{
|
||||
if (postProcessingVolume == null)
|
||||
return;
|
||||
|
||||
// 动态调整权重
|
||||
DOTween.To(() => postProcessingVolume.weight, x => postProcessingVolume.weight = x, targetWeight, duration);
|
||||
}
|
||||
@@ -381,10 +389,10 @@ namespace AibisDream.FixSystem
|
||||
private void ResetPresentationState()
|
||||
{
|
||||
if (fadeMaterial != null)
|
||||
fadeMaterial.SetFloat("_DirectionalDistortionFade", FadeMaterialStartValue);
|
||||
SetFloatIfExists(DirectionalDistortionFadeId, FadeMaterialStartValue);
|
||||
ResetSpriteTuning();
|
||||
memoryFinishedSpriteRenderer.color = Color.black;
|
||||
memoryProcessVolume.weight = 0;
|
||||
SetVolumeWeight(memoryProcessVolume, 0f);
|
||||
_activePunchTape = null;
|
||||
|
||||
playBackground.gameObject.SetActive(false);
|
||||
@@ -414,8 +422,12 @@ namespace AibisDream.FixSystem
|
||||
{
|
||||
if (fadeMaterial == null) yield break;
|
||||
|
||||
fadeMaterial.SetFloat("_DirectionalDistortionFade", FadeMaterialStartValue);
|
||||
Tween tween = fadeMaterial.DOFloat(0, "_DirectionalDistortionFade", 3);
|
||||
SetFloatIfExists(DirectionalDistortionFadeId, FadeMaterialStartValue);
|
||||
DG.Tweening.Sequence sequence = DOTween.Sequence();
|
||||
AppendMaterialFloatTween(sequence, fadeMaterial, 0f, DirectionalDistortionFadeProperty, 3f);
|
||||
if (runtimeNoColorMemoryMaterial != null && runtimeNoColorMemoryMaterial != fadeMaterial)
|
||||
AppendMaterialFloatTween(sequence, runtimeNoColorMemoryMaterial, 0f, DirectionalDistortionFadeProperty, 3f);
|
||||
Tween tween = sequence;
|
||||
yield return tween.WaitForCompletion();
|
||||
}
|
||||
|
||||
@@ -428,7 +440,7 @@ namespace AibisDream.FixSystem
|
||||
if (useYarn)
|
||||
{
|
||||
if (fadeMaterial != null)
|
||||
fadeMaterial.SetFloat("_DirectionalDistortionFade", FadeMaterialStartValue);
|
||||
SetFloatIfExists(DirectionalDistortionFadeId, FadeMaterialStartValue);
|
||||
var memoryKey = string.Format(MemorySpritePath, memName);
|
||||
var memoryHandle = ResourceSystem.LoadAsync<Sprite>(memoryKey);
|
||||
yield return memoryHandle;
|
||||
@@ -501,14 +513,14 @@ namespace AibisDream.FixSystem
|
||||
Debug.LogError("Memory not found: " + searchMemoryKey);
|
||||
}
|
||||
|
||||
memoryProcessVolume.weight = 1;
|
||||
SetVolumeWeight(memoryProcessVolume, 1f);
|
||||
AudioManager.Instance.PlaySfx("event:/Scriptal/mem_load");
|
||||
|
||||
yield return new WaitForSeconds(SearchStartDelay);
|
||||
AudioManager.Instance.SetSfxParam("event:/Amb/amb_mem_tuning", "is_mem_tuning", 1);
|
||||
|
||||
memoryFinishedSpriteRenderer.color = Color.white;
|
||||
memoryProcessVolume.weight = 0;
|
||||
SetVolumeWeight(memoryProcessVolume, 0f);
|
||||
isProcessing = true;
|
||||
frequencySlider.PrepareForSearch();
|
||||
claritySlider.PrepareForSearch();
|
||||
@@ -545,8 +557,6 @@ namespace AibisDream.FixSystem
|
||||
SetFloatIfExists(ClarityTuningId, strength);
|
||||
SetFloatIfExists(EnableUvDistortId, active ? 1f : 0f);
|
||||
SetFloatIfExists(UvDistortFadeId, strength * MaxClarityDistortion);
|
||||
SetFloatIfExists(EnableSaturationId, active ? 1f : 0f);
|
||||
SetFloatIfExists(SaturationId, Mathf.Lerp(1f, 0.25f, strength));
|
||||
}
|
||||
|
||||
private void ResetSpriteTuning()
|
||||
@@ -560,8 +570,32 @@ namespace AibisDream.FixSystem
|
||||
|
||||
private void SetFloatIfExists(int propertyId, float value)
|
||||
{
|
||||
if (fadeMaterial.HasProperty(propertyId))
|
||||
fadeMaterial.SetFloat(propertyId, value);
|
||||
SetFloatIfExists(fadeMaterial, propertyId, value);
|
||||
if (runtimeNoColorMemoryMaterial != null && runtimeNoColorMemoryMaterial != fadeMaterial)
|
||||
SetFloatIfExists(runtimeNoColorMemoryMaterial, propertyId, value);
|
||||
}
|
||||
|
||||
private static void SetVolumeWeight(Volume volume, float weight)
|
||||
{
|
||||
if (volume != null)
|
||||
volume.weight = weight;
|
||||
}
|
||||
|
||||
private static void SetFloatIfExists(Material material, int propertyId, float value)
|
||||
{
|
||||
if (material != null && material.HasProperty(propertyId))
|
||||
material.SetFloat(propertyId, value);
|
||||
}
|
||||
|
||||
private static void AppendMaterialFloatTween(
|
||||
DG.Tweening.Sequence sequence,
|
||||
Material material,
|
||||
float target,
|
||||
string property,
|
||||
float duration)
|
||||
{
|
||||
if (sequence != null && material != null && material.HasProperty(property))
|
||||
sequence.Join(material.DOFloat(target, property, duration));
|
||||
}
|
||||
|
||||
private void PrepareRuntimeMemoryMaterial()
|
||||
@@ -578,13 +612,39 @@ namespace AibisDream.FixSystem
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeMemoryMaterial = new Material(fadeMaterial)
|
||||
{
|
||||
shader = shader,
|
||||
name = $"{fadeMaterial.name}_RuntimeMemoryTuning"
|
||||
};
|
||||
runtimeMemoryMaterial = CreateRuntimeMemoryMaterial(fadeMaterial, shader, "Color", 0f, 1f);
|
||||
memoryFinishedSpriteRenderer.sharedMaterial = runtimeMemoryMaterial;
|
||||
fadeMaterial = runtimeMemoryMaterial;
|
||||
|
||||
if (memoryFinishedImageNoColor != null && memoryFinishedImageNoColor.sharedMaterial != null)
|
||||
{
|
||||
runtimeNoColorMemoryMaterial = CreateRuntimeMemoryMaterial(
|
||||
memoryFinishedImageNoColor.sharedMaterial,
|
||||
shader,
|
||||
"NoColor",
|
||||
1f,
|
||||
1.8f);
|
||||
memoryFinishedImageNoColor.sharedMaterial = runtimeNoColorMemoryMaterial;
|
||||
}
|
||||
|
||||
ResetSpriteTuning();
|
||||
}
|
||||
|
||||
private static Material CreateRuntimeMemoryMaterial(
|
||||
Material source,
|
||||
Shader shader,
|
||||
string suffix,
|
||||
float grayscale,
|
||||
float contrast)
|
||||
{
|
||||
var material = new Material(source)
|
||||
{
|
||||
shader = shader,
|
||||
name = $"{source.name}_RuntimeMemoryTuning_{suffix}"
|
||||
};
|
||||
SetFloatIfExists(material, MemoryGrayscaleId, grayscale);
|
||||
SetFloatIfExists(material, MemoryContrastId, contrast);
|
||||
return material;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ Shader "AibisDream/MemoryTuningSprite"
|
||||
_DistortStrength ("Distort Strength", Range(0,0.05)) = 0.018
|
||||
_ChromaticStrength ("Chromatic Strength", Range(0,0.03)) = 0.008
|
||||
_FadeDistortStrength ("Fade Distort Strength", Range(0,0.2)) = 0.08
|
||||
_PixelateFade ("Pixelate Fade", Range(0,1)) = 0
|
||||
_PixelatePixelDensity ("Pixelate Pixel Density", Range(6,160)) = 96
|
||||
_GaussianBlurFade ("Gaussian Blur Fade", Range(0,1)) = 0
|
||||
_GaussianBlurOffset ("Gaussian Blur Offset", Range(0,1)) = 0.05
|
||||
_UVDistortFade ("UV Distort Fade", Range(0,1)) = 0
|
||||
_MemoryGrayscale ("Memory Grayscale", Range(0,1)) = 0
|
||||
_MemoryContrast ("Memory Contrast", Range(0,3)) = 1
|
||||
}
|
||||
|
||||
SubShader
|
||||
@@ -73,6 +80,13 @@ Shader "AibisDream/MemoryTuningSprite"
|
||||
half _DistortStrength;
|
||||
half _ChromaticStrength;
|
||||
half _FadeDistortStrength;
|
||||
half _PixelateFade;
|
||||
half _PixelatePixelDensity;
|
||||
half _GaussianBlurFade;
|
||||
half _GaussianBlurOffset;
|
||||
half _UVDistortFade;
|
||||
half _MemoryGrayscale;
|
||||
half _MemoryContrast;
|
||||
CBUFFER_END
|
||||
|
||||
Varyings vert(Attributes input)
|
||||
@@ -89,54 +103,77 @@ Shader "AibisDream/MemoryTuningSprite"
|
||||
|
||||
half4 SampleSprite(float2 uv)
|
||||
{
|
||||
return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, saturate(uv));
|
||||
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, saturate(uv));
|
||||
half luma = dot(col.rgb, half3(0.299, 0.587, 0.114));
|
||||
col.rgb = lerp(col.rgb, half3(luma, luma, luma), saturate(_MemoryGrayscale));
|
||||
col.rgb = saturate(lerp(half3(0.5, 0.5, 0.5), col.rgb, _MemoryContrast));
|
||||
return col;
|
||||
}
|
||||
|
||||
float2 PixelSnap(float2 uv, half strength)
|
||||
float2 PixelSnap(float2 uv, half strength, half density)
|
||||
{
|
||||
half pixels = lerp(_PixelMax, _PixelMin, strength);
|
||||
half pixels = max(1.0, lerp(_PixelMax, _PixelMin, strength));
|
||||
pixels = lerp(pixels, max(1.0, density), step(0.001, density));
|
||||
float2 aspectPixels = float2(pixels, max(1.0, pixels * _MainTex_TexelSize.z / _MainTex_TexelSize.w));
|
||||
return (floor(uv * aspectPixels) + 0.5) / aspectPixels;
|
||||
return round((uv - 0.5) * aspectPixels) / aspectPixels + 0.5;
|
||||
}
|
||||
|
||||
float2 DistortUv(float2 uv, half strength)
|
||||
{
|
||||
float angle = radians(40.0);
|
||||
float angle = radians(130.0);
|
||||
float2 dir = float2(cos(angle), sin(angle));
|
||||
float2 side = float2(-sin(angle), cos(angle));
|
||||
float wave = sin(dot(uv - 0.5, dir) * 85.0 + _Time.y * 1.35);
|
||||
return uv + side * wave * _DistortStrength * strength;
|
||||
float2 edge = smoothstep(0.0, 0.12, uv) * smoothstep(0.0, 0.12, 1.0 - uv);
|
||||
float edgeMask = edge.x * edge.y;
|
||||
float wave = sin(dot(uv - 0.5, dir) * 27.2 + _Time.y * 2.15);
|
||||
float volFxStrength = lerp(0.006, 0.026, saturate(_UVDistortFade)) * strength;
|
||||
return uv + side * wave * volFxStrength * edgeMask;
|
||||
}
|
||||
|
||||
half4 BlurSample(float2 uv, half strength)
|
||||
{
|
||||
float radial = distance(uv, 0.5) * 0.45;
|
||||
float stepSize = _BlurStep * strength * (1.0 + radial);
|
||||
float2 stepX = float2(stepSize, 0);
|
||||
float2 stepY = float2(0, stepSize);
|
||||
float angle = radians(111.0);
|
||||
float radial = distance(uv, 0.5) * 0.0026;
|
||||
float stepSize = (0.014 + radial + _GaussianBlurOffset * 0.004) * strength;
|
||||
float2 stepDir = normalize(float2(sin(angle), cos(angle)));
|
||||
float2 stepUv = stepDir * stepSize;
|
||||
|
||||
half4 col = SampleSprite(uv) * 0.36;
|
||||
col += SampleSprite(uv + stepX) * 0.12;
|
||||
col += SampleSprite(uv - stepX) * 0.12;
|
||||
col += SampleSprite(uv + stepY) * 0.12;
|
||||
col += SampleSprite(uv - stepY) * 0.12;
|
||||
col += SampleSprite(uv + stepX + stepY) * 0.05;
|
||||
col += SampleSprite(uv - stepX - stepY) * 0.05;
|
||||
col += SampleSprite(uv + stepX - stepY) * 0.03;
|
||||
col += SampleSprite(uv - stepX + stepY) * 0.03;
|
||||
half4 col = SampleSprite(uv) * 0.18;
|
||||
col += SampleSprite(uv + stepUv * 1.0) * 0.15;
|
||||
col += SampleSprite(uv - stepUv * 1.0) * 0.15;
|
||||
col += SampleSprite(uv + stepUv * 2.0) * 0.12;
|
||||
col += SampleSprite(uv - stepUv * 2.0) * 0.12;
|
||||
col += SampleSprite(uv + stepUv * 3.0) * 0.09;
|
||||
col += SampleSprite(uv - stepUv * 3.0) * 0.09;
|
||||
col += SampleSprite(uv + stepUv * 4.0) * 0.05;
|
||||
col += SampleSprite(uv - stepUv * 4.0) * 0.05;
|
||||
return col;
|
||||
}
|
||||
|
||||
half3 ApplySaturation(half3 color, half saturation)
|
||||
half4 ChromaticSample(float2 uv, half4 source, half strength)
|
||||
{
|
||||
half luma = dot(color, half3(0.299, 0.587, 0.114));
|
||||
return lerp(half3(luma, luma, luma), color, saturation);
|
||||
float aspect = max(0.001, _MainTex_TexelSize.z / _MainTex_TexelSize.w);
|
||||
float angle = 0.496 * 6.2831853;
|
||||
float2 dirA = float2(cos(angle) / aspect, sin(angle));
|
||||
float2 dirB = -dirA;
|
||||
float response = pow(saturate(strength), 0.75);
|
||||
float mov = (0.07 + pow(distance(float2(0.5, 0.5), uv), 3.0) * 0.644) * response;
|
||||
|
||||
half4 colA = SampleSprite(uv + dirA * mov) * half4(1.0, 0.9888, 0.705, 1.0);
|
||||
half4 colB = SampleSprite(uv + dirB * mov) * half4(0.705, 0.729, 1.0, 1.0);
|
||||
half3 splitRgb = (colA.rgb + colB.rgb) * 0.5865;
|
||||
half splitAlpha = max(max(colA.a, colB.a), source.a);
|
||||
half4 splitCol = half4(splitRgb, splitAlpha);
|
||||
return lerp(source, splitCol, 0.85 * response);
|
||||
}
|
||||
|
||||
half4 frag(Varyings input) : SV_Target
|
||||
{
|
||||
half clarity = saturate(_ClarityTuning);
|
||||
half frequency = saturate(_FrequencyTuning);
|
||||
half pixelate = pow(max(frequency, saturate(_PixelateFade)), 0.75);
|
||||
half blur = pow(max(frequency, saturate(_GaussianBlurFade)), 0.75);
|
||||
half distortion = pow(max(clarity, saturate(_UVDistortFade / 0.58)), 0.75);
|
||||
|
||||
float2 uv = input.uv;
|
||||
half fade = saturate((_DirectionalDistortionFade + 15.0) / 15.0);
|
||||
@@ -146,22 +183,12 @@ Shader "AibisDream/MemoryTuningSprite"
|
||||
uv.x += fadeWave * _FadeDistortStrength * fade;
|
||||
}
|
||||
|
||||
uv = DistortUv(uv, clarity);
|
||||
float2 pixelUv = PixelSnap(uv, frequency);
|
||||
uv = lerp(uv, pixelUv, frequency);
|
||||
uv = DistortUv(uv, distortion);
|
||||
float2 pixelUv = PixelSnap(uv, pixelate, _PixelatePixelDensity);
|
||||
uv = lerp(uv, pixelUv, pixelate);
|
||||
|
||||
half4 baseCol = lerp(SampleSprite(uv), BlurSample(uv, frequency), frequency * 0.65);
|
||||
|
||||
half chroma = _ChromaticStrength * clarity;
|
||||
float radial = pow(distance(uv, 0.5), 3.0) * 3.0;
|
||||
float2 chromaOffset = float2(chroma + radial * chroma, chroma * 0.35);
|
||||
half4 r = SampleSprite(uv + chromaOffset);
|
||||
half4 g = baseCol;
|
||||
half4 b = SampleSprite(uv - chromaOffset.yx);
|
||||
half4 chromaCol = half4(r.r, g.g, b.b, max(max(r.a, g.a), b.a));
|
||||
|
||||
half4 col = lerp(baseCol, chromaCol, clarity);
|
||||
col.rgb = ApplySaturation(col.rgb, lerp(1.0, 0.28, clarity));
|
||||
half4 col = lerp(SampleSprite(uv), BlurSample(uv, blur), blur);
|
||||
col = ChromaticSample(uv, col, clarity);
|
||||
col *= input.color;
|
||||
return col;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
# MemoryProcess Sprite Shader Notes
|
||||
|
||||
本文记录 `FixSystem/Memory` 记忆调频表现的结构与维护边界。该系统属于旧版 `FixSystem`,但仍承载佩佩修复场景里的记忆播放、打孔带检索和双滑杆调频表现。
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `Assets/Scripts/FixSystem/Memory/MemoryProcess.cs`
|
||||
- `Assets/Scripts/FixSystem/Memory/MemorySlider.cs`
|
||||
- `Assets/Shader/Shader/MemoryTuningSprite.shader`
|
||||
- 历史 VolFx profile 参考位于 `Assets/Scenes/VFXtest/`
|
||||
|
||||
## 当前结构
|
||||
|
||||
记忆图像由两层 `SpriteRenderer` 叠加:
|
||||
|
||||
- `memoryFinishedSpriteRenderer`:彩色记忆层。
|
||||
- `memoryFinishedImageNoColor`:无色底图层。
|
||||
|
||||
旧版表现主要依赖 VolFx 后处理。现在调频阶段默认由 `AibisDream/MemoryTuningSprite` 在 sprite 材质上完成。运行时会为两层分别创建材质实例,并把同一组调频参数同步写入两层,避免只扰动彩色层时露出或错开无色底图。
|
||||
|
||||
`memoryFinishedImageNoColor` 使用同一个 shader,但通过材质参数保留无色底图观感:
|
||||
|
||||
- `_MemoryGrayscale = 1`
|
||||
- `_MemoryContrast = 1.8`
|
||||
|
||||
彩色层保持:
|
||||
|
||||
- `_MemoryGrayscale = 0`
|
||||
- `_MemoryContrast = 1`
|
||||
|
||||
## 调频语义
|
||||
|
||||
`MemorySlider` 输出的是距离目标值的归一化偏差:
|
||||
|
||||
- 越接近目标区间,传出的值越接近 `0`。
|
||||
- 越远离目标区间,传出的值越接近 `1`。
|
||||
|
||||
因此 shader 表现应遵循“远离目标时混乱,靠近目标时清晰稳定”的方向。
|
||||
|
||||
目前两个轴的职责是:
|
||||
|
||||
- 频率轴:像素化、颗粒化、焦糊感。
|
||||
- 清晰度轴:色散、轻微相位错位、弱 UV 扭曲。
|
||||
|
||||
后续如果要增强反馈,优先保持两个轴的视觉语义差异,不要让两个轴都只表现为普通模糊。
|
||||
|
||||
## 后处理迁移边界
|
||||
|
||||
旧 VolFx profile 可以作为视觉参考,但不要直接照搬参数到 sprite shader。原因是后处理作用于最终合成画面,而 sprite shader 只作用于单个 sprite 层。尤其是 UV 扭曲:
|
||||
|
||||
- 后处理中的强扭曲通常不会暴露底层。
|
||||
- sprite 层上的强扭曲会撕开当前层边缘,露出下面的 `nocolor` 层或背景。
|
||||
|
||||
因此 sprite shader 中的扭曲应保持较弱,并在 UV 边缘做衰减。
|
||||
|
||||
## 旧 VolFx 参考
|
||||
|
||||
调频滑杆的历史 profile:
|
||||
|
||||
- `Assets/Scenes/VFXtest/记忆像素滑块.asset`
|
||||
- `PixelationVol`
|
||||
- `BlurVol`
|
||||
- `Assets/Scenes/VFXtest/记忆清晰度滑块.asset`
|
||||
- `ChromaticVol`
|
||||
- `DistortVol`
|
||||
|
||||
加载与屏幕类历史 profile:
|
||||
|
||||
- `Assets/Scenes/VFXtest/花屏.asset`
|
||||
- 用于放入记忆卡带后的加载花屏。
|
||||
- 不属于双滑杆调频效果。
|
||||
- `Assets/Scenes/VFXtest/记忆屏幕.asset`
|
||||
- 曾用于 `mainEffect` 的默认记忆屏幕后处理。
|
||||
|
||||
这些 profile 的用途不同,迁移或复刻时需要先确认当前目标是“调频反馈”、“卡带加载过场”,还是“进入记忆界面的默认屏幕质感”。
|
||||
|
||||
## Volume 字段现状
|
||||
|
||||
`MemoryProcess` 中仍保留若干 Volume 字段:
|
||||
|
||||
- `memoryClarityVolume`
|
||||
- `memoryFrequencyVolume`
|
||||
- `memoryProcessVolume`
|
||||
- `mainEffect`
|
||||
|
||||
当 `useSpriteShaderTuning = true` 时,`memoryClarityVolume` 与 `memoryFrequencyVolume` 不再驱动调频表现,只作为后处理模式的兼容入口。
|
||||
|
||||
`memoryProcessVolume` 仍可用于放入记忆卡带后的加载花屏,并已做空引用安全处理。
|
||||
|
||||
`mainEffect` 曾指向默认记忆屏幕后处理。如果未来要恢复或迁移它,需要先明确是否要作为常驻屏幕质感,而不是误接到卡带加载流程中。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### sprite 变紫
|
||||
|
||||
优先检查 `MemoryTuningSprite.shader` 编译错误。Unity 的紫色材质通常表示 shader 编译失败或材质 shader 丢失。
|
||||
|
||||
如果 Unity Console 不方便读取,可以查看:
|
||||
|
||||
`%LOCALAPPDATA%\Unity\Editor\Editor.log`
|
||||
|
||||
曾经出现过的坑:
|
||||
|
||||
- HLSL 局部变量命名为 `line` 会触发 `syntax error: unexpected token 'line'`。
|
||||
- 与 Unity/URP include 中的函数名冲突也可能导致编译失败,工具函数建议使用项目专属前缀。
|
||||
|
||||
### nocolor 层露出
|
||||
|
||||
通常是彩色层和无色层没有同步应用同一套采样扰动,或 UV 扭曲太强。检查:
|
||||
|
||||
- 两层是否都使用运行时材质。
|
||||
- 调频参数是否同步写入两层。
|
||||
- 扭曲是否有边缘衰减。
|
||||
|
||||
### 调频差异不明显
|
||||
|
||||
优先调整 shader 内响应曲线,而不是恢复 VolFx 后处理。可以从以下方向处理:
|
||||
|
||||
- 频率轴加强像素密度、模糊半径或响应曲线。
|
||||
- 清晰度轴加强色散方向、相位错位或轻微漂移。
|
||||
- 避免把两个轴都调成类似的模糊/噪声效果。
|
||||
|
||||
## 维护建议
|
||||
|
||||
- 手动编辑 shader 后,及时检查 Unity Console 或 `Editor.log`。
|
||||
- 不要把后处理参数机械映射到 sprite shader。
|
||||
- 涉及两层记忆图像时,优先考虑两层同步。
|
||||
- 如果要迁移新的后处理效果,先确认它属于调频、加载过场还是默认屏幕氛围。
|
||||
Reference in New Issue
Block a user