199 lines
6.4 KiB
C#
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();
|
|
}
|
|
}
|