199 lines
6.4 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
/// <summary>
/// 카메라 전환 시 크로스 디졸브 블렌딩을 위한 URP Renderer Feature
/// Unity 6 Render Graph API 사용
/// </summary>
public class CameraBlendRendererFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
// BeforeRenderingPostProcessing으로 변경 - 포스트 프로세싱 전에 블렌딩
public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
public Material blendMaterial;
}
public Settings settings = new Settings();
private CameraBlendRenderPass blendPass;
public override void Create()
{
blendPass = new CameraBlendRenderPass(settings);
blendPass.renderPassEvent = settings.renderPassEvent;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (settings.blendMaterial == null)
return;
// 게임 카메라만 처리
if (renderingData.cameraData.cameraType != CameraType.Game)
return;
// 블렌딩이 활성화된 경우에만 패스 추가
if (CameraBlendController.IsBlending && CameraBlendController.BlendTexture != null)
{
renderer.EnqueuePass(blendPass);
}
}
protected override void Dispose(bool disposing)
{
blendPass?.Dispose();
}
}
public class CameraBlendRenderPass : ScriptableRenderPass
{
private CameraBlendRendererFeature.Settings settings;
private static readonly int BlendAmountProperty = Shader.PropertyToID("_BlendAmount");
private static readonly int PrevTexProperty = Shader.PropertyToID("_PrevTex");
private class PassData
{
public Material blendMaterial;
public float blendAmount;
public RenderTexture blendTexture;
public TextureHandle sourceTexture;
public TextureHandle destinationTexture;
}
public CameraBlendRenderPass(CameraBlendRendererFeature.Settings settings)
{
this.settings = settings;
profilingSampler = new ProfilingSampler("Camera Blend Pass");
ConfigureInput(ScriptableRenderPassInput.Color);
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if (settings.blendMaterial == null)
return;
if (!CameraBlendController.IsBlending || CameraBlendController.BlendTexture == null)
return;
var resourceData = frameData.Get<UniversalResourceData>();
var cameraData = frameData.Get<UniversalCameraData>();
// 백버퍼인 경우 스킵 (BeforeRenderingPostProcessing에서는 일반적으로 false)
if (resourceData.isActiveTargetBackBuffer)
{
Debug.LogWarning("[CameraBlend] isActiveTargetBackBuffer - skipping");
return;
}
var source = resourceData.activeColorTexture;
// source가 유효한지 확인
if (!source.IsValid())
{
Debug.LogWarning("[CameraBlend] source texture is not valid");
return;
}
// cameraColorDesc 사용 - 카메라 색상 텍스처 설명자
var cameraTargetDesc = renderGraph.GetTextureDesc(resourceData.cameraColor);
cameraTargetDesc.name = "_CameraBlendDestination";
cameraTargetDesc.clearBuffer = false;
var destination = renderGraph.CreateTexture(cameraTargetDesc);
// 블렌딩 패스
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Camera Blend", out var passData, profilingSampler))
{
passData.blendMaterial = settings.blendMaterial;
passData.blendAmount = CameraBlendController.BlendAmount;
passData.blendTexture = CameraBlendController.BlendTexture;
passData.sourceTexture = source;
builder.UseTexture(source, AccessFlags.Read);
builder.SetRenderAttachment(destination, 0, AccessFlags.Write);
builder.AllowPassCulling(false);
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
data.blendMaterial.SetFloat(BlendAmountProperty, data.blendAmount);
data.blendMaterial.SetTexture(PrevTexProperty, data.blendTexture);
Blitter.BlitTexture(context.cmd, data.sourceTexture, new Vector4(1, 1, 0, 0), data.blendMaterial, 0);
});
}
// 결과를 source로 복사
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Camera Blend Copy Back", out var copyData, profilingSampler))
{
copyData.sourceTexture = destination;
builder.UseTexture(destination, AccessFlags.Read);
builder.SetRenderAttachment(source, 0, AccessFlags.Write);
builder.AllowPassCulling(false);
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
Blitter.BlitTexture(context.cmd, data.sourceTexture, new Vector4(1, 1, 0, 0), 0, false);
});
}
}
[System.Obsolete("This rendering path is for compatibility mode only (when Render Graph is disabled). Use Render Graph API instead.", false)]
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// Legacy path
}
public void Dispose()
{
}
}
/// <summary>
/// 카메라 블렌딩을 제어하는 정적 컨트롤러
/// </summary>
public static class CameraBlendController
{
private static bool isBlending = false;
private static float blendAmount = 1f;
private static RenderTexture blendTexture;
public static bool IsBlending
{
get => isBlending;
set => isBlending = value;
}
public static float BlendAmount
{
get => blendAmount;
set => blendAmount = Mathf.Clamp01(value);
}
public static RenderTexture BlendTexture
{
get => blendTexture;
set => blendTexture = value;
}
public static void StartBlend(RenderTexture texture)
{
blendTexture = texture;
blendAmount = 0f;
isBlending = true;
}
public static void EndBlend()
{
isBlending = false;
blendAmount = 1f;
blendTexture = null;
}
public static void Reset()
{
EndBlend();
}
}