一、贴纹理
1.获取纹理
// 初始化旋转纹理
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\flareoutputB.dds", nullptr, m_pTextureInputA.GetAddressOf()));
//获取六个不同的纹理
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\brick.dds", nullptr, m_pTextureOne.GetAddressOf()));
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\checkboard.dds", nullptr, m_pTextureTwo.GetAddressOf()));
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\WireFence.dds", nullptr, m_pTextureThree.GetAddressOf()));
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\floor.dds", nullptr, m_pTextureFour.GetAddressOf()));
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\ice.dds", nullptr, m_pTextureFive.GetAddressOf()));
HR(CreateDDSTextureFromFile(m_pd3dDevice.Get(), L"..\\Texture\\water.dds", nullptr, m_pTextureSix.GetAddressOf()));
// 初始化火焰纹理
WCHAR strFile[40];
m_pFireAnims.resize(120);
for (int i = 1; i <= 120; ++i)
{
wsprintf(strFile, L"..\\Texture\\FireAnim\\Fire%03d.bmp", i);
HR(CreateWICTextureFromFile(m_pd3dDevice.Get(), strFile, nullptr, m_pFireAnims[static_cast<size_t>(i) - 1].GetAddressOf()));
}
我们可以获取两种纹理,一种是使用 CreateDDSTextureFromFile函数读取DDS纹理,一种是通过CreateWICTextureFromFile函数读取WIC纹理,两种都是从文件读取。我们读取的七个纹理是dds纹理,因此使用CreateDDSTextureFromFile函数。
CreateDDSTextureFromFile函数原型:
HRESULT CreateDDSTextureFromFile(
ID3D11Device* d3dDevice, // [In]D3D设备
const wchar_t* szFileName, // [In]dds图片文件名
ID3D11Resource** texture, // [Out]输出一个指向资源接口类的指针,也可以填nullptr
ID3D11ShaderResourceView** textureView, // [Out]输出一个指向着色器资源视图的指针,也可以填nullptr
size_t maxsize = 0, // [In]忽略
DDS_ALPHA_MODE* alphaMode = nullptr); // [In]忽略
纹理不能直接绑定到着色器中,为了给着色器使用纹理资源,我们要创建纹理对应的着色器资源视图,因此我们在参数4填入来获取资源视图的指针
因为火焰纹理是wic纹理,因此使用CreateDDSTextureFromFile函数。
函数原型:
HRESULT CreateWICTextureFromFile(
ID3D11Device* d3dDevice, // [In]D3D设备
const wchar_t* szFileName, // [In]wic所支持格式的图片文件名
ID3D11Resource** texture, // [Out]输出一个指向资源接口类的指针,也可以填nullptr
ID3D11ShaderResourceView** textureView, // [Out]输出一个指向着色器资源视图的指针,也可以填nullptr
size_t maxsize = 0); // [In]忽略
与CreateDDSTextureFromFile函数的使用是类似的
2.过滤器
前言:纹理有一维,二维和三维的。对于我们新手而言,可以理解二维纹理就是一张照片贴在某个地方上或物体上。
纹理不是一成不变的,它可能在某些情况下需要放大或缩小,我们怎样定义纹理的范围呢?我们需要引入纹理坐标系,纹理坐标系中,u表示水平方向轴,v表示垂直方向轴,范围都是【0,1】。
我们有提到说,纹理需要放缩,但是我们看到纹理与设备上下文(即屏幕)的像素总是不契合的。比如一张纹理是256像素,但屏幕是1920*1080像素,我们该如何将像素填满整个屏幕,或者说把纹理缩小为屏幕的一个像素呢?
这就引入了采样器和过滤器的概念了!
纹理的放大
常量插值法:
这跟取样类似,就是纹理在放大的时候对周围像素四舍五入取整数映射到原来的像素中。
线性插值法:
线性,顾名思义就是一维单向的插值。
这里有三种方法:
- X方向使用常量插值法,Y方向使用线性插值法
- X方向使用线性插值法,Y方向使用常量插值法
- X和Y方向均使用线性插值法
(左)常量插值法(右)线性插值法
纹理的缩小
多级渐近贴图映射构建多级渐近纹理层(即缩小过程中的同一个纹理不同像素的组合)。
点过滤:在多级渐进纹理层取最匹配的纹理
线性过滤:在多级渐进纹理层取两个最匹配的纹理,然后再对他们进行线性插值或常量插值,得到最优的纹理。
各向异性过滤:当多边形的法线向量与摄像机的观察向量夹角过大时,可以缓解失真
(左)线性过滤(右)各向异性线性过滤
3.采样器
// 初始化采样器状态
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
HR(m_pd3dDevice->CreateSamplerState(&sampDesc, m_pSamplerState.GetAddressOf()));
了解过滤器后,我们来创建采样器解决纹理进行放大与缩小的问题。
采样器描述D3D11_SAMPLER_DESC原型:
typedef struct D3D11_SAMPLER_DESC
{
D3D11_FILTER Filter; // 所选过滤器
D3D11_TEXTURE_ADDRESS_MODE AddressU; // U方向寻址模式
D3D11_TEXTURE_ADDRESS_MODE AddressV; // V方向寻址模式
D3D11_TEXTURE_ADDRESS_MODE AddressW; // W方向寻址模式
FLOAT MipLODBias; // mipmap等级偏移值,最终算出的mipmap等级会加上该偏移值
UINT MaxAnisotropy; // 最大各向异性等级(1-16)
D3D11_COMPARISON_FUNC ComparisonFunc; // 这节不讨论
FLOAT BorderColor[ 4 ]; // 边界外的颜色,使用D3D11_TEXTURE_BORDER_COLOR时需要指定
FLOAT MinLOD; // 若mipmap等级低于MinLOD,则使用等级MinLOD。最小允许设为0
FLOAT MaxLOD; // 若mipmap等级高于MaxLOD,则使用等级MaxLOD。必须比MinLOD大
} D3D11_SAMPLER_DESC;
过滤器取值:
枚举值 | 缩小 | 放大 | mipmap |
---|---|---|---|
D3D11_FILTER_MIN_MAG_MIP_POINT | 点采样 | 点采样 | 点采样 |
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR | 点采样 | 点采样 | 线性采样 |
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT | 点采样 | 线性采样 | 点采样 |
D3D11_FILTER_MIN_MAG_MIP_LINEAR | 线性采样 | 线性采样 | 线性采样 |
D3D11_FILTER_ANISOTROPIC | 各向异性 | 各向异性 | 各向异性 |
过滤器我们已经了解,现在我们看看寻址模式:
寻址模式:
D3D11_TEXTURE_ADDRESS_MODE 成员 | 描述 |
D3D11_TEXTURE_ADDRESS_WRAP | 在每个整点连接处重复图像来扩展纹理 |
D3D11_TEXTURE_ADDRESS_MIRROR | 在每个整点连接处镜像图像来扩展纹理 |
D3D11_TEXTURE_ADDRESS_CLAMP | 将每个不在[0,1]2区间内的(u,v)映射为颜色T(u0,v0)来扩展纹理。其中,(u0,v0)∈[0,1]2,(u0,v0)是与(u,v)距离最近的点 |
D3D11_TEXTURE_ADDRESS_BORDER | 将每个不在[0,1]2区间内的(u,v)映射为程序员指定的某个颜色来扩展纹理 |
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE | 相当于MIRROR和CLAMP的结合,仅[-1,1]的范围内镜像有效,其余范围都会取到-1或者1 |
然后创建:
HRESULT ID3D11Device::CreateSamplerState(
const D3D11_SAMPLER_DESC *pSamplerDesc, // [In]采样器状态描述
ID3D11SamplerState **ppSamplerState); // [Out]输出的采样器
4.绑定
//设置纹理资源
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureInputA.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureOne.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureTwo.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureThree.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureFour.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureFive.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureSix.GetAddressOf());
// 像素着色阶段设置好采样器
m_pd3dImmediateContext->PSSetSamplers(0, 1, m_pSamplerState.GetAddressOf());
纹理不能直接绑定到着色器中,为了给着色器使用纹理资源,因此我们要创建纹理对应的着色器资源视图,如何绑定,这是需要用到PSSetShaderResources函数
PSSetShaderResources函数原型:
参数1:对于的索引槽,即对于HLSL中的寄存器
参数2:视图的数量
参数3:视图的数组或指针(这里我们在获取纹理那里已经获取到了)
二、上光照
1.c++对应HLSL的光照:
2.初始化光照
// 初始化默认光照
// 方向光
m_DirLight.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
m_DirLight.diffuse = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f);
m_DirLight.specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_DirLight.direction = XMFLOAT3(-0.577f, -0.577f, 0.577f);
// 点光
m_PointLight.position = XMFLOAT3(0.0f, 0.0f, -10.0f);
m_PointLight.ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
m_PointLight.diffuse = XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f);
m_PointLight.specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_PointLight.att = XMFLOAT3(0.0f, 0.1f, 0.0f);
m_PointLight.range = 25.0f;
// 聚光灯
m_SpotLight.position = XMFLOAT3(0.0f, 0.0f, -5.0f);
m_SpotLight.direction = XMFLOAT3(0.0f, 0.0f, 1.0f);
m_SpotLight.ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_SpotLight.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
m_SpotLight.specular = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
m_SpotLight.att = XMFLOAT3(1.0f, 0.0f, 0.0f);
m_SpotLight.spot = 12.0f;
m_SpotLight.range = 10000.0f;
// 注意不要忘记设置此处的观察位置,否则高亮部分会有问题
m_PSConstantBuffer.eyePos = XMFLOAT4(0.0f, 0.0f, -5.0f, 0.0f);
// 使用默认平行光
m_PSConstantBuffer.dirLight[0] = m_DirLight;
m_PSConstantBuffer.numDirLight = 1;
m_PSConstantBuffer.numPointLight = 1;
m_PSConstantBuffer.numSpotLight = 1;
3.初始化材质
// 初始化材质
m_PSConstantBuffer.material.ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_PSConstantBuffer.material.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
m_PSConstantBuffer.material.specular = XMFLOAT4(0.1f, 0.1f, 0.1f, 5.0f);
三、绘文字
1.imgui的引入
在官网下载源码后,引入头文件,有两种方式
附录包含目录添加:
直接包含(注意输入路径):
2.初始化
bool D3DApp::InitImGui()
{
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 允许键盘控制
io.ConfigWindowsMoveFromTitleBarOnly = true; // 仅允许标题拖动
// 设置Dear ImGui风格
ImGui::StyleColorsDark();
//io.Fonts->AddFontFromMemoryTTF
// 设置平台/渲染器后端
ImGui_ImplWin32_Init(m_hMainWnd);
ImGui_ImplDX11_Init(m_pd3dDevice.Get(), m_pd3dImmediateContext.Get());
return true;
}
imgui的初始化:
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
imgui的全局消息回调函数:
int D3DApp::Run()
{
MSG msg = { 0 };
m_Timer.Reset();
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
m_Timer.Tick();
if (!m_AppPaused)
{
CalculateFrameStats();
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
UpdateScene(m_Timer.DeltaTime());
DrawScene();
}
else
{
Sleep(100);
}
}
}
return (int)msg.wParam;
}
Run函数的修改
void GameApp::DrawScene()
{
assert(m_pd3dImmediateContext);
assert(m_pSwapChain);
m_pd3dImmediateContext->ClearRenderTargetView(m_pRenderTargetView.Get(), reinterpret_cast<const float*>(&Colors::Pink));
m_pd3dImmediateContext->ClearDepthStencilView(m_pDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// 绘制几何模型
if (m_CurrMode == ShowMode::Test1)
{
for (int i = 0; i < m_IndexCount; i += 3)
{
if (i == 0)
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureOne.GetAddressOf());
else if (i == 6)
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureTwo.GetAddressOf());
else if (i == 12)
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureThree.GetAddressOf());
else if (i == 18)
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureFour.GetAddressOf());
else if (i == 24)
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureFive.GetAddressOf());
else if (i == 30)
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureSix.GetAddressOf());
m_pd3dImmediateContext->DrawIndexed(3, i, 0);
}
}
else //if(m_CurrMode == ShowMode::Test3)
m_pd3dImmediateContext->DrawIndexed(m_IndexCount, 0, 0);
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
HR(m_pSwapChain->Present(0, 0));
}
DrawScene函数的修改:
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
imgui的释放:
3.字体的添加
找ttf字体文件,在imgui/misc/font目录下 用命令行解码,输入 binary_to_compressed_c.exe <解码文件> -nocompressed ><输出文件名> ,就可以得到.hpp文件
ImFontConfig font;
font.FontDataOwnedByAtlas = false;
m_font = io.Fonts->AddFontFromMemoryTTF((void*)baidu_font_data, baidu_font_size, 27.0f, &font, io.Fonts->GetGlyphRangesChineseFull());
AddFontFromMemoryTTF函数:
参数1:字体数组
参数2:字体数组的长度
参数3:字体大小
参数4:授权指针
参数5:我们要输出中文,因此选择GetGlyphRangesChineseFull()
注意:对于参数4,如果授权不为flase,那么字体会在最后释放内存,它会将所有权交给FontDataOwnedByAtlas,会出现以下情况
4.绘制:
float fontsize = 20.0f;//字体大小
ImGui::GetForegroundDrawList()->AddText(m_font, fontsize, ImVec2(m_ClientWidth - m_ClientWidth, m_ClientHeight - m_ClientHeight), ImColor(255, 255, 255, 255), "好帅啊!看什么看!说的就是你!");
AddText函数:
参1:字体
参2:字体大小
参3:文字开始位置
参4:文字颜色
参5:文字内容
5.效果:
四、键鼠的改动
之前是W/A/S/D/ UP/DOWN/LEFT/RIGHT键控制绕x/y轴的旋转,I/U键控制缩放
鼠标左键长按控制绕x/y轴的旋转,滑轮键控制缩放
现在如下:
if (mouseState.rightButton == true && m_MouseTracker.rightButton == m_MouseTracker.PRESSED) //&& AutoRotation==falseRELEASED
{
if (AutoRotation == true)
AutoRotation = false;
else
AutoRotation = true;
}//当鼠标左键长按时可进行绕Y轴或X轴的旋转
if (AutoRotation == false)
{
cubePhi += 0.0005f, cubeTheta += 0.00075f;
XMMATRIX W = XMMatrixRotationX(cubePhi) * XMMatrixRotationY(cubeTheta);
m_VSConstantBuffer1.world = XMMatrixTranspose(W);
m_VSConstantBuffer1.worldInvTranspose = XMMatrixTranspose(InverseTranspose(W));
//AutoRotation = true;
}
else
{
cubePhi += 0.0f, cubeTheta += 0.00f;
XMMATRIX W = XMMatrixRotationX(cubePhi) * XMMatrixRotationY(cubeTheta);
m_VSConstantBuffer1.world = XMMatrixTranspose(W);
m_VSConstantBuffer1.worldInvTranspose = XMMatrixTranspose(InverseTranspose(W));
}
右键点击-选择是否自动旋转
注意:这里的旋转角度要和鼠标左键长按的同步,即上面图所示的cubephi和cubetheta的作用于长按鼠标左键的旋转和自动旋转,否则如上:
if (m_KeyboardTracker.IsKeyPressed(Keyboard::Q))
{
m_PSConstantBuffer.dirLight[0] = m_DirLight;
m_PSConstantBuffer.pointLight[0] = PointLight();
m_PSConstantBuffer.spotLight[0] = SpotLight();
}
else if (m_KeyboardTracker.IsKeyPressed(Keyboard::W))
{
m_PSConstantBuffer.dirLight[0] = DirectionalLight();
m_PSConstantBuffer.pointLight[0] = m_PointLight;
m_PSConstantBuffer.spotLight[0] = SpotLight();
}
else if (m_KeyboardTracker.IsKeyPressed(Keyboard::E))
{
m_PSConstantBuffer.dirLight[0] = DirectionalLight();
m_PSConstantBuffer.pointLight[0] = PointLight();
m_PSConstantBuffer.spotLight[0] = m_SpotLight;
}
else if (m_KeyboardTracker.IsKeyPressed(Keyboard::R))
{
m_PSConstantBuffer.dirLight[0] = DirectionalLight();
m_PSConstantBuffer.pointLight[0] = PointLight();
m_PSConstantBuffer.spotLight[0] = SpotLight();
}
Q/W/E/R键分别对应 方向光/点光/聚光灯/关灯
// 键盘切换模式
if (m_KeyboardTracker.IsKeyPressed(Keyboard::D1) && m_CurrMode != ShowMode::Test1)
{
// 播放木箱动画
m_CurrMode = ShowMode::Test1;
m_pd3dImmediateContext->IASetInputLayout(m_pVertexLayout3D.Get());
auto meshData = Geometry::CreateBox();
ResetMesh(meshData);
m_pd3dImmediateContext->VSSetShader(m_pVertexShader3D.Get(), nullptr, 0);
m_pd3dImmediateContext->PSSetShader(m_pPixelShader3D.Get(), nullptr, 0);
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureOne.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureTwo.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureThree.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureFour.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureFive.GetAddressOf());
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureSix.GetAddressOf());
}
else if (m_KeyboardTracker.IsKeyPressed(Keyboard::D2) && m_CurrMode != ShowMode::Test2)
{
m_CurrMode = ShowMode::Test2;
m_CurrFrame = 0;
m_pd3dImmediateContext->IASetInputLayout(m_pVertexLayout2D.Get());
auto meshData = Geometry::Create2DShow();
ResetMesh(meshData);
m_pd3dImmediateContext->VSSetShader(m_pVertexShader2D.Get(), nullptr, 0);
m_pd3dImmediateContext->PSSetShader(m_pPixelShader2D.Get(), nullptr, 0);
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pFireAnims[0].GetAddressOf());
}
else if (m_KeyboardTracker.IsKeyPressed(Keyboard::D3) && m_CurrMode != ShowMode::Test3)
{
// 播放木箱动画
m_CurrMode = ShowMode::Test3;
m_pd3dImmediateContext->IASetInputLayout(m_pVertexLayout3D.Get());
auto meshData = Geometry::CreateBox();
ResetMesh(meshData);
m_pd3dImmediateContext->VSSetShader(m_pVertexShader3D.Get(), nullptr, 0);
m_pd3dImmediateContext->PSSetShader(m_pPixelShader3D.Get(), nullptr, 0);
m_pd3dImmediateContext->PSSetShaderResources(0, 1, m_pTextureInputA.GetAddressOf());
}
数字1/2/3键切换不同的纹理动画,1为六个不同纹理,2为火焰纹理动画,3为旋转纹理
其中A/S/D/W的旋转功能取消,其他如I/U UP/DOWN/LEFT/RIGHT键以及鼠标左键和滑轮的功能如上一篇文章一样
五、纹理的旋转
因为在像素着色器变换浪费计算量,我们就在顶点着色器中变换
// 顶点着色器(3D)
VertexPosHWNormalTex VS(VertexPosNormalTex vIn)
{
VertexPosHWNormalTex vOut;
matrix viewProj = mul(g_View, g_Proj);
float4 posW = mul(float4(vIn.PosL, 1.0f), g_World);
vOut.PosH = mul(posW, viewProj);
vOut.PosW = posW.xyz;
vOut.NormalW = mul(vIn.NormalL, (float3x3) g_WorldInvTranspose);
vOut.Tex = mul(float4(vIn.Tex,0.0f,1.0f),g_RotationMatrix);
return vOut;
}
对应c++应用层,因为纹理的uv(即水平垂直)范围是(0,1)的,但是我们要实现纹理绕纹理中心旋转,所以我们要先平移回原点,再旋转,旋转后再平移回去,我想要纹理顺时针旋转,所以phi2是减的
static float phi2 = 0.0f;
phi2 -= 0.01f;
XMMATRIX texMat = XMMatrixTranslation(-0.5f, -0.5f, 0.0f) * XMMatrixRotationZ(phi2) * XMMatrixTranslation(0.5f, 0.5f, 0.0f);
m_VSConstantBuffer3.RotationMatrix = XMMatrixTranspose(texMat);
问题1:
问题所在:旋转纹理的边界发光
解决:采样器的寻址模式的取值并调颜色(如上),修改寻址模式为D3D11_TEXTURE_ADDRESS_BORDER,以默认颜色填充边界,这里我们取的黑色
问题2:
问题所在:因为同一个项目中,我们用的是同一个顶点着色器,所以虽然在test1的六个不同纹理中的纹理没有使用旋转矩阵,但是也跟着旋转了
解决:我们要在不同物体使用不同的变换矩阵(如上),m_VSConstantBuffer3和m_VSConstantBuffer1一个转置变换矩阵,一个转置单位阵