博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DirectX11 几何体示例Demo
阅读量:4088 次
发布时间:2019-05-25

本文共 20309 字,大约阅读时间需要 67 分钟。

DirectX11 几何体示例Demo

我们将下来描述如何建立其他两个几何体形状:圆柱体和球体。这些形状对于天空盒、调试、可视化碰撞检测,和减少渲染是非常有帮助的。比如,你可能想把所有游戏角色都渲染成一个球体来调试测试。

1. 如何产生圆柱体网格?

我们将圆柱体分为三个部分:侧面、顶部圆盖和底部圆盖。(注意这里说的圆柱体不是单纯的圆柱体,也可以泛指圆台、圆锥。当顶部圆盖半径为0就是圆锥。)我们可以定义一个圆柱体,通过指定其底部和顶部半径,还有高度,以及片(Slide)和层(Stack)数。如下图所示:

这里写图片描述
(图中左边的圆柱体有8片,4层。片数和层数可以控制三角形的密度。)

2. 如何产生圆柱体侧面网格?

上图有【层数+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+1

n是每一环的顶点数。因此,创建索引缓存的关键的思想是每一层中的每一片应用上述公式。

注意:

1. 每个环的第一个和最后一个顶点在位置上重复,但纹理坐标不重复。我们必须这样做才能正确地使用纹理。
2. 代码中包含创建圆柱体对象额外的顶点数据,例如法线和纹理坐标,这些为以后的演示提供方便,现在不用担心这些代码。

3. 产生圆柱体侧面网格源代码

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);}

4. 如何产生圆柱体顶部圆盖网格和底面圆盖网格?(源代码实现)

原理就是产生一个顶部环足够多的片来近似产生一个圆,我们直接看源代码,底部和顶部的代码是几乎一样的:

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);    }}

5. 如何产生球体网格?

书中介绍了两种方法,一种是GeometryGenerator::CreateSphere,另外一种是GeometryGenerator::CreateGeosphere。

6. CreateSphere产生球体源代码实现

下图是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);    }}

6. CreateGeosphere产生球体源代码实现

下图是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));    }}

7. Shape示例Demo

现在来看下这个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::vector
vertices(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));}

8. 程序运行结果截图

这里写图片描述

这里写图片描述

你可能感兴趣的文章
【Unity】封装SQLite管理类
查看>>
【Unity】面试题整理
查看>>
【C#】如何实现一个迭代器
查看>>
【Unity】Destroy和DestroyImmediate的区别
查看>>
【Lua】Mac系统下配置SublimeText的Lua编译环境
查看>>
【C#】利用Conditional属性完成编译忽略
查看>>
【Unity】微信登录后将头像存为bytes,将bytes读取成sprite图片
查看>>
【Unity】使用GPS定位经纬度
查看>>
【UGUI/NGUI】一键换Text/Label字体
查看>>
【C#】身份证本地验证
查看>>
【Unity】坑爹的Bug
查看>>
【算法】求数组中某两个数的和为目标值
查看>>
如何高效学习动态规划?
查看>>
动态规划法(六)鸡蛋掉落问题(一)
查看>>
LeetCode 887.鸡蛋掉落(C++)
查看>>
Dijkstra‘s algorithm (C++)
查看>>
奇异值分解(SVD)的原理详解及推导
查看>>
算法数据结构 思维导图学习系列(1)- 数据结构 8种数据结构 数组(Array)链表(Linked List)队列(Queue)栈(Stack)树(Tree)散列表(Hash)堆(Heap)图
查看>>
求LCA最近公共祖先的离线Tarjan算法_C++
查看>>
Leetcode 834. 树中距离之和 C++
查看>>