DirectX 不正确的纹理

DirectX incorrect texture

我的 DirectX 应用程序无法正确渲染纹理。结果:

预计来自 VS 编辑器:

如您所见,猫的纹理并未完全绘制。

我正在使用 WaveFrontReader to load the .OBJ and the .MTL files and WicTextureLoader 加载 PNG/JPG。

我的 HLSL:

cbuffer constants : register(b0)
{
    row_major float4x4 transform;
    row_major float4x4 projection;
    float3 lightvector;
}

struct vs_in
{
    float3 position : POS;
    float3 normal   : NOR;
    float2 texcoord : TEX;
    float4 color    : COL;
};

struct vs_out
{
    float4 position : SV_POSITION;
    float2 texcoord : TEX;
    float4 color    : COL;
};

Texture2D    mytexture : register(t0);
SamplerState mysampler : register(s0);

vs_out vs_main(vs_in input)
{
    float light = clamp(dot(normalize(mul(float4(input.normal, 0.0f), transform).xyz), normalize(-lightvector)), 0.0f, 1.0f) * 0.8f + 0.2f;

    vs_out output;

    output.position = mul(float4(input.position, 1.0f), mul(transform, projection));
    output.texcoord = input.texcoord;
    output.color    = float4(input.color.rgb * light, input.color.a);

    return output;
}

float4 ps_main(vs_out input) : SV_TARGET
{
    return mytexture.Sample(mysampler, input.texcoord) * input.color;
}

我的准备:

void Config3DWindow()
{
const wchar_t* tf = L"1.hlsl";

d2d.m_swapChain1->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&frameBuffer));
d2d.device->CreateRenderTargetView(frameBuffer, nullptr, &frameBufferView);

frameBuffer->GetDesc(&depthBufferDesc); // base on framebuffer properties
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;

CComPtr<ID3DBlob> vsBlob;
D3DCompileFromFile(tf, nullptr, nullptr, "vs_main", "vs_5_0", 0, 0, &vsBlob, nullptr);
d2d.device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &vertexShader);
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] =
{
    { "POS", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,                            0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NOR", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEX", 0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
d2d.device->CreateInputLayout(inputElementDesc, ARRAYSIZE(inputElementDesc), vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &inputLayout);

///////////////////////////////////////////////////////////////////////////////////////////////
CComPtr<ID3DBlob> psBlob;
D3DCompileFromFile(tf, nullptr, nullptr, "ps_main", "ps_5_0", 0, 0, &psBlob, nullptr);
d2d.device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, &pixelShader);


D3D11_BUFFER_DESC constantBufferDesc = {};
constantBufferDesc.ByteWidth = sizeof(Constants) + 0xf & 0xfffffff0;
constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;


d2d.device->CreateBuffer(&constantBufferDesc, nullptr, &constantBuffer);
}

正在加载对象:

WaveFrontReader<UINT> wfr;
wfr.Load(L"12221_Cat_v1_l3.oobj");
wfr.LoadMTL(L"12221_Cat_v1_l3.mtl");
obj.CreateDirect3D2(wfr);

CreateDirect3D2() 函数:

std::vector<float> Vertices;
 //    float VertexDataX[] = // float3 position, float3 normal, float2 texcoord, float4 color

auto numV = wf.vertices.size();
Vertices.resize(numV * 12);
for (size_t i = 0; i < numV; i++)
{
    auto& v = wf.vertices[i];
    float* i2 = Vertices.data() + (i * 12);

    // position
    i2[0] = v.position.x;
    i2[1] = v.position.y;
    i2[2] = v.position.z;

    // normal
    i2[3] = v.normal.x;
    i2[4] = v.normal.y;
    i2[5] = v.normal.z;

    // tx
    i2[6] = v.textureCoordinate.x;
    i2[7] = v.textureCoordinate.y;

    // Colors
    i2[8] = 1.0f;
    i2[9] = 1.0f;
    i2[10] = 1.0f;
    i2[11] = 1.0f;

}

D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.ByteWidth = Vertices.size() * sizeof(float);
vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vertexData = { Vertices.data() }; // in data.h
vertexBuffer = 0;
d2d.device->CreateBuffer(&vertexBufferDesc, &vertexData, &vertexBuffer);


// Indices
std::vector<UINT>& Indices = wf.indices;

D3D11_BUFFER_DESC indexBufferDesc = {};
IndicesSize = Indices.size() * sizeof(UINT);

indexBufferDesc.ByteWidth = IndicesSize;
indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA indexData = { Indices.data() }; // in data.h
indexBuffer = 0;
d2d.device->CreateBuffer(&indexBufferDesc, &indexData, &indexBuffer);

for (auto& ma : wf.materials)
{
    CComPtr<ID3D11Resource> tex;
    CComPtr<ID3D11ShaderResourceView> texv;

    CreateWICTextureFromFile(d2d.device, d2d.context, ma.strTexture, &tex, &texv,0);

    if (tex && texv)
    {
        OBJFT ot;
        ot.texture = tex;
        ot.textureView = texv;
        textures.push_back(ot);
    }
    tex = 0;
    texv = 0;

}

绘图函数:

