gpt4 book ai didi

graphics - unity3d:使用主相机的深度缓冲区来渲染另一个相机 View

转载 作者:行者123 更新时间:2023-12-04 03:20:19 25 4
gpt4 key购买 nike

在我的主相机渲染后,我想使用(或复制)它的深度缓冲区到(禁用)相机的深度缓冲区。
我的目标是在绘制不透明对象后使用深度缓冲区将粒子绘制到较小的渲染目标上(使用单独的相机)。
我无法在单个相机中执行此操作,因为出于性能原因,目标是为粒子使用较小的渲染目标。

Unity 中的替换着色器也不是一种选择:我希望我的粒子使用它们现有的着色器 - 我只想在绘制粒子之前用主相机深度缓冲区的二次采样版本覆盖粒子相机的深度缓冲区。

我没有收到任何回复 to my earlier question ;因此,转贴。

这是附加到我的主相机的脚本。它渲染所有非粒子层,我使用 OnRenderImage调用粒子相机。

public class MagicRenderer : MonoBehaviour {
public Shader particleShader; // shader that uses the main camera's depth buffer to depth test particle Z
public Material blendMat; // material that uses a simple blend shader
public int downSampleFactor = 1;

private RenderTexture particleRT;
private static GameObject pCam;

void Awake () {
// make the main cameras depth buffer available to the shaders via _CameraDepthTexture
camera.depthTextureMode = DepthTextureMode.Depth;
}

// Update is called once per frame
void Update () {

}

void OnRenderImage(RenderTexture src, RenderTexture dest) {
// create tmp RT
particleRT = RenderTexture.GetTemporary (Screen.width / downSampleFactor, Screen.height / downSampleFactor, 0);
particleRT.antiAliasing = 1;

// create particle cam
Camera pCam = GetPCam ();
pCam.CopyFrom (camera);
pCam.clearFlags = CameraClearFlags.SolidColor;
pCam.backgroundColor = new Color (0.0f, 0.0f, 0.0f, 0.0f);
pCam.cullingMask = 1 << LayerMask.NameToLayer ("Particles");
pCam.useOcclusionCulling = false;
pCam.targetTexture = particleRT;
pCam.depth = 0;

// Draw to particleRT's colorBuffer using mainCam's depth buffer
// ?? - how do i transfer this camera's depth buffer to pCam?
pCam.Render ();
// pCam.RenderWithShader (particleShader, "Transparent"); // I don't want to replace the shaders my particles use; os shader replacement isnt an option.

// blend mainCam's colorBuffer with particleRT's colorBuffer
// Graphics.Blit(pCam.targetTexture, src, blendMat);

// copy resulting buffer to destination
Graphics.Blit (pCam.targetTexture, dest);


// clean up
RenderTexture.ReleaseTemporary(particleRT);
}

static public Camera GetPCam() {
if (!pCam) {
GameObject oldpcam = GameObject.Find("pCam");
Debug.Log (oldpcam);
if (oldpcam) Destroy(oldpcam);

pCam = new GameObject("pCam");
pCam.AddComponent<Camera>();
pCam.camera.enabled = false;
pCam.hideFlags = HideFlags.DontSave;
}

return pCam.camera;
}

}

我还有几个问题:

1) 为什么 camera.depthTextureMode = DepthTextureMode.Depth;最终绘制场景中的所有对象只是为了写入 Z 缓冲区?使用 Intel GPA,我看到之前两次通过 OnRenderImage被称为:
(i) Z-PrePass,仅写入深度缓冲区
(ii) 颜色 channel ,写入颜色和深度缓冲区。

2)我使用替换着色器将不透明对象重新渲染到 pCam 的 RT,该着色器使用 ZWrite On 将 (0,0,0,0) 写入 colorBuffer (克服深度缓冲传输问题)。之后,我按如下方式重置图层并清除蒙版:
pCam.cullingMask = 1 << LayerMask.NameToLayer ("Particles");
pCam.clearFlags = CameraClearFlags.Nothing;

并使用 pCam.Render() 渲染它们.

我认为这会使用 ZTest 的现有着色器渲染粒子。
不幸的是,我注意到深度模板缓冲区在绘制粒子之前被清除(尽管我没有清除任何东西......)。

为什么会发生这种情况?

最佳答案

已经 5 年了,但我开发了一个几乎完整的解决方案,用于在较小的单独渲染目标中渲染粒子。我写这个给 future 的访客。还需要很多知识。

复制深度

首先,您必须以较小的渲染纹理的分辨率获得场景深度。
这可以通过使用颜色格式“深度”创建新的渲染纹理来完成。
要将场景深度写入低分辨率深度,请创建一个仅输出深度的着色器:

struct fragOut{
float depth : DEPTH;
};

sampler2D _LastCameraDepthTexture;

fragOut frag (v2f i){
fragOut tOut;
tOut.depth = tex2D(_LastCameraDepthTexture, i.uv).x;
return tOut;
}

_LastCameraDepthTexture 由 Unity 自动填充,但有一个缺点。
仅当主相机使用延迟渲染进行渲染时,它才会免费提供。
对于前向着色,Unity 似乎仅针对深度纹理再次渲染场景。
检查帧调试器。

然后,向执行着色器的主相机添加后期处理效果:
protected virtual void OnRenderImage(RenderTexture pFrom, RenderTexture pTo) {
Graphics.Blit(pFrom, mSmallerSceneDepthTexture, mRenderToDepthMaterial);
Graphics.Blit(pFrom, pTo);
}

你可能可以在没有第二个 blit 的情况下做到这一点,但对我来说更容易进行测试。

使用复制的深度进行渲染

要为第二台相机使用新的深度纹理,请调用
mSecondCamera.SetTargetBuffers(mParticleRenderTexture.colorBuffer, mSmallerSceneDepthTexture.depthBuffer);

保持 targetTexture 为空。
然后,您必须确保第二个摄像头不会清除深度,而只会清除颜色。
为此,完全禁用第二台相机上的清除并像这样手动清除
Graphics.SetRenderTarget(mParticleRenderTexture);
GL.Clear(false, true, Color.clear);

我建议也手动渲染第二台相机。禁用它并调用
mSecondCamera.Render();

清除后。

合并

现在您必须合并主 View 和单独的图层。
根据您的渲染,您可能最终会得到具有所谓预乘 alpha 的渲染纹理。

要将其与其余部分混合,请在主相机上使用后期处理步骤
fixed4 tBasis = tex2D(_MainTex, i.uv);
fixed4 tToInsert = tex2D(TransparentFX, i.uv);

//beware premultiplied alpha in insert
tBasis.rgb = tBasis.rgb * (1.0f- tToInsert.a) + tToInsert.rgb;
return tBasis;

添加 Material 开箱即用,但 alpha 混合则不然。
您必须创建一个带有自定义混合的着色器来创建工作 alpha 混合 Material 。混合是
Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha

这会更改为每次执行的混合修改 Alpha channel 的方式。

结果

在 alpha 混合前添加混合
add blended in front of alpha blended

效果层rgb
rgb

效果层阿尔法
alpha

alpha 混合在添加混合之前
alpha blended in front of add blended

效果层rgb
rgb

效果层阿尔法
alpha

我还没有测试性能是否真的提高了。
如果有人有更简单的解决方案,请告诉我。

关于graphics - unity3d:使用主相机的深度缓冲区来渲染另一个相机 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22696123/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com