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 的加载程序中加载图像或纹理时出现问题。
我的 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 的加载程序中加载图像或纹理时出现问题。