void Present(OBJF& o, int Count, _3DP& _3, D2D1_COLOR_F bcol)
{
    float w = static_cast<float>(depthBufferDesc.Width);  // width
    float h = static_cast<float>(depthBufferDesc.Height); // height
    float n = 1000.0f;                                    // near
    float f = 1000000.0f;                                 // far

    matrix rotateX = { 1, 0, 0, 0, 0, static_cast<float>(cos(_3.rotation[0])), -static_cast<float>(sin(_3.rotation[0])), 0, 0, static_cast<float>(sin(_3.rotation[0])), static_cast<float>(cos(_3.rotation[0])), 0, 0, 0, 0, 1 };
    matrix rotateY = { static_cast<float>(cos(_3.rotation[1])), 0, static_cast<float>(sin(_3.rotation[1])), 0, 0, 1, 0, 0, -static_cast<float>(sin(_3.rotation[1])), 0, static_cast<float>(cos(_3.rotation[1])), 0, 0, 0, 0, 1 };
    matrix rotateZ = { static_cast<float>(cos(_3.rotation[2])), -static_cast<float>(sin(_3.rotation[2])), 0, 0, static_cast<float>(sin(_3.rotation[2])), static_cast<float>(cos(_3.rotation[2])), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
    matrix scale = { _3.scale[0], 0, 0, 0, 0, _3.scale[1], 0, 0, 0, 0, _3.scale[2], 0, 0, 0, 0, 1 };
    matrix translate = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, _3.translation[0], _3.translation[1], _3.translation[2], 1 };

    ///////////////////////////////////////////////////////////////////////////////////////////
    D3D11_MAPPED_SUBRESOURCE mappedSubresource = {};
    d2d.context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubresource);
    Constants* constants = reinterpret_cast<Constants*>(mappedSubresource.pData);
    constants->Transform = rotateX * rotateY * rotateZ * scale * translate;
    constants->Projection = { 2 * n / w, 0, 0, 0, 0, 2 * n / h, 0, 0, 0, 0, f / (f - n), 1, 0, 0, n * f / (n - f), 0 };
    constants->LightVector = { 1.0f, 1.0f, 1.0f };
    d2d.context->Unmap(constantBuffer, 0);

    ///////////////////////////////////////////////////////////////////////////////////////////

    FLOAT backgroundColor[4] = { 0.00f, 0.00f, 0.00f, 1.0f };
    if (bcol.a > 0)
    {
        backgroundColor[0] = bcol.r;
        backgroundColor[1] = bcol.g;
        backgroundColor[2] = bcol.b;
        backgroundColor[3] = bcol.a;
    }

    UINT stride = 12 * 4; // vertex size (12 floats: float3 position, float3 normal, float2 texcoord, float4 color)
    UINT offset = 0;

    D3D11_VIEWPORT viewport = { 0.0f, 0.0f, w, h, 0.0f, 1.0f };

///////////////////////////////////////////////////////////////////////////////////////////

    auto deviceContext = d2d.context;
    deviceContext->ClearRenderTargetView(frameBufferView, backgroundColor);
    deviceContext->ClearDepthStencilView(depthBufferView, D3D11_CLEAR_DEPTH, 1.0f, 0);

    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    deviceContext->IASetInputLayout(inputLayout);
    deviceContext->IASetVertexBuffers(0, 1, &o.vertexBuffer.p, &stride, &offset);
    deviceContext->IASetIndexBuffer(o.indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    deviceContext->VSSetShader(vertexShader, nullptr, 0);
    deviceContext->VSSetConstantBuffers(0, 1, &constantBuffer.p);
    deviceContext->RSSetViewports(1, &viewport);
    deviceContext->PSSetShader(pixelShader, nullptr, 0);

    std::vector<ID3D11ShaderResourceView*> rsx;
    for (auto& t : o.textures)
        rsx.push_back(t.textureView);
    ID3D11ShaderResourceView** rr = rsx.data();
    deviceContext->PSSetShaderResources(0, rsx.size(), rr);

    deviceContext->PSSetSamplers(0, 1, &samplerState.p);

    deviceContext->OMSetRenderTargets(1, &frameBufferView.p, depthBufferView);
    deviceContext->OMSetDepthStencilState(depthStencilState, 0);

    ///////////////////////////////////////////////////////////////////////////////////////////

    DXGI_RGBA ra = { 1,1,1,1 };
    deviceContext->DrawIndexed(o.IndicesSize, 0, 0);
    d2d.m_swapChain1->Present(1, 0);
}

整个项目在这里:https://drive.google.com/open?id=1BbW3DUd20bAwei4KjnkUPwgm5Ia1aRxl

这是我能够在我这边重现 OP 问题后得到的结果:

我唯一的改变是我在着色器代码中排除了光照:

vs_out vs_main(vs_in input)
{
    float light = 1.0f;
    //float light = clamp(dot(normalize(mul(float4(input.normal, 0.0f), transform).xyz), normalize(-lightvector)), 0.0f, 1.0f) * 0.8f + 0.2f;

    vs_out output;

    output.position = mul(float4(input.position, 1.0f), mul(transform, projection));
    output.texcoord = input.texcoord;
    output.color    = float4(input.color.rgb * light, input.color.a);

    return output;
}

然后我发现了猫尾巴上的猫眼

这让我想起很多图像格式是从上到下存储图像的。

OpenGL 纹理(可能还有 Direct3D)的原点通常在左下角。因此,纹理图像不是 un-usual 垂直镜像(在从文件加载图像期间或之后以及在将其发送到 GPU 之前)。

为了证明我的怀疑,我手动镜像了图像(在 GIMP 中)然后(没有 re-compiling)得到了这个:

看来我的猜测是对的

OP 的加载程序中加载图像或纹理时出现问题。