拓冰建站拓冰建站
首页 / 资讯中心 / 正文

游戏内置相机模式与景深虚化算法:中秋合影功能实现

游戏内置相机模式与景深虚化算法中秋合影功能实现在中秋节日活动或大型社交版本上线期间“拍照模式”Photo Mode / 相机合影功能是激发玩家社交传播、提高游戏活跃度的核心功能之一。玩家希望在明月中秋之夜与帮派好友或 NPC 角色并肩而立自由调节焦距、光圈、旋转构图拍出具有单反级大光圈虚化Bokeh Depth of Field与节日氛围感的高清游戏截图。很多项目的内置拍照功能往往只是简单地隐藏 UI 并调用ScreenCapture.CaptureScreenshot()导致拍出来的照片缺乏层次感与光学真实感。在引擎渲染管线中实现一套高质量的实时景深虚化DoF与单反相机物理参数模拟系统是提升游戏视觉质感的关键环节。光学物理模型与弥散圆Circle of Confusion, CoC计算真实单反相机的景深效果由薄透镜成像定律Thin Lens Equation决定。当物体不处于对焦平面Focus Plane时物点在传感器上成像为一个圆形光斑称为弥散圆Circle of Confusion, CoC。CoC 的物理直径 $c$ 可通过焦距 $f$、光圈数 $N$F-stop、对焦距离 $d_{\text{focus}}$ 以及物体实际深度 $z$ 计算得出$$c \frac{f^2}{N \cdot (d_{\text{focus}} - f)} \cdot \frac{|z - d_{\text{focus}}|}{z}$$在实时着色器中我们通常将该物理公式转化为屏幕归一化坐标下的 CoC 半径值并将景深解耦为**近景虚化区Near Field与远景虚化区Far Field**分别计算以防止前景物体的颜色错误溢出到背景深色区域Foreground Bleeding Artifacts。// HLSL: 物理相机 CoC 计算 Pass (CameraCoC.hlsl) #ifndef PHYSICAL_CAMERA_COC_INCLUDED #define PHYSICAL_CAMERA_COC_INCLUDED #include Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl Texture2D _CameraDepthTexture; SamplerState sampler_CameraDepthTexture; CBUFFER_START(PhysicalCameraParams) float _FocalLength; // 镜头焦距 (米如 0.05 代表 50mm) float _ApertureFStop; // 光圈 F 值 (如 1.4, 2.8) float _FocusDistance; // 对焦距离 (米) float _MaxCoCRadius; // 最大弥散圆像素半径 float4 _ZBufferParamsCopy; CBUFFER_END // 计算线性真实深度 (米) float GetLinearDepth(float rawDepth) { return LinearEyeDepth(rawDepth, _ZBufferParamsCopy); } // 片元着色器输出 CoC 因子到 R16G16F 纹理 (x: 远景 CoC, y: 近景 CoC) float2 FragCalculateCoC(float2 uv : TEXCOORD0) : SV_Target { float rawDepth _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, uv, 0).r; float z GetLinearDepth(rawDepth); // 计算透镜孔径直径 A f / N float apertureDiameter _FocalLength / _ApertureFStop; // 计算弥散圆直径 (薄透镜近似公式) float coc (apertureDiameter * _FocalLength * abs(z - _FocusDistance)) / (_FocusDistance * (z - _FocalLength) 1e-5); // 映射至屏幕像素空间 float pixelCoC (coc / 0.036) * _ScreenParams.x; // 假设 36mm 全画幅传感器底片 pixelCoC clamp(pixelCoC, 0.0, _MaxCoCRadius); float farCoC 0.0; float nearCoC 0.0; if (z _FocusDistance) { // 远景虚化 farCoC pixelCoC; } else { // 近景虚化 nearCoC pixelCoC; } return float2(farCoC, nearCoC); } #endif多边形光斑模拟Gather-based Circular / Hexagonal Bokeh Blur传统的双向高斯模糊虽然计算快速但只能产生雾状的平滑模糊完全失去了大光圈下明亮光源形成的晶莹剔透的多边形/圆形光斑Bokeh。高质量景深通常采用基于收集Gather-based的圆盘或六边形泊松采样Poisson Disk Sampling / Golden Spiral。在片元着色器中对采样点的 HDR 颜色进行亮度加权Highlight Boost使得高光区域能够放大为璀璨的节日光斑。// HLSL: 高质量圆盘光斑收集模糊 Pass #define SAMPLE_COUNT 32 static const float2 GoldenSpiralSamples[SAMPLE_COUNT] { float2(0.000, 0.000), float2(0.125, 0.216), float2(-0.216, 0.125), float2(0.245, -0.245), float2(-0.353, -0.204), float2(0.380, 0.285), // ... 黄金螺旋泊松圆盘采样点分布 float2(-0.707, 0.707), float2(0.866, -0.500), float2(-0.950, -0.312) }; Texture2D _MainTex; SamplerState sampler_MainTex; Texture2D _CoCTexture; SamplerState sampler_CoCTexture; float4 FragGatherBokeh(float2 uv : TEXCOORD0) : SV_Target { float2 centerCoC _CoCTexture.SampleLevel(sampler_CoCTexture, uv, 0).xy; float effectiveCoC max(centerCoC.x, centerCoC.y); if (effectiveCoC 0.5) { // 焦点清晰区域直接返回原图跳过昂贵的循环采样 return _MainTex.SampleLevel(sampler_MainTex, uv, 0); } float4 accColor 0; float totalWeight 0; [unroll(SAMPLE_COUNT)] for (int i 0; i SAMPLE_COUNT; i) { float2 offset GoldenSpiralSamples[i] * effectiveCoC * _ScreenParams.zw; float2 sampleUV uv offset; float4 color _MainTex.SampleLevel(sampler_MainTex, sampleUV, 0); float2 sampleCoC _CoCTexture.SampleLevel(sampler_CoCTexture, sampleUV, 0).xy; // 深度权重混合抑制近景向远景的溢色瑕疵 float sampleRadius max(sampleCoC.x, sampleCoC.y); float weight saturate((sampleRadius - length(offset * _ScreenParams.xy)) 1.0); // HDR 高光增益突出中秋月光与灯笼的晶莹光斑 float luminance dot(color.rgb, float3(0.2126, 0.7152, 0.0722)); float highlightFactor 1.0 pow(saturate(luminance - 0.8), 2.0) * 5.0; accColor color * (weight * highlightFactor); totalWeight weight * highlightFactor; } return accColor / (totalWeight 1e-4); }相机控制器与高分辨率截屏管线设计为了给玩家提供类似专业相机的操控体验客户端封装了完整的对焦测距射线检测Tap-to-Focus与无 UI 纯净超清截屏管线。using UnityEngine; using System.IO; public class GamePhotoStudioController : MonoBehaviour { [Header(相机镜头硬件参数)] [SerializeField] private Camera photoCamera; [Range(0.024f, 0.200f)] [SerializeField] private float focalLength 0.085f; // 85mm 人像黄金焦段 [Range(1.2f, 16.0f)] [SerializeField] private float apertureFStop 1.8f; // F1.8 大光圈 [SerializeField] private float focusDistance 3.5f; [Header(滤镜与后处理)] [SerializeField] private Material dofMaterial; void Update() { // 玩家点击屏幕自动对焦 (Tap to Focus) if (Input.GetMouseButtonDown(0)) { Ray ray photoCamera.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit, 100.0f)) { focusDistance Vector3.Distance(photoCamera.transform.position, hit.point); UpdateCameraParameters(); } } } public void UpdateCameraParameters() { dofMaterial.SetFloat(_FocalLength, focalLength); dofMaterial.SetFloat(_ApertureFStop, apertureFStop); dofMaterial.SetFloat(_FocusDistance, focusDistance); } public void CaptureUltraHDPhoto(int superSamplingMultiplier, string saveFileName) { int width Screen.width * superSamplingMultiplier; int height Screen.height * superSamplingMultiplier; var rt RenderTexture.GetTemporary(width, height, 24, RenderTextureFormat.ARGB32); photoCamera.targetTexture rt; photoCamera.Render(); RenderTexture.active rt; var screenshot new Texture2D(width, height, TextureFormat.RGB24, false); screenshot.ReadPixels(new Rect(0, 0, width, height), 0, 0); screenshot.Apply(); photoCamera.targetTexture null; RenderTexture.active null; RenderTexture.ReleaseTemporary(rt); // 异步将截屏编码并保存到本地相册 byte[] bytes screenshot.EncodeToPNG(); Destroy(screenshot); File.WriteAllBytes(saveFileName, bytes); Debug.Log($[PhotoMode] UltraHD Photo saved to {saveFileName}); } }在中秋活动场景中通过将 85mm 人像长焦镜头模型、F1.8 大光圈虚化以及圆盘光斑算法深度集成玩家拍摄中秋月下合影时远处的满月与灯笼能够自然化作如梦似幻的圆形光斑而近处的人物发丝与服饰细节清晰锐利大幅提升了玩家在社交媒体上的分享欲望与画面口碑。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门