C++ D3D11 DrawIndexed()正在绘制到错误的渲染目标

C++ D3D11 DrawIndexed()正在绘制到错误的渲染目标,c++,directx,direct3d,render-to-texture,oculus,C++,Directx,Direct3d,Render To Texture,Oculus,我正在尝试将场景渲染为两种纹理(左侧和右侧),以用于Oculus Rift。当我将渲染目标设置为2D纹理渲染视图并调用DrawIndexed()时,它将渲染到后缓冲区而不是纹理。我正在使用VisualStudio,我已经在上面运行了图形诊断。在DrawIndexed()事件中,它显示渲染目标是纹理,但像素历史记录不显示该事件。如果我不清除backbuffer,屏幕上将显示该场景 在下面的代码中,RenderLeft()函数应将图像渲染到绿色背景上的平面,并将渲染目标设置为左渲染纹理。然后Rend

我正在尝试将场景渲染为两种纹理(左侧和右侧),以用于Oculus Rift。当我将渲染目标设置为2D纹理渲染视图并调用DrawIndexed()时,它将渲染到后缓冲区而不是纹理。我正在使用VisualStudio,我已经在上面运行了图形诊断。在DrawIndexed()事件中,它显示渲染目标是纹理,但像素历史记录不显示该事件。如果我不清除backbuffer,屏幕上将显示该场景

在下面的代码中,RenderLeft()函数应将图像渲染到绿色背景上的平面,并将渲染目标设置为左渲染纹理。然后RenderRight()应获取RenderLeft()渲染的纹理,并将其渲染到平面,然后在后缓冲区中输出该纹理。(注意:这不是正常设置。这只是为了帮助查看纹理是否正在渲染到)

在最终输出中,屏幕左侧应该没有任何内容,右侧应该是黑色背景上绿色矩形内的源图像

相反,我得到的是:

RenderLeft渲染到后缓冲区,即使渲染目标是纹理,因此RenderRight使用的纹理只是用于清除它的颜色

这是我目前正在使用的代码。我想我已经包括了所有相关的内容

// this is the function used to render a single frame
void  Direct3D::RenderFrame()
{

CreateTransforms(); //this creates matFinalLeft and matFinalRight, which is  (world matrix)*(view matrix)*(projection matrix) with the proper offsets for a stereoscopic view.

setVertices(); //this sets the vertex and index buffers.

setMainShaders(); // this sets the shaders used to render the 3D scene

RenderLeft(pTextureLeftRenderView, matFinalLeft, viewportLeft, true); //this renders an image to a plane on a green background. It SHOULD render to a texture.

RenderRight(backbuffer, matFinalRight, viewportRight, false);//this renders the render target from RenderLeft to the plane and renders to the back buffer.

swapchain->Present(0, 0); //output back buffer to screen.
}
此部分应渲染渲染纹理左侧带有图像纹理的矩形

//Render the scene to the left side of a texture
void Direct3D::RenderLeft(ID3D11RenderTargetView *RenderTarget, D3DXMATRIX matFinal, D3D11_VIEWPORT viewport, bool clearRenderTarget){

devcon->OMSetRenderTargets(1, &RenderTarget, zbuffer);

devcon->RSSetViewports(1, &viewport);

// update shader resources
devcon->UpdateSubresource(pCBufferPrimaryShader, 0, 0, &matFinal, 0, 0);
devcon->PSSetShaderResources(0, 1, &pTextureLeftResourceView);

// clear the depth buffer and render target texture
devcon->ClearDepthStencilView(zbuffer, D3D11_CLEAR_DEPTH, 1.0f, 0);
if (clearRenderTarget){
    devcon->ClearRenderTargetView(RenderTarget, D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f));
}

// render to texture on left side (oculus) or full texture
devcon->DrawIndexed(6, 0, 0);
}
这一部分应该渲染一个矩形,纹理从RenderLeft()到后缓冲区

//Render the scene to the right side of the back buffer
void Direct3D::RenderRight(ID3D11RenderTargetView *RenderTarget, D3DXMATRIX matFinal, D3D11_VIEWPORT viewport, bool clearRenderTarget){

//render to texture
devcon->OMSetRenderTargets(1, &RenderTarget, zbuffer);

devcon->RSSetViewports(1, &viewport);

// update shader resources
devcon->UpdateSubresource(pCBufferPrimaryShader, 0, 0, &matFinal, 0, 0);
devcon->PSSetShaderResources(0, 1, &pRenderTextureLeftResourceView);


// clear the depth buffer and render target texture
devcon->ClearDepthStencilView(zbuffer, D3D11_CLEAR_DEPTH, 1.0f, 0);
if (clearRenderTarget){
    devcon->ClearRenderTargetView(RenderTarget, D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f));
}

