【发布时间】:2017-10-23 09:10:53
【问题描述】:
我正在尝试将网格加载到我的 directx 应用程序中。我可以成功加载任何网格,但网格一侧的纹理坐标错误。 (只有一面。另一面的纹理映射正确) ScreenShot
这是我的代码。
模型.h
#ifndef MODEL_H
#define MODEL_H
#include <vector>
#include <d3d11_1.h>
#include <DirectXMath.h>
#include <D3DX10.h>
#include <Importer.hpp>
#include <scene.h>
#include <postprocess.h>
#include "Mesh.h"
using namespace DirectX;
class CModel
{
public:
CModel();
~CModel();
bool Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon, std::string filename);
void Draw(ID3D11DeviceContext* devcon);
void Close();
private:
ID3D11Device *dev;
ID3D11DeviceContext *devcon;
std::vector<Mesh> meshes;
string directory;
vector<Texture> textures_loaded;
HWND hwnd;
void processNode(aiNode* node, const aiScene* scene);
Mesh processMesh(aiMesh* mesh, const aiScene* scene);
vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene);
string determineTextureType(const aiScene* scene, aiMaterial* mat);
int getTextureIndex(aiString* str);
ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex);
};
#endif
模型.cpp
#include "Model.h"
CModel::CModel()
{
}
CModel::~CModel()
{
}
bool CModel::Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon,
std::string filename)
{
Assimp::Importer importer;
const aiScene* pScene = importer.ReadFile(filename,
aiProcess_Triangulate |
aiProcess_ConvertToLeftHanded |
aiProcess_FlipUVs);
if (pScene == NULL)
return false;
this->directory = filename.substr(0, filename.find_last_of('/'));
this->dev = dev;
this->hwnd = hwnd;
processNode(pScene->mRootNode, pScene);
return true;
}
void CModel::processNode(aiNode* node, const aiScene* scene)
{
for (UINT i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(this->processMesh(mesh, scene));
}
for (UINT i = 0; i < node->mNumChildren; i++)
{
this->processNode(node->mChildren[i], scene);
}
}
string textype;
Mesh CModel::processMesh(aiMesh* mesh, const aiScene* scene)
{
// Data to fill
vector<VERTEX> vertices;
vector<DWORD> indices;
vector<Texture> textures;
if (mesh->mMaterialIndex >= 0)
{
aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
if(textype.empty()) textype = determineTextureType(scene, mat);
}
// Walk through each of the mesh's vertices
for (UINT i = 0; i < mesh->mNumVertices; i++)
{
VERTEX vertex;
vertex.X = mesh->mVertices[i].x;
vertex.Y = mesh->mVertices[i].y;
vertex.Z = mesh->mVertices[i].z;
if (mesh->mTextureCoords[0])
{
vertex.TEXX = mesh->mTextureCoords[0][i].x;
vertex.TEXY = mesh->mTextureCoords[0][i].y;
}
else
{
vertex.TEXX = 0.0f;
vertex.TEXY = 0.0f;
}
vertices.push_back(vertex);
}
for (UINT i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (UINT j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
if (mesh->mMaterialIndex >= 0)
{
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
//vector<Texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
//textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
}
return Mesh(dev, vertices, indices, textures);
}
vector<Texture> CModel::loadMaterialTextures(aiMaterial* mat, aiTextureType
type, string typeName, const aiScene* scene)
{
vector<Texture> textures;
for (UINT i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
bool skip = false;
for (UINT j = 0; j < textures_loaded.size(); j++)
{
if (std::strcmp(textures_loaded[j].path.C_Str(), str.C_Str()) == 0)
{
textures.push_back(textures_loaded[j]);
skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
break;
}
}
if (!skip)
{ // If texture hasn't been loaded already, load it
HRESULT hr;
Texture texture;
if (textype == "embedded compressed texture")
{
int textureindex = getTextureIndex(&str);
texture.texture = getTextureFromModel(scene, textureindex);
}
else
{
string filename = string(str.C_Str());
filename = directory + '/' + filename;
hr = D3DX11CreateShaderResourceViewFromFile(dev, filename.c_str(), nullptr, nullptr, &texture.texture, nullptr);
if (FAILED(hr))
MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
}
texture.type = typeName;
texture.path = str;
textures.push_back(texture);
this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
}
}
return textures;
}
void CModel::Draw(ID3D11DeviceContext* devcon)
{
for (int i = 0; i < meshes.size(); i++)
{
meshes[i].Draw(devcon);
}
}
void CModel::Close()
{
for (int i = 0; i < meshes.size(); i++)
{
meshes[i].Close();
}
dev->Release();
}
string CModel::determineTextureType(const aiScene* scene, aiMaterial* mat)
{
aiString textypeStr;
mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
string textypeteststr = textypeStr.C_Str();
if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5")
{
if (scene->mTextures[0]->mHeight == 0)
{
return "embedded compressed texture";
}
else
{
return "embedded non-compressed texture";
}
}
if (textypeteststr.find('.') != string::npos)
{
return "textures are on disk";
}
}
int CModel::getTextureIndex(aiString* str)
{
string tistr;
tistr = str->C_Str();
tistr = tistr.substr(1);
return stoi(tistr);
}
ID3D11ShaderResourceView * CModel::getTextureFromModel(const aiScene * scene, int textureindex)
{
HRESULT hr;
ID3D11ShaderResourceView *texture;
int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth);
hr = D3DX11CreateShaderResourceViewFromMemory(dev, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, nullptr, &texture, nullptr);
if (FAILED(hr))
MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
return texture;
}
Mesh.h(这是一个只有头文件的类)
#ifndef MESH_H
#define MESH_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
#include <vector>
#include <d3d11_1.h>
#include <DirectXMath.h>
#include <D3DX11.h>
#include <D3DX10.h>
using namespace DirectX;
struct VERTEX {
FLOAT X, Y, Z;
D3DXCOLOR color;
FLOAT TEXX, TEXY;
};
struct Texture {
string type;
aiString path;
ID3D11ShaderResourceView *texture;
};
class Mesh {
public:
vector<VERTEX> vertices;
vector<DWORD> indices;
vector<Texture> textures;
ID3D11Device *dev;
Mesh(ID3D11Device *dev,vector<VERTEX> vertices, vector<DWORD> indices, vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->dev = dev;
this->setupMesh(dev);
}
void Draw(ID3D11DeviceContext *devcon)
{
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->PSSetShaderResources(0, 1, &textures[0].texture);
devcon->DrawIndexed(indices.size(), 0, 0);
}
void Close()
{
VertexBuffer->Release();
IndexBuffer->Release();
}
private:
/* Render data */
ID3D11Buffer *VertexBuffer, *IndexBuffer;
/* Functions */
// Initializes all the buffer objects/arrays
bool setupMesh(ID3D11Device *dev)
{
HRESULT hr;
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(VERTEX) * vertices.size();
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = &vertices[0];
hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
if (FAILED(hr))
return false;
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(DWORD) * indices.size();
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
initData.pSysMem = &indices[0];
hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
if (FAILED(hr))
return false;
}
};
#endif
谢谢。
【问题讨论】:
-
你的加载器代码看起来不错。您是否也使用 appviewer 打开了模型?纹理坐标在那里看起来如何?
-
是的,我有,它显示正确。某些模型在此代码中也可以正确渲染,但有些则不正确(它们的纹理映射的某些部分不正确。)非常感谢您尝试帮助我 :)
-
可能是错误的索引?里面有节点吗?很难在这里看到错误。您可以在我们的 github 页面上生成问题。
-
好的。我将在您的 github 页面上生成一个问题,但是当我在 OpenGL 中使用此代码本身时,此代码可以完美运行而不会出现任何错误。
-
另外,当我使用 aiProcess_ConvertToLeftHanded 标志时,它会使网格的错误一侧正确映射而另一侧错误。
标签: c++ directx textures assimp