经过调试,发现贴图总是为最后一个材质面的材质,这是在装载贴图时,最终装载贴图的地址是一样的。
通过调用
D3DX11CreateShaderResourceViewFromFileA(
ID3D11Device* pDevice,
LPCSTR pSrcFile,
D3DX11_IMAGE_LOAD_INFO *pLoadInfo,
ID3DX11ThreadPump* pPump,
ID3D11ShaderResourceView** ppShaderResourceView,
HRESULT* pHResult);
这个函数,把pSrcFile这个文件装载到 ID3D11ShaderResourceView 中 , 为什么贴图地址会一样呢?
在装载时使用下面的函数
//提取材质文件中材质信息
bool ObjLoader::ParseMaterialFile(ID3D11Device* device, char* fileName)
{
std::ifstream inFile; //声明一个文件输入流对象
std::string fullFileName = m_strResPath + fileName; //获取文件全名
inFile.open(fullFileName); //打开文件
if(inFile.fail()) //判断文件打开是否成功
{
return false;
}
ObjMaterial* pMat = nullptr; //声明一个ObjMaterial材质对象
while(true) //通过循环逐行读取材质文件中的内容
{
std::string input;
inFile>>input;
if(input == "newmtl") //如果读入input的值为newmtl则创建一个新材质信息
{
if(pMat != NULL) //如果pMat里本来就存在材质信息(针对一个mtl文件定义多种材质的情况)
{
m_Material.push_back(*pMat); //则将材质信息推入m_Material成员
pMat->Release();
delete pMat;
}
pMat = new ObjMaterial(); //新建一个材质对象
inFile>>pMat->strName; //将newmtl后的字符串设置为材质名称
}
else if(pMat != NULL) //如果材质对象pMat不为空
{
if(input == "Ka") //如果读入input的值为Ka则后面的值为材质的环境光反射率
{
//设置材质的环境光反射率
inFile>>pMat->vAmbient.x;
inFile>>pMat->vAmbient.y;
inFile>>pMat->vAmbient.z;
}
else if(input == "Kd") //如果读入input的值为Kd则后面的值为材质的散射光反射率
{
//设置材质的散射光反射率
inFile>>pMat->vDiffuse.x;
inFile>>pMat->vDiffuse.y;
inFile>>pMat->vDiffuse.z;
}
else if(input == "Ks") //如果读入input的值为Ks则后面的值为材质的镜面光光反射率
{
//设置材质的镜面光反射率
inFile>>pMat->vSpecular.x;
inFile>>pMat->vSpecular.y;
inFile>>pMat->vSpecular.z;
}
else if(input == "Ns") //如果读入input的值为Ns则后面的值为材质的镜面光光反射率
{
inFile>>pMat->nShininess; //设置镜面反射系数
}
else if(input == "map_Kd") //如果读入input的值为map_Kd则后面的值为纹理文件名
{
// 首先判断文件名是否存在,如果不存在,那么下一个字符将是'\n'
char ch;
inFile.get(ch);
if(ch == ' ' || ch == '\t')
{
inFile.get(ch);
}
if(ch == '\n') //如果后面没有文件名
{
pMat->pTextureRV = NULL;//则设置纹理为空
if( inFile.eof() ) //如果是文件结尾则跳出循环
break;
else //否则继续循环
continue;
}
std::string mapFileName; //声明字符串来读取文件名
inFile>>mapFileName;
// 此处需要为纹理文件名添加上路径,因为OBJ文件是不包含路径信息的
mapFileName = ch + mapFileName;
mapFileName = m_strResPath + mapFileName;
//从纹理文件中读取文件并将读取的信息存入材质对象的pTextureRV成员
pMat->texturename = mapFileName; //自己加入的用于判别出贴图名字
HRESULT result = D3DX11CreateShaderResourceViewFromFileA(
device, mapFileName.c_str(), NULL, NULL, &pMat->pTextureRV, NULL);
if(FAILED(result))
{
::MessageBoxA(NULL, "Create texture failed", "Notice", 0);
return false;
}
}
}
inFile.ignore( 1024 , '\n' );
if( inFile.eof() ) //文件结束则跳出循环
break;
}
// 最后pMat还要添加一次,这是针对一个mtl文件只有一个材质信息的情况
// 或者有多个材质信息的情况,将最后一个材质信息推入m_Material对象
if(pMat != NULL)
{
m_Material.push_back(*pMat);
}
return true;
}
在 if(pMat != NULL) //如果pMat里本来就存在材质信息(针对一个mtl文件定义多种材质的情况)
{
m_Material.push_back(*pMat); //则将材质信息推入m_Material成员
pMat->Release();
delete pMat;
}
pMat = new ObjMaterial(); //新建一个材质对象
这几行中,由于你装进向量组m_Material中的是一个指针,释放它之后再新建,根据参考https://blog.csdn.net/novocane/article/details/39972029
你的新建位置还是原来的地址,但是之后的装载贴图使用的也是这个地址,因此最后一个贴图是真正保存在贴图存放地址中的,
但是存入向量组m_Material的所有贴图地址都指向这一块地址,因此模型显示的贴图是一样的,该案例取自《基于DX11的3D图形程序设计案例教程》