DirectX11 With Windows SDK -- 07 练习题

1. 尝试修改本章Demo的光照,让方向光只射出红光,点光灯只射出绿光,聚光灯只射出蓝光。
这里只需要修改在GameApp.cpp里面的InitResources函数里的初始化默认光照的颜色即可:

	// 初始化默认光照// 方向光m_DirLight.ambient = XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);m_DirLight.diffuse = XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);m_DirLight.specular = XMFLOAT4(1.0f, 0.0f, 0.0f, 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.0f, 1.0f, 0.0f, 1.0f);m_PointLight.diffuse = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);m_PointLight.specular = XMFLOAT4(0.0f, 1.0f, 0.0f, 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(0.0f, 0.0f, 1.0f, 1.0f);m_SpotLight.specular = XMFLOAT4(0.0f, 0.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;

2. 尝试修改本章Demo所用到的材质,让其只反射红光。
修改材质的反光系数即可:

	// 初始化用于PS的常量缓冲区的值m_PSConstantBuffer.material.ambient = XMFLOAT4(0.5f, 0.0f, 0.0f, 1.0f);m_PSConstantBuffer.material.diffuse = XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);m_PSConstantBuffer.material.specular = XMFLOAT4(0.5f, 0.0f, 0.0f, 5.0f);

3. 尝试修改本章Demo所用到的聚光灯,通过鼠标滚轮的形式,对光照汇聚强度增加/减少,范围为2-512,观察效果。
因为鼠标滚轮只是调节聚光灯的效果,所以我们首先需要判断当前光照是否为聚光灯光照,如果是的话,并且此时滚动鼠标滚轮,我们就该表光照汇聚程度。
第一步:我们需要重载‘==’运算符。
在LightHelper.h里面,我们需要对SpotLight进行‘==’重载,如下所示:

	bool operator==(SpotLight& s) {if (this->ambient.x != s.ambient.x || this->ambient.y != s.ambient.y || this->ambient.z != s.ambient.z || this->ambient.w != s.ambient.w)return false;if(this->diffuse.x != s.diffuse.x || this->diffuse.y != s.diffuse.y || this->diffuse.z != s.diffuse.z || this->diffuse.w != s.diffuse.w)return false;if (this->specular.x != s.specular.x || this->specular.y != s.specular.y || this->specular.z != s.specular.z || this->specular.w != s.specular.w)return false;if (this->position.x != s.position.x || this->position.y != s.position.y || this->position.z != s.position.z)return false;if (this->range != s.range)return false;if (this->direction.x != s.direction.x || this->direction.y != s.direction.y || this->direction.z != s.direction.z)return false;if (this->att.x != s.att.x || this->att.y != s.att.y || this->att.z != s.att.z)return false;return true;}

第二步:判断是否符合调节强度的条件,并做出相应的改变。

	// 通过鼠标滚轮改变聚光灯强度,范围为2-512Mouse::State mState = m_pMouse->GetState();m_MouseTracker.Update(mState);if (m_PSConstantBuffer.spotLight == m_SpotLight && mState.scrollWheelValue){float temp = m_SpotLight.spot;temp -= mState.scrollWheelValue / 100.0;//限制强度范围while (temp > 512.0){temp -= 512.0;if (temp < 2.0) temp += 2.0;}while (temp < 2.0){temp += 2.0;}m_PSConstantBuffer.spotLight.spot = temp;}

在这里插入图片描述
修改了下,蓝色背景和白色胶囊体,方便更好显示效果:
在这里插入图片描述

4. 尝试修改本章Demo所用到的材质,看看如果镜面反射强度的值小于1会发生什么情况。
通过
由图上所知,p小于1的话,变化就更加缓慢,我们就几乎看不出高光的大小,代码展示如下:

	// 初始化用于PS的常量缓冲区的值m_PSConstantBuffer.material.ambient = XMFLOAT4(0.5f, 0.0f, 0.0f, 1.0f);m_PSConstantBuffer.material.diffuse = XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);m_PSConstantBuffer.material.specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 0.10f);

5. 实现一个函数用于创建胶囊(capsule)几何体,需要指定上下半球的半径(radius)、柱体部分高度(height)、球面三角形切片数(slices)和上下半球的层级数(levels),并且实现顶点要包含位(position)、法向量(normal)。若已经接触过纹理映射与法线贴图,则可以考虑额外实现纹理坐标(texcoord)和切线向量(tangent)。
我们需要修改Geometry.h,添加胶囊几何体。
第一步:在命名空间Geometry中定义胶囊几何体模板。

	template<class VertexType = VertexPosNormalTex, class IndexType = DWORD>MeshData<VertexType, IndexType> CreateCapsule(float radius = 1.0f, float height = 2.0f, UINT levels = 20, UINT slices = 20,const DirectX::XMFLOAT4& color = { 1.0f, 1.0f, 1.0f, 1.0f });

