DirectX实现球面纹理映射

http://www.cnblogs.com/graphics/archive/2011/09/13/2174022.html

DirectX实现球面纹理映射

介绍

球面纹理映射就是将一个平面纹理映射到球面上。见下图。


实现球面纹理映射有两种方法,一种是使用顶点的法向量来生成纹理坐标,另一个是使用顶点的位置向量来生成纹理坐标。

使用顶点的法向量生成纹理坐标

分析

问题的本质是根据球面上每个点的法向量坐标生成对应的纹理坐标,请看下图,下图中外部的方框表示二维纹理坐标,其范围是(u,v)min = (0,0), (u,v)max = (1,1),中间的圆形表示球面法向量坐标,其x,y分量的范围是(x,y)min = (-1,-1), (x,y)max = (1,1)。


所以问题的本质变成了两组坐标的映射,也即将区间(x,y)min - (x,y)max映射到区间(u,v)min - (u,v)max。这里我们使用反正弦函数y = acrsin(x)来实现。先看一下它的函数图象。


由这个图象知,它的定义域x = (-1,1),值域是y = (-pi / 2, pi / 2)。我们稍作变型,得到下面两个公式。正好完成了由(-1, 1)到(0, 1)的映射。这里tu表示纹理的x坐标,tv表示纹理的y坐标,Nx表示顶点法向量的x轴分量,Ny表示顶点法向量的y轴分量。

tu = arcsin(Nx) / PI + 0.5
tv = arcsin(Ny) / PI + 0.5

代码

具体实现分以下几个步骤

  • 用D3DXCreateSphere生成球体

  • 克隆一份该球体的Mesh

  • 对新的Mesh添加纹理坐标

  • 绘制新的Mesh

核心代码如下

复制代码
struct VERTEX
{
    D3DXVECTOR3 pos ;    // Vertex position
    D3DXVECTOR3 norm ;    // Vertex normal
float tu ;            // Texture coordinate u
float tv ;            // Texture coordinate v
} ;

#define FVF_VERTEX D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1

LPD3DXMESH GenerateSphereMesh(LPDIRECT3DDEVICE9 pDev, 
float fRadius, UINT slices, UINT stacks)
{
    // Create D3D sphere
    LPD3DXMESH mesh ;
    if(FAILED(D3DXCreateSphere(pDev, fRadius, slices, stacks, &mesh, NULL)))
    {
        return NULL ;
    }

    // Get a copy of the sphere mesh
    LPD3DXMESH texMesh ;
    if (FAILED(mesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM, FVF_VERTEX, pDev, &texMesh)))
    {
        return NULL ;
    }

    // Release original mesh
    mesh->Release() ;

    // add texture coordinates
    VERTEX* pVerts ;
    if (SUCCEEDED(texMesh->LockVertexBuffer(0, (void**)&pVerts)))
    {
        // Get vertex count
int numVerts = texMesh->GetNumVertices() ;

        for (int i =0; i < numVerts; ++i)
        {
            // Calculates texture coordinates
            pVerts->tu = asinf(pVerts->norm.x) / D3DX_PI +0.5f ;
            pVerts->tv = asinf(pVerts->norm.y) / D3DX_PI +0.5f ;
            ++pVerts ;
        }

        // Unlock the vertex buffer
        texMesh->UnlockVertexBuffer() ;
    }

    return texMesh ;
}
复制代码

在render函数中调用如下代码

复制代码
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
    // Set texture
    g_pd3dDevice->SetTexture(0, g_pTexture) ;
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );

    // Draw mesh
    g_pMesh->DrawSubset(0) ;
g_pd3dDevice->EndScene(); }
复制代码

另一种更快的方法是使用下面的公式生成纹理坐标,这里省去了三角函数的计算,用除2代替除pi,速度上快了一些。但是这个方法生成的坐标并不是线性的。

tu = Nx/2 + 0.5
tv = Ny/2 + 0.5

使用顶点的位置向量生成纹理坐标

分析

上面的方法在某些场合下并不适用,比如当模型是立方体的时候,使用顶点法向量就不合适了,因为立方体使用的是面法向量,也就是位于同一个面的顶点的法向量是相同的,这时候应该使用顶点的位置来计算纹理坐标。可以用顶点的位置坐标与模型的中心坐标做差,这样得到一个向量,相当于由中心到一个假想球体的投影,这里并不是真正意义的球面映射,只不过在映射过程中有一个假想球而已。如下图所示。


代码

复制代码
LPD3DXMESH GenerateBoxMesh(LPDIRECT3DDEVICE9 pDev)
{
    // Create D3D sphere
    LPD3DXMESH mesh ;
    if(FAILED(D3DXCreateBox(pDev, 1.0f, 1.0f, 1.0f, &mesh, NULL)))
    {
        return NULL ;
    }

    // Get a copy of the sphere mesh
    LPD3DXMESH texMesh ;
    if (FAILED(mesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM, FVF_VERTEX, pDev, &texMesh)))
    {
        return NULL ;
    }

    // Release original mesh
    mesh->Release() ;

    // add texture coordinates
    VERTEX* pVerts ;
    if (SUCCEEDED(texMesh->LockVertexBuffer(0, (void**)&pVerts)))
    {
        // Get vertex count
int numVerts = texMesh->GetNumVertices() ;

        for (int i =0; i < numVerts; ++i)
        {
            D3DXVECTOR3 v = pVerts->pos ;
            D3DXVec3Normalize(&v, &v) ;

            // Calculates texture coordinates
            pVerts->tu = asinf(v.x) / D3DX_PI +0.5f ;
            pVerts->tv = asinf(v.y) / D3DX_PI +0.5f ;

            ++pVerts ;
        }

        // Unlock the vertex buffer
        texMesh->UnlockVertexBuffer() ;
    }

    return texMesh ;
}
复制代码

效果图

参考

http://www.mvps.org/directx/articles/spheremap.htm

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值