// render to texture on left side (oculus) or full texture
devcon->DrawIndexed(6, 0, 0);
}
最后是创建各种视图和视口的代码

void Direct3D::InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;

// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

// fill the swap chain description struct
scd.BufferCount = 1;                                    // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
scd.BufferDesc.Width = screen_width;
scd.BufferDesc.Height = screen_height;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;      // how swap chain is to be used
scd.OutputWindow = hWnd;                                // the window to be used
scd.SampleDesc.Count = 4;                               // how many multisamples
scd.Windowed = TRUE;                                    // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
    D3D_DRIVER_TYPE_HARDWARE,
    NULL,
    NULL,
    NULL,
    NULL,
    D3D11_SDK_VERSION,
    &scd,
    &swapchain,
    &dev,
    NULL,
    &devcon);

// create the depth buffer texture
D3D11_TEXTURE2D_DESC texd;
ZeroMemory(&texd, sizeof(texd));

texd.Width = screen_width;
texd.Height = screen_height;
texd.ArraySize = 1;
texd.MipLevels = 1;
texd.SampleDesc.Count = 4;
texd.Format = DXGI_FORMAT_D32_FLOAT;
texd.BindFlags = D3D11_BIND_DEPTH_STENCIL;

ID3D11Texture2D *pDepthBuffer;
dev->CreateTexture2D(&texd, NULL, &pDepthBuffer);

// create the depth buffer
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd;
ZeroMemory(&dsvd, sizeof(dsvd));

dsvd.Format = DXGI_FORMAT_D32_FLOAT;
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;

dev->CreateDepthStencilView(pDepthBuffer, &dsvd, &zbuffer);
pDepthBuffer->Release();

// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;

swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();

//create intermediate render textures
ID3D11Texture2D *pRenderTextureLeft;

D3D11_TEXTURE2D_DESC textureDesc;
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;

ZeroMemory(&textureDesc, sizeof(textureDesc));


textureDesc.Width = screen_width;
textureDesc.Height = screen_height;
if (oculus){
    textureDesc.Width = (UINT)((FLOAT)textureDesc.Width * oculus->renderScale);
    textureDesc.Height = (UINT)((FLOAT)textureDesc.Height *oculus->renderScale);
}
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;

dev->CreateTexture2D(&textureDesc, NULL, &pRenderTextureLeft);

renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;

dev->CreateRenderTargetView(pRenderTextureLeft, &renderTargetViewDesc, &pTextureLeftRenderView);

shaderResourceViewDesc.Format = textureDesc.Format;
shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
shaderResourceViewDesc.Texture2D.MipLevels = 1;

dev->CreateShaderResourceView(pRenderTextureLeft, &shaderResourceViewDesc, &pRenderTextureLeftResourceView);

ID3D11Texture2D *pRenderTextureRight;

dev->CreateTexture2D(&textureDesc, NULL, &pRenderTextureRight);

dev->CreateRenderTargetView(pRenderTextureRight, &renderTargetViewDesc, &pTextureRightRenderView);

dev->CreateShaderResourceView(pRenderTextureRight, &shaderResourceViewDesc, &pRenderTextureRightResourceView);

/*if (oculus){
    pOculusOutputDevice = oculus->searchForOculusDisplay(oculus->hmd.DisplayDeviceName);
    swapchain->SetFullscreenState(TRUE, pOculusOutputDevice);
}*/

// Set the viewport

ZeroMemory(&viewportLeft, sizeof(D3D11_VIEWPORT));
ZeroMemory(&viewportRight, sizeof(D3D11_VIEWPORT));
ZeroMemory(&viewportCenter, sizeof(D3D11_VIEWPORT));

viewportCenter.TopLeftX = 0.0f;
viewportCenter.TopLeftY = 0.0f;
if (oculus){
    viewportCenter.Width = (FLOAT)screen_width*oculus->renderScale;
    viewportCenter.Height = (FLOAT)screen_height*oculus->renderScale;
}
else{
    viewportCenter.Width = (FLOAT)screen_width;
    viewportCenter.Height = (FLOAT)screen_height;
}
viewportCenter.MinDepth = 0.0f;
viewportCenter.MaxDepth = 1.0f;

