unity3d,多个渲染目标 - Direct3D/OpenGl 中的不同行为

问题描述 投票:0回答:2

我正在为unity3d编写着色器。着色器使用多个渲染目标来渲染后处理效果。

但是,我遇到了有趣的问题。

当 Unity3d 在 direct3d 模式下运行时,默认情况下所有标准着色器仅将数据写入第一个颜色缓冲区(即索引为 0)。 IE。如果我将 3 个颜色缓冲区附加到相机,则调用索引为 0 的

Camera.Render
颜色缓冲区将包含渲染场景,并且所有其他缓冲区将保持不变,除非某些着色器专门写入其中。我的着色器利用了这种行为(我使用索引为 1 和 2 的缓冲区来积累后期处理效果所需的数据)。

但是,在 OpenGL 模式下,标准 unity3d 着色器会立即写入所有颜色缓冲区。 IE。如果我将多个渲染缓冲区附加到相机,请调用

Camera.Render
所有 3 个缓冲区将包含渲染场景的副本。

这会破坏我在 OpenGL 模式下的着色器。

我该如何解决这个问题?我需要一次性渲染整个场景,并且只有具有特定着色器的对象才应该修改额外的颜色缓冲区。

我需要一次性渲染场景,因为使用图层蒙版会导致统一重新计算所有灯光的投影仪阴影,并且我需要阴影正确。

建议?

opengl unity-game-engine directx shader cg
2个回答
1
投票

遗憾的是,事实证明“不写入渲染目标之一”是 opengl 中未记录的行为。标准统一着色器在为前向渲染路径编译时会产生

gl_FragData[0] = ...;
分配并仅写入一个缓冲区,这会触发未记录的行为并导致混乱。

为了解决这个问题,我需要让 Unity 将数据显式写入标准着色器中的附加渲染目标。不幸的是,这是无法完成的,因为没有“入口点”来“挂钩”标准着色器并将附加数据写入其他颜色缓冲区。最接近的是 "finalcolor" 修饰符,但它实际上不允许通过 CG 着色器写入额外的缓冲区(这需要来自片段着色器的额外数据,这是无法从表面着色器访问的),这是唯一可能的修改一种颜色。

我决定重写着色器的一部分(这样它就不会触发 OpenGL 中未记录的行为)并放弃在效果中提供统一阴影贴图支持。据我所知,除了修改 Unity 引擎(需要“特殊安排”和源代码访问)或用我自己的替换整个照明系统之外,没有其他选择。


0
投票

如果您想决定输出哪个RenderTarget,而不需要执行多个单独的通道,您可以使用#pragma 5.0 然后是 SV_RenderTargetArrayIndex 语义:

struct v2f
{
    float4 vertex : SV_POSITION;
    uint renderTargetIndex : SV_RenderTargetArrayIndex;
};

v2f vert(appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
                
    // Determine the render target index based on your criteria
    // For example, based on the vertex position or any other condition
    o.renderTargetIndex = /* your render target index calculation */;
                
    return o;
}

fixed4 frag(v2f i) : SV_Target
{
    // The output will be written to the render target specified by i.renderTargetIndex
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.