精华内容
下载资源
问答
  • Matlab在共形映射中的应用.pdf
  • 共形映射族 (2001年)

    2021-05-21 01:51:31
    应用覆盖曲面的理论,研究了拟共形映射族,建立了一个基本不等式,得到几个关于拟共形映射的正规定理.
  • 该代码使用 [1] 中的快速方法计算具有磁盘拓扑结构的三角形网格的磁盘共形参数化(即在单位磁盘上的保角映射),该方法已应用于纹理映射、表面配准、机械工程等。 欢迎任何意见和建议。 如果您在自己的工作中使用此...
  • 此代码使用 [1] 中的线性方法计算第 0 类闭合三角形网格的球形保角参数化(即单位球体上的保角映射),该方法已应用于人脑映射、纹理映射、表面配准、心脏映射等。 欢迎任何意见和建议。 如果您在自己的工作中使用...
  • 在本文中,我们利用了在Borel平面上的Adler函数的解析结构,该结构允许定义保变量的幂的改进微扰展开,该保变量将切好的Borel平面映射到单位圆盘上。 新的扩展收敛于Borel平面的较大区域,并且当以强耦合的幂...
  • 该代码使用 [1] 中的快速方法计算具有磁盘拓扑结构的三角形网格的矩形保角参数化(即在矩形上的保角映射),该方法已应用于纹理映射、表面配准、形状分析等。 欢迎任何意见和建议。 如果您在自己的工作中使用此代码...
  • 通过共形映射恢复泰勒级数的数值工具。 目前仅是初步的MATLAB实验,包括使用Schwarz-Christoffel工具箱处理常规多边形区域的版本。 作者:亚历克斯·巴内特(Alex Barnett)。 19/31/19 任务 令其为在原点处分析的...
  • 共形映照及其在黎曼面中应用 李忠老师的书 方便大家自学
  • 形粘合在Teichmu¨ller理论和拟共形映射的发展中起着关键作用。文中应用有界度圆填充构造了由一个拟对称映射诱导的形粘合映射及其相关拟圆周的离散近似,并证明了它们的收敛性。这为形粘合映射提供了一种更一般...
  • 在“应用程序扩展”中,可以设定对特定扩展名的请求的处理方式,比如.aspx,.ascx,.asmx,.ashx这几个都设定为由“c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”来处理。我们可以添加一个新
    
    
    1. 在“应用程序扩展”中,可以设定对特定扩展名的请求的处理方式,比如.aspx,.ascx,.asmx,.ashx这几个都设定为由“c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”来处理。我们可以添加一个新的扩展名,如.happy,也将它交给“c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”来处理。
    2. 在“应用程序扩展”中,添加新的映射时,扩展名一栏不能直接填“.*”,而只能填写形如“.aspx”之类具体的扩展名,这就是“通配符应用程序映射”的用处了。插入一个“通配符应用程序映射”后,比如,插入“c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”,则所有扩展名的请求都会由“c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”来处理。
    3. 当我们在“应用程序扩展”中添加了对应于.happy扩展名的映射,或者干脆直接添加了“通配符应用程序映射”后,在地址栏中直接输入形如“http://localhost/WebApplication1/haha.happy”的请求时,还是会报错,因为“c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”默认也没有提供对.happy这种请求的处理,所以,我们还需要在web.config文件中添加用来处理.happy请求的handler,比如:                                            <httpHandlers>
                <add verb="*" path="*.happy" validate="false" type="WebApplication1.MyHandler, WebApplication1"/>
      </httpHandlers>当然,其中的WebApplication1.MyHandler这个类是需要我们自己写的,实现IHttpHandler接口即可。
    展开全文
  • 纹理映射应用1 Normal Maps及切线空间2 Bump Maps3 Displacement Maps4 Environment MapsReference 在上一节内容中,我们详细介绍了纹理映射的概念,以及纹理贴图过大过小带来的种种问题与解决方案,但纹理映射的...

    (本篇文章同步发表于知乎专栏:https://zhuanlan.zhihu.com/p/144357517 欢迎三连关注)

    在上一节内容中,我们详细介绍了纹理映射的概念,以及纹理贴图过大过小带来的种种问题与解决方案,但纹理映射的应用远不止单单作为diffuse的反射系数来表现出不同颜色。本文会详细介绍一些主要的纹理映射的应用及其原理,首先从法线映射和切线空间开始说起。

    1 Normal Maps及切线空间

    在Blinn-Phong光照模型中,法线向量扮演着重要的一环,不同的法线向量对光照的计算结果有着很大的影响,打个比方,倘若将一个高精度模型法线信息套用在低精度模型之上,会使低精度模型的渲染效果有着巨大的提升。

    那么如何做到呢?我们知道Texture上可以存储3维的颜色信息作为漫反射系数,那么自然也就可以存储法线向量的信息!同样利用(u,v)坐标去查询每个点的法线向量,而不使用原来模型法线信息,达到各种不同的效果,这就是Normal Maps。

    明白了Normal Maps的原理之后,有一点重要的是,如何在存储这些法线信息呢?一种可选的方法是,存储object space下的法线向量坐标(这会使得法线贴图看起来五颜六色的),好处是取出来转换到世界坐标就可以直接使用,坏处是一但该法线向量的三角形面发生了变形,那么该法线向量就不再正确。这也就引出了第二种方法,存储切线空间之的法线向量坐标(这会使得法线贴图大部分呈蓝色,原因下文会提)。任何空间坐标系都要由3个互相正交的基底向量构成,切线空间也不例外,如下图所示:

    其z轴由原来该面上的几何法线n构成,指向物体表面的外侧。x,y轴分别由该面所对应的贴图上U,V增加的两个方向构成,称之为tangant轴和bitangent轴。这样我们称tangant轴(t)、bitangent轴(b)及法线轴(N)所组成的坐标系,即切线空间(tbn)。

    法线向量N可以根据原来的模型信息得到,如何去计算t,b呢?

    如上图所示,记一个三角形的面的三个顶点分别为p0,p1,p2,并且使用(ui,vi)来表示对应顶点的texture坐标,那么根据顶点坐标的差值,纹理坐标的差值,以及t,b两轴,可以得到如下关系
    p i − p j = ( u i − u j ) t + ( v i − v j ) b \boldsymbol{p}_{i}-\boldsymbol{p}_{j}=\left(u_{i}-u_{j}\right) \mathbf{t}+\left(v_{i}-v_{j}\right) \mathbf{b} pipj=(uiuj)t+(vivj)b
    为了进一步简化公式,设:
    e 1 = p 1 − p 0 , ( x 1 , y 1 ) = ( u 1 − u 0 , v 1 − v 0 ) e 2 = p 2 − p 0 , ( x 2 , y 2 ) = ( u 2 − u 0 , v 2 − v 0 ) \begin{array}{ll} \mathbf{e}_{1}=\boldsymbol{p}_{1}-\boldsymbol{p}_{0}, & \left(x_{1}, y_{1}\right)=\left(u_{1}-u_{0}, v_{1}-v_{0}\right) \\ \mathbf{e}_{2}=\boldsymbol{p}_{2}-\boldsymbol{p}_{0}, & \left(x_{2}, y_{2}\right)=\left(u_{2}-u_{0}, v_{2}-v_{0}\right) \end{array} e1=p1p0,e2=p2p0,(x1,y1)=(u1u0,v1v0)(x2,y2)=(u2u0,v2v0)
    那么便可以把第一个公式简化为如下形式:
    e 1 = x 1 t + y 1 b e 2 = x 2 t + y 2 b \begin{array}{l} \mathbf{e}_{1}=x_{1} \mathbf{t}+y_{1} \mathbf{b} \\ \mathbf{e}_{2}=x_{2} \mathbf{t}+y_{2} \mathbf{b} \end{array} e1=x1t+y1be2=x2t+y2b
    利用线代知识,将其写为矩阵形式:
    [ ↑ ↑ e 1 e 2 ↓ ↓ ] = [ ↑ ↑ t b ↓ ↓ ] [ x 1 x 2 y 1 y 2 ] \left[\begin{array}{ll} \uparrow & \uparrow \\ \mathbf{e}_{1} & \mathbf{e}_{2} \\ \downarrow & \downarrow \end{array}\right]=\left[\begin{array}{ll} \uparrow & \uparrow \\ \mathbf{t} & \mathbf{b} \\ \downarrow & \downarrow \end{array}\right]\left[\begin{array}{ll} x_{1} & x_{2} \\ y_{1} & y_{2} \end{array}\right] e1e2=tb[x1y1x2y2]
    相信熟悉线性方程组的同学,已经知道如何解出t,b向量了,两边同乘系数矩阵的逆即可得到:
    [ ↑ ↑ t b ↓ ↓ ] = 1 x 1 y 2 − x 2 y 1 [ ↑ ↑ e 1 e 2 ↓ ↓ ] [ y 2 − x 2 − y 1 x 1 ] \left[\begin{array}{ll} \uparrow & \uparrow \\ \mathbf{t} & \mathbf{b} \\ \downarrow & \downarrow \end{array}\right]=\frac{1}{x_{1} y_{2}-x_{2} y_{1}}\left[\begin{array}{ll} \uparrow & \uparrow \\ \mathbf{e}_{1} & \mathbf{e}_{2} \\ \downarrow & \downarrow \end{array}\right]\left[\begin{array}{cc} y_{2} & -x_{2} \\ -y_{1} & x_{1} \end{array}\right] tb=x1y2x2y11e1e2[y2y1x2x1]
    其中右边式子中的变量全部已知,自然就已经成功求出t,b两轴向量,再加上原几何法线向量n,至此便已经得出了切线空间(tbn)。法线贴图的数据就存储在空间之下,对于没有变动的法线向量就是(0,0,1)而这恰巧也就解释了为什么法线贴图大部分都是蓝色的(因为大部分法线一般不变动)。

    具体实施的时候只需利用[t b n]向量组成的矩阵乘以法线贴图上的存储3维信息,即可得到正确的法线向量了,此时正确法线向量所存在的坐标系与用在构建该坐标系的n是同一个坐标系下(当然也就是记录p0,p1,p2的坐标系)。

    以下tips不想深究的可以跳过,不影响之后阅读

    tips: 1.求出来的t,b两轴并不一定保证垂直,有时候还需再加一步施密特正交化如下:(提一句施密特正交化的几何意义就是减去除了与之垂直的所有分量值,剩下的就只有垂直分量了)

    t ⊥ = normolized ⁡ ( t − ( t ⋅ n ) n ) \mathbf{t}_{\perp}=\operatorname{normolized}(\mathbf{t}-(\mathbf{t} \cdot \mathbf{n}) \mathbf{n}) t=normolized(t(tn)n)(t减去t平行于n的分量,得到t与n垂直分量)

    b ⊥ = normolized ⁡ ( b − ( b ⋅ n ) n − ( b ⋅ t ⊥ ) t ⊥ ) \mathbf{b}_{\perp}=\operatorname{normolized}\left(\mathbf{b}-(\mathbf{b} \cdot \mathbf{n}) \mathbf{n}-\left(\mathbf{b} \cdot \mathbf{t}_{\perp}\right) \mathbf{t}_{\perp}\right) b=normolized(b(bn)n(bt)t)
    (b减去b平行于 t ⊥ t_{\perp} t的分量,再减去与n的平行分量,剩下的就是与n, t ⊥ t_{\perp} t垂直的分量,想象将b分为3个沿着基向量方向的向量之和即可)

    tips: 2.真正存储的时候只需要t 和 n即可,第三轴可以直接叉乘得到。并且将t和n作为顶点的属性进行存储,正如顶点n是共享该点的面法线均值,t同样是所有共享该点的三角面分别计算出来t的均值,与法线可以作为定点属性插值一样,t也可以

    2 Bump Maps

    Bump Maps其实与Normal Maps十分类似,Normal Maps直接存储了法线信息,而Bump Maps存储的是该点逻辑上的相对高度(可为负值),该高度的变化实际上表现了物体表面凹凸不平的特质,利用该高度信息,再计算出该点法线向量,最后再利用该法线计算光照,这就是Bump Maps的过程,只不过比直接的Normal Maps多了一步从height到normal向量。

    那么所需要关心的问题就是,如何从相对高度计算出法线向量呢?

    该过程也很容易理解,这里就直接用闫老师课上的Slides作为解答了,2维情况如下:

    3维情况可以类推得到:


    正如最后一点所标注的,所有计算出来的法线都是局部坐标即切线空间之下,因此还需要左乘[t b n]矩阵转到(世界)相机坐标系之下得到正确法向!

    3 Displacement Maps

    Displacement Maps其实又与Bump Maps十分类似了,在第二章作者提到了,Bump Maps是逻辑上的高度改变,而Displacement Maps则是物理上的高度改变,二者的区别就在此处,可以通过物体阴影的边缘发现这点:

    4 Environment Maps

    终于到了最后一点,环境光映射了,顾名思义就是将环境光存储在一个贴图之上。想象这样一个情形,光照离我们的物体的距离十分遥远,因此对于物体上的各个点光照方向几乎没有区别,那么唯一的变量就是人眼所观察的方向了,因此各个方向的光源就可以用一个球体进行存储,即任意一个3D方向,都标志着一个texel:

    进一步就像地球仪一样,利用墨卡托投影或是其它类似的方法将球上的信息转换成一个平面上,就得到了环境Texture了:

    以下给出分别在光线追踪以及Blinn-Phong模型利用环境映射的伪代码:(不熟悉光线追踪可以掠过该部分伪代码)

    可以看到在光线未能撞击物体的时候,会利用光线方向求得展开之后贴图上的(u,v)坐标,再去查询颜色返回。

    对于Blinn-Phong模型来说只需增加一项反射的颜色即可,如下:


    利用观察方向相对于法线的反射方向去查询环境映射的颜色值。

    但是用一个球体来存储环境光有一个比较明显的缺点,仔细观察上文当中展开的那副Texture图可以观察看到,上方和下方均有较为严重的扭曲,因此另外一种存储的方法就是Cube Map,也就是天空盒:

    一个天空盒有6幅Texture来表示,明显相对球体少了很多扭曲的情况,但是中间多了一步从方向到面上的计算:

    简单来说就是利用方向计算出与对应平面上的交点坐标,剔除平面所对应的一维,剩下来的两维坐标转换到(0,1)范围之内即为(u,v)坐标。

    举个例子: 一个方向为(1,2,3)则其与z = 1平面的交点为(1/3,2/3,1) (找最近的平面交点),剔除z轴之后剩下为(1/3,2/3), 在进行(1+x)/2的转换(因为方向存在负值,而uv坐标不存在),则得到z = 1的那一幅Texture上的 uv坐标为(2/3,5/6)。

    5 阴影贴图Shadow Maps

    5.1 阴影贴图的原理及其缺陷

    从光栅化的过程一路走来会发现阴影这个问题一直没有涉及,今天就可以真正的利用阴影贴图来一定程度上的解决这个问题了!

    首先,思考一个问题,为什么会有阴影?

    因为光源照射不到,更具体点,摄像机能看到的地方,光源“看”不见。

    而这正是启发阴影贴图这种做法的动机,接下来我们便来看看详细过程是怎么样的。

    第一步,把光源当做一个摄像机让它去看,去渲染整个场景一遍从而得到从光源视角的深度Buffer,记为 d m a p d_{map} dmap
    (注:此时得到的这个 d m a p d_{map} dmap 即为shadow maps)

    第二步,从设定好的摄像机位置去真正的渲染场景得到摄像机视角的深度Buffer,记为 d d d

    第三步,将所有摄像机视角可见点,利用光源视角下的那一套投影矩阵,重新投影回光源,找到与之对应的 d m a p d_{map} dmap上的深度值

    如果该点在 d m a p d_{map} dmap上的深度值与 d d d上的深度值相等,则说明此点可被光源与摄像机共同看见,因此不在阴影中,如下图这种情况

    如果该点在 d m a p d_{map} dmap上的深度值小于 d d d上的深度值,则说明此点不可被光源看见,但摄像机看得见,即该点前方有物体遮挡,因此在阴影中,如下图这种情况

    如此便能确定每个可见像素点是否在阴影之中了,如果在阴影之中就不去计算Blinn-Phong中的镜面反射项与漫反射项。效果如下图:

    对应可视化的shadow maps如下,距离光源越近代表深度越小,所以颜色越黑,反之亦然:

    对于shadow maps还有几点小细节可以谈(可略过)
    1 浮点数难以判断相等,所以一般会有一个tolerance

    2 shadow maps查询时不采用双线性插值,只寻找最近的点,因为倘若插值发生在物体边缘时,与邻接点的深度差距很大,会导致插值结果会有很大的误差

    3 属于硬阴影,只适用于点光源

    软硬阴影示意如下,上方棱角分明为硬阴影,下方为软阴影:
    在这里插入图片描述
    产生这种问题的原因是因为光源具有体积,导致,有的地方完全看不到光源(本影, Umbra), 有的地方能看到一部分光源(半影,Penumbra)。所以阴影的边缘会有过渡的情况,从而产生软阴影现象,就像上图中太阳与地球的示意一样(全日食与半日食)

    总结

    这部分纹理映射的应用内容很多,也有一定的难度,我写的时候也在闫令琪老师课上所讲的内容之上添加了不少东西,参考了不少其它的书籍资料。

    最后如果大家觉得有用的话求点赞求收藏求一个大大的关注 😃 ,后序会持续更新,感谢阅读!

    Reference

    [1] Fundamentals of Computer Graphics 4th
    [2] GAMES101-现代计算机图形学入门-闫令琪
    [3]【D3D11游戏编程】学习笔记二十四:切线空间(Tangent Space)
    [4]Foundations of Game Engine Development, Volume 2

    展开全文
  • 为了实现二次曲面的纹理映射在分析OpenGL纹理映射技术的基础上,详细讨论了球形曲面纹理坐标的生成和设置,然后利用OpenGL函数库,在VC++环境下,实现了雷达天线罩迷彩纹理贴图的效果展示,
  • 将基于图像拉伸和折叠获得的新二维映射用于图像位置置乱,将含有混沌映射的扩散函数用来改变原图各像素点的灰度值,从而得到位置置乱和灰度置乱相结合的加密算法。实验仿真结果表明该算法能够很好地实现对任意大小和...
  • 纹理映射

    千次阅读 2017-10-23 09:30:03
    实时渲染领域内,纹理拾取、映射及过滤涉及大量理论知识,本文是对这些知识的...纹理拾取、映射及过滤在实际应用主要集中在pixel shader阶段。Shader Model 3.0引入vertex texture fetch(VTF,可实现Height Ma

        实时渲染领域内,纹理拾取、映射及过滤涉及大量理论知识,本文是对这些知识的总结和梳理。

    纹理拾取、映射及过滤在实际应用主要集中在pixel shader阶段。Shader Model 3.0引入vertex texture fetch(VTF,可实现Height Mapping和Displacement Mapping),开启了在非pixel shader阶段进行纹理拾取的大门,而最新的Shader Model5.0,纹理拾取可以在任意shader阶段进行(例如tessellation后在domain shader进行Displacement Mapping),但是,在实际编码过程中有一些疑问:为什么tex2D(或TextureObject.Sample)函数只能在pixel shader内使用?Pixel的纹理坐标就真如某些入门书籍说的那样简单的线性插值就可以得出?为什么会出现mipmap chain?纹理LOD又是什么,如何确定?这篇总结阐述渲染流水线内纹理映射的过程及原理,当理解原理后,问题的正确答案就会出现。

    纹理映射过程主要分为三个步骤:1.为三维模型顶点与纹理坐标建立合理的映射关系;2.通过渲染流水线光栅化,顶点纹理坐标将转换为屏幕像素对应的纹理坐标;3.根据像素对应的纹理坐标及采样算法拾取纹理。

    建立映射关系

    顶点与纹理坐标建立映射关系,这种关系可以是数学的(例如球体,圆柱体的纹理坐标可以通过计算得到),也可以是手工指定的(例如不规则形状的纹理坐标)。这种映射关系可以在建模的时候建立并保存在三维模型的顶点数据内,也可以推迟到渲染的时候才确定(例如在vertex shader内指定),甚至还可以两者结合。

    目前主流3D实时渲染 API,纹理坐标都是使用规格化[0,1]区间表示,这样做的好处就是建模时不需要考虑纹理的具体分辨率。规格化纹理坐标和纹理分辨率之间的转换逻辑由纹理采样算法处理,也就是在GPU的TMU内处理。

    屏幕像素对应的纹理坐标

    建立好映射关系的顶点数据,将交由渲染流水线进行渲染。在渲染流水线的Geometry Stage(包括Input Assembly、Vertex Shader、Hull Shader、Tessellator、Domain Shader、Geometry Shader)内可以对纹理坐标做一些转换,例如旋转和平移(texture animation)。当顶点数据通过Geometry Stage后,将到达Rasterizer Stage(GPU对应的模块ROP),经过Rasterizer Stage的Triangle Setup和Triangle Traversal后,得到待shading的pixel(Triangle Traversal就是光栅化,扫描triangle覆盖的fragment,这些fragment将会提交到pixel shader处理),这些pixel将得到来自triangle顶点经插值后的数据,例如颜色(color),纹理坐标(texcoord)和normal。值得注意的是,插值算法常见有两种:1.线性插值;2.经透视修插值(perspective-correct interpolation);从D3D10开始,顶点数据到像素数据的插值算法可手动指定。

    顶点数据线性插值

    使用线性插值,性能最佳,但应用于纹理坐标时,失真严重:

    如上图,左边是纹理坐标线性插值的结果,右边是透视修正插值的结果。理论上,vertex属性都应该使用透视修正插值,但是,有些属性即使使用线性插值,造成的失真也不易被察觉,例如color属性,所以,出于性能的考虑(透视修正插值需要除法运算),一些早期(十几年前)的图形加速器对vertex的color使用的就是线性插值。

    顶点数据透视修正插值

    vertex属性在screen space下线性插值得到的结果并不准确,如下图

    在screen space下线性插值c点属性intensity是0.5,因为c是ab的中点。事实上,c点由C透视投影所得,C属性intensity并不是0.5,因为C并不是AB的中点。计算c点intensity属性的值其实就是计算C点intensity属性。再观察,C的属性就如C的view space下z坐标一样是线性变化的,如果能计算出C的view space下z坐标,C的其他属性就可以根据相同的方法计算出来,如下图:

    观察得知,由于C点view space下z坐标Zt与C点属性都由AB线性插值得到,只要计算出Zt与s的关系,c的属性It也可以用同样的方法得到。Zt与s的关系推导过程如下:

    首先,根据上图,可得到如下结论

     

    根据线性插值,得到

    把(4)和(5)代入(3)得到

    把(1)和(2)代入(7)得到

    把(6)代入(8)得到

    于是得到

    把(10)代入(6)得到

    化简

    等式(12)表示,Zt倒数可由Z1、Z2倒数线性插值得到。需要注意的是,这里的Z1、Z2、Zt均是view space下的z坐标,也就是经过projection transform之后的w。得到等式(12)后,It的计算就易于反掌了,其推导过程如下:

    首先,It表示为

    把(10)代入得到

    可整理成

    观察分母为Zt的倒数,所以得到

    所以,通过s以线性插值方式仍然可以得到正确的It,但插值的对象是I1/Z1、I2/Z2,插值之后还要除以1/Zt。

    纹理拾取

    经过Triangle Traversal得到的pixel将提交到pixel shader处理,这些pixel对应的经插值后的vertex属性将成为pixel shader的输入。需要注意的是,Triangle Traversal并不是按扫描线一行一行的进行,而是按“Z”形式进行,顺序如:

    1  2  5  6

    3  4  7  8

    9  10

    11  12

    并且,pixel shader也会以最小为4并行度执行。按“Z”形式光栅化及最小为4并行执行pixel shader为纹理拾取及过滤提供基础支持,要理解这种设计就需要了解纹理拾取过程遇到的问题和解决方法。

    纹理拾取过程中,由于纹理坐标是规格化[0,1]区间内的浮点数,在换算成具体的纹理坐标时,可能得到非整数的情况:坐标值在两个texel之间,例如纹理分辨率为256*256,规格化纹理坐标是u,v(0.01,0.01),对应的具体坐标就是(2.56,2.56)。通过规格化纹理坐标采样纹理的方法称为纹理过滤算法。就上述情况,有两个过滤算法可供选择:1.最近点采样;2.双线性插值。这两个算法是最基本纹理过滤算法,而一些更高级的过滤算法提供了更高质量的采样效果,例如三线性过滤及各项异性过滤,下面将逐一介绍:

    最近点采样 Nearest Point Sampling

    假如具体坐标就是(2.56,2.56),由于2.56与3这个整数最接近,所以,采样将发生在(3,3)这个位置。最近点采样性能最优,因为它只需要1次访存;效果自然是最差,无论放大还是缩小,只要当pixel与texel不是一一对应时,失真严重。经典游戏CS使用软渲染方法时,纹理拾取就是最近点采样,有兴趣的可以去看看效果。

    双线性插值 Bilinear Interpolation

    双线性插值,与最近点采样算法差不多,只不过把采样数目提升到4,然后在混合得到最终pixel的颜色。例如具体坐标(2.56,2.56),则会在(2,2) (2,3) (3,2) (3,3)进行采样,然后在u和v方向各做一次线性插值,得到最后的颜色。

    双线性插值会产生4次访存,由于现时的GPU texture cache(对了,请注意cache的发音与cash相同,也可以用</span><span style="font-family: 宋体;">来代表,例如</span><span style="font-family: Times New Roman;">L2&nbsp;<script type="math/tex" id="MathJax-Element-5">来代表,例如L2 </script>就是只L2 cache)系统也是按“Z”形式进行prefetch,所以这4次访存的cache命中率相当高,对性能影响有限。

    三线性插值 Trilinear Interpolation

    使用上述两种方法,可以根据一个规格化纹理坐标拾取一个颜色值。接下来,一个新的问题出现,试想一张256*256的texture映射到一个远离投影平面的三角形上,这个三角形只覆盖了4个pixel,那么,这4个pixel无论使用最近点采样还是双线性插值,都无法反映整个texture的内容,因为这4个pixel只反映了texture的很小一部分内容,也就是说产生了失真。

        要消除失真,就要弄明白失真产生的原理。一个pixel覆盖多少个texel,是由pixel对应的三角形到投影平面的距离决定,距离越远,覆盖的texel就越多。当pixel覆盖多个texel,失真就产生了,因为采样频率——pixel严重低于信号频率——texel。那么,消除失真就是a.提升采样频率,用足够多的采样确定一个pixel;b.降低信号频率,降低texture的细节,当pixel一一对应texel时,失真也就消除了。

        按常理来说,方法a是首选的,而事实上,解决纹理映射失真使用的是b方法。这是因为,要求解一个pixel需要多高的采样频率并按这个频率进行采样再混合,是无法在常量资源需求及常量时间内完成,所以这个方法不适用于实时渲染。方法b降低texture细节通过mipmap实现。

    mipmap生成一个金字塔,最底层是原始texture,然后每增加一层,就缩小1/4大小(4texel混合为一个texel),直到只剩下一个texel为止,如图:

    当一个pixel进行纹理映射(texture mapping)时,如果pixel覆盖的texel少,就使用较底层的mipmap进行采样,如果覆盖像素多,就使用较顶层的mipmap采样,务求保证pixel一一对应texel,减少失真。实际操作过程中,一个pixel使用哪一层(或两层)mipmap进行采样并不是由pixel覆盖多少个texel来决定(如方法a,这种计算不适用于实时渲染),而是由pixel纹理坐标变化率决定,当变化率越大,就说明pixel覆盖的texel数量越多。

    如何计算出pixel的纹理坐标变化率?似乎与微分、导数有关,而实际应用中,计算pixel与邻近pixel属性(例如纹理坐标)的一阶差分,可近似得到属性的数值导数。计算一阶差分由HLSL内置函数ddx,ddy完成。ddx是pixel的属性延屏幕x方向的数值导数,ddy就是pixel的属性延屏幕y方向的数值导数。注意,ddx和ddy只能在pixel shader内使用,这是因为:1.只有pixel shader阶段,才有屏幕方向的概念,pixel shader处理的正是屏幕上的pixel,其他shader阶段根本就没有pixel的概念;2.pixel的属性只是计算过程的中间变量,要计算邻近pixel中间变量之差,这些邻近pixel必须在同一时间处理,而且在屏幕x及y方向最小并行粒度必须是2。前面提及,光栅化过程是以“Z”形式进行,而且pixel shader并行度最小为4,这都是为了ddx及ddy而产生的设计。下面举例说明ddx(原理和ddy类似)是怎么执行的。假如下面4个像素对应的pixel shader并行执行到ddx函数:

    A B

    C D

    负责A像素的pixel shader调用ddx(texcoord),那么,将可能返回A.texcoord - B.texcoord,B像素的pixel shader调用ddx(texcoord)时,将可能返回B.texcoord - A.texcoord。

        使用ddx和ddy计算出变化率后,就可以根据变化率确定mipmap层。一般情况下,使用变化率最大值来决定mipmap层,这个值就叫LOD(level of detail)。实际上LOD通常不是整数,即落在两层mipmap之间,这时,采样会先在相关的两层mipmap内进行一次双线性插值采样,得到两个参考值,然后根据这两个参考值,使用LOD再次进行双线性插值,得到最终结果。这就是三线性插值。这个过程在pixel shader内可使用TextureObject.Sample(sampler_state, uv)来完成,其实质就是TextureObject.SampleGrad(sampler_state, uv, ddx(uv), ddy(uv))。因为TextureObject.Sample隐含依赖ddx和ddy,所以这个方法只能在pixel shader内使用。在非pixle shader阶段采样纹理,就需要手动指定LOD,使用方法TextureObject.SampleLevel(sampler_state, uv, lod)。

    各向异性过滤 Anisotropic Filter

        三线性插值对平行于投影平面的三角形能得到很好的纹理过滤效果。因为平行于投影平面的三角形无论远离还是接近视点,三角形所对应的pixel在屏幕坐标x和y方向对纹理坐标uv的变化是相等的——即各向同性(isotropy),而mipmap的产生方式也是各向同性,uv方向都为1/4,所以两者配合得天衣无缝。

    而实际应用中,三角形与投影平面总是带一定的夹角,这使得pixel在屏幕坐标x和y方向对纹理坐标uv的变化不相等——各向异性(anisotropy),例如沥青路面的pixel纹理坐标u变化少,但v变化大,如果使用三线性过滤,沥青路面远处就会出现模糊现象。因为三线性过滤的依据使用变化率最大值来决定LOD,又由于三线性过滤是各向同性过滤,所以采样结果是纹理坐标u方向和v都混合了,但我们希望,远处依然清晰可辨,即u方向的混合程度要少于v方向。能够得到这个效果的纹理过滤方法就叫做各向异性过滤(anisotropic filter)。

    下面是各向异性过滤的一种实现方式,如图:

    这种方法,屏幕像素反向投影到纹理空间,在纹理空间形成一个不规则的4边形。这个4边形的短边用以确定mipmap层(LOD)。用短边确定mipmap层保证纹理细节(高频率)。4变形长边方向,生成一条贯穿4变形中心的线段,按过滤等级高低,在线段上进行多次采样并合成,得到最终采样结果。随着过滤等级的提高(16x),在纹理上的采样频率也会提升,最大限度保证纹理的还原度,这种方法的思路也符合前面提到的消除失真方法的a方法。

    这种方式实现的各向异性过滤没有任何方向性的约束,纹理与投影平面无论方向如何、夹角如何,都能得到最佳效果(记得早些年某些GPU各向异性过滤效果会在某些角度失真,它们的实现方式可能是ripmap或者summed-area table)。当然,这种方式会触发大量的纹理拾取,GPU的texture cache机制要足够的强大才能保证性能不会有大的损失。

    结束

        pixel shader通过纹理过滤算法拾取纹理,把拾取结果用于光照计算,并根据具体情况,决定是否把计算结果输出到Output Merge阶段(pixel shader clip/discard)。pixel shader一旦决定把计算结果输出到Output Merge阶段,这些计算结果就会参与z test、stencil test,当全部test都pass后,这些结果就会记录到render target对应的位置。当这个render target是back buffer时,在present之后,就可以通过屏幕观察到这些pixel。

    展开全文
  • 得到全景图纹理,如何将这个纹理应用与其他物体上呢? 举个例子,比如需要映射茶壶上的一个点(A点),首先计算眼睛(E点)在这点的反射向量r。如何计算r? 很简单 r = 2 * (v · n)*n - v 其中v为顶点A到E的...

    尼玛等了135天,终于第二个shader出炉了,哥,汗颜啊,真TM扯蛋,不过这几个月都在看一些基础图形的数学知识以及RTR,看了几本过后还是感觉实践才能真正理解所学的东西.好了废话不多说了,这个shader花了我三天的时间(准备的说是三个晚上)国际惯例,先上图:

     

     

     

     

    换个角度

    再换个角度

     

     

    用的图为OGRE里面的那张spheremap.png

     

     

     

     

    下面这个是OGRE里面做出来的效果,它还加了个锈的贴图累加起来的,我就没有做累加了

     

     

     

    另外网上也可以找到另外一张球形环境纹理

     

    我们也用它来show一下(原谅我,好不容易自己写个shader,并且中间有个地方花了我一个小时才改出来,就让我多show一下吧- -!!)

    各种角度:

     

    OK,图就到此吧,下面开始讲下原理,呵呵!

     

    Sphere mapping 和 Cube mapping是常见环境映射技术。Sphere map更早,是较早提出的环境映射的方法。

    这里着重讲下 Sphere mapping 的原理。

    首先给出它的GLSL代码

     

    vec2 SphereMap(in vec3 ecPosition3,in vec3 normal)  
      
    {  
      
        float m;  
      
        vec3 r, u;  
      
        u = normalize( ecPosition3 );  
      
        r = reflect( u, normal);    
        m = 2.0 * sqrt( r.x * r.x + r.y * r.y + ( r.z + 1.0 ) * ( r.z * 1.0 ) );  
      
        return vec2( r.x / m + 0.5, r.y / m + 0.5);  
      
    } 


    我们先会基于这个代码来讲解下原理

    Sphere mapping 是基于这样一个事实:将一个理想高反射的球体置于场景中央,从一个角度无穷远处拍摄此球体,将得到一张全景图。

    例如:

    当然说是全景图,但是在球体背对拍摄方向的场景是看不到的,所以这个全景图是言过其实的,但是的实际效果上是不错的。

    通常我们在场景建模中朝z轴正方向,利用正交投影模拟无穷远处进行渲染就可以得到这个纹理图 或者其它方法。

     

    得到全景图纹理,如何将这个纹理应用与其他物体上呢?

    举个例子,比如需要映射茶壶上的一个点(A点),首先计算眼睛(E点)在这点的反射向量r。如何计算r?

    很简单 r = 2 * (v · n)*n - v

    其中v为顶点A到E的单位方向向量:v =normalize( E - A);

    n为顶点A的单位法线向量。 这样得到的r也为单位向量。

     

    现在我们得到了茶壶上A点眼睛在这点的反射向量,那么如何从纹理上找出与之对应的点呢?

     

    很简单,我们只需要找出纹理上的某点(B点),眼睛在B点的反射向量与A点中眼睛在A点的反射向量一致即可。

    注意:这里观察A点和观察B点的眼睛坐标是不一样,另外A点的单位法向量已经知道,B点的单位法向量并不知道

     

    所以,这里我们需要假设B点中眼睛的反射向量与A点中眼睛的反射向量一致即也为r,从而求出B点的球面坐标

     

    这里最最重要的一点是需要知道的是:纹理是从(0,0,1)方向拍摄的(即B点眼睛的坐标)(注意DX里面是(0,0,-1)),所以将知道的反射光线和(0,0,1)相加,就得出了对应的法线值。 即(r.x,r.y,r.z+1)为B点法线的值,将它进行单位化(r.x,r.y,r.z+1)/sqrt(r.x*r.x+r.y*r.y+(r.z+1.0)*(r.z+1.0)).这样就得到B点处的单位法线向量n'。

    由于点B是在球面上,所以单位法线向量可以想像成点B在单位球面上,为了从3维的球面(当然只是前半球)映射到2维的单位圆上(注意只是个圆,不是正方形),只需要取n'.x,n'.y为2维纹理坐标即可完成映射。

     

    最后这样得到的2维纹理坐标范围为[-1,1],由于纹理坐标的范围为[0,1],我们需要将坐标范围缩小一半,并右移0.5就得到纹理坐标范围。 OK,整个流程结束!

     

    原理讲完了,上代码吧!有些细节的地方我会在代码里标明:

    /*------------------------------------------------------------
    	SphereEnvMapping.cpp -- achieve sphere environment mapping
    			(c) Seamanj.2013/7/23
    ------------------------------------------------------------*/
    //phase1 : add teapot
    //phase2 : add camera
    //phase3 : add sphere environment mapping shader
    #include "DXUT.h"
    #include "resource.h"
    
    #define phase1 1
    #define phase2 1
    #define phase3 1
    #if phase1
    // Global variables
    ID3DXMesh* pTeapotMesh = 0;
    #endif
    #if phase2
    #include "DXUTcamera.h"
    CModelViewerCamera g_Camera;
    #endif
    #if phase3
    #include "SDKmisc.h"
    ID3DXEffect*		g_pEffect = NULL;       // D3DX effect interface
    IDirect3DTexture9*	g_pSphereEnvTex = 0;
    D3DXHANDLE			g_hTech = 0;
    D3DXHANDLE			g_hWorldViewProj = NULL;       // Handle for world+view+proj matrix in effect
    D3DXHANDLE			g_hWorldView = NULL;
    D3DXHANDLE			g_hWorldViewInv = NULL;
    D3DXHANDLE			g_hSphereEnvTex = NULL;
    #endif
    //--------------------------------------------------------------------------------------
    // Rejects any D3D9 devices that aren't acceptable to the app by returning false
    //--------------------------------------------------------------------------------------
    bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
                                          bool bWindowed, void* pUserContext )
    {
        // Typically want to skip back buffer formats that don't support alpha blending
        IDirect3D9* pD3D = DXUTGetD3D9Object();
        if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
                                             AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
                                             D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
            return false;
    
        return true;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Before a device is created, modify the device settings as needed
    //--------------------------------------------------------------------------------------
    bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
    {
    #if phase2
    	pDeviceSettings->d3d9.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    #endif
        return true;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
    // and aren't tied to the back buffer size
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                         void* pUserContext )
    {
    #if phase1
    	D3DXCreateTeapot( pd3dDevice, &pTeapotMesh, 0);
    #endif
    #if phase2
    // Setup the camera's view parameters    
    	D3DXVECTOR3 vecEye( 0.0f, 0.0f, -5.0f );  
    	D3DXVECTOR3 vecAt ( 0.0f, 0.0f, -0.0f );  
    	g_Camera.SetViewParams( &vecEye, &vecAt );  
    	FLOAT fObjectRadius=1;  
    	//摄像机缩放的3个参数
    	g_Camera.SetRadius( fObjectRadius * 3.0f, fObjectRadius * 0.5f, fObjectRadius * 10.0f );
    	g_Camera.SetEnablePositionMovement( true );
    #endif
    #if phase3
    	HRESULT hr;
    	// Create vertex shader
    	WCHAR str[MAX_PATH];
    	// Read the D3DX effect file
        V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"SphereEnvMapping.fx" ) );
    	// Create the effect 
    	LPD3DXBUFFER pErrorBuff;
    	V_RETURN( D3DXCreateEffectFromFile(
    		pd3dDevice,		// associated device
    		str,			// effect filename
    		NULL,			// no preprocessor definitions
    		NULL,			// no ID3DXInclude interface
    		D3DXSHADER_DEBUG,	// compile flags
    		NULL,			// don't share parameters
    		&g_pEffect,		// return effect
    		&pErrorBuff			// return error messages
    		) );
    	//pErrorBuff
    	// Get handle
    	g_hTech = g_pEffect->GetTechniqueByName("myTechnique");
    	g_hWorldViewProj = g_pEffect->GetParameterByName(0, "g_mWorldViewProj");
    	g_hWorldView = g_pEffect->GetParameterByName(0, "g_mWorldView");
    	g_hWorldViewInv = g_pEffect->GetParameterByName(0, "g_mWorldViewInv");
    	g_hSphereEnvTex = g_pEffect->GetParameterByName(0, "g_txSphereEnvMap");
    
    	// Set texture:
    	D3DXCreateTextureFromFile(pd3dDevice, L"spheremap.bmp", &g_pSphereEnvTex);
    #endif
        return S_OK;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) 
    // or that are tied to the back buffer size 
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                        void* pUserContext )
    {
    #if phase3
    	HRESULT hr;
    	if( g_pEffect )
            V_RETURN( g_pEffect->OnResetDevice() );
    #endif
    #if phase2
    	pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );  
    	//关闭光照处理, 默认情况下启用光照处理   
    	pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );  
    //Setup the camera's projection parameters   
    	float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;  
    	  
    	g_Camera.SetProjParams( D3DX_PI / 2, fAspectRatio, 0.1f, 5000.0f );  
    	g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );  
    	g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_RIGHT_BUTTON ); 
    #endif
    
        return S_OK;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Handle updates to the scene.  This is called regardless of which D3D API is used
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
    {
    #if phase2
    	g_Camera.FrameMove( fElapsedTime );
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Render the scene using the D3D9 device
    //--------------------------------------------------------------------------------------
    void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        HRESULT hr;
    
        // Clear the render target and the zbuffer 
        V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) );
        // Render the scene
        if( SUCCEEDED( pd3dDevice->BeginScene() ) )
        {
    #if phase3
    		UINT iPass, cPasses;
    		D3DXMATRIXA16 mWorldViewProjection,mWorldView,mWorldViewInv;
    		V(g_pEffect->SetTechnique(g_hTech));
    		V( g_pEffect->Begin( &cPasses, 0 ) );
    		for( iPass = 0; iPass < cPasses; iPass++ )
    		{
    			V( g_pEffect->BeginPass( iPass ) );
    			//set WorldViewProject matrix
    			mWorldViewProjection = *g_Camera.GetWorldMatrix() * *g_Camera.GetViewMatrix() * 
    				*g_Camera.GetProjMatrix();
    			 V( g_pEffect->SetMatrix( g_hWorldViewProj, &mWorldViewProjection) );
    			 //set WorldView matrix
    			 mWorldView = *g_Camera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
    			 V( g_pEffect->SetMatrix( g_hWorldView, &mWorldView) );
    			 //set WorldViewInv matrix
    			mWorldViewInv = *D3DXMatrixInverse(&mWorldViewInv, 0, &mWorldView);
    			V( g_pEffect->SetMatrix( g_hWorldViewInv, &mWorldViewInv) );
    			 //set texture
    			 V( g_pEffect->SetTexture( g_hSphereEnvTex, g_pSphereEnvTex) );
    
    
    #if phase1
    			pTeapotMesh->DrawSubset( 0 );
    #endif
    			V( g_pEffect->EndPass() );
    		}
    		V( g_pEffect->End() );
    #endif
            V( pd3dDevice->EndScene() );
        }
    }
    
    
    //--------------------------------------------------------------------------------------
    // Handle messages to the application 
    //--------------------------------------------------------------------------------------
    LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                              bool* pbNoFurtherProcessing, void* pUserContext )
    {
    #if phase2
    	g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
    #endif
        return 0;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Release D3D9 resources created in the OnD3D9ResetDevice callback 
    //--------------------------------------------------------------------------------------
    void CALLBACK OnD3D9LostDevice( void* pUserContext )
    {
    #if phase3
    	if( g_pEffect )
            g_pEffect->OnLostDevice();
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Release D3D9 resources created in the OnD3D9CreateDevice callback 
    //--------------------------------------------------------------------------------------
    void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
    {
    #if phase1
    	SAFE_RELEASE(pTeapotMesh);
    #endif
    #if phase3
    	SAFE_RELEASE(g_pEffect);
    	SAFE_RELEASE(g_pSphereEnvTex);
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Initialize everything and go into a render loop
    //--------------------------------------------------------------------------------------
    INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
    {
        // Enable run-time memory check for debug builds.
    #if defined(DEBUG) | defined(_DEBUG)
        _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif
    
        // Set the callback functions
        DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
        DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
        DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
        DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
        DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
        DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
        DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
        DXUTSetCallbackMsgProc( MsgProc );
        DXUTSetCallbackFrameMove( OnFrameMove );
    
        // TODO: Perform any application-level initialization here
    
        // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
        DXUTInit( true, true ); // Parse the command line and show msgboxes
        DXUTSetHotkeyHandling( true, true, true );  // handle the default hotkeys
        DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
        DXUTCreateWindow( L"SphereEnvMapping" );
        DXUTCreateDevice( true, 640, 480 );
    
        // Start the render loop
        DXUTMainLoop();
    
        // TODO: Perform any application-level cleanup here
    
        return DXUTGetExitCode();
    }
    
    
    


     

    /*--------------------------------------------------------------------------
    	SphereEnvMapping.fx -- Sphere environment mapping shader 
    						(c) Seamanj.2013/7/23
    --------------------------------------------------------------------------*/
    
    //--------------------------------------------------------------------------------------
    // Global variables
    //--------------------------------------------------------------------------------------
    float4x4 g_mWorldViewProj;
    float4x4 g_mWorldView;
    float4x4 g_mWorldViewInv;
    texture g_txSphereEnvMap;
    //-----------------------------------------------------------------------------
    // Sampler
    //-----------------------------------------------------------------------------
    sampler2D g_samShereEnvMap =
    sampler_state
    {
        Texture = <g_txSphereEnvMap>;
        MinFilter = Linear;
        MagFilter = Linear;
        MipFilter = Linear;
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex shader output structure
    //--------------------------------------------------------------------------------------
    struct VS_Output {
      float4 position : POSITION;
      float2 EnvTex : TEXCOORD0;
    };
    
    
    float2 SphereMap(float3 position, float3 normal)
    {
    	float m;
    	float3 r,u;
    	u = normalize(position);
    	r = reflect(u, normal);
    	m = 2.0 * sqrt( r.x * r.x + r.y * r.y + (r.z - 1.0) * (r.z - 1.0) );//DX中这里是减
    	return float2(r.x / m + 0.5, r.y / m + 0.5);
    }
    
    
    
    //--------------------------------------------------------------------------------------
    // Vertex shader
    //--------------------------------------------------------------------------------------
    VS_Output myVertexEntry(float4 position : POSITION,float3 normal : NORMAL)
    {	
      VS_Output OUT;
    
      OUT.position = mul ( position, g_mWorldViewProj);
      position = mul( position, g_mWorldViewProj);
      //normal = mul( normal, (float3x3)g_mWorldView);//这句太重要了,花了我一个小时,如果没这句,环境上的贴图会跟着茶壶转
      //另外本来应该是乘以变换矩阵的转置的逆,但是这里只考虑了旋转对法向量的影响,毕竟平移对法向量没有影响
      //所以只需要左上角3x3子矩阵的转置的逆,由于本例只包括了旋转所以左上角的3x3子矩阵是个正交矩阵,我们可以
      //用法向量直接这个子矩阵,但是为了严谨我们还是乘以它的转置的逆(因为除了旋转和反射是正交矩阵,缩放和挤压可不是),
      //然后再单位化下,真TM扯蛋,hlsl不支持矩阵的逆
      normal = mul ( normal, transpose((float3x3)g_mWorldViewInv));
      normal = normalize(normal);
      OUT.EnvTex = SphereMap(position.xyz , normal);
      return OUT;	
    }
    
    
    
    //--------------------------------------------------------------------------------------
    // Pixel shader
    //--------------------------------------------------------------------------------------
    float4 myPixelEntry(float2 Tex : TEXCOORD0) : COLOR
    {	
    
      return tex2D(g_samShereEnvMap, Tex);
    }
    
    
    //--------------------------------------------------------------------------------------
    // Renders scene to render target
    //--------------------------------------------------------------------------------------
    technique myTechnique
    {
        pass P0
        {          
            VertexShader = compile vs_2_0 myVertexEntry();
            PixelShader = compile ps_2_0 myPixelEntry();
        }
    }


     

     

     

    可执行程序以及相关源代码请点击这里下载

     

    不好意思,要收你10分,呵呵 ,因为我的分实在不够用了,好了,睡觉了,6点20了....

     

    展开全文
  • JS图像映射应用,在一个图片点击或移动到不同位置有不同响应 function writeText(txt) { document.getElementById("desc").innerHTML=txt
  • 计算共形几何讲座笔记

    千次阅读 2017-08-28 11:36:43
    2)为什么研究共形几何?有哪些好处 3)能解决哪些问题?工程中有什么应用?现在还有哪些问题需要解决   现代几何在工程和医学中的应用   几何是研究各种变换群下的不变量。工程上常用的几何是 1)拓扑:...
  • OpenGL 纹理映射

    千次阅读 2014-02-06 11:11:37
    纹理映射 (texture mapping) 本章你将学到 纹理映射基础知识纹理坐标纹理对象及绑定纹理过滤mipmap和自动生成mipmap纹理参数, 外包模式, 细节级别纹理环境和纹理函数 Table of Contents 1 ...
  • 我们在描述紧凑自由玻色子及其their 2 $$ {\ mathrm {\ mathbb {Z}}} _ 2 $$球面的二维c = 1共形场理论之间构造了一类共形界面。 通过在相应的c = 2乘积理论中构造边界状态并应用展开过程来获得界面。 我们计算所有...
  • 四元数指数映射旋转参数化的实际应用哪吒三太子 2016/3/26 于上海卢湾下面为本文使用术语表,表中所有词条大多直接采用英文术语,请各位读者自行伸缩去取,笔者在此不做所谓”直译”. - DOF(degree-of-freedom) 旋转...
  • 应用到研究单一性极限附近的超冷原子气体的推动,我们研究了非相对论共形场论(NRCFTs)中算子乘积展开(OPE)的结构。 我们分析中使用的主要工具是NR-CFT中带电(即非零粒子数)算子的表示理论,尤其是非相对论...
  • Three.js进阶篇之9 - 纹理映射和UV映射

    千次阅读 2017-03-28 00:35:06
    本文将详细描述如何使用Three.js给3D对象添加贴图(Texture Map,也译作纹理映射,“贴图”的翻译要更直观,而“纹理映射”更准确。)。为了能够查看在线演示效果,你需要有一个兼容WebGL的现代浏览器(最好是Chrome...
  • Hololens入门之空间映射

    千次阅读 热门讨论 2016-09-07 15:45:57
    Hololens入门之空间映射 本文主要讲述使用HoloToolkit项目中提供的空间映射组件,便捷快速的开始使用空间映射特性,...通过将真实世界和虚拟世界的合并,一个应用程序可以使得全息图像显得更加真实。 空间映射(Spat
  • 数据库应用技术考作业一 第一章 思索和练习题 一选择题 1三级模式间存在两种映射它们是? c A模式和子模式间模式和内模式间 B子模式和内模式间外模式和内模式间 C外模式和模式间模式和内模式间 D模式和内模式间模式...
  • 数据库应用技术考作业一 第一章 思索和练习题 一选择题 1三级模式间存在两种映射它们是? c A模式和子模式间模式和内模式间 B子模式和内模式间外模式和内模式间 C外模式和模式间模式和内模式间 D模式和内模式间模式...
  • windwos 端口转发、端口映射

    千次阅读 2018-08-09 14:38:14
    端口映射、转发的应用场景一般在于将两个不可以直接建立连接的设备,通过一个中间媒介建立一个类似于直接连接的间接连接。 举个例子,A和B是两个不同局域网内的设备,A和B之间不互通,但C既在A所在的局域网内也在B...
  • 介绍了 Hessian矩阵在多元向量值...在调和映射方面,提供了用 Hessian矩阵刻画水平弱共形映射的完全提升仍然是水平弱共形映射的等价条件,并在证明过程中揭示出 Hessian矩阵与齐二次多项式、Nabla算子存在的密切关系。
  • 什么是映射

    千次阅读 2018-07-12 05:08:23
    人机之间的映射与数学映射不同。在数学里,映射是个术语,指两个元素的集之间元素相互“对应”的关系,为名词。映射,或者射影,在数学及相关的领域经常等同于函数。 基于此...
  • Python 映射 list

    千次阅读 2013-07-05 14:05:31
    Python 的强大特性之一是其对 list 的解析,它提供一种紧凑的方法,可以通过对 list 中的每个元素应用一个函数,从而将一个 list 映射为另一个 list。 1. List 解析介绍 >>> li = [1, 9, 8, 4] >>> [elem*2 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,660
精华内容 27,064
关键字:

共形映射的应用