这里为了方便展示,我只控制了胶囊两头半球以及胶囊圆柱体的高度,而胶囊圆柱体分层使用默认层数。
第二步:实现胶囊几何体模板。
这里,我们需要借助原始默认的球体模板和圆柱体的侧面模板(注意最初得到的物体均处于局部坐标系中),在胶囊几何体实现里面对齐进行组装,这里需要用到基本的坐标转换,即将两个半球从局部坐标系转换到世界坐标系下,代码如下:

	template<class VertexType, class IndexType>inline MeshData<VertexType, IndexType> CreateCapsule(float radius, float height, UINT levels, UINT slices, const DirectX::XMFLOAT4& color){using namespace DirectX;auto meshData = CreateCylinderNoCap<VertexPosNormalColor>(radius, height, slices);UINT vertexCount = 2 + (slices + 1) * (10 + levels);UINT indexCount = 6 * slices * (9 + levels);meshData.vertexVec.resize(vertexCount);meshData.indexVec.resize(indexCount);IndexType vIndex = (slices + 1) * 11, iIndex = 6 * slices * 10;IndexType offset = vIndex;//将局部坐标转换为世界坐标时需要的平移矩阵XMMATRIX trans1 = XMMatrixTranslation(0, height / 2, 0);XMMATRIX trans2 = XMMatrixTranslation(0, -height / 2, 0);auto sphere = CreateSphere<VertexType, IndexType>(radius, 20, slices);//放入上半球for (int i = 0; i < sphere.vertexVec.size()/2; ++i){auto& des = meshData.vertexVec[vIndex++];auto source = sphere.vertexVec[i];auto pos = source.pos;auto t = XMLoadFloat3(&pos);auto t1 = XMVectorSet(XMVectorGetX(t), XMVectorGetY(t), XMVectorGetZ(t), 1.0f);auto t2 = XMVector4Transform(t1, trans1);source.pos = XMFLOAT3(XMVectorGetX(t2), XMVectorGetY(t2), XMVectorGetZ(t2));memcpy_s(reinterpret_cast<char*>(&des), sizeof(des), reinterpret_cast<char*>(&source), sizeof(source));}//放入下半球for (int i = sphere.vertexVec.size() / 2; i < sphere.vertexVec.size(); ++i){auto& des = meshData.vertexVec[vIndex++];auto source = sphere.vertexVec[i];auto pos = source.pos;auto t = XMLoadFloat3(&pos);auto t1 = XMVectorSet(XMVectorGetX(t), XMVectorGetY(t), XMVectorGetZ(t), 1.0f);auto t2 = XMVector4Transform(t1, trans2);source.pos = XMFLOAT3(XMVectorGetX(t2), XMVectorGetY(t2), XMVectorGetZ(t2));memcpy_s(reinterpret_cast<char*>(&des), sizeof(des), reinterpret_cast<char*>(&source), sizeof(source));}//放入索引for (int i = 0; i < sphere.indexVec.size(); ++i)meshData.indexVec[iIndex++] = offset + sphere.indexVec[i];return meshData;}

第三步:更新UpdateScene

	else if (m_KeyboardTracker.IsKeyPressed(Keyboard::T)){auto meshData = Geometry::CreateCapsule<VertexPosNormalColor>();ResetMesh(meshData);}

在这里插入图片描述
6. 修改当前演示程序,首先禁用背面剔除(D3D11_CULL_NONE)并运行程序;随后,再代以正面剔除(D3D11_CULL_FRONT)试之。用线框模式输出程序的绘图效果,可便于我们观察不同剔除模式之间的绘制差别。
只需要修改初始化光栅状态处代码,如下:

	// ******************// 初始化光栅化状态//D3D11_RASTERIZER_DESC rasterizerDesc;ZeroMemory(&rasterizerDesc, sizeof(rasterizerDesc));rasterizerDesc.FillMode = D3D11_FILL_WIREFRAME;rasterizerDesc.CullMode = D3D11_CULL_NONE; //D3D11_CULL_FRONT;rasterizerDesc.FrontCounterClockwise = false;rasterizerDesc.DepthClipEnable = true;HR(m_pd3dDevice->CreateRasterizerState(&rasterizerDesc, m_pRSWireframe.GetAddressOf()));

7. 利用光栅化状态,尝试同时画出立方体和其三角形边界(题图无光照)
题图无光照,实际这一块需要在UpdateScene里面取消光照,然后为几何顶点添加颜色以方便光栅化时有图像,不过这样做比较麻烦,且此题本质是考察如何同时画出立方体和三角形边界,所以个人目前还是使用平行光方便显示,其于步骤如下(此处参考了Askwhy的思路,链接:https://blog.nowcoder.net/n/0299b27cccca45a0960babe5b1d07e34):
第一步:UpdateScene

m_pd3dImmediateContext->RSSetState(m_pRSWireframe.Get());
m_PSConstantBuffer.material.diffuse = XMFLOAT4(0.0f, 0.0f, 0.0f,0.0f);

第二步:DrawScene

// 第一次绘制
m_pd3dImmediateContext->DrawIndexed(m_IndexCount, 0, 0);
// 第二次绘制
m_pd3dImmediateContext->RSSetState(nullptr);
// 颜色更改为白色
m_PSConstantBuffer.material.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.0f);
D3D11_MAPPED_SUBRESOURCE mappedData;
HR(m_pd3dImmediateContext->Map(m_pConstantBuffers[1].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
memcpy_s(mappedData.pData, sizeof(PSConstantBuffer), &m_PSConstantBuffer, sizeof(PSConstantBuffer));
m_pd3dImmediateContext->Unmap(m_pConstantBuffers[1].Get(), 0);
// 绘制几何模型
m_pd3dImmediateContext->DrawIndexed(m_IndexCount, 0, 0);

以上为这一课习题答案,个人水平有限,仅供参考,欢迎讨论。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部