本文共 20309 字,大约阅读时间需要 67 分钟。
我们将下来描述如何建立其他两个几何体形状:圆柱体和球体。这些形状对于天空盒、调试、可视化碰撞检测,和减少渲染是非常有帮助的。比如,你可能想把所有游戏角色都渲染成一个球体来调试测试。
我们将圆柱体分为三个部分:侧面、顶部圆盖和底部圆盖。(注意这里说的圆柱体不是单纯的圆柱体,也可以泛指圆台、圆锥。当顶部圆盖半径为0就是圆锥。)我们可以定义一个圆柱体,通过指定其底部和顶部半径,还有高度,以及片(Slide)和层(Stack)数。如下图所示:
(图中左边的圆柱体有8片,4层。片数和层数可以控制三角形的密度。)上图有【层数+1】个环(ring),每个环都有片数个顶点。
每两个连续的环的半径之差△r为:△r = (顶部圆盖半径 - 底部圆盖半径) / 层数
如果底部的环的下标是0,那么第i个环半径r(i):
r(i) = 底部环半径+ iΔr。
△h是层的高度,h是圆柱体高度。那么第i个环的高度h(i)是:
h(i) = -h/2 + i△h
所以我们的基本实现就是迭代每一环来产生每一环上的顶点。
那么如何指定索引呢?
观察下图,每一层中的每一片都有一个四边形(两个三角形)。下图显示了第i层中的第j片:
(顶点 A,B,C,D包含第i层中的第j片)ΔABC=(i·n+j, (i+1)·n+j), (i+1)·n+j+1)
ΔACD=(i·n+j, (i+1)·n+j+1, i·n+j+1n是每一环的顶点数。因此,创建索引缓存的关键的思想是每一层中的每一片应用上述公式。
注意: 1. 每个环的第一个和最后一个顶点在位置上重复,但纹理坐标不重复。我们必须这样做才能正确地使用纹理。 2. 代码中包含创建圆柱体对象额外的顶点数据,例如法线和纹理坐标,这些为以后的演示提供方便,现在不用担心这些代码。
void GeometryGenerator::CreateCylinder(float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount, MeshData& meshData){ meshData.Vertices.clear(); meshData.Indices.clear(); // // 建立层 // float stackHeight = height / stackCount; // 根据层的级数,自底向上增加半径的步长 float radiusStep = (topRadius - bottomRadius) / stackCount; UINT ringCount = stackCount+1; // 自底向上计算每个层环的顶点 for(UINT i = 0; i < ringCount; ++i) { float y = -0.5f*height + i*stackHeight; float r = bottomRadius + i*radiusStep; // 环的顶点 float dTheta = 2.0f*XM_PI/sliceCount; for(UINT j = 0; j <= sliceCount; ++j) { Vertex vertex; float c = cosf(j*dTheta); float s = sinf(j*dTheta); vertex.Position = XMFLOAT3(r*c, y, r*s); vertex.TexC.x = (float)j/sliceCount; vertex.TexC.y = 1.0f - (float)i/stackCount; vertex.TangentU = XMFLOAT3(-s, 0.0f, c); float dr = bottomRadius-topRadius; XMFLOAT3 bitangent(dr*c, -height, dr*s); XMVECTOR T = XMLoadFloat3(&vertex.TangentU); XMVECTOR B = XMLoadFloat3(&bitangent); XMVECTOR N = XMVector3Normalize(XMVector3Cross(T, B)); XMStoreFloat3(&vertex.Normal, N); meshData.Vertices.push_back(vertex); } } // 因为第一个顶点和最后一个顶点的贴图坐标是不同的,我们将顶点数加1 UINT ringVertexCount = sliceCount+1; // 计算每层的顶点 for(UINT i = 0; i < stackCount; ++i) { for(UINT j = 0; j < sliceCount; ++j) { meshData.Indices.push_back(i*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j+1); meshData.Indices.push_back(i*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j+1); meshData.Indices.push_back(i*ringVertexCount + j+1); } } //下面两个函数调用产生顶部圆盖和底部圆盖网格,接下来会说到 BuildCylinderTopCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData); BuildCylinderBottomCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);}
原理就是产生一个顶部环足够多的片来近似产生一个圆,我们直接看源代码,底部和顶部的代码是几乎一样的:
void GeometryGenerator::BuildCylinderTopCap(float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount, MeshData& meshData){ UINT baseIndex = (UINT)meshData.Vertices.size(); float y = 0.5f*height; float dTheta = 2.0f*XM_PI/sliceCount; // 因为圆柱体顶部的环顶点的贴图坐标和法线向量是不同的,我们要复制顶部的顶点 for(UINT i = 0; i <= sliceCount; ++i) { float x = topRadius*cosf(i*dTheta); float z = topRadius*sinf(i*dTheta); // Scale down by the height to try and make top cap texture coord area proportional to base. float u = x/height + 0.5f; float v = z/height + 0.5f; meshData.Vertices.push_back( Vertex(x, y, z, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) ); } // 盖中心的顶点 meshData.Vertices.push_back( Vertex(0.0f, y, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f) ); // 中心顶点的索引 UINT centerIndex = (UINT)meshData.Vertices.size()-1; for(UINT i = 0; i < sliceCount; ++i) { meshData.Indices.push_back(centerIndex); meshData.Indices.push_back(baseIndex + i+1); meshData.Indices.push_back(baseIndex + i); }}
void GeometryGenerator::BuildCylinderBottomCap(float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount, MeshData& meshData){ // // 建立底部盖 // UINT baseIndex = (UINT)meshData.Vertices.size(); float y = -0.5f*height; // 环的顶点 float dTheta = 2.0f*XM_PI/sliceCount; for(UINT i = 0; i <= sliceCount; ++i) { float x = bottomRadius*cosf(i*dTheta); float z = bottomRadius*sinf(i*dTheta); // Scale down by the height to try and make top cap texture coord area proportional to base. float u = x/height + 0.5f; float v = z/height + 0.5f; meshData.Vertices.push_back( Vertex(x, y, z, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) ); } // 盖中心的顶点 meshData.Vertices.push_back( Vertex(0.0f, y, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f) ); // 中心顶点的索引缓存 UINT centerIndex = (UINT)meshData.Vertices.size()-1; for(UINT i = 0; i < sliceCount; ++i) { meshData.Indices.push_back(centerIndex); meshData.Indices.push_back(baseIndex + i); meshData.Indices.push_back(baseIndex + i+1); }}
书中介绍了两种方法,一种是GeometryGenerator::CreateSphere,另外一种是GeometryGenerator::CreateGeosphere。
下图是CreateSphere方法产生的球体。
这个方法也是通过指定片数和层数来创建的,生成的算法和圆柱体生成算法是非常相似的,但每环的半径变化是依据三角函数产生的非线性变换。以CreateSphere这种方式产生的三角形不是等边三角形,三角形之间也未必相等,而以CreateGeosphere方式产生的三角形则是等边三角形,而且它们是全等三角形,可以参见下一幅图的Geosphere,比较一下两种球体网格的不同之处。这里只给出源代码,不再赘述。(英文注释未翻译部分并非当前章节所学的知识,暂时无需关注)
void GeometryGenerator::CreateSphere(float radius, UINT sliceCount, UINT stackCount, MeshData& meshData){ meshData.Vertices.clear(); meshData.Indices.clear(); // 计算顶端的极端点,并且向下移动堆 // // 极端点:注意贴图坐标可能会扭曲,因为正方形贴图映射到球体导致没有合适的位置映射到极端点。 Vertex topVertex(0.0f, +radius, 0.0f, 0.0f, +1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); Vertex bottomVertex(0.0f, -radius, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f); meshData.Vertices.push_back( topVertex ); float phiStep = XM_PI/stackCount; float thetaStep = 2.0f*XM_PI/sliceCount; // 计算每个栈环的顶点(不将极端点视为环) for(UINT i = 1; i <= stackCount-1; ++i) { float phi = i*phiStep; // 环的顶点 for(UINT j = 0; j <= sliceCount; ++j) { float theta = j*thetaStep; Vertex v; // 球面到笛卡尔坐标系 v.Position.x = radius*sinf(phi)*cosf(theta); v.Position.y = radius*cosf(phi); v.Position.z = radius*sinf(phi)*sinf(theta); // Partial derivative of P with respect to theta v.TangentU.x = -radius*sinf(phi)*sinf(theta); v.TangentU.y = 0.0f; v.TangentU.z = +radius*sinf(phi)*cosf(theta); XMVECTOR T = XMLoadFloat3(&v.TangentU); XMStoreFloat3(&v.TangentU, XMVector3Normalize(T)); XMVECTOR p = XMLoadFloat3(&v.Position); XMStoreFloat3(&v.Normal, XMVector3Normalize(p)); v.TexC.x = theta / XM_2PI; v.TexC.y = phi / XM_PI; meshData.Vertices.push_back( v ); } } meshData.Vertices.push_back( bottomVertex ); // // 计算堆的索引。堆顶是顶点缓存第一个数据,并且连接顶端的极端点到第一个环。 // for(UINT i = 1; i <= sliceCount; ++i) { meshData.Indices.push_back(0); meshData.Indices.push_back(i+1); meshData.Indices.push_back(i); } // // 计算内堆的索引。(不包括极端点) // 第一个顶点到第一个环的索引偏移 // 这里仅仅跳过顶端的极端顶点 UINT baseIndex = 1; UINT ringVertexCount = sliceCount+1; for(UINT i = 0; i < stackCount-2; ++i) { for(UINT j = 0; j < sliceCount; ++j) { meshData.Indices.push_back(baseIndex + i*ringVertexCount + j); meshData.Indices.push_back(baseIndex + i*ringVertexCount + j+1); meshData.Indices.push_back(baseIndex + (i+1)*ringVertexCount + j); meshData.Indices.push_back(baseIndex + (i+1)*ringVertexCount + j); meshData.Indices.push_back(baseIndex + i*ringVertexCount + j+1); meshData.Indices.push_back(baseIndex + (i+1)*ringVertexCount + j+1); } } // // 计算底堆的索引。底堆是最后写到顶点缓存的,并且连接低端的极端点和底端环 // // 南极端顶点是最后添加的 UINT southPoleIndex = (UINT)meshData.Vertices.size()-1; // 第一个顶点到最后一个环的偏移索引 baseIndex = southPoleIndex - ringVertexCount; for(UINT i = 0; i < sliceCount; ++i) { meshData.Indices.push_back(southPoleIndex); meshData.Indices.push_back(baseIndex+i); meshData.Indices.push_back(baseIndex+i+1); }}
下图是Geosphere的产生过程。它的原理是通过二十面体来细分,再将细分后的顶点映射到一个球体。也可以重复这个过程来产生细分度更高的球体。
我们通过取一个三角形的每条边的中点来产生四个小三角形,如下图:
这时候这几个顶点都是在同一个平面的,接下来再将所有顶点位置向量的大小变为半径大小(这个过程相当于将20面体的所有新产生的顶点映射到球体表面),就产生了一个细分度更高的球体。
通过如下公式,可以将顶点位置向量的大小变为半径大小:现在,我们有足够的知识来看源代码了:
void GeometryGenerator::CreateGeosphere(float radius, UINT numSubdivisions, MeshData& meshData){ // Put a cap on the number of subdivisions. // 细分数 numSubdivisions = MathHelper::Min(numSubdivisions, 5u); // Approximate a sphere by tessellating an icosahedron. // 通过细分二十面体来产生球体 const float X = 0.525731f; const float Z = 0.850651f; XMFLOAT3 pos[12] = { XMFLOAT3(-X, 0.0f, Z), XMFLOAT3(X, 0.0f, Z), XMFLOAT3(-X, 0.0f, -Z), XMFLOAT3(X, 0.0f, -Z), XMFLOAT3(0.0f, Z, X), XMFLOAT3(0.0f, Z, -X), XMFLOAT3(0.0f, -Z, X), XMFLOAT3(0.0f, -Z, -X), XMFLOAT3(Z, X, 0.0f), XMFLOAT3(-Z, X, 0.0f), XMFLOAT3(Z, -X, 0.0f), XMFLOAT3(-Z, -X, 0.0f) }; DWORD k[60] = { 1,4,0, 4,9,0, 4,5,9, 8,5,4, 1,8,4, 1,10,8, 10,3,8, 8,3,5, 3,2,5, 3,7,2, 3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0, 10,1,6, 11,0,9, 2,11,9, 5,2,9, 11,2,7 }; meshData.Vertices.resize(12); meshData.Indices.resize(60); for(UINT i = 0; i < 12; ++i) meshData.Vertices[i].Position = pos[i]; for(UINT i = 0; i < 60; ++i) meshData.Indices[i] = k[i]; for(UINT i = 0; i < numSubdivisions; ++i) Subdivide(meshData); // 投射顶点到球体并且进行缩放 for(UINT i = 0; i < meshData.Vertices.size(); ++i) { // 投射到单位球 XMVECTOR n = XMVector3Normalize(XMLoadFloat3(&meshData.Vertices[i].Position)); // 投射到符合半径的球体 XMVECTOR p = radius*n; XMStoreFloat3(&meshData.Vertices[i].Position, p); XMStoreFloat3(&meshData.Vertices[i].Normal, n); // 从球面坐标导出纹理坐标 float theta = MathHelper::AngleFromXY( meshData.Vertices[i].Position.x, meshData.Vertices[i].Position.z); float phi = acosf(meshData.Vertices[i].Position.y / radius); meshData.Vertices[i].TexC.x = theta/XM_2PI; meshData.Vertices[i].TexC.y = phi/XM_PI; // Partial derivative of P with respect to theta meshData.Vertices[i].TangentU.x = -radius*sinf(phi)*sinf(theta); meshData.Vertices[i].TangentU.y = 0.0f; meshData.Vertices[i].TangentU.z = +radius*sinf(phi)*cosf(theta); XMVECTOR T = XMLoadFloat3(&meshData.Vertices[i].TangentU); XMStoreFloat3(&meshData.Vertices[i].TangentU, XMVector3Normalize(T)); }}
现在来看下这个Demo,它将展示多个球体和圆柱体,还有之前使用过的正方体。我们通过不同的世界坐标矩阵来绘制多个物体。
// 定义从局部坐标系转换到世界坐标系的矩阵XMFLOAT4X4 mSphe reWorld[10]; XMFLOAT4X4 mCylWorld[10]; XMFLOAT4X4 mBoxWorld; XMFLOAT4X4 mGridWorld; XMFLOAT4X4 mCe nte rSphe re ; XMMATRIX I = XMMatrixIde ntity(); XMStore Float4x4(&mGridWorld, I); XMMATRIX boxScale = XMMatrixScaling(2.0f, 1.0f, 2.0f); XMMATRIX boxOffset = XMMatrixTranslation(0.0f, 0.5f, 0.0f); XMStore Float4x4(&mBoxWorld, XMMatrixMultiply(boxScale , boxOffset)); XMMATRIX ce nte rSphere Scale = XMMatrixScaling(2.0f, 2.0f, 2.0f); XMMATRIX ce nte rSphere Offset = XMMatrixTranslation(0.0f, 2.0f, 0.0f); XMStore Float4x4(&mCe nte rSphe re , XMMatrixMultiply(ce nte rSphe re Scale , cente rSphe re Offset)); // We create 5 rows of 2 cylinders and spheres per row. for(inti=0;i<5;++i) { XMStoreFloat4x4(&mCylWorld[i*2+0], XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i*5.0f)); XMStoreFloat4x4(&mCylWorld[i*2+1], XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i*5.0f)); XMStoreFloat4x4(&mSphere World[i*2+0], XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i*5.0f)); XMStoreFloat4x4(&mSphere World[i*2+1], XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i*5.0f)); }
我们将所有的网格顶点和索引都放到同一个顶点和索引缓存,通过拼接顶点和索引数组。所以当我们绘制一个物体时,我们只是绘制顶点和索引缓冲区的子集。
下面的代码演示了如何创建几何缓冲区,以及如何绘制对象。
void ShapesApp::BuildGeometryBuffers(){ GeometryGenerator::MeshData box; GeometryGenerator::MeshData grid; GeometryGenerator::MeshData sphere; GeometryGenerator::MeshData cylinder; GeometryGenerator geoGen; geoGen.CreateBox(1.0f, 1.0f, 1.0f, box); geoGen.CreateGrid(20.0f, 30.0f, 60, 40, grid); geoGen.CreateSphere(0.5f, 20, 20, sphere); //geoGen.CreateGeosphere(0.5f, 2, sphere); geoGen.CreateCylinder(0.5f, 0.3f, 3.0f, 20, 20, cylinder); // 连续的顶点缓存中每个物体的顶点偏移缓存 mBoxVertexOffset = 0; mGridVertexOffset = box.Vertices.size(); mSphereVertexOffset = mGridVertexOffset + grid.Vertices.size(); mCylinderVertexOffset = mSphereVertexOffset + sphere.Vertices.size(); // 每个物体的索引数量缓存 mBoxIndexCount = box.Indices.size(); mGridIndexCount = grid.Indices.size(); mSphereIndexCount = sphere.Indices.size(); mCylinderIndexCount = cylinder.Indices.size(); // 连续的索引缓存中每个物体的开始索引缓存 mBoxIndexOffset = 0; mGridIndexOffset = mBoxIndexCount; mSphereIndexOffset = mGridIndexOffset + mGridIndexCount; mCylinderIndexOffset = mSphereIndexOffset + mSphereIndexCount; UINT totalVertexCount = box.Vertices.size() + grid.Vertices.size() + sphere.Vertices.size() + cylinder.Vertices.size(); UINT totalIndexCount = mBoxIndexCount + mGridIndexCount + mSphereIndexCount + mCylinderIndexCount; // // 提取我们感兴趣的顶点元素,并将所有网格顶点打包成一个顶点缓存 // std::vectorvertices(totalVertexCount); XMFLOAT4 black(0.0f, 0.0f, 0.0f, 1.0f); UINT k = 0; for(size_t i = 0; i < box.Vertices.size(); ++i, ++k) { vertices[k].Pos = box.Vertices[i].Position; vertices[k].Color = black; } for(size_t i = 0; i < grid.Vertices.size(); ++i, ++k) { vertices[k].Pos = grid.Vertices[i].Position; vertices[k].Color = black; } for(size_t i = 0; i < sphere.Vertices.size(); ++i, ++k) { vertices[k].Pos = sphere.Vertices[i].Position; vertices[k].Color = black; } for(size_t i = 0; i < cylinder.Vertices.size(); ++i, ++k) { vertices[k].Pos = cylinder.Vertices[i].Position; vertices[k].Color = black; } D3D11_BUFFER_DESC vbd; vbd.Usage = D3D11_USAGE_IMMUTABLE; vbd.ByteWidth = sizeof(Vertex) * totalVertexCount; vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbd.CPUAccessFlags = 0; vbd.MiscFlags = 0; D3D11_SUBRESOURCE_DATA vinitData; vinitData.pSysMem = &vertices[0]; HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mVB)); // // 打包所有网格的索引到一个索引缓存 // std::vector indices; indices.insert(indices.end(), box.Indices.begin(), box.Indices.end()); indices.insert(indices.end(), grid.Indices.begin(), grid.Indices.end()); indices.insert(indices.end(), sphere.Indices.begin(), sphere.Indices.end()); indices.insert(indices.end(), cylinder.Indices.begin(), cylinder.Indices.end()); D3D11_BUFFER_DESC ibd; ibd.Usage = D3D11_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(UINT) * totalIndexCount; ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = &indices[0]; HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB));}
ShapesApp::ShapesApp(HINSTANCE hInstance): D3DApp(hInstance), mVB(0), mIB(0), mFX(0), mTech(0), mfxWorldViewProj(0), mInputLayout(0), mWireframeRS(0), mTheta(1.5f*MathHelper::Pi), mPhi(0.1f*MathHelper::Pi), mRadius(15.0f){ mMainWndCaption = L"Shapes Demo"; mLastMousePos.x = 0; mLastMousePos.y = 0; XMMATRIX I = XMMatrixIdentity(); XMStoreFloat4x4(&mGridWorld, I); XMStoreFloat4x4(&mView, I); XMStoreFloat4x4(&mProj, I); XMMATRIX boxScale = XMMatrixScaling(2.0f, 1.0f, 2.0f); XMMATRIX boxOffset = XMMatrixTranslation(0.0f, 0.5f, 0.0f); XMStoreFloat4x4(&mBoxWorld, XMMatrixMultiply(boxScale, boxOffset)); XMMATRIX centerSphereScale = XMMatrixScaling(2.0f, 2.0f, 2.0f); XMMATRIX centerSphereOffset = XMMatrixTranslation(0.0f, 2.0f, 0.0f); XMStoreFloat4x4(&mCenterSphere, XMMatrixMultiply(centerSphereScale, centerSphereOffset)); for(int i = 0; i < 5; ++i) { XMStoreFloat4x4(&mCylWorld[i*2+0], XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i*5.0f)); XMStoreFloat4x4(&mCylWorld[i*2+1], XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i*5.0f)); XMStoreFloat4x4(&mSphereWorld[i*2+0], XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i*5.0f)); XMStoreFloat4x4(&mSphereWorld[i*2+1], XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i*5.0f)); }}
void ShapesApp::UpdateScene(float dt){ // Convert Spherical to Cartesian coordinates. float x = mRadius*sinf(mPhi)*cosf(mTheta); float z = mRadius*sinf(mPhi)*sinf(mTheta); float y = mRadius*cosf(mPhi); // Build the view matrix. XMVECTOR pos = XMVectorSet(x, y, z, 1.0f); XMVECTOR target = XMVectorZero(); XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMMATRIX V = XMMatrixLookAtLH(pos, target, up); XMStoreFloat4x4(&mView, V);}
void ShapesApp::DrawScene()`{ md3dImmediateContext->ClearRenderTargetView(mRenderTargetView, reinterpret_cast(&Colors::LightSteelBlue)); md3dImmediateContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); md3dImmediateContext->IASetInputLayout(mInputLayout); md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); md3dImmediateContext->RSSetState(mWireframeRS); UINT stride = sizeof(Vertex); UINT offset = 0; md3dImmediateContext->IASetVertexBuffers(0, 1, &mVB, &stride, &offset); md3dImmediateContext->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0); // Set constants XMMATRIX view = XMLoadFloat4x4(&mView); XMMATRIX proj = XMLoadFloat4x4(&mProj); XMMATRIX viewProj = view*proj; D3DX11_TECHNIQUE_DESC techDesc; mTech->GetDesc( &techDesc ); for(UINT p = 0; p < techDesc.Passes; ++p) { // Draw the grid. XMMATRIX world = XMLoadFloat4x4(&mGridWorld); mfxWorldViewProj->SetMatrix(reinterpret_cast (&(world*viewProj))); mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext); md3dImmediateContext->DrawIndexed(mGridIndexCount, mGridIndexOffset, mGridVertexOffset); // Draw the box. world = XMLoadFloat4x4(&mBoxWorld); mfxWorldViewProj->SetMatrix(reinterpret_cast (&(world*viewProj))); mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext); md3dImmediateContext->DrawIndexed(mBoxIndexCount, mBoxIndexOffset, mBoxVertexOffset); // Draw center sphere. world = XMLoadFloat4x4(&mCenterSphere); mfxWorldViewProj->SetMatrix(reinterpret_cast (&(world*viewProj))); mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext); md3dImmediateContext->DrawIndexed(mSphereIndexCount, mSphereIndexOffset, mSphereVertexOffset); // Draw the cylinders. for(int i = 0; i < 10; ++i) { world = XMLoadFloat4x4(&mCylWorld[i]); mfxWorldViewProj->SetMatrix(reinterpret_cast (&(world*viewProj))); mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext); md3dImmediateContext->DrawIndexed(mCylinderIndexCount, mCylinderIndexOffset, mCylinderVertexOffset); } // Draw the spheres. for(int i = 0; i < 10; ++i) { world = XMLoadFloat4x4(&mSphereWorld[i]); mfxWorldViewProj->SetMatrix(reinterpret_cast (&(world*viewProj))); mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext); md3dImmediateContext->DrawIndexed(mSphereIndexCount, mSphereIndexOffset, mSphereVertexOffset); } } HR(mSwapChain->Present(0, 0));}