zoukankan      html  css  js  c++  java
  • CubeMap视线反射方向计算详解

    其基本原理很多例子上有讲到。下面给出一些比较合适的链接

    http://developer.nvidia.com/object/cube_map_ogl_tutorial.html    NVIDIA官网上的 Opengl Cube texture mapping
    http://www.zwqxin.com/archives/shaderglsl/review-cube-mapping-shader.html  某位兄弟的个人BLOG。
    以上两位都适合OPENGL控。
    本文给出一个DX HLSL例子。并解释了反射方向计算的数学模型。希望能给大家一定的帮助。
    CUBE映射主要分为两步:
    一、在VS中根据法线和观察位置计算反射方向,并且得到观察空间中的反射方向。
    反射方向有两种计算方法。
    1、在世界坐标系空间中计算,然后再将计算到的反射方向转换到观察空间。 这要求我们转入观察位置。
    2、在观察空间中进行计算,此时观察位置已经为0,0,0,于是不需要传入观察位置,并且得到的向量即为所求。本文的代码采用此种方式。


    值得说明的一点是。在进行计算时,入射方向和反射方向以及法线方向并未要求一定要单位化。
    二、用这个反射方向在PS中对CUBE纹理进行采样。

    下面是一个对反射向量计算的通用求解过程。

    我们假设顶点位置为Pos 即点O,视点为Eye 即点A (均为同一坐标系空间)
    那么,我们的观察方向便是Pos-Eye, 即AO。而我们的反射方向便是OC。 法线为OB或OD方向。
    下面我们来看看反射方向的求法
    而由上图可知,OC = AD ;
    而又由OA+AD = OD;OD = 2*OB;可得
     OC = 2*OB-OA;
    而OA = Eye-Pos;
    可得,OC = 2*OB-(Eye-Pos);
    那么,最后我们可以看出,只要求出OB,则可以求出OC。
    而从图上我们可以看到OB即为OA在(法线)OD上的投影。 由此可知, OB = dot(OA,Normal);
    于是可以写出如下公式。
    float3 EyeR = Eye - Pos;  float3 reflectVec = 2*dot(EyeR,Normal)*Normal - EyeR;

    当然,你也可以使用高级语言中的reflect函数来求反射
    在HLSL中。
    ret reflect(i, n)

    v = i - 2 * dot(i, n) * n

    上面的公式中。i为入射方向,v为反射方向,n为法线。
    由于EyeR 为观察方向的反方向,即入射方向的反方向
    所以 reflectVec = reflect(-EyeR,Normal)即可求得。

    最后将reflectVec转换到观察空间,然后对CUBE纹理进行采样即可。

    下面是HLSL中我使用的代码。该代码在D3D SDK的HDRCubeMap.fx中可见。

    //VS
    float4x4 matView;
    float4x4 matProjection;
    struct VS_INPUT 
    {
       float4 Position : POSITION0;
       float2 Texcoord : TEXCOORD0;
       float3 Normal :NORMAL;
    }
    ;

    struct VS_OUTPUT 
    {
       float4 Position : POSITION0;
       float3 Texcoord : TEXCOORD0;
    }
    ;

    VS_OUTPUT vs_main( VS_INPUT Input )
    {
       VS_OUTPUT Output;
       Output.Position 
    = mul(Input.Position,matView);
       
       float3 vN 
    = mul(Input.Normal,matView);
       float3 vEyeR 
    = -normalize(Output.Position);
      
       Output.Texcoord 
    = 2 * dot( vEyeR, vN ) * vN - vEyeR;
       
       Output.Position 
    = mul(Output.Position,matProjection);
       
    return( Output );
    }


    //PS
    samplerCUBE baseMap;

    struct PS_INPUT 
    {
       float3 Texcoord : TEXCOORD0;
       
    }
    ;

    float4 ps_main( PS_INPUT Input ) : COLOR0
    {
       
    return texCUBE( baseMap, Input.Texcoord );
       
    }


    在此对float3 vEyeR = -normalize(Output.Position);作一下解释。
    我们上面讲到的 EyeR的计算为Eye- Pos。 但是,由于N和Pos已转入摄相机空间。则此时的Eye为(0,0,0)。 并且,不一定要单位化vEyeR
    所以上面的解法可以让你不用再传入观察点。
    最后,我们来围观一下效果。




    我是在RenderMonkey中测试的SHADER,所以,上面贴出来的,即为原码。
    下面是用到的cubemap图的样子


    OK,谢谢欣赏,欢迎交流
    GMAIL :BoYueGame

  • 相关阅读:
    第36课 经典问题解析三
    第35课 函数对象分析
    67. Add Binary
    66. Plus One
    58. Length of Last Word
    53. Maximum Subarray
    38. Count and Say
    35. Search Insert Position
    28. Implement strStr()
    27. Remove Element
  • 原文地址:https://www.cnblogs.com/qilinzi/p/1929667.html
Copyright © 2011-2022 走看看