一次渲染到完整的3D渲染目标

一次渲染到完整的3D渲染目标

本文介绍了一次渲染到完整的3D渲染目标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用DirectX 11,我创建了3D体积纹理,可以将其绑定为渲染目标:

Using DirectX 11, I created a 3D volume texture that can be bound as a render target:

D3D11_TEXTURE3D_DESC texDesc3d;
// ...
texDesc3d.Usage     = D3D11_USAGE_DEFAULT;
texDesc3d.BindFlags = D3D11_BIND_RENDER_TARGET;

// Create volume texture and views
m_dxDevice->CreateTexture3D(&texDesc3d, nullptr, &m_tex3d);
m_dxDevice->CreateRenderTargetView(m_tex3d, nullptr, &m_tex3dRTView);

我现在想更新整个渲染目标并将其填充在像素着色器中生成的过程数据,类似于使用全屏传递"更新2D渲染目标.我生成数据所需的一切就是相关像素的UVW坐标.

I would now like to update the whole render target and fill it with procedural data generated in a pixel shader, similar to updating a 2D render target with a 'fullscreen pass'. Everything I need to generate the data is the UVW coordinates of the pixel in question.

对于2D,可以构建一个渲染全屏三角形的简单顶点着色器:

For 2D, a simple vertex shader that renders a full screen triangle can be built:

struct VS_OUTPUT
{
    float4 position : SV_Position;
    float2 uv: TexCoord;
};

// input: three empty vertices
VS_OUTPUT main( uint vertexID : SV_VertexID )
{
    VS_OUTPUT result;
    result.uv = float2((vertexID << 1) & 2, vertexID & 2);
    result.position = float4(result.uv * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
    return result;
}

我很难理解如何将这一原理用于3D.在DirectX 11中甚至可以做到这一点,还是必须按照?

I have a hard time wrapping my head around how to adopt this principle for 3D. Is this even possible in DirectX 11, or do I have to render to individual slices of the volume texture as described here?

推荐答案

以下是使用管道版本进行操作的示例代码.您基本上可以批处理N个三角形,并使用Geometry Shader将每个实例路由到一个体积切片.

Here is some sample code doing it with pipeline version. You basically batch N triangles and route each instance to a volume slice using Geometry Shader.

struct VS_OUTPUT
{
    float4 position : SV_Position;
    float2 uv: TexCoord;
    uint index: SLICEINDEX;
};

VS_OUTPUT main( uint vertexID : SV_VertexID, uint ii : SV_InstanceID )
{
    VS_OUTPUT result;
    result.uv = float2((vertexID << 1) & 2, vertexID & 2);
    result.position = float4(result.uv * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
    result.index= ii;
    return result;
}

现在您需要调用具有3个顶点和N个实例(其中N是您的体积切片计数)的N个实例的DrawInstanced

Now you need to call DrawInstanced with 3 vertices and N instances where N is your volume slices count

然后您将三角形分配给GS,如下所示:

Then you assign triangles to GS like this:

struct psInput
{
    float4 pos : SV_POSITION;
    float2 uv: TEXCOORD0;
uint index : SV_RenderTargetArrayIndex; //This will write your vertex to a specific slice, which you can read in pixel shader too
};

[maxvertexcount(3)]
void GS( triangle VS_OUTPUT input[3], inout TriangleStream<psInput> gsout )
{
psInput output;
for (uint i = 0; i < 3; i++)
{
    output.pos = input[i].pos;
    output.uv = input[i].uv;
    output.index= input[0].index; //Use 0 as we need to push a full triangle to the slice
    gsout.Append(output);
}
gsout.RestartStrip();
}

现在您可以在像素着色器中访问切片索引:

Now you have access to slice index in your pixel shader:

float4 PS(psInput input) : SV_Target
{
//Do something with uvs, and use slice input as Z
}

计算着色器版本(不要忘记为您的卷创建UAV),这里的numthreads完全是任意的

Compute shader version (don't forget to create a UAV for your volume), and numthreads here is totally arbirtary

[numthreads(8,8,8)]
void CS(uint3 tid : SV_DispatchThreadID)
{
     //Standard overflow safeguards

     //Generate data using tid coordinates
}

现在,您需要使用以下命令调用dispatch宽度/8,高度/8,深度/8

Now instead you need to call dispatch withwidth/8, height/8, depth/8

这篇关于一次渲染到完整的3D渲染目标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-04 23:58