【渲染流水线】[输出阶段]-[双缓冲机制]以UnityURP为例
- 最终将处理结果写入颜色/深度/模板缓冲区
- 可独立控制各通道写入权限
【从UnityURP开始探索游戏渲染】专栏-直达
双缓冲机制介绍
双缓冲(Double Buffer)是一种图形渲染中的常用技术,通过使用两个缓冲区(前台缓冲区和后台缓冲区)来解决图形渲染过程中的闪烁和撕裂问题。在Unity URP中,双缓冲机制主要用于管理渲染目标,确保渲染过程的平滑进行。
双缓冲的核心原理是:一个缓冲区用于当前显示的帧(前台缓冲区),另一个缓冲区用于绘制新帧(后台缓冲区)。当后台缓冲区完成绘制后,系统会执行交换操作,将两个缓冲区瞬时交换。现代GPU通常使用三重缓冲等多缓冲技术来进一步优化性能。
历史发展流程
双缓冲技术最早应用于图形显示领域,用于解决屏幕刷新和图形绘制之间的同步问题。在Unity引擎中,双缓冲机制随着渲染管线的演进不断优化:
- 内置渲染管线时期:Unity早期版本使用内置渲染管线,双缓冲主要通过命令缓冲区(CommandBuffer)实现,开发者可以手动管理渲染目标的切换。
- 可编程渲染管线(SRP)引入:Unity 2018版本引入可编程渲染管线概念,为双缓冲提供了更灵活的接口。
- URP成熟期:在URP(Universal Render Pipeline)中,双缓冲机制被系统化封装,形成了SwapBufferSystem等高级抽象,优化了后处理流程。
内置管线与URP中的双缓冲变量
内置管线中的双缓冲变量
在内置渲染管线中,双缓冲主要通过以下变量和机制实现:
CommandBuffer:存储一系列渲染指令的容器,可用于设置渲染目标RenderTexture:临时渲染纹理,常被用作后台缓冲区BuiltinRenderTextureType:内置纹理类型,包括CurrentActive和CameraTarget等
URP中的双缓冲变量
URP对双缓冲机制进行了更高级的封装,主要涉及以下变量和类:
SwapBufferSystem:URP中的双缓冲系统实现,包含m_A和m_B两个SwapBuffer结构体RenderTargetHandle:URP中表示渲染目标的句柄ScriptableRenderPass:渲染通道基类,包含设置渲染目标的接口UniversalRenderer:URP默认渲染器,管理双缓冲的初始化和交换
底层原理解析
底层实现核心类与变量
在Unity URP中,双缓冲机制主要通过SwapBufferSystem类实现,该类包含两个关键变量m_A和m_B,分别代表前后缓冲区。具体实现位于UniversalRenderer类中,作为渲染目标管理系统的核心组件。
主要实现细节
SwapBuffer结构体:包含name(缓冲区名称)和rt(RenderTexture)两个字段SwapBufferSystem类:管理两个SwapBuffer实例的交换逻辑UniversalRenderer类:初始化并控制双缓冲系统的生命周期
缓冲区创建
- 在
UniversalRenderer的Setup方法中创建两个渲染目标,这些目标实际上是纹理支持的帧缓冲。
描述符控制
- 通过
cameraTargetDescriptor参数描述渲染目标的内存分配方式,可以在AddRenderPasses阶段修改这些参数来"劫持"渲染目标。
交换机制
- URP使用
SwapBufferSystem维护两个渲染目标缓冲区(m_A和m_B),在渲染过程中交替使用,避免中间环节的重复拷贝。
同步控制
- 双缓冲与VSync信号配合工作,确保缓冲区交换与屏幕刷新同步,防止画面撕裂.
双缓冲机制URP示例
后处理效果双缓冲实现
PostProcessFeature.cs
后处理效果中如何使用临时渲染目标实现双缓冲交换,避免直接修改原始帧缓冲导致的问题
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal; public class CustomPostProcessPass : ScriptableRenderPass
{
private Material m_Material;
private RenderTargetHandle m_TemporaryColorTexture;
private RenderTargetHandle m_CameraColorTexture; public CustomPostProcessPass(Material material)
{
m_Material = material;
m_TemporaryColorTexture.Init("_TemporaryColorTexture");
} public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
cmd.GetTemporaryRT(m_TemporaryColorTexture.id, cameraTextureDescriptor);
} public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get("Custom Post Processing"); // 双缓冲交换
Blit(cmd, m_CameraColorTexture.Identifier(),
m_TemporaryColorTexture.Identifier(), m_Material);
Blit(cmd, m_TemporaryColorTexture.Identifier(),
m_CameraColorTexture.Identifier()); context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
} public override void FrameCleanup(CommandBuffer cmd)
{
cmd.ReleaseTemporaryRT(m_TemporaryColorTexture.id);
}
}
自定义渲染目标双缓冲系统
CustomBufferSystem.cs
实现了一个简单的双缓冲系统示例,可用于需要多帧数据累积的效果如运动模糊
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal; public class CustomBufferSystem
{
private RenderTargetHandle[] m_Buffers = new RenderTargetHandle[2];
private int m_CurrentBufferIndex = 0; public void Initialize(string name)
{
m_Buffers[0].Init(name + "_Buffer0");
m_Buffers[1].Init(name + "_Buffer1");
} public RenderTargetHandle GetCurrentBuffer()
{
return m_Buffers[m_CurrentBufferIndex];
} public RenderTargetHandle GetNextBuffer()
{
return m_Buffers[(m_CurrentBufferIndex + 1) % 2];
} public void Swap()
{
m_CurrentBufferIndex = (m_CurrentBufferIndex + 1) % 2;
} public void Dispose(CommandBuffer cmd)
{
cmd.ReleaseTemporaryRT(m_Buffers[0].id);
cmd.ReleaseTemporaryRT(m_Buffers[1].id);
}
}
URP多相机渲染双缓冲同步
MultiCameraRenderer.cs
多相机渲染场景中如何使用双缓冲机制实现平滑的相机切换效果
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal; public class MultiCameraRenderer : MonoBehaviour
{
public Camera[] cameras;
private RenderTexture[] buffers = new RenderTexture[2];
private int currentBufferIndex = 0; void Start()
{
buffers[0] = new RenderTexture(Screen.width, Screen.height, 24);
buffers[1] = new RenderTexture(Screen.width, Screen.height, 24);
} void Update()
{
var renderer = (UniversalRenderPipelineAsset)GraphicsSettings.currentRenderPipeline; // 渲染到后台缓冲区
int nextBufferIndex = (currentBufferIndex + 1) % 2;
cameras[0].targetTexture = buffers[nextBufferIndex]; // 交换缓冲区
currentBufferIndex = nextBufferIndex; // 显示当前缓冲区
Graphics.Blit(buffers[currentBufferIndex], null as RenderTexture);
}
}
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,)
【渲染流水线】[输出阶段]-[双缓冲机制]以UnityURP为例的更多相关文章
- Qt5双缓冲机制与实例
1. 双缓冲机制 所谓双缓冲机制,是指在绘制控件时,首先将要绘制的内容绘制在一个图片中,再将图片一次性地绘制到控件上. 在早期的Qt版本中,若直接在控件上进行绘制工作,则在控件重绘时会产生闪烁的现象, ...
- Qt双缓冲机制:实现一个简单的绘图工具(纯代码实现)
http://blog.csdn.net/rl529014/article/details/51658350
- VC GDI双缓冲机制绘图防屏幕闪烁实现步骤
在OnDraw(CDC* pDC) 中添加如下代码 CDC MemDC; //首先定义一个显示设备对象 CBitmap MemBitmap;//定义一个位图对象 //随后建立与屏幕显示兼容的内存显示设 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线 学习目标 了解几个用以表达真实场景的标志和2D图像 ...
- STM32的bulk双缓冲传输速度的讨论,硬件的坑永远填不完
详情:http://bbs.21ic.com/forum.php?mod=viewthread&tid=109584 USB 1.0的最高12Mbps. USB 2.0的高速模式480Mb ...
- 双缓冲绘图和窗口控件的绘制——ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 .
双缓冲绘图和窗口控件的绘制 ---ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 cheungmine 我们通常使用ATL COM组件,生成一个带窗口的ActiveX控件,然后 ...
- 【MFC】利用双缓冲和随机函数rand()实现蒲公英飞舞
原始日期:2014-05-29 22:44 这几天有些懒,几乎没怎么学MFC了,好容易有个题目:用双缓冲实现蒲公英飞舞,想来想去也没想到好方法,索性动手开始 写了 ,这一写,得,出来了,呵呵,无意中产 ...
- 双缓冲解决控制台应用程序输出“闪屏”(C/C++,Windows)
使用 C 语言编写游戏的小伙伴们想必起初都要遇到这样的问题,在不断清屏输出数据的过程中,控制台中的输出内容会不断地闪屏.出现这个问题的原因是程序对数据处理花掉的时间影响到了数据显示,或许你可以使用局部 ...
- avalon与双缓冲技术
avalon与双缓冲技术 avalon1.5一个重要技术升级是引进异步渲染.异步渲染在游戏界有一个更专业的名字,叫双缓冲.游戏界要刷新界面与我们刷新浏览器视图,面临的问题是一致的.视图是由许多存在套嵌 ...
- 《UnityShader入门精要》学习笔记之渲染流水线
第一种分类方式: 图形管道(如下7步): 顶点数据 : 由3D模型传递的三角形网格 顶点着色 : 编写CG程序对各个顶点进行着色 生成几何图元 : 连接特定的顶点生成几何图元,例如连接三个顶点生成一个 ...
随机推荐
- 记一次 .NET 某发证机系统 崩溃分析
一:背景 1. 讲故事 前些天有位朋友在微信上找到我,说他的系统有偶发崩溃,自己也没找到原因,让我帮忙看下怎么回事,我分析dump一直都是免费的,毕竟对这些东西挺感兴趣,有问题可以直接call我,好了 ...
- XXL-JOB分布式任务调度平台
简介 概述 XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速.学习简单.轻量级.易扩展.现已开放源代码并接入多家公司线上产品线,开箱即用. 特性 1.简单:支持通过Web页面对任务进行 ...
- 【C#】字符串提取(获取两个字符串中间的字符串)
[C#]字符串提取(获取两个字符串中间的字符串) https://blog.csdn.net/weixin_43553508/article/details/102673668 C#三行代码实现提取两 ...
- dotnet (.Net) Core在不是Web 项目中使用HttpClientFactory正确用法
在不是web 项目中也不是Api 中使用 HttpClientFactory 先需要添加 Microsoft.Extensions.DependencyInjection.Abstractions M ...
- 快速傅里叶变换(FFT) 笔记
2.upd.2025.7.10 oi.polo.fft 快速傅里叶变换(Fast Fourier Transform) FFT三问: 1.什么是FFT 一个快速处理卷积的算法 2.什么是卷积 就是多项 ...
- vue 停止检查 eslint
简介 写项目的时候,用这个在开发的时候简直想死的心都有了,如何屏蔽呢 step vscode 搜索字符串 config.dev.useEslint 变为 ...(config.dev.useEslin ...
- matlab 求解高阶方程
简介 van der Pol 方程 code dy = @(t,y)[y(2); 1000 * (1-y(1)^2)*y(2)-y(1)]; % 定义匿名函数 [t,y]= ode15s(dy,[0 ...
- MySQL 数据同步至 S3file,并接入 Hive 访问:SeaTunnel 实践指南
作者 | 番兄 如何借助 Apache SeaTunnel 将 MySQL 数据高效同步至 S3file?本文详述的步骤已全部通过测试验证,适用于构建基于对象存储的数据中台场景,具备部署灵活.扩展性强 ...
- 产品更新丨谷云科技ETLCloud 3.9.3 版本发布
在数字化集成领域不断探索创新的谷云科技,为持续提升 ETLCloud 集成平台的性能和用户体验,于近期发布了 3.9.3 版本.本次迭代带来了新功能.对现有组件进行了优化,同时修复了多个影响系统稳定性 ...
- Transformers/SpaCy安装在Android手机(Termux)的Python Data Science开发环境
安装Rust(Python库safetensors依赖Rust)并启用本地仓库crates加速下载: $ rm -rf ~/.cargo #删除所有Rust残余旧版本 $ pkg install ru ...