当前位置: 首页 > 工具软件 > D3Notice > 使用案例 >

使用d3d绘制obj物体时 贴图所有贴图总是显示最后一个的原因

陈斌
2023-12-01

经过调试,发现贴图总是为最后一个材质面的材质,这是在装载贴图时,最终装载贴图的地址是一样的。

通过调用  
    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图形程序设计案例教程》

 类似资料: