DirectX9 проблема в развертке текстуры на моделе
Исследование проблемы наложения UV-развертки без учета текстурных координат Введение:
В ходе работы над проектом, связанным с трехмерной графикой, была обнаружена проблема, связанная с наложением UV-развертки на модель без учета текстурных координат. Данная проблема проявляется при рендеринге, что затрудняет корректное отображение текстур на модели.
Методы исследования:
Была проведена проверка корректности загрузки и отображения UV-развертки в программе Blender 3D.
В проверке было установлено, что UV-развертка загружается стабильно и корректно отображается в редакторе UV.
Отладка:
В результате отладки было установлено, что текстурные координаты передаются в шейдеры, однако проблема с наложением текстуры на модель сохраняется.
Описание проблемы:
При рендеринге модели наблюдается следующая проблема: UV-развертка накладывается на модель без учета текстурных координат.
Вот код инициализации DirectX9 и рендер состояний:
bool Render::Initialize(HWND hWnd, RectWnd rect) {
d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d)
return false;
D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_2_SAMPLES;
DWORD qualityLevels;
if (!(SUCCEEDED(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, TRUE, multisampleType, &qualityLevels))))
multisampleType = D3DMULTISAMPLE_NONE;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.hDeviceWindow = hWnd;
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferCount = 3;
d3dpp.BackBufferWidth = rect.Width;
d3dpp.BackBufferHeight = rect.Height;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.MultiSampleType = multisampleType;
d3dpp.MultiSampleQuality = qualityLevels - 1;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
HRESULT hr = d3d->CreateDevice(
D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &d3ddev);
if (FAILED(hr)) {
IDirect3D9_Release(d3d);
d3d = NULL;
return false;
}
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
d3ddev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);
d3ddev->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
d3ddev->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
d3ddev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
D3DXVECTOR3 vEyePt(0.0f, 25.0f, -100.0f);
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 80.0f);
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&matView_, &vEyePt, &vLookatPt, &vUpVec);
meshes_.reserve(10);
rect_ = rect;
return true;
}
Тут сам рендер меша:
void Render::Update(void) {
if (d3ddev) {
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
if (SUCCEEDED(d3ddev->BeginScene())) {
static float angle = 0.0f;
angle += 0.01f;
D3DXMatrixRotationY(&matWorld_, angle);
D3DXMatrixPerspectiveFovLH(&matProj_, D3DX_PI / 4, static_cast<FLOAT>(rect_.Height / rect_.Width), 1.0f, 200.0f);
d3ddev->SetTransform(D3DTS_WORLD, &matWorld_);
d3ddev->SetTransform(D3DTS_VIEW, &matView_);
d3ddev->SetTransform(D3DTS_PROJECTION, &matProj_);
float lightIntensity = 0.0f;
D3DXVECTOR4 lightPosition(50.0f, 3.0f, -100.0f, 1.0f);
D3DXVECTOR4 lightColor(1.0f, 1.0f, 1.0f, 1.0f);
D3DXMATRIX worldViewProjection = matWorld_ * matView_ * matProj_;
shader_->vertexShaderConstantTable_->SetMatrix(d3ddev, "WorldViewProjection", &worldViewProjection);
shader_->vertexShaderConstantTable_->SetVector(d3ddev, "LightPosition", &lightPosition);
shader_->vertexShaderConstantTable_->SetVector(d3ddev, "LightColor", &lightColor);
shader_->vertexShaderConstantTable_->SetFloat(d3ddev, "LightIntensity", lightIntensity);
shader_->vertexShaderConstantTable_->SetMatrix(d3ddev, "World", &matWorld_);
d3ddev->SetVertexShader(shader_->GetVertexShader());
d3ddev->SetPixelShader(shader_->GetPixelShader());
for (const Mesh* mesh : meshes_) {
if (mesh && mesh->vertexBuffer_ && mesh->indexBuffer_) {
if (!mesh->textures_.empty()) {
D3DMATERIAL9 material = mesh->materials_[0].material;
D3DXVECTOR4 materialColor(material.Diffuse.r, material.Diffuse.g, material.Diffuse.b, material.Diffuse.a);
float materialDiffuse = material.Diffuse.a;
float materialSpecular = material.Specular.a;
float materialShininess = material.Power;
shader_->vertexShaderConstantTable_->SetVector(d3ddev, "MaterialColor", &materialColor);
shader_->vertexShaderConstantTable_->SetFloat(d3ddev, "MaterialDiffuse", materialDiffuse);
shader_->vertexShaderConstantTable_->SetFloat(d3ddev, "MaterialSpecular", materialSpecular);
shader_->vertexShaderConstantTable_->SetFloat(d3ddev, "MaterialShininess", materialShininess);
d3ddev->SetTexture(0, mesh->textures_[0]);
}
d3ddev->SetStreamSource(0, mesh->vertexBuffer_, 0, sizeof(Vertex));
d3ddev->SetIndices(mesh->indexBuffer_);
d3ddev->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mesh->vertexCount_, 0, mesh->indexCount_ / 3);
}
}
d3ddev->EndScene();
}
d3ddev->Present(NULL, NULL, NULL, NULL);
}
}
А тут шейдеры:
struct VS_INPUT
{
float4 Position : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Position : POSITION;
float3 Normal : TEXCOORD1;
float2 TexCoord : TEXCOORD0;
float4 Color : COLOR0;
};
float4x4 WorldViewProjection;
float4x4 World;
float4 LightPosition;
float4 LightColor;
float LightIntensity;
float4 MaterialColor;
float MaterialDiffuse;
float MaterialSpecular;
float MaterialShininess;
VS_OUTPUT VS(VS_INPUT input)
{
VS_OUTPUT output;
output.Position = mul(input.Position, WorldViewProjection);
output.TexCoord = input.TexCoord;
output.Normal = normalize(mul(input.Normal, (float3x3) World));
float3 worldPosition = mul(input.Position, World).xyz;
float3 lightDir = normalize(LightPosition.xyz - worldPosition);
float diffuse = max(dot(output.Normal, lightDir), 0.0);
output.Color = LightColor * diffuse * LightIntensity * MaterialDiffuse;
float3 viewDir = normalize(-worldPosition);
float3 reflectDir = reflect(-lightDir, output.Normal);
float specular = pow(max(dot(viewDir, reflectDir), 0.0), MaterialShininess);
output.Color += LightColor * specular * MaterialSpecular;
output.Color += MaterialColor * (1.0 - MaterialDiffuse);
return output;
}
И пиксельный шейдер:
sampler2D TextureSampler;
struct PS_INPUT
{
float2 TexCoord : TEXCOORD0;
float4 Color : COLOR0;
};
float4 PS(PS_INPUT input) : COLOR
{
float4 textureColor = tex2D(TextureSampler, input.TexCoord);
return textureColor * input.Color;
}
Результат такой...