如何在 Unity C# 脚本中以 DirectX blob 形式访问已编译的着色器?

发布于 2025-01-11 03:36:23 字数 5580 浏览 0 评论 0 原文

我需要将 HLSL 着色器作为 ID3DBlob 进行访问,但我不确定如何在 Unity 中执行此操作。

我正在使用的示例

我正在使用 Unity 中的本机 API,我已使用 此处描述,每 这个答案。此 API 在示例中包含以下 C++ 调用(您可以从此处下载 ):

varjo_MRD3D11ConfigureShader(m_session, m_d3d11Device.Get(), varjo_ShaderType_VideoPostProcess, &shaderConfig,
            (shaderBlob ? static_cast<char*>(shaderBlob->GetBufferPointer()) : nullptr),
            shaderBlob ? static_cast<int32_t>(shaderBlob->GetBufferSize()) : 0);

这来自“实验性 API 视频后处理 API”一些文档此处(您必须下载“用于自定义引擎的 Varjo Experimental SDK”< /a> 然后导航到“/docs/_varjo__mr__experimental_8h.html#a01df1512b747fe2e8c75007ad5998d93”文件以获得正确的文档)。完整文档的屏幕截图如下:

在此处输入图像描述

我已确定 const char * 类型的 shaderData 参数包含正在发送的着色器数据到耳机。本问题开头的示例代码(取自链接的开发人员提供的示例)传递来自变量 shaderBlob 的数据,该变量的类型为 ID3DBlob 并且是 < a href="https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/nn-d3dcommon-id3d10blob" rel="nofollow noreferrer">在此处记录为 DirectX 的一部分。

在开发人员提供的 C++ 示例中,通过调用另一个 DirectX 函数 (ID3DBlob 数据结构-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dcompile" rel="nofollow noreferrer">记录在此处), D3DCompile

LOG_INFO("Loading shader source: HLSL Source: %s", shaderFilename.c_str());
auto shaderData = loadFile(shaderFilename);
if (!shaderData.empty()) {
    ComPtr<ID3DBlob> errorMsgs;
    
    // The function of interest - comment my own...
    HRESULT hr = D3DCompile(shaderData.data(), shaderData.size(), shaderFilename.c_str(), nullptr, nullptr, c_shaderEntrypoint, c_shaderTarget, 0,
        0, &shaderBlob, &errorMsgs);
    // --------------------------------------------

    if (FAILED(hr) && errorMsgs) {
        std::string err(reinterpret_cast<char*>(errorMsgs->GetBufferPointer()), errorMsgs->GetBufferSize());
        LOG_ERROR("Compiling post process shader failed: %s", err.c_str());
        return false;
    }
} else {
    return false;
}

微软还提供了一些额外的此处使用 DirectX 编译着色器的说明

这些开发人员提供的示例都是独立的 C++ 应用程序。

我想要做什么

使用Unity文档DllImport 属性文档传递结构教程,我已经从我的 C# 脚本设置了 API 调用,如下所示:

public class NativeSDKWrapper : MonoBehaviour
{
    #region Constants for DLL
    // ...

    /// <summary>
    /// See: http://[your localhost here]/_varjo__types__mr__experimental_8h.html
    /// </summary>
    private const Int64 VARJO_SHADER_TYPE_VIDEO_POST_PROCESS = 1;

    // ...
    #endregion

    #region Varjo Functions from DLL
    // ...

    [DllImport("VarjoLib")]
    private static extern void varjo_MRD3D11ConfigureShader(
        IntPtr session,
        IntPtr device,
        Int64 shaderType,
        ref VarjoShaderConfig shaderConfig, // I have defined the appropriate structs for this
        [MarshalAs(UnmanagedType.LPStr)]string data, // See: https://stackoverflow.com/questions/39987435/pass-char-to-c-dll-from-c-sharp-string
        int shaderSize);

    // ...
    #endregion

    public void LoadShaderFromFile(ShaderParams shaderParams)
    {
        // Shader asset accessed here, and the Varjo lock acquired,
        //     and then shader config set up.
        // ...
        
        // Send the shader to the Varjo headset.
        varjo_MRD3D11ConfigureShader(
            this._session,
            , // Still need to figure out getting the device.
            NativeSDKWrapper.VARJO_SHADER_TYPE_VIDEO_POST_PROCESS,
            ref shaderConfig,
            , // WHAT GOES HERE??? (this is the string type translated from ID3DBlob.
              // The blob's (string's?) size will go here
        );

        // Varjo unlock here...
        // ...
    }
}

How do I get from a Shader asset in my Unity Assets folder to the input string required for that function call (so as type [ MarshalAs(UnmanagedType.LPStr)]字符串数据)?我使用了 string 来与上面的屏幕截图相对应,将该输入记录为 const char *。同样,在开发人员提供的 C++ 示例中,此输入的类型为 ID3DBlob

Unity 是否公开了通过 D3DCompile 编译的 DirectX 着色器的等效项?这个问题还有道理吗? Unity 是否会为我处理该编译,并且我可以从某处以所需格式以字符串形式获取所需数据,并将其放入此本机 API 调用中?

我还阅读了一些 Unity DirectX 文档,但还没有发现它很有帮助。

I need to access an HLSL shader as an ID3DBlob, and I am unsure how to do this in Unity.

The example I am working from

I am working with a native API in Unity, which I have imported using a .dll file using the technique described here, per this answer. This API includes the following C++ call in the examples (you can download from here):

varjo_MRD3D11ConfigureShader(m_session, m_d3d11Device.Get(), varjo_ShaderType_VideoPostProcess, &shaderConfig,
            (shaderBlob ? static_cast<char*>(shaderBlob->GetBufferPointer()) : nullptr),
            shaderBlob ? static_cast<int32_t>(shaderBlob->GetBufferSize()) : 0);

This is from the "Experimental API Video post-processing API" some documentation here (you have to download the "Varjo Experimental SDK for Custom Engines" and then navigate to the "/docs/_varjo__mr__experimental_8h.html#a01df1512b747fe2e8c75007ad5998d93" file for proper documentation). A screenshot of the full documentation follows:

enter image description here

I have determined that the shaderData parameter of type const char * is what contains the shader data being sent to the headset. The example code in the beginning of this question (taken from the linked developer-provided examples) passes in the data from the variable shaderBlob, which is of type ID3DBlob and is documented as part of DirectX here.

In the developer-provided C++ example, the HLSL file is read in and converted to this ID3DBlob data structure by calling another DirectX function (documented here), D3DCompile:

LOG_INFO("Loading shader source: HLSL Source: %s", shaderFilename.c_str());
auto shaderData = loadFile(shaderFilename);
if (!shaderData.empty()) {
    ComPtr<ID3DBlob> errorMsgs;
    
    // The function of interest - comment my own...
    HRESULT hr = D3DCompile(shaderData.data(), shaderData.size(), shaderFilename.c_str(), nullptr, nullptr, c_shaderEntrypoint, c_shaderTarget, 0,
        0, &shaderBlob, &errorMsgs);
    // --------------------------------------------

    if (FAILED(hr) && errorMsgs) {
        std::string err(reinterpret_cast<char*>(errorMsgs->GetBufferPointer()), errorMsgs->GetBufferSize());
        LOG_ERROR("Compiling post process shader failed: %s", err.c_str());
        return false;
    }
} else {
    return false;
}

Microsoft also provides some additional explanation of compiling shaders using DirectX here.

These developer-provided examples are all a stand-alone C++ app.

What I am trying to do

Using the Unity documentation and the DllImport attribute documentation and the passing structs tutorial, I have set up the API call from my C# script as follows:

public class NativeSDKWrapper : MonoBehaviour
{
    #region Constants for DLL
    // ...

    /// <summary>
    /// See: http://[your localhost here]/_varjo__types__mr__experimental_8h.html
    /// </summary>
    private const Int64 VARJO_SHADER_TYPE_VIDEO_POST_PROCESS = 1;

    // ...
    #endregion

    #region Varjo Functions from DLL
    // ...

    [DllImport("VarjoLib")]
    private static extern void varjo_MRD3D11ConfigureShader(
        IntPtr session,
        IntPtr device,
        Int64 shaderType,
        ref VarjoShaderConfig shaderConfig, // I have defined the appropriate structs for this
        [MarshalAs(UnmanagedType.LPStr)]string data, // See: https://stackoverflow.com/questions/39987435/pass-char-to-c-dll-from-c-sharp-string
        int shaderSize);

    // ...
    #endregion

    public void LoadShaderFromFile(ShaderParams shaderParams)
    {
        // Shader asset accessed here, and the Varjo lock acquired,
        //     and then shader config set up.
        // ...
        
        // Send the shader to the Varjo headset.
        varjo_MRD3D11ConfigureShader(
            this._session,
            , // Still need to figure out getting the device.
            NativeSDKWrapper.VARJO_SHADER_TYPE_VIDEO_POST_PROCESS,
            ref shaderConfig,
            , // WHAT GOES HERE??? (this is the string type translated from ID3DBlob.
              // The blob's (string's?) size will go here
        );

        // Varjo unlock here...
        // ...
    }
}

How do I get from a shader asset in my Unity Assets folder to the input string needed for that function call (so as type [MarshalAs(UnmanagedType.LPStr)]string data)? I went with the string to correspond with the screenshot above documenting that input as a const char *. Again, in the developer-provided C++ example this input is of type ID3DBlob.

Does Unity expose an equivalent to that DirectX shader compiling through D3DCompile? Does that question even make sense? Does Unity handle that compiling for me, and I can just grab the needed data as a string in the needed format from somewhere to put into this native API call?

I have also read through some of the Unity DirectX documentation but have not found it helpful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文