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

DirectX实现球面纹理映射的更多相关文章

  1. Direct-X学习笔记--纹理映射

    一.介绍 之前学习了如何绘制物体,还画了个DX自带的茶壶,然而这个东东并不怎么好看....离我们现实的物体简直相隔千里. 仅仅能说像美术他们用来写生的模型...那么要怎么样才干让我们的东西看起来更像真 ...

  2. 【转载】Direct3D纹理映射

    原文:Direct3D纹理映射 更详细的文章:DirectX中的纹理映射相关技术 (转)   创建纹理对象 1: HRESULT CreateTexture( 2:   UINT Width,//宽度 ...

  3. 《F4+2》——团队项目的原型设计与开发

      目 录 1 · 团队信息 2 · NABCD模型 3.  原型设计的工具 4 · 原型设计 5 · PSP表格 6 · 团队设计过程 7 · 原型设计心得   一 · 团 队 信 息 成 员 列 ...

  4. DirectX 基础学习系列5 纹理映射

    1 纹理坐标 类似BMP图像坐标系,左上为原点 纹理坐标为了规范化,范围限定在[0,1]之间,使用纹理的时候,需要修改顶点结构 struct ColorVetex { float x, y,z; fl ...

  5. 用DirectX实现魔方(一)

    关于魔方 魔方英文名字叫做Rubik's Cube,是由匈牙利建筑学教授和雕塑家Ernő Rubik于1974年发明,最初叫做Magic Cube(这大概也是中文名字的来历吧),1980年Ideal ...

  6. SharpGL学习笔记(十六) 多重纹理映射

    多重纹理就把多张贴图隔和在一起.比如下面示例中,一个表现砖墙的纹理,配合一个表现聚光灯效果的灰度图,就形成了砖墙被一个聚光灯照亮的效果,这便是所谓的光照贴图技术. 多重纹理只在OpenGL扩展库中才提 ...

  7. directX学习系列8 颜色融合(转)

    1, Multipass(多通道)    将一个任务划分成几个阶段,由多个pass处理不同阶段,后续pass总是处理前一个pass的结果.例如复杂的光照方程可以分成几个pass来计算.    用不同的 ...

  8. DirectX 总结和DirectX 9.0 学习笔记

    转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...

  9. NeHe OpenGL教程 第二十三课:球面映射

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

随机推荐

  1. return和exit的差别

    #include<stdio.h> #include<sys/types.h> #include<sys/wait.h> #include<unistd.h& ...

  2. 网络摄像机IPCamera RTSP直播播放网络/权限/音视频数据/花屏问题检测与分析助手EasyRTSPClient

    前言 最近在项目中遇到一个奇怪的问题,同样的SDK调用,访问海康摄像机的RTSP流,发保活OPTIONS命令保活,一个正常,而另一个一发就会被IPC断开,先看现场截图: 图1:发OPTIONS,摄像机 ...

  3. 九度OJ 1100:最短路径 (最短路径)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4185 解决:619 题目描述: N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的 ...

  4. HDFS被设计成能够在一个大集群中跨机器可靠地存储超大文件

    HDFS被设计成能够在一个大集群中跨机器可靠地存储超大文件.它将每个文件存储成一系列的数据块,除了最后一个,所有的数据块都是同样大小的.为了容错,文件的所有数据块都会有副本.每个文件的数据块大小和副本 ...

  5. java之异常的捕获及处理

    在java中程序的错误主要是语法错误和语义错误(也就是逻辑错误). java中异常处理语句的格式: try{ //有可能出现异常的语句 }catch(异常类 异常对象){ //编写异常的处理语句 }c ...

  6. Jquery AJAX如何使用Promise/Deferred实现顺序执行?

    有的时候有我有N个AJAX请求,第下个请求可能要依赖上个请求的返回值, 可以用 $.ajax("test1.php").then(function(data) { // data ...

  7. [IR课程笔记]统计语言模型

    Basic idea 1.一个文档(document)只有一个主题(topic) 2.主题指的是这个主题下文档中词语是如何出现的 3.在某一主题下文档中经常出现的词语,这个词语在这个主题中也是经常出现 ...

  8. holiday和vacation的区别

    holiday:假日vacation:假期a.对于英国人或者澳大利亚人来说,“假日”的意思等同于“假期”(尽管他们很少用“假期”)b.如果你是美国人,“假日”是指一个特殊的日子,好像圣诞节,而“假期” ...

  9. ArcGIS服务器的feature图层限制

    今天遇到了esri.layers.FeatureLayer发布一个宗地图层,里面有些数据未显示,导致数据显示不全,原来是服务中数据返回参数限制. ArcGIS的feature图层(在JavaScrip ...

  10. poj3461 Oulipo —— KMP

    题目链接:http://poj.org/problem?id=3461 代码如下: #include<cstdio>//poj 3461 kmp #include<cstring&g ...