if (dual_mode){
    viewportLeft.TopLeftX = 0.0f;
    viewportLeft.TopLeftY = 0.0f;
    viewportLeft.Width = (FLOAT)screen_width / 2.0f;
    viewportLeft.Height = (FLOAT)screen_height;
    viewportLeft.MinDepth = 0.0f;
    viewportLeft.MaxDepth = 1.0f;

    viewportRight.TopLeftX = (FLOAT)screen_width / 2.0f;
    viewportRight.TopLeftY = 0.0f;
    viewportRight.Width = (FLOAT)screen_width / 2.0f;
    viewportRight.Height = (FLOAT)screen_height;
    viewportRight.MinDepth = 0.0f;
    viewportRight.MaxDepth = 1.0f;
}

devcon->RSSetViewports(1, &viewportCenter);

InitPipeline();
InitGraphics();
}
对于每个请求,这里还有一些代码:

我包含了整个Direct3D类标题,因此您可以看到哪些是成员变量,哪些不是成员变量

#pragma once

#include "Oculus.h"
#include <OVR.h>
#include "Camera.h"

#include <d3d11.h>
#include <D3DX11.h>
#include <D3DX10.h>

#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")

class Direct3D
{
public:
struct VERTEX{ FLOAT X, Y, Z; D3DXCOLOR Color; FLOAT U, V; };
struct DISTORTION{
    FLOAT LensCenter[2];
    FLOAT ScreenCenter[2];
    FLOAT Scale[2];
    FLOAT ScaleIn[2];
    FLOAT HmdWarpParam[4];
};

IDXGISwapChain *swapchain;             // the pointer to the swap chain interface
ID3D11Device *dev;                     // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon;           // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer;
IDXGIOutput* pOculusOutputDevice;
ID3D11VertexShader *pVS_Primary;    // the vertex shader
ID3D11PixelShader *pPS_Primary;     // the pixel shader
ID3D11VertexShader *pVS_Distortion;
ID3D11PixelShader *pPS_Distortion;     // the pixel shader
ID3D11Buffer *pVBuffer;     //vertec buffer
ID3D11Buffer *pIBuffer;
ID3D11InputLayout *pLayout_Primary;
ID3D11InputLayout *pLayout_Distortion;
D3D11_VIEWPORT viewportLeft;
D3D11_VIEWPORT viewportRight;
D3D11_VIEWPORT viewportCenter;
ID3D11Buffer *pCBufferPrimaryShader;
ID3D11Buffer *pCBufferDistortionShader;
ID3D11DepthStencilView *zbuffer;       // the pointer to our depth buffer
ID3D11ShaderResourceView *pTextureLeftResourceView;    // the pointer to the texture
ID3D11ShaderResourceView *pTextureRightResourceView;
ID3D11ShaderResourceView *pRenderTextureLeftResourceView;
ID3D11ShaderResourceView *pRenderTextureRightResourceView;
ID3D11RenderTargetView *pTextureLeftRenderView;
ID3D11RenderTargetView *pTextureRightRenderView;
D3DXMATRIX matFinalLeft;
D3DXMATRIX matFinalRight;

Camera cameraLeft, cameraRight;

int screen_width;
int screen_height;

bool dual_mode;

Oculus* oculus;

Direct3D(Oculus* oculus);
Direct3D();
~Direct3D();

void InitD3D(HWND hWnd);     // sets up and initializes Direct3D
void CleanD3D(void);         // closes Direct3D and releases memory
void RenderFrame();
void InitPipeline();
void InitGraphics();
void RenderLeft(ID3D11RenderTargetView *RenderTarget, D3DXMATRIX matFinal, D3D11_VIEWPORT viewport, bool clearRenderTarget);
void RenderRight(ID3D11RenderTargetView *RenderTarget, D3DXMATRIX matFinal, D3D11_VIEWPORT viewport, bool clearRenderTarget);
void DistortionCorrection(ID3D11RenderTargetView *RenderTarget);
void CreateTransforms();
void setVertices();
void setMainShaders();
void OVRMatrix4fToD3DXMatrix(OVR::Matrix4f& source, D3DXMATRIX& dest);
};
为了以防万一,这里是渲染管道的初始化

