使用 D3D9、SH3 和 HLSL 将 3D 对象淡化到背景中
Fading a 3D object into the background, using D3D9, SH3 & HLSL
我有一个使用 DirectX 3D 9 和 HLSL 渲染几个 3D 对象的简单程序。我刚开始使用 HLSL,我没有 3D 渲染经验。
我能够更改模型的纹理和颜色并在两个纹理之间淡入淡出而不会出现问题,但是我想知道简单地淡化 3D 对象(将其与背景混合)的最佳方法是什么。我假设它不会在两个纹理之间淡化(使用 lerp
),因为我希望对象淡化到整个背景,所以它后面会有许多不同的纹理。
我使用LPD3DXEFFECT
作为我的效果class,DrawIndexedPrimitive
作为我每遍的绘图函数,我只有一个遍。我也在使用 Shader Model 3,因为这是一个较旧的项目。
我认为可能的唯一方法是在应用任何更改之前简单地获取像素的颜色,然后使用模型纹理的颜色对其进行计算以获得褪色像素。然而,在浏览互联网后,似乎实际上不可能在使用 HLSL 对像素进行任何操作之前获取像素的颜色。
甚至可以使用 HLSL 做这样的事情吗?我是否遗漏了一些可以帮助我的东西?
感谢任何帮助!
请原谅我的误解,但听起来您是在尝试模拟透明度而不是使用 built-in 透明度。
如果您试图获取对象后面像素的颜色并希望避免使用透明度,我会首先尝试使用最后渲染的帧作为纹理,然后在您当前的图像中引用该纹理着色器。可能有一些方法可以在同一帧内完成 - 强制所有其他渲染先进行,然后处理一个对象 - 但我不知道。
经过长时间的研究,我终于找到了一个很好的解决方法来解决我的问题,我会尝试向其他有问题的人解释我对它的理解。感谢 Alexander Stewart 建议可能有 in-built 的方法。
方法说明
除了在 HLSL 像素着色器中处理背景淡入淡出,还有另一种方法,使用称为 Frame Buffer Alpha Blending 的方法(完整的 MS Docs 文档: https://docs.microsoft.com/en-us/windows/win32/direct3d9/frame-buffer-alpha).
此方法背后的基本思想是提供一种将要渲染的给定像素与屏幕上的现有像素混合的简单方法。遵循一个公式:FinalColor = ObjectPixelColor * SourceBlendFactor + BackgroundPixelColor * DestinationBlendFactor
,所有这些“变量”都是 4 个浮点值的组,格式为 (R, G, B, A)。
我是如何实现的
在对实际着色器进行任何操作之前,在我的 Visual Studio C++ 文件中,我必须向我的渲染设备传递一些标志(我使用 LPDIRECT3DDEVICE9
作为我的设备 class) .我必须为 D3DRS_SRCBLEND
和 D3DRS_DESTBLEND
设置渲染状态,它们在上面的公式中分别引用 ObjectPixelColor
和 DestinationBlendFactor
。这些将是我的因素,它们将乘以我的每一个对象和背景像素颜色。有许多可能的值可以分配给 D3DRS_SRCBLEND
和 D3DRS_DESTBLEND
,完整列表在上面的 MS 文档 link 中可用,但为了实现我想要的(只是一种方式将一个对象淡化到背景中,alpha 数字从 0 到 1),我想出标志应该是这样的:SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
.
设置这些标志后,在通过我的着色器和渲染之前,我只需要再设置一个标志:SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
。我也可以在 TRUE
和 FALSE
之间切换,而无需更改任何其他内容,没有渲染问题(虽然我的项目非常简单,但它可能会在更大的项目上引起问题)。然后您可以将任何您想要的参数(例如 alpha 数字)作为全局变量传递给 HLSL 着色器(我使用 SetValue()
做到了)。
回到我的 HLSL 着色器,在这些更改之后,传递从我的像素着色器的 tex2D()
函数中获取的颜色 float4
变量,其 alpha 值介于 0 和 1 之间,产生了正确的 alpha ,如果没有其他问题(我当时有但没有意识到的另一个问题是我的透明对象实际上在背景之前渲染,所以我只能建议在渲染时检查渲染顺序项目)。
我敢肯定,使用最新的 DirectX 可能有更好的方法来实现这一点,但我的编译器仅支持 Shader Model 3 及更低版本。
我有一个使用 DirectX 3D 9 和 HLSL 渲染几个 3D 对象的简单程序。我刚开始使用 HLSL,我没有 3D 渲染经验。
我能够更改模型的纹理和颜色并在两个纹理之间淡入淡出而不会出现问题,但是我想知道简单地淡化 3D 对象(将其与背景混合)的最佳方法是什么。我假设它不会在两个纹理之间淡化(使用 lerp
),因为我希望对象淡化到整个背景,所以它后面会有许多不同的纹理。
我使用LPD3DXEFFECT
作为我的效果class,DrawIndexedPrimitive
作为我每遍的绘图函数,我只有一个遍。我也在使用 Shader Model 3,因为这是一个较旧的项目。
我认为可能的唯一方法是在应用任何更改之前简单地获取像素的颜色,然后使用模型纹理的颜色对其进行计算以获得褪色像素。然而,在浏览互联网后,似乎实际上不可能在使用 HLSL 对像素进行任何操作之前获取像素的颜色。
甚至可以使用 HLSL 做这样的事情吗?我是否遗漏了一些可以帮助我的东西?
感谢任何帮助!
请原谅我的误解,但听起来您是在尝试模拟透明度而不是使用 built-in 透明度。
如果您试图获取对象后面像素的颜色并希望避免使用透明度,我会首先尝试使用最后渲染的帧作为纹理,然后在您当前的图像中引用该纹理着色器。可能有一些方法可以在同一帧内完成 - 强制所有其他渲染先进行,然后处理一个对象 - 但我不知道。
经过长时间的研究,我终于找到了一个很好的解决方法来解决我的问题,我会尝试向其他有问题的人解释我对它的理解。感谢 Alexander Stewart 建议可能有 in-built 的方法。
方法说明
除了在 HLSL 像素着色器中处理背景淡入淡出,还有另一种方法,使用称为 Frame Buffer Alpha Blending 的方法(完整的 MS Docs 文档: https://docs.microsoft.com/en-us/windows/win32/direct3d9/frame-buffer-alpha).
此方法背后的基本思想是提供一种将要渲染的给定像素与屏幕上的现有像素混合的简单方法。遵循一个公式:FinalColor = ObjectPixelColor * SourceBlendFactor + BackgroundPixelColor * DestinationBlendFactor
,所有这些“变量”都是 4 个浮点值的组,格式为 (R, G, B, A)。
我是如何实现的
在对实际着色器进行任何操作之前,在我的 Visual Studio C++ 文件中,我必须向我的渲染设备传递一些标志(我使用 LPDIRECT3DDEVICE9
作为我的设备 class) .我必须为 D3DRS_SRCBLEND
和 D3DRS_DESTBLEND
设置渲染状态,它们在上面的公式中分别引用 ObjectPixelColor
和 DestinationBlendFactor
。这些将是我的因素,它们将乘以我的每一个对象和背景像素颜色。有许多可能的值可以分配给 D3DRS_SRCBLEND
和 D3DRS_DESTBLEND
,完整列表在上面的 MS 文档 link 中可用,但为了实现我想要的(只是一种方式将一个对象淡化到背景中,alpha 数字从 0 到 1),我想出标志应该是这样的:SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
.
设置这些标志后,在通过我的着色器和渲染之前,我只需要再设置一个标志:SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
。我也可以在 TRUE
和 FALSE
之间切换,而无需更改任何其他内容,没有渲染问题(虽然我的项目非常简单,但它可能会在更大的项目上引起问题)。然后您可以将任何您想要的参数(例如 alpha 数字)作为全局变量传递给 HLSL 着色器(我使用 SetValue()
做到了)。
回到我的 HLSL 着色器,在这些更改之后,传递从我的像素着色器的 tex2D()
函数中获取的颜色 float4
变量,其 alpha 值介于 0 和 1 之间,产生了正确的 alpha ,如果没有其他问题(我当时有但没有意识到的另一个问题是我的透明对象实际上在背景之前渲染,所以我只能建议在渲染时检查渲染顺序项目)。
我敢肯定,使用最新的 DirectX 可能有更好的方法来实现这一点,但我的编译器仅支持 Shader Model 3 及更低版本。