• 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

  • 相关阅读:
    最大公约数
    面向对象(jianli)(游客买门票)
    String
    ATM模拟取款
    常用快捷键归纳
    购物清单
    jxls使用模版导出Excel
    IText 生成pdf,处理table cell列跨页缺失的问题
    Java使用IText(VM模版)导出PDF
    js ajax post提交 ie和火狐、谷歌提交的编码不一致,导致中文乱码
  • 原文地址:https://www.cnblogs.com/nafio/p/9137320.html
Copyright © 2020-2023  润新知