void Direct3D::InitPipeline()
{
// compile the shaders
ID3D10Blob *VS_Primary, *PS_Primary, *VS_Distortion, *PS_Distortion;
D3DX11CompileFromFile("vs_primary.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS_Primary, 0, 0);
D3DX11CompileFromFile("ps_primary.hlsl", 0, 0, "PShader", "ps_5_0", 0, 0, 0, &PS_Primary, 0, 0);
D3DX11CompileFromFile("vs_distortion.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS_Distortion, 0, 0);
D3DX11CompileFromFile("ps_distortion.hlsl", 0, 0, "main", "ps_5_0", 0, 0, 0, &PS_Distortion, 0, 0);

// create the shader objects
dev->CreateVertexShader(VS_Primary->GetBufferPointer(), VS_Primary->GetBufferSize(), NULL, &pVS_Primary);
dev->CreatePixelShader(PS_Primary->GetBufferPointer(), PS_Primary->GetBufferSize(), NULL, &pPS_Primary);
dev->CreateVertexShader(VS_Distortion->GetBufferPointer(), VS_Distortion->GetBufferSize(), NULL, &pVS_Distortion);
dev->CreatePixelShader(PS_Distortion->GetBufferPointer(), PS_Distortion->GetBufferSize(), NULL, &pPS_Distortion);

// set the shader objects
devcon->VSSetShader(pVS_Primary, 0, 0);
devcon->PSSetShader(pPS_Primary, 0, 0);

// create the input element object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

// use the input element descriptions to create the input layout
dev->CreateInputLayout(ied, 3, VS_Primary->GetBufferPointer(), VS_Primary->GetBufferSize(), &pLayout_Primary);
devcon->IASetInputLayout(pLayout_Primary);

dev->CreateInputLayout(ied, 3, VS_Distortion->GetBufferPointer(), VS_Distortion->GetBufferSize(), &pLayout_Distortion);
devcon->IASetInputLayout(pLayout_Distortion);
// create the constant buffer

D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));

bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = 64;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

dev->CreateBuffer(&bd, NULL, &pCBufferPrimaryShader);

devcon->VSSetConstantBuffers(0, 1, &pCBufferPrimaryShader);

ZeroMemory(&bd, sizeof(bd));

bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = 48;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
dev->CreateBuffer(&bd, NULL, &pCBufferDistortionShader);
}
像素着色器:

Texture2D Texture;
SamplerState ss;

float4 PShader(float4 color : COLOR, float2 texcoord : TEXCOORD0) : SV_TARGET
{
return color * Texture.Sample(ss, texcoord);
}
顶点着色器:

cbuffer ConstantBuffer
{
float4x4 matFinal;
}

struct VOut
{
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 position : SV_POSITION;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR, float2 texcoord : TEXCOORD0)
{
VOut output;

output.position = mul(matFinal, position);
output.color = color;
output.texcoord = texcoord;

return output;
}

在下面的代码中,我没有看到如何将纹理从RenderLeft()传递到RenderRight()。只需将backbuffer传递给RenderRight()


因此,结果是渲染到左视口的纹理,而右视口仅显示backbuffer的颜色(绿色)。

pRenderTextureLeftResourceView是链接到与PteTextReleFTRenderView相同纹理的资源视图。它们都是Direct3D类的成员变量,因此不必将它们传递给函数。我只添加了一些参数,所以当我想测试一些东西时,更容易进行更改。RenderLeft应渲染到PtextReleFTRenderView,然后在RenderRight中设置相同纹理的着色器资源。问题不在于RenderRight使用了错误的纹理。问题是,当后缓冲区不是渲染目标时,RenderLeft正在渲染到后缓冲区。请显示更多代码,好吗?特别是加载和绘制狗的纹理的代码。我编辑了这个问题以包含更多的代码。如果您认为还有其他相关内容。让我知道。
cbuffer ConstantBuffer
{
float4x4 matFinal;
}

struct VOut
{
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 position : SV_POSITION;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR, float2 texcoord : TEXCOORD0)
{
VOut output;

output.position = mul(matFinal, position);
output.color = color;
output.texcoord = texcoord;

return output;
}
RenderLeft(pTextureLeftRenderView, matFinalLeft, viewportLeft, true); 
RenderRight(backbuffer, matFinalRight, viewportRight, false);